6

考虑下面的简单程序:

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

int main(int argc, char *argv[])
{
        weakf();
}

当用 gcc 编译它并在 Linux PC 上运行它时,它会出现段错误。在 ARM CM0 (arm-none-eabi-gcc) 上运行它时,链接器通过跳转到以下指令和 nop 来替换未定义的符号。

这种行为记录在哪里?是否有可能通过命令行选项更改它?我已经通过GCCLD文档,没有关于此的信息。

但是,如果我检查 ARM 编译器文档,就会清楚地解释这一点

4

2 回答 2

3

man nm

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

man nm

说:

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

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

nm是 GCC 在后台使用的 Binutils 的一部分,因此这应该足够规范。

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

主程序

__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,但用于未定义的变量(对象):如何使弱链接与 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.

这意味着它在 PLT 得到解决

然后由于我不完全理解 PLT,我通过实验验证它可以解决 0 和段错误:

gdb -nh -ex run -ex bt main.out

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

于 2019-02-09T00:29:20.070 回答
1

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

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

所以我建议你测试一下:

if (weakf == NULL) printf ("weakf not found\n");
else weakf();
于 2015-07-03T14:02:03.767 回答