NASM中,在64位模式下,可以使用下面的寄存器:
AL/AH, CL/CH, DL/DH, BL/BH, SPL, BPL, SIL, DIL, R8B−R15B
AX, CX, DX, BX, SP, BP, SI, DI, R8W−R15W
EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, R8D−R15D
RAX, RCX, RDX, RBX, RSP, RBP, RSI, RDI, R8−R15
还有一些用于浮点数的寄存器,这些先不介绍,有机会会在后面的文章中单独介绍。
常用的寄存器有rax,rbx,rcx,rdx,rsi,rdi,rbp,rsp,r8-r15,这16个寄存器。这些寄存器中,有的具有特定的用途,有些是通用的。
rax:通用寄存器。系统调用中保存系统调用号;在函数中,返回值一般存放到rax中,当返回的是指针时,rax保存指针。
rcx:可以用于计数,与loop循环指令有关。
rbp:基址寄存器,保存栈的起始地址。
rsp:栈顶寄存器,保存栈的顶部地址。始终指向栈顶。
这些寄存器都是64位长度,8个字节。
示例代码:test_reg.asm
; test_reg.asm
; nasm -f elf64 -o test_reg.o test_reg.asm
; ld -o test_reg test_reg.o
; ./test_reg
section .data
section .text
global _start
_start:
mov rax, 3 ; rax = 3
mov rbx, rax ; rbx = rax = 3
push rax ; rsp = rsp-8, [rsp] = rax = 3
pop rcx ; rcx = [rsp] = 3, rsp = rsp + 8
mov rax, 60 ; exit
syscall
在代码中,使用mov指令让rax=3,
接着,rbx = rax = 3
然后使用push指令,将rax入栈。
栈是向低地址增长的,因此先将rsp减8,(字节),然后rax的值入栈。
pop指令将栈顶元素弹出,到rcx中,rcx=3,弹出后,rsp = rsp+8。
最后,进行系统调用,系统调用号是60,exit,退出程序。
在汇编中,很重要的一点是,操作数的大小要相同。
比如mov rax,3 这条指令中,rax是64位的,因此立即数3也是64位的。
mov rbx, rax
寄存器rbx,rax都是64位的,如果这样写:mov rbx, eax 就会出现错误,因为eax是32位,与rax的长度不匹配。
一般在程序中,不随便对rsp和rbp进行修改,这里说的是不随便,需要对其修改的时候,一定要明确目的。栈是一段空间,每个函数在调用的时候会有自己的函数栈,随意对rsp和rbp进行修改,会引起程序错误。