在共享库中不使用 PLT 调用另一个目标文件中的函数?

Call a function in another object file without using PLT within a shared library?

我有两个汇编代码,code1.scode2.s,我想从这两个代码构建一个可重定位(使用 -fPIC 开关)共享库。

我想 code2.s 调用一个名为 myfun1 的函数,它在 code1.s.

中定义

当我在 code2.s 中使用 call myfun1@PLT 时,它会找到该函数并且它的工作原理非常棒,但它使用 PLT 部分来调用位于同一共享库中的该函数。我想在不遵守 PLT 部分的情况下执行此操作。当我删除 @PLT 时,我收到 myfun1.

relocation R_X86_64_PC32 against symbol 错误

如何在不使用 PLT 部分的情况下执行此操作?有什么办法吗?我认为这应该是可行的,因为共享库应该是可重定位的,但不需要它的每个目标文件,因此为什么在同一个库中调用函数应该通过 PLT 部分。

这是我的编译命令:

对于codeX.s:

gcc -c codeX.s -fPIC -DPIC -o codeX.o

gcc -c codeX.s -o codeX.o

以及名为 libcodes.so 的共享库:

gcc -shared -fPIC -DPIC -o libcodes.so code1.o code2.o

正如你可能好奇我为什么这样做一样,我有很多目标文件,每个目标文件都想调用myfun1。在这里,我只是让询问技术部分变得更简单。即使我尝试将 myfun1 放入所有 codeX.s 文件中,但我收到多次定义 myfun1 的错误。我不太关心 space 以及是否要将 myfun1 放入所有文件中。

好吧,我找不到任何方法来这样做,但是当我编辑我的问题时,我不想在所有目标文件中放入 myfun1

我遇到的问题是链接器输出错误,我在多个地方定义了 myfun1,这都是因为我有 myfun1globl 指令,当我删除它时线它得到修复。

感谢 Ross Ridge 再次推动我尝试。

在一个源文件中,您只能使用两个标签 (),一个带有 .globl,另一个不带。但这还不足以跨共享库中的源文件。

结合以下针对同样导出的函数的答案仍然有用:一个 .hidden 和一个不是,因此您可以在库中高效地调用。


使用.globl.hidden创建一个在当前目标文件外可见的符号,但在当前目标文件外不可见共享库。因此它不受符号插入的影响,来自同一共享库中的其他文件的调用可以直接调用它,而不是通过 PLT 或 GOT。

测试和工作示例

## foo.S
.globl myfunc
.hidden myfunc
myfunc:
   #.globl myfunc_external    # optional, a non-hidden symbol at the same addr
   #myfunc_external:
    ret

## bar.S
.globl bar
bar:
    call myfunc
    ret

使用 gcc -shared foo.S bar.S -o foo.soobjdump -drwC -Mintel foo.so 构建:

Disassembly of section .text:

000000000000024d <myfunc>:
 24d:   c3                      ret    

000000000000024e <bar>:
 24e:   e8 fa ff ff ff          call   24d <myfunc>     # a direct near call
 253:   c3                      ret    

(我实际上也是用 -nostdlib 构建的,为了示例目的,通过省略其他函数(如 __do_global_dtors_auxregister_tm_clones 以及 .init 部分。)


我认为 Glibc 为此使用 strong 或 weak_alias), so calls from within the shared library can use the normal name. Where are syscalls located in glibc source,例如 __chdirchdir

例如glibc's printf.c 定义 __printf 并使 printf 成为它的 strong 别名。

io/chdir.c 定义 __chdir 并使 chdir 成为它的 weak 别名。

其中一个 x86-64 memchr asm 实现也使用 strong_alias 宏(在文件底部)。


相关的 GAS 指令是:

没有强别名 GAS 指令。这可能相当于简单的 foo = foo_internal 或等效的 .set foo, foo_internal.

(TODO:完整的示例和 strong/weak 的更多详细信息。我目前不知道,所以如果我自己没有时间阅读文档,欢迎编辑。 我知道这个东西存在并解决了这个问题,但我不知道具体如何。)