CSAPP - Linking - Strong and weak symbols
Posted on 2007-08-02 23:45 ZelluX 閱讀(871) 評論(0) 編輯 收藏 所屬分類: C/C++ 、System《竊聽風暴》的男主角烏爾里希·穆埃(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.
注意這可能不是main()方法的作者原來的意圖。
類似的情況也可能發生在兩個weak symbol同名的時候。
3. 全局變量類型不同的情況:
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則不會發出警告。
好片子,好演員,可惜了。。。
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;
}
#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并被輸出。int x;
void 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;
}
#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;
}
根據書上的內容,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則不會發出警告。