从程序集中调用 libc 函数
Call libc function from assembly
我在程序集中定义了一个调用 libc 函数 (swapcontext) 的函数。我从我的 C 代码中调用该函数。为了创建可重现的示例,我使用 'puts' 代替:
foo.S:
.globl foo
foo:
call puts
ret
test.c:
void foo(char *str);
int main() {
foo("Hello World\n");
return 0;
}
编译:
gcc test.c foo.S -o test
这编译得很好。然而,反汇编结果二进制文件显示链接器未插入有效的调用指令:
objdump -dR:
0000000000000671 <foo>:
671: e8 00 00 00 00 callq 676 <foo+0x5>
672: R_X86_64_PC32 puts@GLIBC_2.2.5-0x4
676: c3 retq
677: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
67e: 00 00
0000000000000530 <puts@plt>:
530: ff 25 9a 0a 20 00 jmpq *0x200a9a(%rip) # 200fd0 <puts@GLIBC_2.2.5>
536: 68 00 00 00 00 pushq [=13=]x0
53b: e9 e0 ff ff ff jmpq 520 <.plt>
执行:
./test1: Symbol `puts' causes overflow in R_X86_64_PC32 relocation
Segmentation fault
知道为什么吗?
您似乎在反汇编带有重定位的目标文件。
重定位是链接器在加载文件时解析的存根。
要正确查看重定位和符号名称,请使用 objdump -dr test
或 objdump -dR test
。
输出将类似于:
0000000000000000 <foo>:
0: e8 00 00 00 00 callq 5 <foo+0x5>
1: R_X86_64_PLT32 swapcontext-0x4
您也可以考虑在foo
末尾添加一条ret
指令,以防swapcontext
错误。
如您的 objdump -dR
输出所示,这两个都引用了 libc 函数:
670: R_X86_64_PC32 swapcontext@GLIBC_2.2.5-0x4
# 200fd0 <swapcontext@GLIBC_2.2.5>
对于你更新的完全独立的问题,它取代了你关于拆卸 .o
的问题:
半相关: 提到链接器在非 PIE 中为您将对 puts
的引用转换为 puts@plt
的事实(因为如果静态链接),但不在 PIE 中。
libc 被映射到距主可执行文件超过 2GiB,因此 call rel32
无法访问它。
另请参阅 ,其中显示了 AT&T 和 NASM 用于从 PIE 可执行文件调用 libc 函数的语法,通过 PLT call puts@plt
或 gcc -fno-plt
样式与 call *puts@gotpcrel(%rip)
.
我在程序集中定义了一个调用 libc 函数 (swapcontext) 的函数。我从我的 C 代码中调用该函数。为了创建可重现的示例,我使用 'puts' 代替:
foo.S:
.globl foo
foo:
call puts
ret
test.c:
void foo(char *str);
int main() {
foo("Hello World\n");
return 0;
}
编译:
gcc test.c foo.S -o test
这编译得很好。然而,反汇编结果二进制文件显示链接器未插入有效的调用指令:
objdump -dR:
0000000000000671 <foo>:
671: e8 00 00 00 00 callq 676 <foo+0x5>
672: R_X86_64_PC32 puts@GLIBC_2.2.5-0x4
676: c3 retq
677: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
67e: 00 00
0000000000000530 <puts@plt>:
530: ff 25 9a 0a 20 00 jmpq *0x200a9a(%rip) # 200fd0 <puts@GLIBC_2.2.5>
536: 68 00 00 00 00 pushq [=13=]x0
53b: e9 e0 ff ff ff jmpq 520 <.plt>
执行:
./test1: Symbol `puts' causes overflow in R_X86_64_PC32 relocation
Segmentation fault
知道为什么吗?
您似乎在反汇编带有重定位的目标文件。
重定位是链接器在加载文件时解析的存根。
要正确查看重定位和符号名称,请使用 objdump -dr test
或 objdump -dR test
。
输出将类似于:
0000000000000000 <foo>:
0: e8 00 00 00 00 callq 5 <foo+0x5>
1: R_X86_64_PLT32 swapcontext-0x4
您也可以考虑在foo
末尾添加一条ret
指令,以防swapcontext
错误。
如您的 objdump -dR
输出所示,这两个都引用了 libc 函数:
670: R_X86_64_PC32 swapcontext@GLIBC_2.2.5-0x4
# 200fd0 <swapcontext@GLIBC_2.2.5>
对于你更新的完全独立的问题,它取代了你关于拆卸 .o
的问题:
半相关:puts
的引用转换为 puts@plt
的事实(因为如果静态链接),但不在 PIE 中。
libc 被映射到距主可执行文件超过 2GiB,因此 call rel32
无法访问它。
另请参阅 call puts@plt
或 gcc -fno-plt
样式与 call *puts@gotpcrel(%rip)
.