未解析弱函数的GCC行为

未解析弱函数的GCC行为,c,gcc,arm,ld,weak,C,Gcc,Arm,Ld,Weak,考虑下面的简单程序: __attribute__((weak)) void weakf(void); int main(int argc, char *argv[]) { weakf(); } 当使用gcc编译此文件并在Linux PC上运行时,它会出错。当在ARM CM0(ARM none eabi gcc)上运行它时,链接器通过跳转到以下指令和nop来替换未定义的符号 这种行为记录在哪里?是否有可能通过命令行选项进行更改?我已经看了很多资料,没有相关信息 但是,如果我检查

考虑下面的简单程序:

__attribute__((weak)) void weakf(void);

int main(int argc, char *argv[])
{
        weakf();
}
当使用gcc编译此文件并在Linux PC上运行时,它会出错。当在ARM CM0(ARM none eabi gcc)上运行它时,链接器通过跳转到以下指令和nop来替换未定义的符号

这种行为记录在哪里?是否有可能通过命令行选项进行更改?我已经看了很多资料,没有相关信息


但是,如果我检查ARM编译器文档,.

在使用gcc的ARM上,这段代码对我不起作用(使用gcc Debian 4.6.3-14+rpi1在armv7上进行测试)。看起来arm编译器工具链具有不同的行为

我没有找到有关此行为的有用文档。如果weakf在链接时未定义,则它似乎等于NULL

所以我建议你测试一下:

if (weakf == NULL) printf ("weakf not found\n");
else weakf();

man nm

我正在阅读一些文档,偶然发现了一个相关的报价:

man nm
说:

“V”
“v”符号是一个弱对象。当弱定义符号与正常定义符号链接时,使用正常定义符号时不会出现错误。链接弱的未定义符号时 符号未定义,弱符号的值变为零,没有错误。在某些系统上,大写表示已指定默认值

“W”
“w”符号是一个弱符号,未被专门标记为弱对象符号。当弱定义符号与正常定义符号链接时,正常定义符号为 使用无误。当链接弱未定义符号且未定义该符号时,符号的值将以系统特定的方式确定,不会出现错误。在一些制度上,, 大写表示已指定默认值

nm
是Binutils的一部分,GCC在引擎盖下使用Binutils,因此这应该足够规范

然后,以源文件为例:

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,但这用于未定义的变量(即对象):

然后:

给出:

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.

我假设同样的情况也发生在ARM上,它也必须将其设置为0。

我在寻找文档中的官方行为,不是我所知道的任何解决方法,但此功能不是C标准的一部分,它看起来像是许多GCC的功能没有足够的文档化弱弱属性导致声明作为弱符号而不是全局符号发出。这在定义可以在用户代码中重写的库函数时非常有用,但也可以与非函数声明一起使用。使用GNU汇编程序和链接器时,ELF目标和a.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.
gdb -nh -ex run -ex bt main.out