c - Unresolved 弱函数的 GCC 行为

标签 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 来替换 undefined symbol 。

此行为记录在何处?有没有可能通过命令行选项更改它的方法?我已经通过GCCLD文档,没有相关信息。

但是,如果我查看 ARM 编译器文档,this is clearly explained .

最佳答案

man nm

我正在阅读一些文档,碰巧遇到了与此相关的引用:

man nm

说:

"V"
"v" The symbol is a weak object. 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" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol. 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 是 Binutils 的一部分,GCC 在后台使用它,因此这应该足够规范了。

然后,在您的源文件中举例:

主.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,但它用于 undefined variable (对象):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。

关于c - Unresolved 弱函数的 GCC 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31203402/

相关文章:

c++ - 体验在 Raspberry Pi 上为 PCF8575 I/O 扩展器编写 C 代码

c - 为什么GCC在编译C代码时不使用更多寄存器

c++ - g++ 无法解析模板函数重载

ios - LLVM 编译汇编文件的操作数中存在意外标记。替代说明?

assembly - 在ARM cortex m0中,第一条指令是什么?

iphone - 使用 GDB 从崩溃中检查 Objective C 类(HandleDelegateSource 错误访问)

c - 在 ATtiny85 上设置高速 PWM

c - 方案到 C 转换器

c - 如何在 Netbeans IDE 中用 C 编程语言触发 EOF(文件结束符)

c - ld 使我的所有函数都链接到头文件中的最后一个函数