add2.c:
int counter=0;
int a=0;
int b;
int c;
int add(int a, int b) {
return a+b;
}
编译: gcc -c add2.c -o add2.o
读取符号表: readelf --symbols add2.o
Symbol table '.symtab' contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS add2.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 2
4: 00000000 0 SECTION LOCAL DEFAULT 3
5: 00000000 0 SECTION LOCAL DEFAULT 5
6: 00000000 0 SECTION LOCAL DEFAULT 4
7: 00000000 4 OBJECT GLOBAL DEFAULT 3 counter
8: 00000004 4 OBJECT GLOBAL DEFAULT 3 a
9: 00000004 4 OBJECT GLOBAL DEFAULT COM b
10: 00000004 4 OBJECT GLOBAL DEFAULT COM c
11: 00000000 14 FUNC GLOBAL DEFAULT 1 add
Ndx 列中的“COM”是什么意思?我知道“counter”和“a”在第 3 节(即 .bss)中定义,“add”在第 1 节(即 .text)中定义,但我期待“b”和“c”也将在 .bss 部分中定义,因此在 Ndx 列中获得“3”。
谢谢
最佳答案
gcc 将未明确声明 extern
的未初始化全局变量视为“通用”符号(因此称为“COM”)。
链接器在创建最终可执行文件时将相同公共(public)符号的多个定义(跨多个目标文件)合并在一起,因此它们都引用相同的存储。其中一个目标文件可能会将其初始化为特定值(在这种情况下它将最终出现在数据部分);如果没有目标文件初始化它,它将在 BSS 中结束;如果有多个对象对其进行初始化,则会出现链接器错误。
总而言之,如果您有两个 int a
的定义:
-
一个对象中的
int a;
和另一个对象中的int a;
是可以的:两者都引用相同的a
,初始化为 0
一个对象中的 int a;
和另一个对象中的int a = 42;
是可以的:两者都引用相同的a
,已初始化到 42
一个对象中的 int a = 23;
和另一个对象中的int a= 42;
将给出链接错误。
请注意,标准 C 在技术上不允许在两个对象中使用同一符号的多个定义;但它作为扩展被许多编译器支持,包括 gcc。 (它列在 C99 规范中的“通用扩展”下——没有双关语意。)
关于c - .symtab 部分的 Ndx 列中的 "COM"是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4137522/