X86汇编
X86汇编
在网上无意间看到“编程达人”的一个讲汇编的视频,觉得讲的挺好的,刚好我也一直没学明白这个东西,然后就花了半天时间看完了,看到头昏脑涨就记住了下边这些东西。
通用寄存器
32位 | 16位 | 8位 |
---|---|---|
EAX | AX | AL |
EBX | BX | BL |
ECX | CX | CL |
EDX | DX | DL |
ESP | SP | AH |
EBP | BP | CH |
ESI | SI | DH |
EDI | DI | BH |
mov eax, 1
使用内存
1.把立即数写入内存
|
|
2.把寄存器的值写入内存
|
|
3.把内存中的值写入寄存器
|
|
4.内存到内存需要特殊的指令
后边会有
内存地址的五种表示形式
形式一: [立即数]
形式二: [reg] reg代表八个通用寄存器中的任何一个
1
mov dword ptr ds:[eax], 12345678 # 其中eax中保存内存的地址
形式三:[reg+立即数]
1
mov dword ptr ds:[eax+4], 12345678 # 其中eax+4中保存内存的地址
形式四:[reg+reg*{1,2,4,8}]
形式五:
[reg+reg*{1,2,4,8}+立即数]
存储模式
大端模式:数据高位在低地址,数据低位在高地址
小端模式:数据低位在低地址
0x1A2C3E4F
的小端模式
地址 | 数字 |
---|---|
0x00 | 4F |
0x01 | 3E |
0x02 | 2C |
0x03 | 1A |
80x86一般都是小端模式
汇编指令
基础指令
1.mov
格式 | 解释 |
---|---|
mov r/m8, r8 | r代表通用寄存器,8代表是8位的 |
mov r/m16, r16 | m代表内存 |
mov r/m32, r32 | |
mov r8, r/m8 | |
mov r16, r/m16 | |
mov r32, r/m32 | |
mov r8, imm8 | imm8 代表8位立即数 |
mov r16, imm16 | |
mov r32, imm32 |
2.ADD
格式 | 解释 |
---|---|
ADD r/m8, imm8 | 中间那个表示目的地址 |
ADD r/m32, r32 | |
ADD r32, r/m32 |
3.SUB和add指令类似
4.AND
5.OR
6.XOR
7.NOT
连续复制数据指令
8.MOVS 移动数据, 内存-内存
指令 | 简写 |
---|---|
MOVS BYTE PTR ES:[EDI], BYTE PTR DS:[ESI] | MOVSB |
MOVS WORD PTR ES:[EDI], WORD PTR DS:[ESI] | MOVSW |
MOVS DWORD PTR ES:[EDI], DWORD PTR DS:[ESI] | MOVSD |
EDI:存储一个地址,目标地址 ESI:存储的是一个地址,源数据的地址
EDI和ESI内的地址会根据EFI的第十位DF的值改变,0 :自增, 1:自减。
9.STOS: 将AL/AX/EAX的值存储到[EDI]指定的内存单元
格式 | 解释 | 简写 |
---|---|---|
STOS BYTE PTR ES:[EDI] | 将AL中的内容写到[EDI]指向的内存空间,EDI内的地址+1/-1(由DF位确定) | STOSB |
STOS WORD PTR ES:[EDI] | STOSW | |
STOS DWORD PTR ES:[EDI] | STOSD |
10.REP : 按照计数寄存器(ECX)中指定的次数重复执行字符串指令
MOV ECX, 10
REP MOVS DWORD PTR ES:[EDI], DWORD PTR DS:[ESI] #或者 REP MOVSD
堆栈操作
ESP寄存器存储栈顶指针,从大地址逐渐减小,向低地址生长。
11.push : 向堆栈中压入数据,并修改esp的值。
格式 | 同义 |
---|---|
PUSH r32 | |
PUSH r16 | |
PUSH m32 | PUSH DWORD PTR DS:[18FFA4] |
PUSH m16 | |
PUSH imm8/imm16/imm32 |
12.pop:
格式 | 同义 |
---|---|
POP r32 | |
POP r16 | |
POP m32 | |
POP m16 |
修改EIP的指令
EIP寄存器里边存储的是CPU下一时刻应该执行的指令。
13.jmp :寄存器/立即数/内存地址
14.call : 先push下一行地址,然后jmp,
15.ret : ADD ESP, 4; MOV EIP, [ESP-4];
函数
函数调用
jmp 来执行函数
call 来调用函数
ret 返回call调用的函数
参数传递
寄存器传参:ecx,edx存储参数,eax存储返回值。
堆栈传参:先将参数压入堆栈,然后call调用函数,eax存储返回值。
堆栈平衡:
- 如果要返回父程序,则当我们在堆栈中进行堆栈操作的时候,一定要保证在RET指令前,ESP指向的是我们压入栈中的地址。
- 如果通过堆栈传递参数,那么在函数执行完毕后,要平衡参数导致的堆栈变化。
ESP寻址
调用函数的时候要保存现场,函数返回前要恢复现场。
EBP寻址
EBP寄存器保存的是栈底的地址。
JCC指令
标志寄存器EFL
31-12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
OF | DF | IF | TF | SF | ZF | 0 | AF | 0 | PF | 1 | CF | |
溢出 | 方向 | 中断使能 | 单步 | 符号 | 零 | 0 | 辅助进位 | 0 | 奇偶 | 1 | 进位 |
CF (Carry flag):若算术操作产生的结果在最高有效位发生进位或者借位将其置1,反之清零。
PF(parity flag): 如果结果的最低有效字节(最低位的一个字节)包含偶数个1,则置1,否则清零。
AF (Auxiliary Carry Flag):如果算术操作在结果的第三位发生进位或者借位则将该标志置1,主要应用于BCD运算。
ZF (Zero Flag): 如果运算的结果为0,则设置为1,否则清零,经常和cmp或者test等指令一起使用
SF (Sign Flag): 该标志被设置为有符号整数的最高有效位,0为正,反之为负
OF (Overflow flag) :溢出标志用于反映有符号数加减运算所得出结果是否溢出。
如果是无符号数运算,是否溢出看CF位;
有符号数看OF
DF (Direction Flag):这个方向标志控制串指令(MOVS, CMPS, SCAS, LODS以及STOS)。设置DF标志使得串指令自动递减,清除该标志则使得串指令自动递增。STD和CLD指令分别用于设置以及清除DF标志。
指令 | 意义 | 标志位 |
---|---|---|
JE, JZ | 结果为零则跳转(相等时跳转) | ZF=1 |
JNE, JNZ | 结果不为零则跳转(不相等时跳转) | ZF=0 |
JS | 结果为负则跳转 | SF=1 |
… | … | … |
清华大学-汇编语言程序设计
基础知识
各类指令集初步
数制与整数表示
浮点数表示
X86汇编(AT&T风格)
AT&T风格的汇编
movl source, dist
其中mov后边的l表示操作的字长, AT&T先原地址后目标地址
80x86计算机组成与保护模式
80386有三种工作模式:
X86指令系统与寻址方式
- 间接寻址
(R): Mem[Reg[R]]
表示寄存器R指定内存的地址,例:movl (%ecx), %eax
基址+偏移量
寻址D(R) : Mem[Reg[R]+D]
寄存器R指定内存起始地址,常数D给出偏移量, 例,movl 8(%ebp), %edx
表示把%ebp
中取出一个数加上8作为内存的地址。- 变址寻址
D(Rb, Ri, S) : Mem[Reg[Rb] + S* Reg[Ri] +D]
, 常量D给出地址偏移量,基址寄存器Rb是8个通用寄存器之一,索引寄存器Ri,S是比例因子,取值为1,2,4,8。
leal src, dist
指令将src
表示的地址计算出来并传递给dist
。 比如:leal (%edx, %edx, 2), %edx
C与x86汇编
x86汇编语言程序格式与基本编程
AT&T和Intel汇编格式主要区别
- 在Intel格式中大多使用大写字母,而AT&T格式中都使用小写字母
- 在AT&T格式中,寄存器名上要加上“%”作为前缀,而Intel格式则不带前缀。
- 在AT&T格式中,指令的源操作数在前,目标在后,恰好和Intel格式完全相反。
- 在AT&T格式中,访问内存指令的操作数大小由操作码后缀来决定。用作操作码后缀的字母有b(表示8位),w(表示16位), l(32位)。而在Intel格式中,则是在表示内存单元的操作数前面加上“BYTE PTR” , “WORD PTR”, “DWORD PTR"来表示的。
- AT&T中的立即数要加上”$“作为前缀,Intel格式不带前缀。
- AT&T格式中,绝对转移或者调用指令jump/call的操作数,要加上”*“作为前缀。Intel格式不用。
- 间接寻址的一般格式:Intel格式:
SECTION:[BASE + INDEX*SCALE+DISP]
;AT&T格式:section:disp(base, index, scale)
- 远程的转移指令和子程序调用指令的操作码名称,在AT&T中为"ljmp"和"lcall”,而在Intel格式中为“JMP FAR”和"CALL FAR"。
linux内核中的汇编语言规则
哈工大李治军操作系统
linux内核中使用了三种汇编
- as86汇编:能产生16位代码的Intel 8086汇编。 主要构成了bootsect, setup代码。
- GNU as汇编:能产生32位代码的AT&T系统V语法。主要构成保护模式代码。
- GNU内嵌汇编:进程调度代码。