引子
汇编不属性,现在拿来复习下
寄存器的分类
通用寄存器
寄存器 | 名称 | 作用 |
---|---|---|
AX | 通常用来保存函数的返回值 | |
CX | 计数器 | 用作计数器 |
DX | ||
BX | ||
SP | 栈顶指针寄存器 | 保存栈顶地址 |
BP | 栈底指针寄存器 | 保存栈底地址 |
SI | 源变址寄存器 | MOVS 或 STOS等指令 |
DI | 目的变址寄存器 |
16位寄存器:(14个)
- 4个数据寄存器(AX,BX,CX,DX)
- 2个变址和指针寄存器(SI,DI)
- 2个指针寄存器(SP,BP)
- 4个段寄存器(ES,CS,DS,SS)
- 1个指令指针寄存器(IP)
- 1个标志寄存器(Flags)
32位寄存器:(16个)
- 4个数据寄存器(EAX,EBX,ECX,EDX)
- 2个变址和指针寄存器(ESI,EDI)
- 2个指针寄存器(ESP,EBP)
- 6个段寄存器(ES、CS、SS、DS、FS、GS)
- 1个指令指针寄存器(EIP)
- 1个标志寄存器(EFlags)
64位寄存器
- 64位有16个寄存器,32位只有8个。但是32位前8个都有不同的命名,分别是e ,而64位前8个使用了r代替e,也就是r 。e开头的寄存器命名依然可以直接运用于相应寄存器的低32位。而剩下的寄存器名则是从r8 - r15,其低位分别用d,w,b指定长度。
- 32位使用栈帧来作为传递的参数的保存位置,而64位使用寄存器,分别用rdi,rsi,rdx,rcx,r8,r9作为第1-6个参数。rax作为返回值
- 64位没有栈帧的指针,32位用ebp作为栈帧指针,64位取消了这个设定,rbp作为通用寄存器使用
- 64位支持一些形式的以PC相关的寻址,而32位只有在jmp的时候才会用到这种寻址方式。
ESP EBP 寄存器
使用IDA 反汇编的时候经常能看到ESP,EBP这种字眼;
但是不明所以
新建一个程序cpp 程序片段
1 | #include"stdio.h" |
这个程序很简单,就是求两个数的值,然后输出即可。所以首先把它用gcc编译链接成a.out,进入gdb进行调试
1 | [root@localhost cpp]# gcc add.cpp -o add.o |
反汇编 disassemble main
1 | [root@localhost cpp]# gdb -q add.o |
反汇编 disassemble add
1 | (gdb) disassemble add |
这里可以看到Add函数和Main函数反汇编出来的代码
现在来看下rbp 和rsp 内容的变化
1 | (gdb) b main |
BP 为基址寄存器,一般在函数中用来保存进入函数时SP的栈顶基址
SP 时栈顶指针,每次指向栈顶
在函数进入时:
push bp //保存bp指针
mov sp,bp //将sp指针传给bp,此时bp指向sp的基地址。这个时候,如果该函数有参数,则[bp-4]则是该子函数的第一个参数,[bp-8]则是该子函数的第二个参数,以此类推,有多少个参数则[bp-4^n]。
…..
…..
函数结束时:
pop bp //恢复原bp的值。
ret //退出子函数
看这个函数
1 | Reading symbols from add.o...done. |
可以看出 在 Main 函数执行的时候
先将 $rbp 寄存器的值放入栈中保存起来,防止后续被破坏,因为后面会使用 bp 寄存器