在共享库中不使用 PLT 调用另一个目标文件中的函数?
Call a function in another object file without using PLT within a shared library?
我有两个汇编代码,code1.s
和 code2.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
,这都是因为我有 myfun1
的 globl
指令,当我删除它时线它得到修复。
感谢 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.so
和 objdump -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_aux
和 register_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,例如 __chdir
和 chdir
。
例如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 的更多详细信息。我目前不知道,所以如果我自己没有时间阅读文档,欢迎编辑。
我知道这个东西存在并解决了这个问题,但我不知道具体如何。)
我有两个汇编代码,code1.s
和 code2.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
,这都是因为我有 myfun1
的 globl
指令,当我删除它时线它得到修复。
感谢 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.so
和 objdump -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_aux
和 register_tm_clones
以及 .init
部分。)
我认为 Glibc 为此使用 strong 或 weak_alias
(__chdir
和 chdir
。
例如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 的更多详细信息。我目前不知道,所以如果我自己没有时间阅读文档,欢迎编辑。 我知道这个东西存在并解决了这个问题,但我不知道具体如何。)