x86寄存器图示
x64寄存器图示
整体介绍
x86的通用寄存器有eax,ebx,ecx,edx,edi,esi。
寄存器在大多数指令中可以任意使用。但是有些指令限制只能使用其中某些寄存器做某种用途,例如idivl,它规定被除数在eax寄存器中,edx寄存器必须位0,除数可以是任意寄存器中,计算机过的商数保存在eax寄存器中(覆盖被除数),余数保存在edx寄存器中
x86的特殊寄存器有ebp,esp,eip,eflags。eip是程序计数器。eflags保存计算过程中产生的标志位,包括进位,溢出,零,负数等标记,在x86的文档中,这几个标记位分别称为CF、OF、ZF、SF。ebp和esp用于维护函数调用过程的栈帧(stack frame)
esp指向栈顶,而ebp为栈帧(stack frame)指针,指向当前调用的栈的底(高地址)。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着函数运行所需要的各种信息。对esp做减法,就是在扩展栈空间。
- 8个32-bit寄存器 %eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp
- 8个16bit寄存器,实际上是上面8个32-bit寄存器的低16位:%ax,%bx,%cx,%dx,%si,%bp,%sp
- 8个8bit寄存器:%ah,%al,%bh,%bl,%ch,%cl,%dh,%dl。它们事实上是寄存器%ax,%bx,%cx,%dx的高8位和低8位
- 6个段寄存器:%cd(code),%ds(data),%ss(stack),%es,%fs,%gs
- 3个控制寄存器:%cr0,%cr2,%cr3
- 6个debug寄存器:%db0,%db1,%db2,%db3,%db6,%db7,
- 2个测试寄存器:%tr6,%tr7
- 8个浮点寄存器栈:%st(0),%st(1),%st(2),%st(3),%st(4),%st(5),%st(6),%st(7)
x64架构向后兼容x86架构,它提供的32位模式,与x86架构完全一样。同时有一个新的64位模式
由于x86_64架构惊人的向后兼容性,同一个寄存器,我们可以使用其中的8bit,16bit,32bit,64bit,以ax寄存器为例,分别是ah/al,ax,eax,rax
- 前缀R,表示64位寄存器。例如RAX。
- 前缀E,表示32位寄存器。例如EAX。
- 后缀L,表示寄存器的低8位。
- 后缀H,表示寄存器的9~16位,高8位
x64中的寄存器,都用r开头,表示64bit,分别是rax,rbx,rcx,rdx,rsi,rdi,rbp,rsp,另外,在x64中还新增了r8-r15,它们作为普通寄存器存在,可以任意使用。
计算结果输出到32位寄存器时,64位寄存器的其他位置会全部自动清零,计算结果输出到8位或16位寄存器时,64位寄存器的其他位置不会清零,这与x86的行为一致
在x64模式下,8位寄存器不能用于所有类型的操作数
寄存器的传统用法
RAX
传统上作为累加寄存器,accumulator register。通过RAX寄存器存储函数返回值属于calling convention。
RAX是64位寄存器,可以拆分。我们操作EAX,就是对RAX的低32位进行操作。同样,AX表示RAX的低16位,AH表示RAX低16位中的高8位,AL表示RAX低16位中的低8位。除了RIP寄存器,其他通用寄存器都可以做类似的拆分,新增的r8~r15也可以拆分,但需要注意不同的拆分表示方法。
一般编译C得到的汇编,函数都会保证除rax以外的通用的寄存器的值,这就是因为rax用来保存函数的返回值(浮点型返回值除外)
main函数最后的return 0,翻译成汇编,常常是xor eax,eax
RBX
传统上作为基址寄存器,base register,用于访问内存的基址。通用寄存器之一
RCX
传统上作为技术寄存器,counter register,用于循环计数。loop指令指定使用此寄存器
RDX
data register,数据寄存器。通用寄存器之一
RSI
source index,源变址寄存器,字符串运算时常用于源地址指针
RDI
destination index,目标变址寄存器,字符串运算时常用于目标指针
RSP
stack pointer,栈顶指针寄存器
- push 和 pop 指令会修改此寄存器的值
- call 和 ret 指令也会修改此寄存器,还有RIP寄存器
- call addr:push return address on stack, then call function at address
- ret: pop return address from stack and return to the address
函数调用向下扩展指针,shadow space
RSP不要用作其他的用途
RBP
base pointer,基址寄存器,一般用来存放栈底地址,stack frame的开始地址。
编译器常常对函数调用
1 | push rbp ;函数最开始,保存rbp到stack |
手写汇编用rbp作为一个函数内不变的anchor很方柏霓,但是编译器已经不用这种pattern了,函数开始prologue和结束epilogue不用在push和pop,而且释放出一个rbp作为free register,可以进一步加速
R8~R15
R8,R9,R10,…,R15属于通用寄存器,一般是可以任意使用,不指定特定用途。
这一组x64新增的通用寄存器也支持拆分,但是拆分的寄存器在命名规则上与特殊功能寄存器有所不同.
32位拆分寄存器以D作为后缀(DWORD),16位寄存器以W作为后缀(WORD),低9位则以B作为后缀(BYTE)没有高八位的拆分
用法:%r14d,%r14w,%r14b或者r14l,intel风格,没有r8h
RIP
instruction pointer,指令指针。只读,不可拆分
永远指向下一条需要执行的指令地址,由CPU自动设置。在x64模式下,可以读取,在x86模式下,读都不行。x64模式下提供了一个居于RIP的相对寻址模式
RFLAGS
这个寄存器虽然也扩展到了64位,但扩展出来的32位还未被使用。标志大都由CPU自动设置
FPR0-FPR7(MMX0-7)
YMM0-YMM15
用于存放packed data,256bit,可以存放多个整数或浮点数。一个YMM支持存放4个64位数值或者8个32位值,支持拆分成XMM0-15(YMM的低128位)
CR0-CR10控制寄存器
控制寄存器,记录CPU运行过程中自身的一些关键信息。