[英]GCC behavior for unresolved weak functions
Consider the simple program below: 考虑下面的简单程序:
__attribute__((weak)) void weakf(void);
int main(int argc, char *argv[])
{
weakf();
}
When compiling this with gcc and running it on a Linux PC, it segfaults. 使用gcc编译并在Linux PC上运行时,会出现段错误。 When running it on ARM CM0 (arm-none-eabi-gcc), the linker replace the undefined symbol by a jump to the following instruction and a nop.
在ARM CM0(arm-none-eabi-gcc)上运行时,链接器通过跳转到以下指令和nop来替换未定义的符号。
Where is this behavior documented? 这种行为记录在哪里? Is there possible ways to change it through command line options?
是否有可能通过命令行选项更改它? I have been through GCC and LD documentations, there is no information about that.
我已经通过GCC和LD文件,没有相关信息。
If I check the ARM compiler doc however, this is clearly explained . 但是,如果我检查ARM编译器doc, 则可以清楚地解释这一点 。
man nm
I was reading some docs and happened to come across a related quote for this: 我正在阅读一些文档,碰巧遇到了相关的引用:
man nm
says: 说:
"V"
“V”
"v" The symbol is a weak object.“v”符号是一个弱对象。 When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error.
当弱定义符号与正常定义的符号链接时,使用正常定义的符号而没有错误。 When a weak undefined symbol is linked and the symbol is not defined, the value of the weak symbol becomes zero with no error.
当链接弱未定义符号且未定义符号时,弱符号的值变为零而没有错误。 On some systems, uppercase indicates that a default value has been specified.
在某些系统上,大写表示已指定默认值。
"W"
“W”
"w" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.“w”符号是一个弱符号,未被特别标记为弱对象符号。 When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error.
当弱定义符号与正常定义的符号链接时,使用正常定义的符号而没有错误。 When a weak undefined symbol is linked and the symbol is not defined, the value of the symbol is determined in a system-specific manner without error.
当链接弱未定义符号且未定义符号时,符号的值以特定于系统的方式确定而没有错误。 On some systems, uppercase indicates that a default value has been specified.
在某些系统上,大写表示已指定默认值。
nm
is part of Binutils, which GCC uses under the hood, so this should be canonical enough. nm
是Binutils的一部分,GCC在引擎盖下使用,所以这应该是规范的。
Then, example on your source file: 然后,在源文件上的示例:
main.c main.c中
__attribute__((weak)) void weakf(void);
int main(int argc, char *argv[])
{
weakf();
}
we do: 我们的确是:
gcc -O0 -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
nm main.out
which contains: 其中包含:
w weakf
and so it is a system-specific value. 所以它是一个特定于系统的值。 I can't find where the per-system behavior is defined however.
但我无法找到定义每系统行为的位置。 I don't think you can do better than reading Binutils source here.
我认为你不能比在这里阅读Binutils来做得更好。
v
would be fixed to 0, but that is used for undefined variables (which are objects): How to make weak linking work with GCC? v
将固定为0,但用于未定义的变量(对象): 如何使弱连接与GCC一起工作?
Then: 然后:
gdb -batch -ex 'disassemble/rs main' main.out
gives: 得到:
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.
which means it gets resolved at the PLT . 这意味着它在PLT得到解决 。
Then since I don't fully understand PLT, I experimentally verify that it resolves to address 0 and segfaults: 然后因为我不完全理解PLT,我通过实验验证它解析为地址0和段错误:
gdb -nh -ex run -ex bt main.out
I'm supposing the same happens on ARM, it must just set it to 0 as well. 我想在ARM上也会发生同样的事情,它也必须将它设置为0。
On ARM with gcc this code does not work for me (test on armv7 with gcc Debian 4.6.3-14+rpi1). 在带有gcc的ARM上,这段代码对我不起作用(使用gcc Debian 4.6.3-14 + rpi1在armv7上测试)。 It looks like the arm compiler toolchain has a different behavior.
看起来arm编译器工具链具有不同的行为。
I do not found useful documentation for this behavior. 我没有找到有关此行为的有用文档。 It seems that the weakf equals NULL if it's undefine at link time.
似乎weakf等于NULL,如果它在链接时未定义。
So I sugest you to test it: 所以我很想你测试它:
if (weakf == NULL) printf ("weakf not found\n");
else weakf();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.