Disagreement of tools for analyzing .bss section size of ELF file
在分析编译为ARM平台的ELF文件的C程序的.bss部分时,我遇到了几种确定大小的方法。问题工具中还提到了我测试的四种方法,用于分析ELF部分和符号的大小。
但是,结果却大不相同:
1 2 3 4 | 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脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #!/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),尽管它们可能是.bss的一部分。但是,并非所有分类为V的节都属于.bss,因此我不能仅将所有V节添加到大小中。那么使用nm不可能完成此任务吗?
这是一个示例汇编器文件,该文件生成一个可执行文件,该可执行文件显示了可能发生的一些事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | .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 |
1 2 | text data bss dec hex filename 0x5c9 0x220 0x2100000 34605033 21007e9 a.out |
1 | [25] .bss NOBITS 0000000001000000 01000000 02100000 0 WA 0 0 16777216 |
但是,符号大小(如
1 2 3 4 5 | 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 之后有大约16 MiB的间隙未使用。由于定义变量的顺序,需要实现var2 的对齐。completed.6963 重用了一些空间。 -
var2 ,var3 ,var4 是别名:符号值相同,因此只有单个对象支持该变量。
此外,由于
1 2 | LOAD 0x000e08 0x0000000000200e08 0x0000000000200e08 0x000220 0x000220 RW 0x200000 LOAD 0x1000000 0x0000000001000000 0x0000000001000000 0x000000 0x2100000 RW 0x200000 |
因此
此示例中的数字肯定过大,但是即使使用常规二进制文件,这些影响也可见,但程度较小。