掌握汇编语言程序设计方法
分析问题,确定算法
根据算法画出程序框图
根据框图编写源程序
上机调试
无分支、无循环、无转移,按照 程序书写的先后顺序以直线方式 单条顺序执行
控制机制
设计要点
由于顺序程序结构就是一条线的往下执行,所以很简单,举几个例子也就明白了。
例1.1 自然数求和程序
.data
num dword 3456
sum qword ?
.code
mov eax,num
add eax,1
mul num
shr edx,1 //无符号数,进行逻辑移位
rcr eax,1 //带进位的循环移位,保证edx的最低位移位到eax的最高位
mov dword ptr sum,eax
mov dword ptr sum + 4,edx
例1.2 显示CPU的Vendor信息
CPUID指令:EAX=0,获取CPU的供应商信息,返回结果存储在EBX,EDX,ECX寄存器
include io32.inc
.data
buffer byte 'The processor vendor ID is ',12 dup(0),0
buffersize = sizeof buffer
.code
start:
mov eax,0
cpuid
mov dword ptr buffer+buffersize - 13,ebx
mov dword ptr buffer+buffersize - 9,edx
mov dword ptr buffer+buffersize - 5,ecx
mov eax,offset buffer
call dispmsg
exit 0
end start
例1.3 复杂的表达式计算
编写程序完成表达式R=((XY+5)+4X)/Z的计算
X,Y,Z 均为DWORD类型的变量
Mov eax,X
Imul Y
add eax,5
Adc edx,0
Mov ebx,eax
Mov ecx,edx
Mov eax,X
mov esi,4
imul esi
add eax,ebx
Adc edx,ecx
Idiv Z
Mov R,eax
Mov R+4,edx
目标:
要点
高级语言
汇编语言
无明确的高级逻辑结构硬指令,通 过比较和跳转指令组合实现
if (op1==0) Cmp op1,0
{ Je L1
x=1; y=2; mov x,0
} mov y,0
else jmp L2
{ L1:
x=0;y=0 ; mov x,1
} mov y,2
L2:
常用的影响状态标志的指令
逻辑指令
位运算
算数运算指令
CPU状态标志
格式:
影响标志:
流程控制机制:
分类
段间转移:不同代码段之间的转移
2. 指令寻址方式
确定下一条指令的方法,操作数的形式
相对寻址方式(段内转移)
直接寻址方式(段间转移)
间接寻址方式
程序无条件改变执行顺序,相当于C/C++的goto
JMP指令的段内寻址方式:
MASM会根据存储模式等信息自动识别
平展存储模式常用格式
1.相对寻址
– JMP label
2.寄存器间接寻址
– JMP reg32
3.存储器间接寻址
– JMP mem32
JMP相对寻址方式
格式:JMP label 操作:EIP =EIP+位移量
位移量=label(目标地址)相对于当前EIP的字节数
范围:
include io32.inc
.data
.code
start:
mov eax,5
cmp eax,0
jz L1
add ebx,10
jmp near ptr L2
L1:
sub ebx,10
L2:
exit 0
end start
无条件转移程序
.data
nvar dword ?
.code
start:
jmp labl1 //相对寻址
nop
labl1:
jmp near ptr labl2
nop
labl2:
mov eax,offset labl3
jmp eax //寄存器间接寻址
nop
labl3:
mov eax,offset labl4
mov nvar,eax
jmp nvar //存储器简介寻址
nop
labl4:
exit 0
end start
不影响标志,利用标志
当状态标志条件为真时,转移到目标地址;否则,顺序 执行下一条指令
格式: Jcc label
label:目标地址,段内相对寻址
cc:一个或多个标志位的标志位条件
include io32.inc
.code
start:
mov ebx,5
cmp eax,0
jz L1
add ebx,10
jmp L2
L1:
sub ebx,10
L2:
exit 0
end start
条件转移指令分类
1.单状态标志类
基于特定标志位的值(单标志位)
基于相等性( ZF位)
2.组合状态标志类
无符号数的比较(ZF判断相对,CF位判断大小)
有符号数的比较(ZF判断相对,SF和OF位判断大小)
Mov eax,lengthof m1
shr eax,1
jnc is_even jc is_odd
jmp is_even
add eax,1 Is_odd:
add eax,1
Is_even:
call dispuid
优化
分支程序是影响程序性能的重要因素之一
Mov eax,lengthof m1
shr eax,1
adc eax,0
call dispuid
当数组长度达到最大(eax=0ffffffffh)会怎样?
例 位测试程序
输入参数eax=1的cpuid指令可以获取CPU特性参数
返回参数edx的bit18代表是否支持PSN(Processor Serial Number)功能,1支持,0不支持
include io32.inc
.data
yes_msg byte 'PSN supported:Yes',0
no_msg byte 'PSN supported:No',0
.code
start:
mov eax,1
cpuid
test edx,040000h
mov edx,offset no_msg
jz disp
mov eax,offset yse_msg
disp:
call dispmsg
exit 0
end start
类似于高级语言的if – then结构语句
要点:与if语句相反
相当于高级语言的if – then - else语句
使用转移指令J(cc)和Jmp实现分支控制
优化为单分支结构
分支处理中又有嵌套的分支,具有多个分支走向
变量地址表程序
复合表达式的实现
C++语言: 汇编语言: 优化:
if (a > b) && (b>c) Mov eax,b Mov eax,b
{ Cmp a,eax Cmp a,eax
x=1; Ja L1 Jbe next
} jmp next Cmp eax,c
L1: Jbe next
Cmp eax,c Mov x,1
Ja L2 Next:
jmp next
L2:
Mov x,1
Next:
组成部分
“先判断、后循环”的循环程序结构
“先循环、后判断”的循环程序结构
例 数组求和程序
//循环初始
mov ecx,lengthof array //ECX = 数组元素个数
xor eax,eax //求和初值为0
mov ebx,eax //数组指针为0
//循环体
again:
add eax,array[ebx*(type array)] //求和
inc ebx //指向下一个数组元素
//循环控制
loop again
mov sum,eax //保存结果
call dispsid //显示结果
通过次数控制循环
计数可以减量进行,即减到0结束
计数可以增量进行,即达到规定值结束
根据条件决定是否进行循环
先行判断的条件控制循环程序
先行循环的条件控制循环程序
例 字符数字统计程序
.data
string byte 'Do you have fun with Assembly?',0 //以0结尾的字符串
.code
start:
xor ebx,ebx //EBx用来记录字符个数,同事也用于指向字符的指针
again:
mov al,string[ebx]
cmp al,0 //用指令“test al,al”更好
jz done
inc ebx //个数加1
jmp again //继续循环
done:
mov eax,ebx //显示个数
call dispuid
exit 0
end start
实际的应用问题
如果内外循环之间没有关系
如果需要传递参数或利用相同的数据
例 冒泡法排序程序
mov ecx,count ;ECX←数组元素个数
dec ecx ;元素个数减1为外循环次数
outlp:
mov edx,ecx ;EDX←内循环次数
mov ebx,offset array
inlp:
mov eax,[ebx] ;取前一个元素
cmp eax,[ebx+1] ;与后一个元素比较
jng next ;前一个不大于后一个,不交换
xchg eax,[ebx+1] ;否则,进行交换
mov [ebx],eax
next:
inc ebx ;下一对元素
dec edx
jnz inlp ;内循环尾
loop outlp ;外循环尾