我目前正在学习汇编,我在64位ubuntu上使用英特尔语法,使用nasm。
所以我找到了两个引用系统调用编号的网站:
这个用于32位寄存器(eax、ebx…(:https://syscalls.kernelgrok.com
这一个用于64位寄存器(rax、rbx…(:https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64
问题是,当我使用64位系统调用编号时,我的代码不起作用,但当我用"r"替换32位寄存器中的"e"时,它起作用,所以例如在sys_write中,我使用rbx来存储fd,而不是rdi-as,它起到了作用。
我现在很迷茫。此代码不起作用:
message db 'Hello, World', 10
section .text
global _start
_start: mov rax,4
mov rdi, 1
mov rsi, message
mov rdx, 13
syscall
mov rax, 1
mov rdi, 0
syscall
运行strace ./my_program
-您进行了一个伪stat
系统调用,然后write
成功,然后从末尾掉下来并segfault。
$ strace ./foo
execve("./foo", ["./foo"], 0x7ffe6b91aa00 /* 51 vars */) = 0
stat(0x1, 0x401000) = -1 EFAULT (Bad address)
write(0, "Hello, Worldn", 13Hello, World
) = 13
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xd} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
你的问题不是注册名,而是电话号码。您使用的是32位呼叫号码,但调用的是64位syscall
ABI
呼叫号码和呼叫约定都不同。
int 0x80
系统调用只关注寄存器的低32位,这就是为什么不应该在64位代码中使用它们的原因。
您在mov rcx, message
的注释中发布的代码可以与mov ecx, message
一起使用,依此类推,如果与mov rcx, message
一起使用,则也可以。请参阅如果在64位代码中使用32位int 0x80 Linux ABI会发生什么?。
请注意,写入32位寄存器0会扩展到完整的64位寄存器,因此应始终使用mov edi, 1
而不是mov rdi, 1
。(虽然NASM会为您进行这种优化以节省代码大小;但它们是如此等效,以至于一些汇编程序会默默地为您进行优化。(