汇编基础总结
本文讨论的是32位intel处理器的汇编
单位
因为计算机本质是二进制的电平01因此最小底层的单位是位bit,一位只有两种状态0/1;而一般而言,为了保证有储存的信息量有一定程度计算机对数据的储存一般是以1字节byte(8位)作为最小储存单位;而为了方方便显示查看一般将每个字节转换位十六进制表示,也就是两位十六进制表示。
在汇编中常见的单位
- byte 字节 8位二进制 2位十六进制
- word 字
关键字 | 中文名 | 二进制长度 | 十六进制从长度 |
---|---|---|---|
bit | 位 | 1 | 四位才有一个长度 |
byte | 字节 | 8 | 2 |
word | 字 | 16 | 4 |
dword | 双字 | 32 | 8 |
而对一般而言的32位处理器,即代表32个bit,4个byte,2个word,一个dword。
位运算指令
汇编中的指令使用分为指令名和操作数
指令名 操作数1,操作数2
代表初始值位
操作数1
然后经过指令使用操作数2
进行变换之后把结果保存到操作数1
类似操作数1+=操作数2
,操作数1=操作数2
一般来说:大部分的汇编指令两个操作数不能同时为内存,一般默认这种情况,如有特殊会说明
基本含义 | 汇编表示 | C语言表示 | ||
---|---|---|---|---|
与 a&b | and a,b | a&=b | ||
或 a\ | b | or a,b | a\ | =b |
异或 a^b | xor a,b | a^=b | ||
非 ~a | not a | a~=a | ||
加 + | add a,b | a+=b | ||
减 - | sub a,b | a-=b | ||
自增 in-count | inc a | a++ | ||
自减 de-count | dec a | a-- |
通用寄存器
完整显示形式
汇编中对于寄存器的操作是直接使用寄存器名称的
类似寄存器的变量名
寄存器 | 特殊用途(约定俗成) | 编号 |
---|---|---|
EAX | ~ | 0 |
ECX | ~ | 1 |
EDX | ~ | 2 |
EBX | ~ | 3 |
ESP | 存储内存中栈顶的地址 | 4 |
EBP | 存储内存中栈底的地址 | 5 |
ESI | 6 | |
EDI | 7 |
其他显示形式
EAX ECX EDX EBX的E代表者32位
用十六进制表示就是
AA BB CC DD
(从左到右,从高到低位——为了向下兼容16位,8位有如下的显示方式
去掉E就是低位的十六位,也就是四个十六进制,例如
AX CX DX BX:CC DD
而低位的十六位可以分为两个八位高位High,低位Low,即在十六位表示的基础上把X替换成对应高低位表示,例如
- AH CH DH BH:
CC
- AL CL DL BL:
DD
标志寄存器
各位简介
- EIP始终指向当前程序运行到哪一行代码的代码地址
- C位(Carry Flag 进位标志) :更准确的来说是无符号数是否溢出的
P位(Parity Flag):也就是,运算结果中二进制表示的数据,1个数的奇偶
- 偶数个1:为1
- 奇数个1:为0
A位(Auxiliary Carry Flag 辅助进位标志):运算结果中半个数据宽度的低位组的最高位是否进位或借位
- 发生进位或者借位为1,不发生则为0
- 例如
0000 1000
变成0001 0000
那么就发生了进位A=1
- 例如
0001 0000
变成0000 1000
那么就发生了进位A=1
Z位(Zero Flag零位标志):运算结果是否为0
- 是0标志为1
- 是1标志位0
S位(Sign Flag符号标志):数值等于运算结果的最高位
- 因此如果把运算结果当作有符号数
S=1
则运算结果为负数,反之为正数- 如果当作无符号数则这个标志位是没有意义的
- O位(Overflow Flag溢出标志位):更准确的来说是代表有符号数是否溢出的标志
*C,O位区分
作为无符号数运算看:C位
- 字面意义上理解的是否有溢出数据宽度
作为有符号数运算看:O位
- 正加正为负(首位变为1)则溢出
- 负加负为正(首位变为0)则溢出
- 负加正 无论如何不溢出,因为不可能超过数据宽度
储存指令
共性
- 立即数:即数字一般用十六进制表示如
0xFFFFFF
- 寄存器:即上一个标题讲的内容,用寄存器名称表示
内存:
单位 ptr ds:[地址]
- 单位只有
byte
,word
,dword
- 地址一般用十六进制表示
- 这个表示过程就相当于对[]的地址进行寻址
- 单位只有
mov:=
- 本质上是赋值
- 除了内存到内存的赋值不能使用它其余的三种数据都可以随意储存
例如
mov eax,ebx
mov dx,cx
mov bl,cl
lea:a=&b
- 本质上是取址保存
例如
mov eax,ebx
xor eax,ebx
;等价于 mov edx,eax*2+ebx
;也就是先*后&
lea edx,byte ptr ds:[eax*2 + ebx]
push:入栈
- 规范:
push 存入的数
。这样会存入对应宽度的数到达栈顶 数据宽度为32位(dword,八个十六进制),16位(word,四个十六进制)不能更小
- 但是有例外:立即数可以存入最小8位的也就是一个字节byte
- 内存中最小的地址单位是byte,8位(两个十六进制)
pop:出栈
- 规范:
pop 取出的数存入的位置
。这样会取出对应宽度的数存道对应的位置 - 取出的数据宽度为32位(dword,八个十六进制),16位(word,四个十六进制)不能更小
push 0xFFFFFFFF
push 0xAAAAAAAA
pop eax ;取出的是0xAAAAAAAA
pop ebx ;取出的是0xFFFFFFFF
pushad和popad
- 无操作数
- pushad是吧寄存器的数值存入栈顶
- popad是吧栈顶的的数值8组32位(8x8=64个地址)的值存入寄存器
- 如果pushad后和popad前的栈顶位置相同,那么具有还原寄存器原有数值的功能,这也被称为堆栈平衡
跳转指令
jmp:无条件跳转
- 本质是修改EIP的值,因为EIP代表程序下一步指向的指令地址,所以代表着跳转
- 规范:
jmp 指令地址
。指令地址可以用寄存器或者立即数表示
call:一般用于函数调用
步骤
- 计算并且保存jmp前的下一行代码的地址,并push进栈中
- jmp到对应地址
- 继续执行
直到retn(return)
- pop eax
- jump eax
cmp:相等与否
- 本质:是sub指令但是不修改数值只是修改标志
- 如果相同:则Z位标志为会变成1,即相减等于0
test:检查是否全为0
- 本质:and指令但是不修改数值只修改标志
- 例如
test eax,eax
- 如果为空:则Z位标志为会变成1,即相减等于0
根据符号位的条件条件跳转
我也没记,用的的时候现查,用多了就记住了https://blog.csdn.net/xuehuafeiwu123/article/details/77480167