X86/ARM 寄存器
1、X86 64寄存器
1.1、x86 通用寄存器16个
寄存器名 | 寄存器作用 |
rdi | 第一个入参 |
rsi | 第二个入参 |
rdx | 第三个入参 |
rcx | 第四个入参 |
r8 | 第五个入参 |
r9 | 第六个入参 更多的参数则通过压栈传入 |
r10--r15 | 临时数据 |
rax |
rax 寄存器可以用来存储函数的返回值、临时存储数据以及进行算术和逻辑运算。 一些常见的用途包括: 1、函数返回值: 当函数返回一个整数值时,通常会将该值存储在 rax 寄存器中。例如,C 语言中的 int 类型的函数返回值。 2、临时数据存储: 由于 rax 是通用寄存器,它可以用来存储临时数据,供计算和操作使用。 3、算术和逻辑运算: rax 可以用于执行各种算术和逻辑运算,例如加法、减法、乘法、与、或、异或等。 4、系统调用: 在进行系统调用时,一些返回值或参数可能存储在 rax 寄存器中。 |
rbx |
存储一般性目的的数据 1、函数调用期间,rbx 通常被视为一个可以被调用者保存的寄存器。这意味着如果函数在使用 rbx 寄存器的时候需要保留其值,那么在函数调用结束时,它需要还原 rbx 的值。 2、rbx 寄存器来保存临时数据、计数器值、数组地址等。 |
rsp |
栈向下生长,rsp 寄存器(栈指针)的主要作用是指示栈的当前位置。栈是一种后进先出(Last-In-First-Out,LIFO)的数据结构,用于存储函数调用、局部变量和其他相关信息。 具体而言,rsp 寄存器的作用包括: 1、栈的增长和收缩: rsp 寄存器的值指示栈的顶部,即最新压入的数据的位置。当新的数据被推送到栈上时,rsp 的值减小;当数据从栈上弹出时,rsp 的值增加。 2、函数调用: 在函数调用时,参数和返回地址通常会被推送到栈上。rsp 的值在函数调用前后发生变化,指示栈的新位置。 3、局部变量的分配和释放: 局部变量通常存储在栈上,通过 rsp 寄存器来管理它们的分配和释放。当函数需要分配一些局部变量空间时,rsp 的值减小;当函数退出时,通过增加 rsp 的值来释放这些空间。 4、栈的边界: rsp 的值还用于检查栈的边界。当 rsp 的值超出了栈的范围时,可能触发栈溢出。 |
rbp |
rbp 寄存器(基址指针)的主要作用是用于建立函数的栈帧。栈帧是函数在运行时在栈上创建的局部存储区域,用于存储局部变量、函数参数、返回地址和其他与函数执行相关的信息。 具体而言,rbp 寄存器的作用包括: 1、建立栈帧: 在函数的开头,通常会执行类似以下的指令序列: assembly Copy code push rbp // 保存调用者的栈底 mov rbp, rsp // 设置当前栈帧的基址
2、这将调用者的栈底地址保存在新栈帧的基址寄存器 rbp 中,并将当前栈顶地址(栈指针 rsp 的值)赋给 rbp,从而建立了一个新的栈帧。 3、局部变量和参数的访问: 通过 rbp,函数可以轻松访问栈上的局部变量和函数参数。局部变量通常是相对于 rbp 的负偏移,而函数参数通常是相对于 rbp 的正偏移。 4、函数调用和返回: 在函数调用时,调用者将返回地址和其他信息推送到栈上。rbp 的使用使得函数可以准确地找到返回地址。在函数返回时,通过 pop rbp 恢复调用者的栈底,从而撤销当前栈帧。 5、更好的调试信息: 使用 rbp 寄存器建立栈帧可以提供更好的调试信息。调试器可以通过 rbp 寄存器更容易地还原函数调用堆栈,从而更方便地进行源代码级别的调试。 |
1.2、 x86 64其他常用寄存器
寄存器名 | 寄存器作用 |
rip |
指令寄存器(RIP)包含下一条将要被执行的指令的逻辑地址。 通常情况下,每取出一条指令后,RIP会自增指向下一条指令。在x86_64中RIP的自增也即偏移一定字节。(可通过disassemble 查看下一个地址,字节大小不一定等长) 但是RIP并不总是自增,也有例外,例如call 指令和ret指令。call指令会将当前RIP的内容压入栈中,将程序的执行权交给目标函数;ret指令则执行出栈操作,将之前压入栈的8个字节的RIP地址弹出,重新放入RIP。 |
2 arm 寄存器
2.1armv8 通用寄存器
寄存器名 | 寄存器作用 |
x0--x7 | 传递子程序的参数和返回值,使用时不需要保存。多余参数用堆栈传递,64位cpu 返回结果保存在x0 寄存器中。 |
x8 | 保存子程序的返回地址,使用时不需要保存。 |
x9--x15 | 临时寄存器,子程序使用时不需要保存。 |
x16--x17 | 子程序内部调用寄存器(IPx) ,使用时不需要保存,尽可能不使用 |
x18 | 平台寄存器,与平台相关,尽量不使用、ABI 相关 |
x19--x28 | 临时寄存器, 子程序使用时必须保存 |
x29 | 帧指针寄存器(FP) 用于连接栈帧,使用时必须保存 frame pointer register |
x30 | 链接寄存器(LR) ,用于保存子程序的返回地址。 procedure link register |
2.2、其他常用寄存器
寄存器名 | 寄存器作用 |
sp、 | 堆栈指针寄存器(SP), 用于指向每一个函数的栈顶 current stack pointer |
pc | program pointer 存储当前正在执行的指令的地址,指向正在执行的下一条指令 |
xzr、wzr | zero 寄存器:XZR(64-bits), WZR(32-bits) |
spsr | 程序状态寄存器(program status register) |
elr | 保存exception 返回值 |
注:由于ARM不允许直接操作内存单元上的数据就,所以需要先将一个寄存器置0,然后再将这个寄存器的值store到内存单元上
3、测试
栈向下生长,栈顶在低地址,栈底在高地址
查看指定地址汇编代码
x/30xi 0x00000000004005e4
查看指定地址的代码数据(堆栈)
x/30x 0x7ffffffac0
3.1 测试程序
#include <stdint.h> void test_func(int param_1, int param_2, int param_3, int param_4, int param_5, int param_6, int param_7, int param_8, int param_9) { int szArr[10]; szArr[1] = param_1; szArr[2] = param_2; szArr[3] = param_3; } int main() { int param_1 = 1, param_2 = 2, param_3 = 3; int param_4 = 4, param_5 = 5, param_6 = 6; int param_7 = 7, param_8 = 8, param_9 = 9; test_func(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8, param_9); return 1; }
可参考:
https://www.bilibili.com/read/cv33449434/