《窃听风暴》的男主角乌尔里希·穆埃(Ulrich Mühe)
病逝了。。。好片子,好演员,可惜了。。。CSAPP 第七章Linking太枯燥了
啃了半天总算看到一点实际经历中遇到过的。
在编译阶段,编译器把全局变量标记为strong或者weak,并导出到汇编程序中,由汇编程序把这些信息隐式地添加到relocatable object file的符号表(symbol table)中。
函数和被初始化的全局变量被标记为strong,未初始化的全局变量被标记为weak。
Unix连接器(linker)使用下面的规则来处理多个符号的情况:
1. 不允许多个strong symbol的存在
2. 如果有一个strong symbol和若干个weak symbol,使用strong symbol
3. 只有若干个weak symbol,则使用其中任意一个
几个例子(未特殊说明的情况,变量定义均在全局范围):
1. foo1.c和bar1.c中都有int main()方法,即存在了两个strong symbol,连接器就会产生一条错误信息。
2.
/* foo3.c */
#include <stdio.h>
void f(void);
int x = 15213;
int main()
{
f();
printf("x = %d\n", x);
return 0;
}
/* bar3.c */
int x;
void f()
{
x = 15212;
}
main()方法调用f()后,x变为15212并被输出。
注意这可能不是main()方法的作者原来的意图。类似的情况也可能发生在两个weak symbol同名的时候。
3. 全局变量类型不同的情况:
/* foo5.c */
#include <stdio.h>
void f(void);
int x = 15213;
int y = 15212;
int main()
{
f();
printf("x = 0x%x y = 0x%x \n", x, y);
return 0;
}
/* bar4.c */
double x;
void f()
{
x = -0.0;
}
根据书上的内容,
linux> gcc -o foobar5 foo5.c bar5.c
linux> ./foobar5
结果应该是
x = 0x0 y = 0x80000000
但是在自己机器上编译时报错了,可能连接器版本较高,会自动找出这种错误
/usr/bin/ld: Warning: alignment 4 of symbol `x' in /tmp/ccupQXSG.o is smaller than 8 in /tmp/ccNNG9XZ.o
是double和int大小不义导致的对齐问题
这些问题都比较细小难以被查觉,通常在程序执行了一段时间后才出现较严重的问题,因此很难被修复,尤其当许多程序员不清楚连接器的工作方式的时候。
另外可以使用GCC的-warn-common标记(flag),使得它在解析多个同名的全局变量时发出警告。
试了下没成功@@
gcc --warn-common提示无法识别的命令行选项,gcc -Wall则不会发出警告。