[英]GCC -O2 and __attribute__((weak))
看起來帶有-O2
和__attribute__((weak))
GCC 會根據您引用弱符號的方式產生不同的結果。 考慮一下:
$ catweak.c
#include <stdio.h>
extern const int weaksym1;
const int weaksym1 __attribute__(( weak )) = 0;
extern const int weaksym2;
const int weaksym2 __attribute__(( weak )) = 0;
extern int weaksym3;
int weaksym3 __attribute__(( weak )) = 0;
void testweak(void)
{
if ( weaksym1 == 0 )
{
printf( "0\n" );
}
else
{
printf( "1\n" );
}
printf( "%d\n", weaksym2 );
if ( weaksym3 == 0 )
{
printf( "0\n" );
}
else
{
printf( "1\n" );
}
}
$ cat test.c
extern const int weaksym1;
const int weaksym1 = 1;
extern const int weaksym2;
const int weaksym2 = 1;
extern int weaksym3;
int weaksym3 = 1;
extern void testweak(void);
void main(void)
{
testweak();
}
$ make
gcc -c weak.c
gcc -c test.c
gcc -o test test.o weak.o
$ ./測試
1
1
1
$ make ADD_FLAGS="-O2"
gcc -O2 -c weak.c
gcc -O2 -c test.c
gcc -O2 -o test test.o weak.o
$ ./測試
0
1
1
問題是,為什么最后一個“./test”產生“0 1 1”,而不是“1 1 1”?
gcc 版本 5.4.0 (GCC)
看起來在進行優化時,編譯器在聲明為const
符號和在同一編譯單元中具有weak
定義時遇到了麻煩。
您可以創建一個單獨的 c 文件並將 const 弱定義移到那里,它將解決這個問題:
弱定義文件
const int weaksym1 __attribute__(( weak )) = 0;
const int weaksym2 __attribute__(( weak )) = 0;
此問題中描述的相同問題: GCC weak attribute on constant variables
概括:
弱符號只有在您不將它們初始化為值時才能正常工作。 鏈接器負責初始化(如果不存在同名的正常符號,它總是將它們初始化為零)。
如果您嘗試將弱符號初始化為任何值,甚至像 OP 那樣初始化為零,C 編譯器可以自由地對其值做出奇怪的假設。 編譯器沒有區分弱符號和普通符號; 這都是(動態)鏈接器魔術。
要修復,請從您聲明為弱的任何符號中刪除初始化 ( = 0
):
extern const int weaksym1;
const int weaksym1 __attribute__((__weak__));
extern const int weaksym2;
const int weaksym2 __attribute__((__weak__));
extern int weaksym3;
int weaksym3 __attribute__((__weak__));
詳細說明:
C 語言沒有“弱符號”的概念。 它是由 ELF 文件格式和使用 ELF 文件格式的(動態)鏈接器提供的功能。
正如man 1 nm
手冊頁在"V"
部分所述,
當弱定義符號與正常定義符號鏈接時,正常定義符號的使用不會出錯。 當一個弱未定義符號被鏈接並且該符號未被定義時,弱符號的值變為零且沒有錯誤。
弱符號聲明不應初始化為任何值,因為如果進程未與同名的普通符號鏈接,它的值將為零。 ( man 1 nm
頁面中的“定義”是指存在於 ELF 符號表中的符號。)
“弱符號”功能旨在與現有的 C 編譯器一起使用。 請記住,C 編譯器在“弱”和“正常”符號之間沒有任何區別。
為了確保這在不違反 C 編譯器行為的情況下工作,“弱”符號必須未初始化,以便 C 編譯器不能對其值做出任何假設。 相反,它會像往常一樣生成獲取符號地址的代碼——這就是正常/弱符號查找魔術發生的地方。
這也意味着弱符號只能“自動初始化”為零,而不是任何其他值,除非被同名的普通初始化符號“覆蓋”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.