【发布时间】:2018-09-01 20:07:36
【问题描述】:
我尝试从 asm 代码调用 printf 函数。
你好.asm:
%macro exit 0
mov eax, 1
mov ebx, 0
int 80h
%endmacro
extern printf ; the C function, to be called
SECTION .data
hello: db 'Hello world!', 0
SECTION .text
GLOBAL main
main:
sub 8, rsp
push dword hello
call printf ; Call C function
add 8, rsp
exit
生成文件:
all:
nasm -f elf64 hello.asm -o hello.o
ld hello.o -e main -o hello -lc -I/lib/ld-linux.so.2
clean:
rm -f hello.o hello
打电话:
nasm -f elf64 hello.asm -o hello.o
hello.asm:16: error: invalid combination of opcode and operands
hello.asm:19: error: invalid combination of opcode and operands
make: *** [all] Error 1
请解释错误以及如何修复代码。
谢谢。
【问题讨论】:
-
sub和add的操作数向后。 Intel 语法是add dst, src,所以你使用sub rsp, 8。您是否从 AT&T 语法翻译并错过了它? -
另外,如果您使用 64 位代码(如 RSP 所示),则不应使用 int 80,而应使用
syscall,它也使用不同的寄存器。 -
@PeterCordes 是的。我修复了它,现在我收到错误 bash: ./hello: Accessing a corrupted shared library
-
@DavidWohlferd:是的,但是对于不需要 64 位输入(如指针)的系统调用(What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?),它仍然可以(在大多数系统上)工作。对于这种情况,更重要的是,x86-64 System V 调用约定不会在堆栈上传递参数。它应该是
mov edi, hello或lea rdi, [rel hello]。 What are the calling conventions for UNIX & Linux system calls on i386 and x86-64. -
@e42d3: 与 gcc 链接,它知道如何传递正确的参数。
gcc -v -nostartfiles -no-pie hello.o。 (-v打印它使用的实际链接器命令,以防你好奇)。不要使用-e main,调用你的入口点_start。 (并且不要与 RSP 混淆,它在 ELF 入口点已经是 16 字节对齐的,不像main。或者更好的是,省略-nostartfiles这样正常的启动内容在 main 之前运行,而不是依赖于动态链接器在调用 stdio 函数之前初始化 libc 的东西。)