对 64 位寄存器感到困惑 - ASM

Confused about 64-bit registers - ASM

我目前正在学习汇编,我在 64 位 ubuntu 上使用 Intel 语法,使用 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 而不是 rdi 来存储 fd,并且它有效。

我现在很迷茫。此代码无效:

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 成功,然后掉到最后并出现段错误。

$ strace ./foo 
execve("./foo", ["./foo"], 0x7ffe6b91aa00 /* 51 vars */) = 0
stat(0x1, 0x401000)                     = -1 EFAULT (Bad address)
write(0, "Hello, World\n", 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 一起工作.参见

请注意,写入 32 位寄存器零扩展到完整的 64 位寄存器,因此您应该始终使用 mov edi, 1 而不是 mov rdi, 1。 (尽管 NASM 会为您进行此优化以节省代码大小;它们非常等价,以至于某些汇编器会默默地为您进行优化。)