虽然以前上课讲过汇编语言,但是当时基础薄弱,再加上没怎么写汇编,就给忘记了。最近强烈意识到自己虽然能看懂大多数汇编,但是自己写却一直下不了手。所以决定好好学习一下intel
汇编语言的写法。
基本数据类型
内存中任何类型的变量,都以字节的形式存储和运行于内存中:
- windows中,一个字等于两个字节;
- 一个字节由两个16进制数表示
- 一个16进制数可用4个二进制数表示
- 一个字节也就是由8个二进制数表示
- 32位程序和64位程序,只需要记住计算机在处理时只对8字节,4字节,2字节和1字节进行处理
计算机的处理:只看字节,不看类型
x86指令集
通用数据传送指令
mov指令
mov
:把源操作数传送到目的操作数
movsx
:带符号扩展传送
movzx
:带零扩展传送
指令格式:mov(movsx,movzx) DEST, SRC
例如:
- mov eax, edx; 将 edx 赋值给 eax
- movsx eax, bl; 将 80H扩展为 ffffff80H 后送到 eax中
- movzx ax, bl; 将 80H 扩展为 0080H 后送到 AX中
操作数类型:
- OPS可以为:存储器、通用寄存器、段寄存器和立即数
- OPD可以为:存储器、通用寄存器和段寄存器(CS除外)
注意:
- 立即数不能送段寄存,其余可以任意搭配;立即数送存储器的指令有时难以确定操作数的长度,需要在存储器操作数的前面加上类型说明
BYTE PTR
或WORD PTR
例如:
- mov BYTE PTR [SI+10H], 30;8位立即数30送偏移地址为 SI+10H 的字节单元;
- Mov WORD PTR [BX+DI], 2;16位立即数送偏移地址为 BX+DI 的 字单元
注意:
- 两存储单元之间不能直接进行数据传送;两个段寄存器之间不能直接进行传送信息,但可以用 CPU 内部寄存器为桥梁来完成这样的传送
例如:
- mov AL, AREA1; mov AREA2, AL;
- mov AX, 1000H; mov DS, AX
- 立即数、代码段寄存器CS只能作源操作数
- IP 寄存器不能作源操作数或目的操作数
push指令
push:操作数进栈
PUSHA:把 AX,CX,DX,BX, SP, BP, SI, DI 依次压入堆栈中
PUSHAD:把 EAX, ECX, EDX, EBX. ESP, EBP, ESI, EDI 依次压入堆栈中
指令格式:PUSH(PUSHA/PUSHAD) SRC
操作数类型:可以是存储器、通用寄存器和段寄存器,但不能是立即数
说明:PUSH指令先将 SP 的内容减 2,然后再将操作数 OPS 的内容送入由 SP 指出的栈顶即偏移地址为 SP 和 SP+1 的两个连续字节中
- PUSH AX; 通用寄存器内容入栈
- PUSH CS; 段寄存器内容入栈
- PUSH [SI]; 字存储单元内容入栈
pop指令
POP:出栈到目的操作数,把当前的 SP 所指向的堆栈顶部的一个字送到指定的目的操作数
POPA:把 DI,SI, BP, SP, BX, DX, CX, AX 依次弹出堆栈
POPAD:把 EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX 依次弹出堆栈
指令格式: POP(POPA/POPAD) DEST
操作数类型:可以是存储器、通用寄存器或段寄存器(但不能是 CS),同样不能是立即数
说明:POP指令先将堆栈指针SP所指示的栈顶存储单元的值弹出到操作数OPD中,然后再将SP的内容加2。
XCHG
交换两操作数,允许通用寄存器之间,通用寄存器和存储器之间交换数据
指令格式:XCHG OPR1,OPR2
例:
- XCHG EAX, EBX;通用寄存器之间交换数据
- XCHG EBX, [ESI];通用寄存器和存储器之间交换数据
注意:两操作数不允许同时为存储器操作数,交换指令不影响标志位
地址传送指令
LEA指令
LEA:将源操作数的有效地址传送到通用寄存器
指令格式:LEA REG, MEM
例:
- LEA EAX, [EBP-4];将 ss段中 EBP-4 指向的存储单元送入 EAX
标志寄存器传送指令
PUSHF:16位标志寄存器进栈
PUSHFD:32位标志寄存器进栈
POPF:16位标志寄存器出栈
POPFD:32位标志寄存器出栈
算术运算指令
加法指令
ADD:将源操作数和目的操作数相加,结果送到目的操作数
ADC:将源操作数与目的操作数以及CF值相加,结果传送到目的操作数。
指令格式:ADD(ADC) DEST, SRC
注意: ADD,ADC 指令影响的标志位是 OF,SF,ZF,AF,PF,CF
INC:目的操作数加一,结果送入目的操作数
- 目的操作数可以为通用寄存器或存储器操作数
指令格式:INC DEST
减法指令
SUB:将目的操作数减去源操作数,结果送入目的操作数
SBB:将目的操作数减去源操作数,再减去CF值,结果送入目的操作数
指令格式:SUB(SBB) DEST, SRC
注意:SUB, SBB 指令影响的标志位是 OF, SF, ZF, AF, PF, CF
DEC:目的操作数减一,结果送入目的操作数(可以为通用寄存器或存储器操作数)
指令格式:DEC DEST
乘法指令
MUL:无符号数乘法指令,将源操作数和目的操作数相乘,结果送入目的操作数
IMUL:有符号数乘法指令,将源操作数和累加器中的操作数相乘,结果送入目的操作数
指令格式:MUL(IMUL) SRC
说明:MUL, IMUL 指令的源操作数为通用寄存器或存储器操作数,目的操作数缺省存放在ACC累加器(AL,AX,EAX)中
除法指令
DIV:无符号除法指令
IDIV:有符号除法指令
指令格式:DIV(IDIV) SRC
说明:DIV、IDIV指令的源操作数作为除数,为通用寄存器或存储器操作数,目的操作数作为被除数,目的操作数缺省存放在 ACC累加器(AL,AX,EAX)中
逻辑运算和移位指令
逻辑运算
AND:逻辑与,目的操作数和源操作数按位进行逻辑与运算,结果存目的操作数
OR:逻辑或,目的操作数和源操作数按位进行逻辑或操作,结果存目的操作数
源操作数可以是通用寄存器、存储器操作数或立即数,目的操作数是通用寄存器或存储器操作数
XOR:逻辑异或,目的操作数和源操作数按位进行逻辑异或运算,结果存目的操作数
指令格式:AND(OR/XOR) DEST, SRC
NOT:逻辑非,对目的操作数按位取反,结果存入目的操作数
指令格式:NOT DEST
TEST:目的操作数与源操作数按位进行逻辑与操作,并修改标志位,结果不送回目的操作数
指令格式:TEST DEST, SRC
注意:TEST指令常用在检测某些条件是否满足,但又不希望改变原有操作数的情况下使用,紧跟在这条指令后面的往往是一条条件注意指令,根据测试结果产生分支,转向不同的处理程序。
算数逻辑移位
SAL:算术左移指令
SHL:逻辑左移指令
指令格式:SAL(SHL) DEST, OPRD
说明:SAL、SHL 指令功能完全相同,按照操作数 OPRD 的规定的移位位数对目的操作数进行左移操作,没移一位,最低为补0,最高位移入标志位CF中。
SAR:算数右移
- 按照操作数OPRD规定的移位位数,对目的操作数进行右移操作,每移一位,最低位移入标志位CF,最高位(符号位)保持不变,相当于对有符号数进行除2操作。
SHR:逻辑右移
- 按照操作数OPRD规定的移位位数,对目的操作数进行右移操作,每移一位,最低位移入标志位CF,最高位补0。
指令格式:SAR(SHR) DEST, OPRD
ROL:循环左移
ROR:循环右移
指令格式:ROL(ROR) DEST, OPRD
串操作数
串指连续存放在存储器中的一些数据字节、字或双字
串操作允许程序对连续存放的数据块进行操作:
串操作通常以DS:ESI来寻址源串,以ES:EDI 来寻址目的串
对于字符串的基本操作,80x86 提供了五个指令:
字符串传送:
字节/字操作:MOVS DEST, SRC;
字节操作:MOVSB
字操作:MOVSW
双字操作: MOVSD
指令功能:字符串传送指令,把由 ESI 作指针的源串的字节或字,传送到 EDI作指针的目的串中,且自动修改指针ESI和EDI
字符串比较:
字节/字操作:CMPS DEST, SRC;
字节操作:CMPSB
字操作:SMPSW
双字操作: SMPSD
指令功能:字符串比较指令,由DS:ESI规定的源串元素减去ES:EDI指出的目的串元素,结果不回送,仅影响标志位CF,AF, PF, OF, ZF 和 SF
字符串扫描:
字节/字操作:SCAS DEST;
字节操作:SCASB
字操作:SCASW
双字操作: SCASD
指令功能:串扫描指令,由EAX的内容减去ES:EDI规定的目的串元素,结果不回送,仅影响标志位
字符串装入:
字节/字操作:LODS SRC;
字节操作:LODSB
字操作:LODSW
双字操作: LODSD
指令功能:串装入指令,将DS:ESI所指的源串元素装入累加器EAX中
字符串存储:
字节/字操作:STOS SRC;
字节操作:STOSB
字操作:STOSW
双字操作: STOSD
指令功能:串存储指令,将累加器EAX中的值存入ES:EDI所指的目的串存储单元中
寻址方式
立即寻址
操作数直接放在指令中,紧跟在操作码之后,他作为指令的一部分存放在代码段中,这种操作数叫做立即数
立即数寻址常用来给寄存器赋初值,不用于访问寄存器、存储器,指令执行速度快
例:MOV EAX, 20H;将一个立即数26H送到EAX寄存器中
注意:立即数只能作为源操作数,不能作为目的操作数,源操作数的长度应该和目的操作数保持一致
寄存器寻址
这种寻址方式由于操作数就在寄存器中,不需要访问存储器来获得操作数
例如:MOV EAX, EBX
操作数存放在寄存器中,在指令中给出具体寄存器,指令执行时会到指定寄存器中取出相应的操作数,源和目的操作数都可以是寄存器
在80x86系统中,内存单元的物理地址由段基址和偏移地址(又称为偏移量)组成
- 段基址:在IA-32的保护模式下,段基址由16位的段选择符得到,这些段选择符存放在6个段寄存器
- 偏移地址的计算包含以下4部分:
- 基址寄存器
- 变址寄存器
- 比例因子
- 位移量
将基址寄存器、变址寄存器、比例因子和位移量四部分,按某种方式组合形成偏移地址,称为有效地址EA
有效地址(EA) = 基址+变址*比例因子+位移量
其中,基址、变址和位移量的值可正可负,比例因子只能为正
直接寻址
操作数在寄存器中,指令中包含有操作数的有效地址(偏移地址)
注意:操作数一般存放在数据段DS,所以操作数的有效地址由DS加上指令中直接给出的16位偏移地址得到
例如:MOV AX, [1234H]
假设 DS=4567H,内存中 [468A4H] = 0001H,那么有效地址EA= [4567H]*16 + [1234H] =[468A4H]
也即,AX = 0001H
直接寻址(段超越前缀)
因为默认的是 DS寄存器,其实也可以指定前缀寄存器,即段超越前缀
MOV AX, SS:[1234H]
把 SS 数据段中偏移地址为1234H 的字复制到寄存器AX
寄存器间接寻址
操作数的有效地址在寄存器中,这种寻址方式为寄存器间接寻址
如果操作数的有效地址在 EAX,EBX,ECX,EDX,ESI和EDI中,以上寄存器默认使用DS作为段寄存器,即DS段寄存器为段基址
如果操作数的有效地址在 ESP,EBP,这两个寄存器默认使用 SS 作为段寄存器,即 SS 段寄存器为段基址
寄存器相对寻址
操作数的有效地址EA为基址寄存器或变址寄存器的内容和指令中的位移量之和
- EAX,EBX,ECX,EDX,ESI和EDI,以上寄存器默认使用DS作为段寄存器
- ESP,EBP,这两个寄存器默认使用SS作为段寄存器
MOV ECX,[EAX+24H],也可以写为 MOV ECX, 24H[EAX];
1 | 1、立即寻址 : MOV AL,05H |
- 本文作者: A1ex
- 本文链接: http://yoursite.com/2020/11/30/intel汇编语言学习/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!