如果我有tmp.c:
char constantFOO [0x12];char constantBAR [0x34];我看到gcc -c tmp.c -o tmp.o&& nm tmp.o显示
0000000000000034 C constantBAR0000000000000012 C constantFOO但如果我……
我编了你的 tmp.c 无论有没有 -flto -ffat-lto-objects ,在 -S 模式(输出汇编语言),使用GCC 8.3。在这两种情况下,都会发出相同的常量基本定义:
tmp.c
-flto -ffat-lto-objects
-S
.comm constantFOO,18,16 .comm constantBAR,52,32
LTO发出的大多数附加数据都会进入名为的ELF部分 .gnu.lto_.something 。 LTO模式添加了一个额外的标记对象:
.gnu.lto_.something
.comm __gnu_lto_v1,1,1
出现在LTO编译的对象中但不出现在没有的对象中。
从表面上看,这不应影响产量 nm 对于这些符号,以及较低级别的工具 readelf -s 为它们生成匹配输出:
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 是一个bug,应该报告给GNU binutils的维护者(参见 https://sourceware.org/binutils/ )。
对于符号值匹配数组长度的“原始输出”,正在发生的是通常符号的值如下所示 nm 是它在目标文件的部分内的偏移量。但是,常见符号不在任何部分中,也没有偏移量 nm 打印符号的大小作为其值。这就是IIRC,历史行为一直追溯到System V的哪一次迭代都增加了对类似FORTRAN的公共数据的支持。注意如何 readelf -s 打印18和52作为 大小 对象和第三个参数 .comm (每个符号的期望对齐)作为它们的值。
.comm
如果你编译 -fno-common 你会看到不同的输出:
-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 部分并在该部分内具有已定义的偏移量。
.bss
注意 char constantFOO[0x12]; 定义一个 写 0x12的数组 char 秒。如果你想让它实际上是恒定的,你需要说 const char 。 (然后它将被放入 .rodata 对象文件的部分和输出 nm 和 readelf 将再次有所不同。)
char constantFOO[0x12];
char
const char
.rodata
readelf