分析ELF文件.bss段大小的工具分歧
Disagreement of tools for analyzing .bss section size of ELF file
在分析为 ARM 平台编译为 ELF 文件的 C++ 程序的 .bss 部分时,我遇到了几种确定大小的方法。我测试的四种方式在问题Tool to analyze size of ELF sections and symbol.
中也有提到
然而,结果却截然不同:
bss size according to nm: 35380
bss size according to readelf: 37632
bss size according to size: 37888
bss size according to objdump: 37594
这可能是什么原因?
Python 用于生成输出的脚本
#!/usr/bin/env python
import re
import subprocess
import sys
fname = sys.argv[1]
# nm
output = subprocess.check_output(['arm-none-eabi-nm','-l','-S','-C',fname])
size = 0
for line in output.splitlines():
m = re.search('[0-9a-f]* ([0-9a-f]*) ([a-zA-Z]) ([^/]*)\s*([^\s]*)',line)
if m:
stype = m.group(2).strip()
if stype in ['B','b']:
size += int(m.group(1),16)
print "bss size according to nm: \t%i" % size
# readelf
output = subprocess.check_output(['arm-none-eabi-readelf','-S',fname])
for line in output.splitlines():
m = re.search('bss\s+[A-Z]+\s+[0-9a-f]+ [0-9a-f]+ ([0-9a-f]+)',line)
if m:
print "bss size according to readelf: \t%i" % int(m.group(1),16)
break
# size
output = subprocess.check_output(['arm-none-eabi-size',fname])
for line in output.splitlines():
m = re.search('[0-9]+\s+[0-9]+\s+([0-9]+)',line)
if m:
print "bss size according to size: \t%i" % int(m.group(1))
break
# objdump
output = subprocess.check_output(['arm-none-eabi-objdump','-C','-t','-j','.bss',fname])
size = 0
for line in output.splitlines():
m = re.search('bss\s+([0-9a-f]*)\s+',line)
if m:
size += int(m.group(1),16)
print "bss size according to objdump: \t%i" % size
编辑: 我发现的一件事是 nm 将函数内部的静态变量(正确地)分类为弱(V),尽管它们可能是 .嘘。但是,并非所有分类为 V 的部分都是 .bss 的一部分,因此我不能只将所有 V 部分添加到大小中。那么这个任务用 nm 是不可能的吗?
这是一个示例汇编程序文件,它生成一个可执行文件,其中显示了一些可能发生的事情:
.section .bss
.globl var1
.size var1, 1
var1:
.skip 1
.align 16777216
.globl var2
.size var2, 1048576
.globl var3
.size var3, 1048576
.globl var4
.size var4, 1048576
var2:
var3:
var4:
.skip 1048576
.text
.globl main
main:
xor %eax, %eax
ret
size -x
给出此输出:
text data bss dec hex filename
0x5c9 0x220 0x2100000 34605033 21007e9 a.out
eu-readelf -S
显示基本相同的信息:
[25] .bss NOBITS 0000000001000000 01000000 02100000 0 WA 0 0 16777216
但是,eu-readelf -s
所示的符号大小完全不同:
32: 0000000001000001 1 OBJECT LOCAL DEFAULT 25 completed.6963
48: 0000000003000000 1048576 NOTYPE GLOBAL DEFAULT 25 var2
49: 0000000003000000 1048576 NOTYPE GLOBAL DEFAULT 25 var4
59: 0000000002000000 1 NOTYPE GLOBAL DEFAULT 25 var1
61: 0000000003000000 1048576 NOTYPE GLOBAL DEFAULT 25 var3
它们的大小之和是 0x300002,而不是 0x2100000。有两个因素促成了这一点:
- 在
var1
之后有大约16MiB的空隙未被使用。由于定义变量的顺序,需要实现var2
的对齐。一些 space 被 completed.6963
重复使用。
var2
、var3
、var4
是别名:符号值相同,所以只有一个对象支持变量。
此外,由于 .bss
对齐要求,.data
部分和 .bss
部分的末尾之间存在很大差距。对于典型的动态加载程序,这只会导致未映射的内存区域:
LOAD 0x000e08 0x0000000000200e08 0x0000000000200e08 0x000220 0x000220 RW 0x200000
LOAD 0x1000000 0x0000000001000000 0x0000000001000000 0x000000 0x2100000 RW 0x200000
所以如果不计算这个差距,size
大概是正确的。
此示例中的数字肯定过多,但即使是常规双星也可以看到这些影响,只是程度较小。
readelf
/size
和 objdump
/nm
差异可能是 ARM 的特性;这些可能是由我的示例中不存在的某些符号类型触发的。
在分析为 ARM 平台编译为 ELF 文件的 C++ 程序的 .bss 部分时,我遇到了几种确定大小的方法。我测试的四种方式在问题Tool to analyze size of ELF sections and symbol.
中也有提到然而,结果却截然不同:
bss size according to nm: 35380
bss size according to readelf: 37632
bss size according to size: 37888
bss size according to objdump: 37594
这可能是什么原因?
Python 用于生成输出的脚本
#!/usr/bin/env python
import re
import subprocess
import sys
fname = sys.argv[1]
# nm
output = subprocess.check_output(['arm-none-eabi-nm','-l','-S','-C',fname])
size = 0
for line in output.splitlines():
m = re.search('[0-9a-f]* ([0-9a-f]*) ([a-zA-Z]) ([^/]*)\s*([^\s]*)',line)
if m:
stype = m.group(2).strip()
if stype in ['B','b']:
size += int(m.group(1),16)
print "bss size according to nm: \t%i" % size
# readelf
output = subprocess.check_output(['arm-none-eabi-readelf','-S',fname])
for line in output.splitlines():
m = re.search('bss\s+[A-Z]+\s+[0-9a-f]+ [0-9a-f]+ ([0-9a-f]+)',line)
if m:
print "bss size according to readelf: \t%i" % int(m.group(1),16)
break
# size
output = subprocess.check_output(['arm-none-eabi-size',fname])
for line in output.splitlines():
m = re.search('[0-9]+\s+[0-9]+\s+([0-9]+)',line)
if m:
print "bss size according to size: \t%i" % int(m.group(1))
break
# objdump
output = subprocess.check_output(['arm-none-eabi-objdump','-C','-t','-j','.bss',fname])
size = 0
for line in output.splitlines():
m = re.search('bss\s+([0-9a-f]*)\s+',line)
if m:
size += int(m.group(1),16)
print "bss size according to objdump: \t%i" % size
编辑: 我发现的一件事是 nm 将函数内部的静态变量(正确地)分类为弱(V),尽管它们可能是 .嘘。但是,并非所有分类为 V 的部分都是 .bss 的一部分,因此我不能只将所有 V 部分添加到大小中。那么这个任务用 nm 是不可能的吗?
这是一个示例汇编程序文件,它生成一个可执行文件,其中显示了一些可能发生的事情:
.section .bss
.globl var1
.size var1, 1
var1:
.skip 1
.align 16777216
.globl var2
.size var2, 1048576
.globl var3
.size var3, 1048576
.globl var4
.size var4, 1048576
var2:
var3:
var4:
.skip 1048576
.text
.globl main
main:
xor %eax, %eax
ret
size -x
给出此输出:
text data bss dec hex filename
0x5c9 0x220 0x2100000 34605033 21007e9 a.out
eu-readelf -S
显示基本相同的信息:
[25] .bss NOBITS 0000000001000000 01000000 02100000 0 WA 0 0 16777216
但是,eu-readelf -s
所示的符号大小完全不同:
32: 0000000001000001 1 OBJECT LOCAL DEFAULT 25 completed.6963
48: 0000000003000000 1048576 NOTYPE GLOBAL DEFAULT 25 var2
49: 0000000003000000 1048576 NOTYPE GLOBAL DEFAULT 25 var4
59: 0000000002000000 1 NOTYPE GLOBAL DEFAULT 25 var1
61: 0000000003000000 1048576 NOTYPE GLOBAL DEFAULT 25 var3
它们的大小之和是 0x300002,而不是 0x2100000。有两个因素促成了这一点:
- 在
var1
之后有大约16MiB的空隙未被使用。由于定义变量的顺序,需要实现var2
的对齐。一些 space 被completed.6963
重复使用。 var2
、var3
、var4
是别名:符号值相同,所以只有一个对象支持变量。
此外,由于 .bss
对齐要求,.data
部分和 .bss
部分的末尾之间存在很大差距。对于典型的动态加载程序,这只会导致未映射的内存区域:
LOAD 0x000e08 0x0000000000200e08 0x0000000000200e08 0x000220 0x000220 RW 0x200000
LOAD 0x1000000 0x0000000001000000 0x0000000001000000 0x000000 0x2100000 RW 0x200000
所以如果不计算这个差距,size
大概是正确的。
此示例中的数字肯定过多,但即使是常规双星也可以看到这些影响,只是程度较小。
readelf
/size
和 objdump
/nm
差异可能是 ARM 的特性;这些可能是由我的示例中不存在的某些符号类型触发的。