简体   繁体   English

未解决的弱函数的GCC行为

[英]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. 我已经通过GCCLD文件,没有相关信息。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM