gpt4 book ai didi

linux - 无法从汇编 (yasm) 代码调用 64 位 Linux 上的 C 标准库函数

转载 作者:IT王子 更新时间:2023-10-29 00:41:59 24 4
gpt4 key购买 nike

我有一个功能 foo用汇编编写并在 Linux (Ubuntu) 64 位上使用 yasm 和 GCC 编译。它只是使用 puts() 将消息打印到标准输出,这是它的外观:

bits 64

extern puts
global foo

section .data

message:
db 'foo() called', 0

section .text

foo:
push rbp
mov rbp, rsp
lea rdi, [rel message]
call puts
pop rbp
ret

它被一个用 GCC 编译的 C 程序调用:
extern void foo();

int main() {
foo();
return 0;
}

构建命令:
yasm -f elf64 foo_64_unix.asm
gcc -c foo_main.c -o foo_main.o
gcc foo_64_unix.o foo_main.o -o foo
./foo

这是问题所在:

运行该程序时,它会打印一条错误消息并在调用 puts 期间立即出现段错误。 :
./foo: Symbol `puts' causes overflow in R_X86_64_PC32 relocation
Segmentation fault

用 objdump 反汇编后,我看到调用的地址错误:
0000000000000660 <foo>:
660: 90 nop
661: 55 push %rbp
662: 48 89 e5 mov %rsp,%rbp
665: 48 8d 3d a4 09 20 00 lea 0x2009a4(%rip),%rdi
66c: e8 00 00 00 00 callq 671 <foo+0x11> <-- here
671: 5d pop %rbp
672: c3 retq

(671 是下一条指令的地址,不是 puts 的地址)

但是,如果我在 C 中重写相同的代码,调用的方式会有所不同:
645:   e8 c6 fe ff ff          callq  510 <puts@plt>

即它引用 puts来自 PLT。

是否可以告诉 yasm 生成类似的代码?

最佳答案

0xe8操作码后跟一个带符号的偏移量,该偏移量将应用于 PC(此时已前进到下一条指令)以计算分支目标。因此 objdump正在将分支目标解释为 0x671 .

YASM 呈现零是因为它可能在该偏移量上进行了重定位,这就是它要求加载程序为 puts 填充正确偏移量的方式。在加载过程中。加载器在计算重定位时遇到溢出,这可能表明 puts与您的调用的偏移量比可以用 32 位有符号偏移量表示的偏移量更远。因此加载程序无法修复此指令,并且您会崩溃。
66c: e8 00 00 00 00显示未填充的地址。如果您查看重定位表,您应该会在 0x66d 上看到重定位。 .汇编器将重定位填充为全零的地址/偏移量并不少见。

This page表明 YASM 有一个 WRT可以控制 .got 的使用的指令, .plt , 等等。

根据 the NASM documentation 上的 S9.2.5 ,看来您可以使用 CALL puts WRT ..plt (假设 YASM 具有相同的语法)。

关于linux - 无法从汇编 (yasm) 代码调用 64 位 Linux 上的 C 标准库函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52126328/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com