寄存器1
Contents
x86-64
X86-64架构寄存器,64位宽,同时兼容IA-32寄存器。
寄存器名 | 寄存器简介 | 主要功能 | 63-0 | 31-0 | 15-0 | 8-0 |
---|---|---|---|---|---|---|
rax | 累加器,是算术运算的主要寄存器 | 存储返回值 | rax | eax | ax | al |
rbx | 基址寄存器,被调用者保存 | 存放存储区的起始地址 | rbx | ebx | bx | bl |
rcx | 计数寄存器 | 循环操作和字串处理的计数控制;函数调用时的第4个参数 | rcx | ecx | cx | cl |
rdx | I/O指针 | I/O操作时提供外部设备接口的端口地址;函数调用时的第3个参数 | rdx | edx | dx | dl |
rsi | (source index)源变址寄存器,与rds段寄存器联用,可以访问数据段中的任一个存储单元 | 函数调用时的第2个参数 | rsi | esi | si | sil |
rdi | (destination index)目的变址寄存器,与res段寄存器联用,可以访问附加段中的任一个存储单元 | 函数调用时的第1个参数 | rdi | edi | di | dil |
rbp | (base pointer)基址指针寄存器,用于提供堆栈内某个单元的偏移地址,与rss段寄存器联用,可以访问堆栈中的任一个存储单元,被调用者保存 | rbp | ebp | bp | bpl | |
rsp | (stack pointer)栈顶指针寄存器,提供堆栈栈顶单元的偏移地址,与rss段寄存器联用,以控制数据进栈和出栈 | rsp | esp | sp | spl | |
r8 | 函数调用时的第5个参数 | r8 | r8d | r8w | r8b | |
r9 | 函数调用时的第6个参数 | r9 | r9d | r9w | r9b | |
r10 | 调用者保存 | r10 | r10d | r10w | r10b | |
r11 | 调用者保存 | r11 | r11d | r11w | r11b | |
r12 | 被调用者保存 | r12 | r12d | r12w | r12b | |
r13 | 被调用者保存 | r13 | r13d | r13w | r13b | |
r14 | 被调用者保存 | r14 | r14d | r14w | r14b | |
r15 | 被调用者保存 | r15 | r15d | r15w | r15b |
CALL和RET
指令CALL和RET用于处理函数调用和返回操作。调用指令CALL的作用是把返回地址压入栈中并且跳转到被调用函数开始处执行。返回地址是程序中紧随调用指令CALL后面一条指令的地址。因此当被调函数返回时就会从该位置继续执行。返回指令RET用于弹出栈顶处的地址并跳转到该地址处。在使用该指令之前,应该先正确处理栈中内容,使得当前栈指针所指位置内容正是先前CALL指令保存的返回地址。另外,若返回值是一个整数或一个指针,那么寄存器eax将被默认用来传递返回值。
call指令执行函数调用。CPU执行call指令时首先会把rip寄存器中的值入栈,然后设置rip值为目标地址,又因为rip寄存器决定了下一条需要执行的指令,所以当CPU执行完当前call指令后就会跳转到目标地址去执行。
ret指令从被调用函数返回调用函数,它的实现原理是把call指令入栈的返回地址弹出给rip寄存器。
ebp
ebp,esp,eip均为32位寄存器,在64位系统里面对应的是64位寄存器rbp,rsp,rip
栈是往低(小)地址方向扩展的,而esp指向当前栈顶处的元素。通过使用push和pop指令我们可以把数据压入栈中或从栈中弹出。对于没有指定初始值的数据所需要的存储空间,我们可以通过把栈指针递减适当的值来做到。类似地,通过增加栈指针值我们可以回收栈中已分配的空间。
大多数CPU上的程序实现使用栈来支持函数调用操作。栈被用来传递函数参数、存储返回信息、临时保存寄存器原有值以备恢复以及用来存储局部数据。单个函数调用操作所使用的栈部分被称为栈帧(stack frame)结构,其一般结构如下图所示。栈帧结构的两端由两个指针来指定。寄存器%ebp通常用做帧指针(frame pointer),而esp则用作栈指针(stack pointer)。在函数执行过程中,栈指针esp会随着数据的入栈和出栈而移动,因此函数中对大部分数据的访问都基于帧指针%ebp进行。(通过对ebp的加减运算来指定在某个数据的地址)
movl 12(%ebp), %eax,等同于Intel格式中的mov EAX, [EBP + 12],AT&T中,源操作数在左,目的操作数在右。“l”是Longword,相当于Intel格式中的dword ptr操作限定符;
表示将地址SS:[EBP +12]指向的双字数据传送至EAX寄存器。
addl 8(%ebp), %eax,等同于Intel格式中的add EAX, [EBP + 8],表示将SS:[EBP + 8]指向的一个双字数据同寄存器EAX中的原值相加,所得的结果保存在EAX寄存器。
Intel格式和AT&T格式的区别,这里有个文档可以作参考:http://blog.sina.com.cn/s/blog_51e9c0ab010099ow.html
比如: movl $0x1,0xfffffffc(%ebp)
就是把1赋值给ebp+0xfffffffc的地址 而ebp+0xfffffffc由于ebp是32位寄存器所以也就是ebp-4的地址
eip
EIP寄存器里存储的是CPU下次要执行的指令的地址。
用例:
|
|
程序从main()函数开始执行,首先将main()函数压入系统调用栈(call stack)(下面如无特殊说明,用栈代指系统调用栈(call stack)),并给它分配一个栈帧用以保存所需信息。然后执行main函数中第一条语句,这是一条函数调用语句,在实际调用执行Add函数前需要做一些准备工作。
首先将5和10两个参数压入栈,同时更新ESP指针的值,如下图所示:
当Add函数调用执行完毕之后,我们需通过某种方式返回到main函数中继续执行下面的指令,在本例中也就是执行print函数。解决这个问题的方式就是将下一条指令的地址压入栈中:
以上准备工作就绪,下面开始调用执行Add函数。
首先,我们需要将main函数用来寻址参数或变量信息的EBP寄存器值压入栈中保存,以便于从Add函数返回之后,从栈中取出EBP的值赋给EBP寄存器让main函数用来寻址参数或变量信息,同时更新ESP的值。为了Add函数能够寻址到所需信息,将此时的ESP寄存器的值赋值给EBP寄存器(图中的EBP-new)。此时将接着执行int c语句,为变量c开辟一段内存空间压入栈中,同时更新ESP的值。接下来执行c=a+b,然后返回c,但main函数中并没有声明变量来存储该返回值,故该返回值丢失。函数返回时将ESP更新为EBP-new,接着将EBP-old弹出赋值给EBP寄存器,让main函数拿来寻址所需信息,此时就从Add函数的栈帧恢复到了main函数的栈帧。接着弹出RET(Add函数的返回地址),对应的汇编代码中会有一条ret指令,该指令会将RET返回地址保存到EIP寄存器中,然后处理器根据这个地址无条件跳转到main函数的相应位置去取下一条指令即print函数继续执行。print函数调用执行过程中压栈出栈过程与Add函数类似,不再细说。
cr2,cr3
CR2寄存器由CPU在页面故障(page fault)时自动设置,并包含导致页面故障的已访问虚拟地址。 存储在CR3寄存器中的一般是4级页表的物理地址(4级页表的根)
控制寄存器(CR0~CR3)用于控制和确定处理器的操作模式以及当前执行任务的特性。CR0中含有控制处理器操作模式和状态的系统控制标志;CR1保留不用;CR2含有导致页错误的线性地址;CR3中含有页目录表物理内存基地址,因此该寄存器也被称为页目录基地址寄存器PDBR(Page-Directory Base address Register)。
Author sorvik
LastMod 2020-02-20