考虑下面的简单程序:
__attribute__((weak)) void weakf(void);
int main(int argc, char *argv[])
{
weakf();
}
当用gcc编译这和Linux的PC上运行它,它出现segfaults。当在ARM CM0(臂-NONE-EABI-GCC)运行它,所述接头通过一个跳转到下面的指令和NOP取代未定义的符号。
这哪里是行为记录?有可能的方式通过命令行选项来改变它呢?我公司已通过GCC和LD文档,也没有这方面的消息。
如果我检查不过ARM编译器文档,this is clearly explained。
man nm
我读了一些文档,碰巧遇到了这样的相关报价:
man nm
说:
“V” “V”的符号是一个弱对象。当弱定义的符号与正常定义的符号链接,正常的定义的符号在使用时没有错误。当弱未定义的符号链接,并且不定义的符号时,弱符号的值变为零,没有错误。在某些系统中,大写字母表示默认值已指定。
“W” “W”的标志是尚未具体标记为弱对象符号的弱符号。当弱定义的符号与正常定义的符号链接,正常的定义的符号在使用时没有错误。当弱未定义的符号链接,并且不定义的符号,符号的值在系统特定的方式没有错误确定。在某些系统中,大写字母表示默认值已指定。
nm
是Binutils的,这GCC引擎盖下使用的一部分,所以这应该是足够的规范。
然后,例如在你的源文件:
main.c中
__attribute__((weak)) void weakf(void);
int main(int argc, char *argv[])
{
weakf();
}
我们的确是:
gcc -O0 -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
nm main.out
其中包含:
w weakf
因此它是一个系统特定的值。我找不到在每个系统的行为无论如何定义。我不认为你可以做的比这里读书Binutils的源码更好。
v
将被固定为0,但用于未定义的变量(其为对象):How to make weak linking work with GCC?
然后:
gdb -batch -ex 'disassemble/rs main' main.out
得到:
Dump of assembler code for function main:
main.c:
4 {
0x0000000000001135 <+0>: 55 push %rbp
0x0000000000001136 <+1>: 48 89 e5 mov %rsp,%rbp
0x0000000000001139 <+4>: 48 83 ec 10 sub $0x10,%rsp
0x000000000000113d <+8>: 89 7d fc mov %edi,-0x4(%rbp)
0x0000000000001140 <+11>: 48 89 75 f0 mov %rsi,-0x10(%rbp)
5 weakf();
0x0000000000001144 <+15>: e8 e7 fe ff ff callq 0x1030 <weakf@plt>
0x0000000000001149 <+20>: b8 00 00 00 00 mov $0x0,%eax
6 }
0x000000000000114e <+25>: c9 leaveq
0x000000000000114f <+26>: c3 retq
End of assembler dump.
这意味着它得到resolved at the PLT。
然后,因为我不完全理解PLT,我用实验来验证它解析为地址0和段错误:
gdb -nh -ex run -ex bt main.out
我假设同样发生在ARM,它必须只将其设置为0为好。
在用gcc ARM这个代码不适合我(在测试的ARMv7与海湾合作委员会的Debian 4.6.3-14 + rpi1)工作。它看起来像ARM编译器工具链有不同的行为。
我没有找到有用的文档,此行为。看来,weakf等于NULL,如果是取消定义在链接时。
因此,我建议你测试一下:
if (weakf == NULL) printf ("weakf not found\n");
else weakf();