【问题标题】:Relocation R_X86_64_PC32 against symbol when calling function from inline assembly从内联汇编调用函数时,针对符号重定位 R_X86_64_PC32
【发布时间】:2018-01-21 17:38:37
【问题描述】:

我正在尝试构建在程序集中具有调用其他函数的某些函数的共享库。当我用代码构建liba.so

void aFunc1()
{
}

asm(
    ".globl aFunc2\n\t"
    ".type aFunc2, @function\n\t"
    "aFunc2:\n\t"
    ".cfi_startproc\n\t"
    "call aFunc1\n\t" /* note here*/
    "ret\n\t"
    ".cfi_endproc\n\t"
);

和命令

gcc -o liba.so a.c -shared -fPIC

我有错误

/usr/bin/ld: /tmp/ccdGBiQv.o: relocation R_X86_64_PC32 against symbol `aFunc1' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status

它告诉我使用选项-fPIC,但我已经使用了该选项!但是我发现使用选项-Wl,-Bsymbolic 可以正常编译。

gcc -o liba.so a.c -shared -fPIC -Wl,-Bsymbolic

不幸的是,当我尝试构建第二个库libb.so 时,问题又出现了,同时还使用了尝试从第一个库调用函数的汇编函数。编译代码

#include <a.h>

asm(
    ".globl bFunc2\n\t"
    ".type bFunc2, @function\n\t"
    "bFunc2:\n\t"
    ".cfi_startproc\n\t"
    "call aFunc1\n\t" /* note here*/
    "ret\n\t"
    ".cfi_endproc\n\t"
);

用命令

gcc -o libb.so b.c liba.so -shared -fPIC -Wl,-Bsymbolic

报错

/usr/bin/ld: /tmp/ccaGvn5d.o: relocation R_X86_64_PC32 against symbol `aFunc1' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status

如您所见,选项 -Wl,Bsymbolic 没有帮助。

我想知道如何构建第二个库以及为什么第一个库需要-Wl,Bsymbolic 选项。我不是组装大师,所以我不知道它是否正确——我正在尝试构建其他库。也许我应该使用其他选项?

【问题讨论】:

  • 跨共享对象边界的函数调用(从一个库或可执行文件到另一个库)需要使用某种间接方式:共享对象可以在虚拟地址空间中加载超过 2GiB,因此 @ 987654336@ 总是无法接通。此外,ASLR 和其他因素意味着位移不能是链接时间常数,并且链接器告诉您运行时修复(编辑机器代码以在动态链接时调整位移)不可用。 2GiB 的限制是为什么 Linux 动态链接不允许这样做。

标签: c gcc assembly


【解决方案1】:

您需要调用 PLT 存根,因为该函数可能已被插入(使调用不再直接,具有固定偏移量):

call aFunc1@plt

使用-Bsymbolic,链接器会将其转换为对aFunc1 的调用(没有双重间接)。

您也可以通过 GOT 调用该函数,类似于 PLT stub 所做的:

jmp *aFunc1@GOTPCREL(%rip)

或者你可以隐藏功能:

.hidden aFunc1
jmp aFunc1

请注意,他也会隐藏定义,因此不再导出该函数。要为单个符号模拟 -Bsymbolic 的行为,您可以使用隐藏别名:

.set aFunc1Alias, aFunc1
.hidden aFunc1Alias
jmp aFunc1Alias

使用隐藏函数和隐藏别名,调用将始终转到相同的函数,即不再可能为这个特定的调用站点插入符号。

【讨论】:

  • 在函数调用中添加@plt 是可行的,但如果可能的话,我不想更改汇编代码。我注意到我正在尝试构建的库是通过讨厌的宏将__attribute__((visibility ("hidden"))) 添加到libb.so 中的aFunc1 声明并在liba.so 中添加任何内容。是否可以通过这种方式做到这一点?当我在我的最小示例中这样做时,libb.so 中仍然存在重定位问题。
  • __attribute__((visibility ("hidden"))) 导致 GCC 发出 .hidden 指令,因此非常相似。但是,如果它只包含在头文件中并且函数不是从 C 中调用的,则它在汇编程序级别可能无效。
猜你喜欢
  • 2019-01-02
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 1970-01-01
  • 2013-01-24
  • 2021-01-17
相关资源
最近更新 更多