看起来GCC和-O2和__attribute__((weak))会根据你引用弱符号的方式产生不同的结果。考虑到这一点:
$ cat弱.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测试。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“产生”01 1“而不是”11 1"?
gcc 5.4.0版(GCC)
发布于 2017-04-03 07:11:59
看起来,在进行优化时,编译器在声明为const的符号和在同一个编译单元中的weak定义方面存在问题。
您可以创建一个单独的c文件并将const弱定义移到那里,它可以解决这个问题:
weak_def.c
const int weaksym1 __attribute__(( weak )) = 0;
const int weaksym2 __attribute__(( weak )) = 0;问题中描述的相同问题:常量变量上的GCC弱属性
发布于 2017-04-03 08:07:01
摘要:
只有当不将弱符号初始化为值时,弱符号才能正确工作。链接器负责初始化(如果不存在相同名称的普通符号,则始终将它们初始化为零)。
如果您尝试将弱符号初始化为任何值,甚至像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编译器不能对其值作出任何假设。相反,它将生成像往常一样获取符号地址的代码--这就是正常/弱符号查找魔术发生的地方。
这也意味着弱符号只能被“自动初始化”为零,而不能被任何其他值,除非被相同名称的普通初始化符号“重写”。
https://stackoverflow.com/questions/43177223
复制相似问题