如何知道使用哪个整数寄存器

How to know which integer register to use

我正在尝试学习汇编,这在一定程度上是有道理的,但我遇到了问题。我有这个源文件 hello.sfml:

; nasm -felf64 hello.asml && ld hello.o

    global _start

    section .text
_start:
    ; write(1, message, 13)
    mov     rax, 1          ; syscall 1 is write
    mov     rdi, 1          ; file handle 1 is stdout
    mov     rsi, message    ; address of string to output
    mov     rdx, 13         ; number of bytes in the string
    syscall                 ; invoke OS to write the string

    ; exit(0)
    mov     rax, 60         ; syscall 60 is exit
    xor     rdi, rdi
    syscall                 ; invoke OS to exit
message:
    db  "Hello, World", 10  ; the 10 is a newline character at the end

效果很好。我只是不明白为什么需要在不同情况下使用特定的整数寄存器。

因此,例如,通过反复试验,我发现在说出我想要的系统调用时,例如

    mov     rax, 1  
    ...
    syscall 

我把值1放入整数寄存器rax,但我也可以使用整数寄存器eaxaxal,或 ah.

我学习汇编的时间不长,所以这很可能是一个很明显的问题。

如果我的问题不是很明显:我想知道如何决定将值移动到哪个整数寄存器,例如如果有一些通用系统,或者如果每个不同的意图使用不同的整数寄存器。

我在 64 位 Ubuntu 上使用 NASM。

编辑: 我的问题不是 this one, 的重复,因为那个人问的是你会在哪里使用 smaller整数寄存器,我要求一种方法来决定 使用哪个 整数寄存器。

程序集或 x86 机器没有定义您应该使用哪个通用寄存器 (GPR),您可以使用任何可用的 GPR(或提供一个),但是,不同的环境定义了不同的寄存器使用和参数约定通过,当你想使用别人的代码时,你必须遵守这些约定。

具体来说,Linux x86-64 使用以下约定,如 X86 psABI(第 3.2.3 节)所述:

  1. If the class is INTEGER, the next available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9 is used.

如果是标准的用户级代码,就是上面第一个例子中选择rdirsirdx的原因,第一个参数是在 rdi 中传递,第二个在 rsi 中传递,第三个在 rdx 中传递。

不过,上面的例子演示了Linux系统调用的内核内部调用约定,它类似于用户级应用程序,但有一些差异(第A.2.1节):

  1. User-level applications use as integer registers for passing the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9. The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9.
  2. A system-call is done via the syscall instruction. The kernel destroys registers %rcx and %r11.
  3. The number of the syscall has to be passed in register %rax.

正如您在示例中所见,每个系统调用都基于 Linux System Call Table for x86-64(如 zx485 所评论)定义了 rax 值。
请注意,系统调用最多可以有 6 个参数,并且与用户级代码不同,不能使用堆栈来获取额外参数。

Windows、32 位或其他环境有不同的 ABI,但我不会在这里详细说明。

关于您对 alaxeax 用法的评论:当使用 x86-64 架构时,要求是在 rax 中指定系统调用的数量,使用任何寄存器的其他部分是基于运气的——如果寄存器其他部分的所有位都是零,那么你可以使用较低的位——但你不应该相信它。
提醒:

rax is the full 64-bit register
eax is the lower 32-bits
ax is the lower 16-bits
al is the lower 8 bits
ah is the value in bits 8 through 15 

如您所见,使用 ah 是错误的,可能会调用不同的系统调用!