Twosmi1e's Blog.

汇编基础

Word count: 4,994 / Reading time: 21 min
2018/11/30 Share

0x00 IA32处理器体系结构

微机的基本结构

Alt text

指令执行周期

Alt text
当指令使用了内存操作数时还需要两个额外的步骤:取操作数和存储输出操作数。
机器指令的执行;

  1. 取指令
  2. 解码
  3. 执行

操作模式

保护模式:处理器的基本模式。
虚拟8086模式:多任务环境中执行是地址模式的软件。
实地址模式:用于运行那些需要直接访问系统内存和硬件设备的MS-DOS程序。
系统管理模式:实现电源管理和系统安全等功能的机制。

基本执行环境

基本寄存器

寄存器中数据在内存中存放数据遵循高高低低的原则

8个通用寄存器

EAX EBX ECX EDX
EBP ESP ESI EDI

Alt text

6个段寄存器
Alt text

一个处理器状态标志寄存器(EFLAGS)和一个指令指针(EIP)寄存器。
Alt text

ESP:栈地址寄存器 任意时刻指向栈顶元素
EBP:扩展帧指针寄存器 指向堆栈上的函数参数和局部变量
EIP:指令指针寄存器
EIP寄存器不能作为MOV指令的⽬标操作数

EFLAGS:由控制CPU的操作或反映CPU某些运算的结果的独立二进制位构成

状态标志

Name
CF 进位标志 进位或借位时CF=1
AC 辅助进位标志 低4位进位或借位时A=1
PF 奇偶标志 偶数P=1
ZF 零标志 结果为0则Z=1
SF 符号标志 S = 符号位值(补码时0=正,1=负)
OF 溢出标志 运算结果超界时O=1
DF Direction Flag
IF Intertupt Flag
TF Trace Flag

内存管理

实地址模式

可以寻址1MB内存 0~FFFFF

20位线性地址

linear address or abssolute address is 20 bits,range from 0 to FFFFF
用段-偏移地址表示

  • CS:16位代码段
  • DS:16位数据段
  • SS:16位堆栈段
  • ES,FS,GS可指向其他数据段

保护模式

可以寻址4GB内存 0~FFFFFFFF
段寄存器指向段描述符表,操作系统使用段描述符表定位程序使用的段的位置。

0x01 汇编语言基础

补码的表示法

  • 正数的补码:与源码相同
  • 负数的补码:反码加1

寻址方式

Alt text
Alt text
Alt text

基本元素

16进制数第一个是字母时要在前面加0

指令

一条汇编指令包括4个部分:

  • 标号(可选)
  • 助记符
  • 操作数
  • 注释(可选)

Alt text

INVOKE

相当于call,调用函数或过程

伪指令

伪指令课用于定义变量、宏以及过程,可用于执行命名段以及执行其他与汇编器相关任务。
.data? :指明未初始化的数据段

NOP指令

占用一个字节的存储,什么也不做。

程序模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TITLE Program Template
; 程序描述:
; 作者:
; 创建日期:
; 修改:
; 日期: 修改者:
INCLUDE Irvine32.inc
.data
;(在此插入变量)
.code
main PROC
;(在此插入可执行代码)
exit
main ENDP
;(在此插入其他子程序)
END main

汇编-链接-执行

Alt text
Alt text

定义数据

字符常量/字符串常量

  • 以单引号或双引号括起来的单个/一串字符
  • 存储为对应字符的ASCII码
后缀 含义
d 十进制
b 二进制
q 八进制
h 十六进制

数据定义语句

初始值可以用?表示不确定,可以是表达式。
可以指定多个初始值,用逗号隔开,变量名代表第一个初始值的偏移。

DUP可以为多个数据项分配存储空间。
V1 BYTE 10 dup (0)V1占用10个字节空间,初值均为0

符号常量

等号伪指令:名字=表达式

计算数组和字符串大小:
1
2
3
4
5
6
7
list BYTE 10, 20, 30
ListSize = ($ - list)

list word 10,20,30,40
ListSize = ($-list)/2

myString_len = ($ - myString)
EQU和TEXTEQU伪指令:

将符号名和整数表达式,文本联系起来。

1
2
3
4
5
6
7
8
name EQU expression
name EQU symbol
name EQU <text>

rowSize = 5
count TEXTEQU %(rowSize * 5)
move TEXTEQU <mov>
setupAL TEXTEQU <move al, count>

setupAL将被汇编成mov al, 10

0x02 数据传送,寻址,算术运算

小尾(小端)顺序

intel处理器使用小端顺序存储,最低字节存储在最低地址单元
Val DWORD 12345678h
Alt text

数据传送指令

操作数类型

  • 立即操作数(immediate)
  • 寄存器操作数(register)
  • 内存操作数(memory)

MOV指令
MOV destination, source

  • 两个操作数尺寸必须一致
  • 不能同时为内存操作数
  • 目的操作数不能是CS, EIP,IP
  • 立即数不能直接送至段寄存器

MOVZX
复制较小值至较大值中。
低八位原样复制,高八位补0扩展,仅适用于无符号整数。
MOVSX
低八位原样复制,高八位补F扩展,仅适用于有符号整数。
LAHF/SAHF
LAHF将标志局存起EFLAGS的低8位复制到AH寄存器,SAHF是将AH复制到EFLAGS
XCHG指令
交换两个操作数的内容。
XCHG reg, reg
XCHG reg, mem
XCHG mem, reg

算数指令

名称 作用 影响标志位
INC 加1 AF OF PF SF ZF 不影响CF
DEC 减1 AF OF PF SF ZF 不影响CF
ADD 相加 CF ZF SF OF AF PF
SUB 相减 CF ZF SF OF AF PF
NEG 取相反数 CF ZF SF OF AF PF

加减法影响标志位

INC和DEC不会影响CF标志位
Alt text
NEG影响的标志位和ADD SUB一样
Alt text

名称 作用
CF进位位 无符号数是无溢出
OF溢出位 有符号数有无溢出
ZF零标位 判断结果是否为0
SF符号位 结果正负
PF奇偶标志 最低有效字节内1的个数是否为偶数
AC辅助进位标志 最低有效字节的第三位向高位进位

加减法算术运算指令的操作数自身不区分有无符号数,程序通过判断不同的标志位来实现对有符号数和无符号数的处理。

和数据相关的操作符和伪指令

名称 作用
OFFSET 取偏移地址
ALIGN 设置对齐值
PTR 重载默认尺寸
TYPE 返回单个元素大小
LENGTHOF 计算数组中元素的数目
SIZEOF 返回LENGTHOF*TYPE
LABEL 插入一个标号并赋予尺寸

加逗号可以多行定义
Alt text
LABEL不会分配存储空间
Alt text

JMP和LOOP

JMP

无条件转移与条件转移
Alt text
JMP 目的地址
功能:接着从目的地址开始执行指令

  • 目的地址一般为标号
  • 通常在当前过程内跳转

LOOP

LOOP 目的地址
功能:将ecx的值减1,接着与0比较,如果不等于0,就执行目的地址开始的指令,如果等于0 ,则不跳转,接着执行紧跟在LOOP指令后的指令

  • 通常,ecx里的值就是循环次数。但如果初值为0,因是先减1再判断是否等于0,所以,实际实际循环次数就是1 00 00 00 00 H
  • LOOPD也使用ecx控制循环,LOOPW使用cx控制循环。
  • 实模式下,使用的是cx作为控制循环的寄存器

实例

数组求和:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
INCLUDE irvine32.inc
.data
vb1 byte 1 , 2 , 3
.code
main proc
mov esi , offset vb1
mov ecx , lengthof vb1
mov al , 0
L1:
add al , [ esi ]
add esi , type vb1
loop L1
exit
main endp
end main

复制字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
INCLUDE irvine32.inc
.data
s1 byte "source string",0
s2 byte sizeof s1 dup(0)
.code
main proc
mov esi , 0
mov ecx , sizeof s1
L1:
mov al , s1[ esi ]
mov s2[esi] , al
inc esi
loop L1
exit
main endp
End main

寻址方式总结

操作数寻址方式

Alt text
数据寻址的基本方式:

  1. 立即寻址
  2. 寄存器寻址
  3. 存储器寻址

存储器寻址有六种类型

Alt text

用寄存器作为指针并操纵寄存器的值。操作数使用间接寻址则叫间接操作数。
Alt text|center
Alt text|center

0x03 过程

堆栈操作

运行时栈

运行时栈是CPU直接管理的内存数组,使用到两个寄存器:SS和ESP

  • 保护模式下,SS是段选择子,应用程序不应该修改它
  • ESP是指向栈的特定位置的一个32位偏移值
  • 一般不会直接修改ESP,而是通过使用CALL,RET,PUSH,POP等指令,由这些指令间接操作ESP。
  • ESP指向最后压入到栈的数据
  • 实模式下,使用的SS和SP

PUSH
PUSH r/m16
PUSH r/m32
PUSH imm32

压栈,将操作数放入堆栈中:

  1. 将ESP减4
  2. 将要压入的32位值拷贝到ESP指向的内存。
    Alt text

对于32位操作数,ESP减4,存到栈中的内容为双字;对于16位操作数,ESP减2,存到栈中的内容为字
POP
POP r/m16
POP r/m32

出栈,从堆栈中取出操作数放到指令中的操作数中

  1. 将ESP所指向内存中的内容取出放到操作数中
  2. 将ESP加4
    Alt text
    对于32位操作数,是先从栈中拷贝双字到操作数中,然后ESP加4;对于16位操作数,是先从栈中拷贝字到操作数中,然后ESP加2。

PUSHFD 把32位标志寄存器压入堆栈
POPFD 从堆栈中弹出32位值到标志寄存器中
两指令无操作数
实模式下标志寄存器是16位的,入栈出栈指令分别是PUSHF,POPF。
PUSHAD 把八个32位通用寄存器按序全部压入堆栈
POPAD是以上序反序从堆栈中依次弹出值到八个32位通用寄存器中

过程定义

PROC

1
2
3
main proc
...
main endp

一般过程需要返回指令ret,起始过程需要调ExitProcess

CALL和RET

call 过程名
将EIP压栈(即当前CALL指令的下一条指令的地址),然后将过程名所在地址赋给EIP(相当于跳转到过程名所在的代码处)
RET
RET指令是从栈中取出32位地址,赋给EIP。
Alt text
使用寄存器传递过程参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.data
dArray DD 1, 2 , 3
dSum DD ?
.code
Main proc
mov ebx , offset dArray
mov ecx , lengthof dArray
call SumOf
mov dSum, eax
exit
Main endp
SumOf proc
push ebx
push ecx
mov eax , 0
L2: add eax , [ebx]
add ebx , 4
loop L2
pop ecx
pop ebx
ret
SumOf endp
End main

0x04 条件处理

布尔和比较指令

名称 作用
AND
OR
XOR 异或
NOT
TEST 与,不改变目的操作数只改变标志位
BT,BTC,BTR,BTS 求补/清零/置位

尺寸相同
AND, OR,XOR总是清除溢出标志和进位标志(CF和OF)
NOT不影响任何标志位

实例

小写转大写:

同一字母的大写字母和小写字母的ASCII码的区别只在第5位不同,其他各位相同,小写字母第5位为1,大写字母第5位为0
如要把小写转大写,则可将小写的ASCII码与11011111B相与

1
2
3
4
5
6
7
8
9
10
11
12
.data
aName byte “Abraham” , 0
nameSize=($-aName)-1
.code
Main proc
mov ecx , nameSize
mov esi , 0
L1:AND aName[esi] , 11011111B
inc esi
loop L1
Main endp
End Main

将0-9之间的整数转换为对应数字符号的ASCII码
1
2
3
4
5
6
7
8
9
10
11
12
13
.data
aNum byte 1,3,2,0
numSize=($-aNum)-1
.code
Main proc
mov ecx , numSize
mov esi , 0
L1:OR aNum[esi] , 110000B
inc esi
loop L1
exit
Main endp
End Main

CMP
功能:对两个操作数作相减运算,不修改操作数,但会影响标志位。会修改OF、SF、ZF、CF、AF、PF。

设置和清除单个CPU状态标志

Alt text
Alt text

条件跳转

基于特定标志位

为真时跳转 为假时跳转 相关标志位
JZ JNZ ZF
JC JNC CF
JO JNO OF
JS JNS SF
JP JNP PF

基于相等比较

助记符 描述
JE 相等跳转 同JZ
JNE 不相等跳转 同JNZ
JCXZ CX=0跳转
JECXZ ECX=0跳转

基于无符号数比较

助记符 描述
JA 大于跳转
JB 小于跳转
JAE 大于等于
JBE 小于等于
JNA 不大于
JNB 不小于
JNBE 同JA
JNAE 同JB

基于有符号数比较

助记符 描述
JG 大于跳转
JL 小于跳转
JGE 大于等于
JLE 小于等于
JNG 不大于
JNL 不小于
JNLE 同JG
JNGE 同JL

实例

将最小有符号数存到AX:

1
2
3
4
5
6
7
8
     Mov ax,v1
Cmp ax,v2
JL L1
mov ax,v2
L1:cmp ax,v3
JL L2
mov ax, v3
L2:

数组的顺序查找
查找第一个非0值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
INCLUDE Irvine32.inc

.data
intArray SWORD 0,0,0,0,5,20,35,-12,66,4,0
noneMsg BYTE "A non-zero value was not found", 0
.code
main PROC
mov ebx, OFFSET intArray
mov ecx, LENGTHOF intArray
L1: cmp WORD PTR [ebx], 0
jne found
add ebx, 2
loop L1
jmp notFound
found:
movsx eax, WORD PTR[ebx]
call WriteInt
jmp quit
notFound:
mov edx, OFFSET noneMsg
call WriteString
quit:
call Crlf
exit
main ENDP
END main

条件循环指令

指令 循环条件
LOOPZ ECX>0 && ZF=1
LOOPE ECX>0 && ZF=1
LOOPNZ ECX>0 && ZF=0
LOOPNE ECX>0 && ZF=0

LOOPE和LOOPZ不影响任何状态标志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.data 
Array SWORD -3,-6,-1,-10,10,30,40,5
Sentinel SWORD 0
.code
; …
mov esi , offset array
mov ecx , lengthof array
L1:test word ptr [esi],8000h
pushfd ; pushfd不修改标志位
add esi , type array
popfd
loopnz L1 ; 注意:loopnz不修改标志位
jnz quit
sub esi , type array
Quit:

0x05 整数算术指令

移位和循环移位

指令 含义
SHL 逻辑左移
SHR 逻辑右移
SAL 算术左移
SAR 算术右移
ROL 循环左移
ROR 循环右移
RCL 带进位的循环左移
RCR 带进位的循环右移
SHLD 双精度左移
SHRD 双精度右移

逻辑移位和算术移位

SHL/SAL
SHL 目的操作数, 移位位数
功能:对目的操作数执行左移操作,最低位补0,移出的最高位送入进位标志CF,原来的进位位将丢失。SHL和SAL功能完全一样。
Alt text

左移的SHL和SAL是等价的。算术移位不改变符号位,逻辑移位可能改变符号位
SHR
SHR 目的操作数, 移位位数
功能:将目的操作数逻辑右移,左边空出的位添0,右边最低位被移出,复制到CF位中
SHR可以实现无符号数的快速除法
Alt text
SAR
有符号数的快速除法,右移过程中最高位保持不变
Alt text
ROL/ROR/RCL/RCR
移出的位又送回另一端
Alt text
SHLD/SHRD
Alt text
应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
BinToAsc PROC  uses eax ebx ecx  esi
;将EAX中的数转换成二进制ASCII码存到ESI指向的数组中
Add esi , 31
Mov ecx ,32
Nxt:
Mov bl, al
And bl , 1
Add bl , 30H
Mov [esi],bl
Shr eax,1
Dec esi
Loop nxt
Ret
BinToAsc ENDP

乘法和除法指令

助记符 描述
MUL 无符号乘法
IMUL 有符号乘法
DIV 无符号除法
IDIV 有符号除法
应用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Mov al, 30h
Mov bl, 4h
Mul bl ;AX =0C0H,CF=0


Mov ax , 2000h
Mov bx ,100h
Mul bx ;DX:AX=0020 0000h,CF=1

Mov al, -4
Mov bl, 4
IMUL bl ;AX=0FFF0H,CF=0

Mov ax, 30h
Mov bx, 4h
IMul bx ;DX:AX =0C0H,CF=0

Mov al, 48
Mov bl, 4
IMUL bl ;AX=00C0H(即十进制的192),CF=1
任意进制的码制转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.data 
ASCIICHAR BYTE '0123456789ABCDEFGHIJKLMNOPQRSTUVWZYX'
.code
ToASC PROC uses eax ebx ecx esi
;将EAX中的数按BL中指定的进制数,转换成ASCII字符串放到ESI指向的数组中
mov ecx , 0 ;
mov cl , bl ; movzx ecx, bl
add esi , 31
nxt_ta:
mov edx , 0
div ecx
mov bl,ASCIICHAR[edx]
mov [esi],bl
dec esi
cmp eax , 0
jnz nxt_ta ; jne
ret
ToASC ENDP

0x06 高级过程

stack frame

给子过程传递参数的两种基本方式

  1. 通过寄存器传递
  • 执行效率高
  • 代码可能显得混乱
  • 寄存器数量有限
    1
    2
    3
    4
    mov esi , offset array
    mov ecx,lengthof array
    mov ebx , type array
    call DumpMem
  1. 通过堆栈传递
  • 方式灵活通用
  • 效率偏低
    1
    2
    3
    4
    push offset array
    push lengthof array
    push type array
    call DumpMem2

使用堆栈传递参数时压入了两类参数:

  • 值参数(变量或常量的值)
  • 引用/指针参数(变量的地址)
实例

传递值

1
2
3
4
5
6
7
.data 
val1 dword 5
val2 dword 6
.code
push val2
push val1
call AddTwo

Alt text
AddTwo(val1,val2)

传递引用

1
2
3
4
5
6
7
.data 
val1 dword 5
val2 dword 6
.code
push offset val2
push offset val1
call AddTwo

Alt text
AddTwo(&val1,&val2)

重点:参数访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.data 
Val1 dword 5
Val2 dword 6
.code
Push val2
Push val1
Call AddTwo

AddTwo proc
push ebp
Mov ebp , esp
mov eax , [ebp + 12] ;取得val2
add eax , [ebp + 8] ;加上val1
pop ebp
ret
AddTwo endp

Alt text

堆栈清理

因为在调用子过程前,给堆栈压入了一些内容,在子过程返回时,必须调整堆栈指针。

  • 在调用完子过程后通过加法指令改变ESP值
  • 通过 RET imm 指令的形式
    add方法:
    1
    2
    3
    4
    5
    6
    7
    8
    .data 
    Val1 dword 5
    Val2 dword 6
    .code
    Push val2
    Push val1
    Call AddTwo
    Add esp , 8

ret方法,在子过程中调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.data 
Val1 dword 5
Val2 dword 6
.code
Push val2
Push val1
Call AddTwo
AddTwo proc
push ebp
mov ebp,esp
mov eax,[ebp+12]
add eax,[ebp+8]
pop ebp
ret 8
AddTwo endp

采用uses操作符保存寄存器,则要注意uses指令是将寄存器的压栈指令放在子过程的开始,即在堆栈帧里push ebp语句之前,这时,参数偏移地址计算将会受到影响

0x07 字符串和数组

CLD 清除方向标志
STD设置方向标志

MOVSB,MOVSW,MOVSD

指令 功能 ESI和EDI修改量
MOVSB 复制字节 1
MOVSW 复制字 2
MOVSD 复制双字 4

复制双字数组

1
2
3
4
5
6
7
8
9
10
11
.data 
source dword 20 dup(0ffh)
target dword 20 dup(?)
.code
; …
cld
mov ecx , lengthof source
mov esi , offset source
mov edi , offset target
rep movsd ;将source开始的20个双字复制到target中
; …

CMPSB,CMPSW,CMPSD

指令 操作
CMPSB 比较字节
CMPSW 比较字
CMPSD 比较双字

单个比较

1
2
3
4
5
6
7
8
9
10
11
.data 
source dword 1234h
target dword 5678h
.code
; …
mov esi , offset source
mov edi , offset target
cmpsd ;比较双字
ja L1 ;如果source>targe跳转至L1
jmp L2 ;如果source<=target跳转至L2,本例即是
; ….

字符串比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.data
CmpsTestSource byte "ABCDE"
CmpsTestTarget byte "AB "
.code
CMPSTEST proc
cld
mov esi , offset CmpsTestSource
mov edi , offset CmpsTestTarget
mov ecx, lengthof CmpsTestSource ;最多比较次数,此例为5
repe cmpsb ; 比较到第三个字母时,因两者不等,重复不再继续,但当前串
; 操作执行完,esi和edi还会增加。所以,最后,esi和edi会指向
; 第四个字母的位置。
ret
CMPSTEST endp

SCASB,SCASW,SCASD

将AL的值与EDI指向的内存内容相比较(相当于cmp AL , [edi]),即相当于是做查找操作,通常会跟重复前缀

  • 如果使用repe前缀,则将查找到EDI开始的内存中第一个不等于AL时中止重复;
  • 如果使用repne前缀,则将查找到EDI开始的内存中第一个等于AL时中止重复;
  • 当然,如果ecx减到0,也会结束查找
    SCASW是用AX作字查找,SCASD是用EAX作双字查找

    扫描一个匹配字符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    .data 
    alpha byte “ABCDEFGH”,0
    .code
    mov edi , offset alpha
    mov al , ‘F’
    mov ecx , lengthof alpha
    cld
    repne scasb ;不相等则重复,即找到第一个相等的
    jnz quit ; 如果这个条件满足,表示是找完整个ecx长度,也没有找到
    dec edi ;回减一,让edi指向找到第一个相等的位置

    Quit:

STOSB,STOSW,STOSD

把AL/AX/EAX的内容存储在EDI指向的内存单元中,同时EDI的值根据方向标志的值增加和减少。
Stosb是存储AL,stosw存储AX,stosd存储EAX 使用rep前缀可以对一段内存进行填充

LODSB,LODSW,LODSD

将从esi指向的内存内容取出存到累加器中,同时,修改esi的值。
lodsb是取出一个字节存到AL中,lodsw是取出一个字存到AX中,lodsd是取出一个双字存到EAX中。
该指令一般不会跟重复前缀

串操作指令对标志位的影响

cmpsscas指令会对标志位有影响,影响效果如同CMP指

CATALOG
  1. 1. 0x00 IA32处理器体系结构
    1. 1.1. 微机的基本结构
    2. 1.2. 指令执行周期
    3. 1.3. 操作模式
    4. 1.4. 基本执行环境
      1. 1.4.1. 基本寄存器
      2. 1.4.2. 状态标志
    5. 1.5. 内存管理
      1. 1.5.1. 实地址模式
        1. 1.5.1.1. 20位线性地址
      2. 1.5.2. 保护模式
  2. 2. 0x01 汇编语言基础
    1. 2.1. 补码的表示法
    2. 2.2. 寻址方式
    3. 2.3. 基本元素
      1. 2.3.1. 指令
        1. 2.3.1.1. INVOKE
        2. 2.3.1.2. 伪指令
        3. 2.3.1.3. NOP指令
      2. 2.3.2. 程序模板
      3. 2.3.3. 汇编-链接-执行
    4. 2.4. 定义数据
      1. 2.4.1. 数据定义语句
      2. 2.4.2. 符号常量
        1. 2.4.2.1. 计算数组和字符串大小:
        2. 2.4.2.2. EQU和TEXTEQU伪指令:
  3. 3. 0x02 数据传送,寻址,算术运算
    1. 3.1. 小尾(小端)顺序
    2. 3.2. 数据传送指令
      1. 3.2.1. 操作数类型
      2. 3.2.2. 算数指令
      3. 3.2.3. 加减法影响标志位
      4. 3.2.4. 和数据相关的操作符和伪指令
    3. 3.3. JMP和LOOP
      1. 3.3.1. JMP
      2. 3.3.2. LOOP
      3. 3.3.3. 实例
    4. 3.4. 寻址方式总结
      1. 3.4.1. 操作数寻址方式
  4. 4. 0x03 过程
    1. 4.1. 堆栈操作
      1. 4.1.1. 运行时栈
    2. 4.2. 过程定义
      1. 4.2.1. PROC
      2. 4.2.2. CALL和RET
  5. 5. 0x04 条件处理
    1. 5.1. 布尔和比较指令
      1. 5.1.1. 实例
        1. 5.1.1.1. 小写转大写:
        2. 5.1.1.2. 将0-9之间的整数转换为对应数字符号的ASCII码
      2. 5.1.2. 设置和清除单个CPU状态标志
    2. 5.2. 条件跳转
      1. 5.2.1. 基于特定标志位
      2. 5.2.2. 基于相等比较
      3. 5.2.3. 基于无符号数比较
      4. 5.2.4. 基于有符号数比较
      5. 5.2.5. 实例
    3. 5.3. 条件循环指令
  6. 6. 0x05 整数算术指令
    1. 6.1. 移位和循环移位
      1. 6.1.1. 逻辑移位和算术移位
      2. 6.1.2. 乘法和除法指令
        1. 6.1.2.1. 应用
        2. 6.1.2.2. 任意进制的码制转换
  7. 7. 0x06 高级过程
    1. 7.1. stack frame
      1. 7.1.1. 给子过程传递参数的两种基本方式
        1. 7.1.1.1. 实例
        2. 7.1.1.2. 重点:参数访问
      2. 7.1.2. 堆栈清理
  8. 8. 0x07 字符串和数组
    1. 8.1. MOVSB,MOVSW,MOVSD
      1. 8.1.1. 复制双字数组
    2. 8.2. CMPSB,CMPSW,CMPSD
      1. 8.2.1. 单个比较
      2. 8.2.2. 字符串比较
    3. 8.3. SCASB,SCASW,SCASD
      1. 8.3.1. 扫描一个匹配字符
    4. 8.4. STOSB,STOSW,STOSD
    5. 8.5. LODSB,LODSW,LODSD
    6. 8.6. 串操作指令对标志位的影响