从内联汇编调用函数时,对符号重新定位R_X86_64_PC32

Mat*_*ost 6 c assembly gcc

我正在尝试构建共享库,这些库在汇编中具有调用其他函数的一些函数.当我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"
);
Run Code Online (Sandbox Code Playgroud)

和命令

gcc -o liba.so a.c -shared -fPIC
Run Code Online (Sandbox Code Playgroud)

我收到了错误

/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
Run Code Online (Sandbox Code Playgroud)

它告诉我使用选项,-fPIC但我已经使用了该选项!但是我发现有了选项-Wl,-Bsymbolic它编译得很好.

gcc -o liba.so a.c -shared -fPIC -Wl,-Bsymbolic
Run Code Online (Sandbox Code Playgroud)

不幸的是,当我尝试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"
);
Run Code Online (Sandbox Code Playgroud)

用命令

gcc -o libb.so b.c liba.so -shared -fPIC -Wl,-Bsymbolic
Run Code Online (Sandbox Code Playgroud)

给出错误

/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
Run Code Online (Sandbox Code Playgroud)

而你可以看到选项-Wl,Bsymbolic没有帮助.

我想知道如何构建第二个库以及为什么第一个库需要-Wl,Bsymbolic选项.我不是集会大师,所以我不知道它是否正确 - 我正在努力建立别人的图书馆.也许我应该使用其他选择?

Flo*_*mer 3

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

call aFunc1@plt
Run Code Online (Sandbox Code Playgroud)

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

您还可以通过 GOT 调用该函数,类似于 PLT 存根的作用:

jmp *aFunc1@GOTPCREL(%rip)
Run Code Online (Sandbox Code Playgroud)

或者您可以隐藏该函数:

.hidden aFunc1
jmp aFunc1
Run Code Online (Sandbox Code Playgroud)

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

.set aFunc1Alias, aFunc1
.hidden aFunc1Alias
jmp aFunc1Alias
Run Code Online (Sandbox Code Playgroud)

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