我使用 GCC 8.3以模式(输出汇编语言)编译tmp.c
了带和不带. 在这两种情况下,都会发出相同的常量基本定义:-flto -ffat-lto-objects
-S
.comm constantFOO,18,16
.comm constantBAR,52,32
LTO 发出的大部分附加数据进入名为.gnu.lto_.something
. LTO 模式添加了一个额外的标记对象:
.comm __gnu_lto_v1,1,1
出现在 LTO 编译的对象中,但不在没有的对象中。
从表面上看,这根本不应该影响nm
这些符号的输出,并且较低级别的工具readelf -s
会为它们生成匹配的输出:
$ readelf -s tmp-normal.o
Symbol table '.symtab' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 4
7: 0000000000000010 18 OBJECT GLOBAL DEFAULT COM constantFOO
8: 0000000000000020 52 OBJECT GLOBAL DEFAULT COM constantBAR
$ readelf -s tmp-lto.o
Symbol table '.symtab' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 4
6: 0000000000000000 0 SECTION LOCAL DEFAULT 5
7: 0000000000000000 0 SECTION LOCAL DEFAULT 6
8: 0000000000000000 0 SECTION LOCAL DEFAULT 7
9: 0000000000000000 0 SECTION LOCAL DEFAULT 8
10: 0000000000000000 0 SECTION LOCAL DEFAULT 9
11: 0000000000000000 0 SECTION LOCAL DEFAULT 10
12: 0000000000000000 0 SECTION LOCAL DEFAULT 12
13: 0000000000000000 0 SECTION LOCAL DEFAULT 11
14: 0000000000000010 18 OBJECT GLOBAL DEFAULT COM constantFOO
15: 0000000000000020 52 OBJECT GLOBAL DEFAULT COM constantBAR
16: 0000000000000001 1 OBJECT GLOBAL DEFAULT COM __gnu_lto_v1
因此我认为 的行为nm
是一个错误,应该向 GNU binutils 的维护者报告(参见https://sourceware.org/binutils/)。
至于符号值与数组长度匹配的“原始输出”,通常情况下,符号的值如图所示nm
是它在目标文件的部分中的偏移量。但是,通用符号不在任何部分中,也没有偏移量,因此nm
将符号的大小打印为其值。这是,IIRC,历史行为一直追溯到 System V 的任何迭代添加了对 FORTRAN 类公共数据的支持。请注意如何将readelf -s
18 和 52 打印为对象的大小,并将第三个参数.comm
(每个符号的所需对齐方式)打印为它们的值。
如果你编译-fno-common
你会看到不同的输出:
$ gcc -c -fno-common tmp.c -o tmp-nc.o
$ nm tmp-nc.o
0000000000000020 B constantBAR
0000000000000000 B constantFOO
$ readelf -s tmp-nc.o | grep constant
7: 0000000000000000 18 OBJECT GLOBAL DEFAULT 3 constantFOO
8: 0000000000000020 52 OBJECT GLOBAL DEFAULT 3 constantBAR
因为现在您的数组在该部分中,并且在该.bss
部分中有一个定义的偏移量。
请注意,它char constantFOO[0x12];
定义了一个0x12 的可写数组char
。如果你希望它实际上是恒定的,你需要说const char
。(然后它将被放在目标文件的部分中,并且.rodata
的输出将再次不同。)nm
readelf