从程序集中调用 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 testobjdump -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@pltgcc -fno-plt 样式与 call *puts@gotpcrel(%rip).