目录
1. 寄存器
通用寄存器:
栈寄存器:
指令指针寄存器:
2. 汇编指令
mov:
add、sub:
lea:
jmp:
call、ret:
3. 总结
我们在学习C语言和C++的期间,有很多时候需要反汇编看语句所对应的汇编是什么样的,这篇文章我就带大家来看一些最常见的一些X86汇编语句,我们就使用 Intel语法。AT&T语法与Intel语法很相似。
在最开始提一下:
Intel 和 AT&T 就明显的有一点是:
Intel语法 操作数 前面是 目的地,后面是源,AT&T 与之相反。
文中 [] 方括号内存放的都是 地址 。
1. 寄存器
为什么要在这里先说寄存器呢,因为有80%汇编语句是围绕着 内存 和 寄存器来操作执行的~,所以在这里我们就来简单说一些比较重要寄存器。
通用寄存器:
eax ecx edx ebx
首先说这个几个寄存器的使用顺序就是上面说的,a、c、d、b
这几个寄存器,通常就是用来存储一些CPU计算时候的临时变量,比如说某个表达式计算出的结果等等。
有一个注意点:通常来说函数在返回一个值的时候都是借助 eax 寄存器
栈寄存器:
esp ebp
以上两个寄存器是记录当前的函数栈帧内存上的地址范围,所以我们可以将他理解成两个指针。
esp指针(寄存器)指向栈顶,ebp指针(寄存器)指向栈底。
我们在调用函数的时候,这两个指针就要改变。
指令指针寄存器:
eip
eip寄存器是用来记录CPU当前执行的命令在内存中的地址,简单说就说 eip中存储的是当前执行的语句的位置。
每次执行完语句,eip寄存器会自动 ++ 到下一条命名的地址上。因为他存储的是地址,所以我们也可以将他理解成一个指针。
在我们调用函数的时候,eip寄存器就会指向被调函数的最开始位置。
2. 汇编指令
这一部分,我们通过一些简单的汇编指令来聊~
mov:
mov eax, 0
上面的语句的意思是:将 0 移动到(赋值给) eax 寄存器
mov eax, ecx
上面的语句的意思是:将 ecx寄存器 的值移动到(赋值给) eax寄存器
mov eax, dword ptr[a]
上面的语句的意思是:将 a变量所对应的内存空间的值 移动到(赋值给) eax寄存器,这里的 "dword ptr []" 我们就不展开说了,大家可以理解成 访问 a变量 所对应的内存空间。
这个地方 a 其实是一个地址, "dword ptr []" 是那这个地址去解引用,以后再细说吧~~
add、sub:
不多说,顾名思义:加 和 减,举个例子直接过:
add eax, 10 # eax += 10sub ecx, 20 # ecx -= 20
lea:
全称:Load Effective Address
作用是:取地址,我们也直接来看例子,一看就懂
int a = 10;
# mov eax, 0Ah
// 这里的 0Ah 是 10 的 十六进制表示形式
# mov dword ptr[a], eaxint *p = &a;
# lea eax, [a]
# mov dword ptr [p], eax
jmp:
全称: jump 跳转指令
jmp 是一个无条件跳转指令,会直接跳转到 操作数 所对应的地址(或者标签)上
在此基础上有一些分支,如 je 相等情况下跳转、jle 相等情况下跳转 ... 有很多,常常用在 if ... else ... 这类分支结构中,这里我们就不细说了。
稍微提一下:如何知道 jle 或者 je 这种指令是否跳转呢,有一个 efl 寄存器(eflag),其中记录了一些执行之后的标志,CPU看这个就知道跳不跳了,这里不细说了。
call、ret:
call 是用来调用函数,有跳转的功能,通常和 ret 配合使用,也有跳转的功能。
call、ret 的使用方法和 jmp 相似,在后面 跟上 要跳转到的地址就可以了。
call 在跳转之前会在函数栈帧中压入未来要返回的地址,ret 在跳转回来之后会将 call 压入的值给函数栈帧中弹出(逻辑上,实际上是直接让 esp + 4)
3. 总结
这篇文章,讲到了一些常见得到 汇编指令的用法和一些简单原理,总体来说不难,意在帮助大家能看懂一些反汇编的指令,更深入的了解C/C++的底层,大家只用常调试,多看,这些自然就懂啦~~