汇编语言(四) - 程序结构
简介
掌握汇编语言程序设计方法
- 顺序程序结构
- 分支程序结构
- 循环程序结构
重点 - 控制转移指令
- 转移指令的寻址方式
编制汇编语言程序的步骤
分析问题,确定算法
- 找出合理的算法及适当的数据结构
根据算法画出程序框图
- 由粗到细把算法逐步地具体化
根据框图编写源程序
上机调试
1.顺序程序结构
无分支、无循环、无转移,按照 程序书写的先后顺序以直线方式 单条顺序执行
控制机制
- CS:主存中代码段的段基地址
- EIP:将要执行指令的偏移地址
- 处理器自动增量EIP
设计要点
- 如何选择简单有效的算法
- 如何选择存储单元和工作单元
由于顺序程序结构就是一条线的往下执行,所以很简单,举几个例子也就明白了。
例1.1 自然数求和程序
- 1+2+3+…+N=?
- 等差数列求和:(1+N)*N/2
.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
2.分支程序结构
目标:
- 理解分支结构的机器实现
- 掌握判断条件的实现与转移指令
- 了解分支结构优化方法
要点
- 条件的实现
- 条件流程控制
- 转移寻址和寻址方式
高级语言与汇编语言的if结构对比
高级语言
- 采用if语句,并根据条件表达式的 结果转向不同的程序分支
汇编语言
无明确的高级逻辑结构硬指令,通 过比较和跳转指令组合实现
- 用比较cmp、and或sub操作影 响(修改)状态标志
- 用条件转移指令判断标志位, 并产生到新地址的分支(跳转到 新地址)
if (op1==0) Cmp op1,0
{ Je L1x=1; y=2; mov x,0} mov y,0else jmp L2
{ L1:x=0;y=0 ; mov x,1
} mov y,2L2:
常用的影响状态标志的指令
逻辑指令
- AND,OR,NOT,XOT,TEST
位运算
- SHL,SHR,SAL,SAR,ROL,ROR,RCL,RCR
算数运算指令
- ADD,ADC,SUB,SBB,CMP
CPU状态标志
CMP指令
格式:
- CMP dest, src
影响标志:
- 溢出OF,符号SF,零ZF,进位CF,辅助进位AF,奇偶PF
转移指令
流程控制机制:
- 代码段寄存器CS指示代码段基地址
- 指令指针寄存器EIP指示将要执行指令的偏移地址
- 顺序执行,根据指令字节长度增加EIP
- 分支执行,根据目的地址修改EIP或CS
分类
- 转移范围:段内、段间
- 寻址方式:相对、直接、间接
1. 转移范围
段内转移:当前代码段范围内的转移 - 只改变EIP(偏移地址)
- 近转移(Near)NEAR32,NEAR16
- 短转移(Short)转移范围在127~-128字节
段间转移:不同代码段之间的转移
- 更改CS(段地址)和EIP(偏移地址)
- 远转移(Far) FAR32 ,FAR16
- 32位线性地址空间,48位远转移FAR32
- 实地址存储模型,32位远转移FAR16
2. 指令寻址方式
确定下一条指令的方法,操作数的形式
相对寻址方式(段内转移)
- 指令代码提供目标地址相对于当前EIP的位移量
- 操作数(位移量)=目标地址 - 当前EIP
- 目标地址(新EIP值)= EIP + 位移量
直接寻址方式(段间转移)
- 指令代码直接提供目标地址
- 操作数 = 目标地址
- 新的CS:EIP = 操作数高地址字:操作数低地址双字
间接寻址方式
- 指令代码指示寄存器或存储单元,目标地址来自寄存器或存储单元
- 操作数 = reg / mem
- 目标地址 = [reg] /[mem]
2.1 无条件转移指令JMP
程序无条件改变执行顺序,相当于C/C++的goto
JMP指令的段内寻址方式:
- 段内转移、相对寻址
标号指明目标地址,指令代码包含位移量
JMP label ;JMP newaddr
EIP ← EIP+位移量 – - 段内转移、间接寻址
通用寄存器或主存单元包含目标指令偏移地址
JMP reg32/reg16 ;JMP ebx
EIP ←reg32/reg16
JMP mem32/mem16 ;JMP near ptr [ebx]
EIP ←[mem32]/[mem16] - 段间转移、直接寻址
标号提供所在段的段选择器和偏移地址
JMP label
EIP = label的偏移地址
CS=label的段选择器 - 段间转移、间接寻址
32位线性地址空间用3字存储单元包含目标地址
JMP m48 ;JMP far ptr [ebx]
EIP = mem48
CS = mem48+4
16位实地址用双字存储单元包含目标地址
JMP mem32 ;JMP far ptr [ebx]
EIP = mem32
CS = mem32+2
MASM会根据存储模式等信息自动识别
平展存储模式常用格式
1.相对寻址
– JMP label
- JMP near ptr label
- JMP label
2.寄存器间接寻址
– JMP reg32
- JMP ebx
3.存储器间接寻址
– JMP mem32
- JMP near ptr [ebx]
JMP相对寻址方式
格式:JMP label 操作:EIP =EIP+位移量
位移量=label(目标地址)相对于当前EIP的字节数
范围:
- 近转移(Near) 范围32位有符号数
- 短转移(Short)范围 8位有符号数
include io32.inc.data.code
start:mov eax,5cmp eax,0jz L1add ebx,10jmp near ptr L2
L1:sub ebx,10
L2:exit 0end start
无条件转移程序
.datanvar dword ?
.code
start:jmp labl1 //相对寻址nop
labl1:jmp near ptr labl2nop
labl2:mov eax,offset labl3jmp eax //寄存器间接寻址nop
labl3:mov eax,offset labl4mov nvar,eaxjmp nvar //存储器简介寻址nop
labl4:exit 0end start
2.2 条件转移指令
不影响标志,利用标志
当状态标志条件为真时,转移到目标地址;否则,顺序 执行下一条指令
格式: Jcc label
label:目标地址,段内相对寻址
- 32位IA32处理器, 32位的全偏移量
cc:一个或多个标志位的标志位条件
- JC, JNC,JZ,JNZ,…
include io32.inc
.code
start:mov ebx,5cmp eax,0jz L1add ebx,10jmp L2
L1:sub ebx,10
L2:exit 0end start
条件转移指令分类
1.单状态标志类
基于特定标志位的值(单标志位)
- JZ,JC,JP,JO,JS
- JNZ,JNC,JNP,JNO,JNS
基于相等性( ZF位)
- JE,JNE
2.组合状态标志类
无符号数的比较(ZF判断相对,CF位判断大小)
- JA,JB,JNA,JNB,JAE,JBE…
有符号数的比较(ZF判断相对,SF和OF位判断大小)
- JG,JL,JNG,JNL,…
例 个数折半程序
将某数组分成元素个数相当的两部分.
Mov eax,lengthof m1shr eax,1jnc is_even jc is_oddjmp is_evenadd 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
.datayes_msg byte 'PSN supported:Yes',0no_msg byte 'PSN supported:No',0
.code
start:mov eax,1cpuidtest edx,040000hmov edx,offset no_msgjz dispmov eax,offset yse_msg
disp:call dispmsgexit 0end start
2.3 单分支结构
类似于高级语言的if – then结构语句
- 当条件满足,发生转移,跳过分支体
- 条件不满足,顺序向下执行分支体
要点:与if语句相反
- 转移指令,条件不成立执行分支体
- if语句,条件成立执行分支体
例 求绝对值
例 小写字母转大写字母 ‘a’ = 61h ‘A’ = 41h
2.4 双分支结构
相当于高级语言的if – then - else语句
使用转移指令J(cc)和Jmp实现分支控制
优化为单分支结构
- 预先执行使用频率较高、不影响判断标志的分支
例 显示ebx中的最高位
2.5 多分支程序
分支处理中又有嵌套的分支,具有多个分支走向
- 利用单分支和双分支结构实现多个分支结构
变量地址表程序
复合表达式的实现
C++语言: 汇编语言: 优化:
if (a > b) && (b>c) Mov eax,b Mov eax,b
{ Cmp a,eax Cmp a,eaxx=1; Ja L1 Jbe next
} jmp next Cmp eax,cL1: Jbe nextCmp eax,c Mov x,1Ja L2 Next:jmp next L2: Mov x,1 Next:
3.循环程序结构
组成部分
- 循环初始:为开始循环准备必要的条件,如循环次 数、必要的初始值;
- 循环体:重复执行的程序代码,包括对循环条件的 修改;
- 循环控制:判断循环条件是否成立,决定是否继续 循环
“先判断、后循环”的循环程序结构
- 对应C/C++语言的while语句
“先循环、后判断”的循环程序结构
- 对应C/C++语言的do语句
3.1 循环指令
例 数组求和程序
//循环初始mov ecx,lengthof array //ECX = 数组元素个数xor eax,eax //求和初值为0mov ebx,eax //数组指针为0//循环体
again:add eax,array[ebx*(type array)] //求和inc ebx //指向下一个数组元素//循环控制loop againmov sum,eax //保存结果call dispsid //显示结果
3.2 计数控制循环
通过次数控制循环
- 利用LOOP指令属于计数控制
- 常见是“先循环、后判断”循环结构
计数可以减量进行,即减到0结束
计数可以增量进行,即达到规定值结束
例 求最大值程序
3.3 条件控制循环
根据条件决定是否进行循环
- 需要使用有条件转移指令实现
- 多见“先判断、后循环”结构
先行判断的条件控制循环程序
- 很像双分支结构
- 主要分支需要重复执行多次 (JMP的目标位置是循环开始)
- 另一个分支用于跳出这个循环
先行循环的条件控制循环程序
- 类似单分支结构,循环体就是分支体
- 顺序执行就跳出循环
例 字符数字统计程序
.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 doneinc ebx //个数加1jmp again //继续循环
done:mov eax,ebx //显示个数call dispuidexit 0end start
3.4 多重循环
实际的应用问题
- 单纯的分支或循环结构
- 循环体中具有分支结构
- 分支体中采用循环结构
- 循环体中嵌套有循环,即形成多重循环结构
如果内外循环之间没有关系
- 比较容易处理
如果需要传递参数或利用相同的数据
- 问题比较复杂
例 冒泡法排序程序
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 ;外循环尾
汇编语言(四) - 程序结构相关推荐
- c语言饿结构_C语言的四种程序结构
C语言的四种程序结构 尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电 ...
- 程序结构程序设计(四)
程序结构&&程序设计 程序结构&&程序设计(二) 程序结构&&程序设计(三) --递归 程序结构&&程序设计(三) 程序结构&& ...
- 【汇编语言】多模块程序结构
多模块程序结构 文章目录 多模块程序结构 一.多模块方法 (1)源文件包含 (2)模块连接 (3)子程序库和库文件包含 1.子程序库 2.库文件包含 二.宏汇编 (1)宏汇编的定义 (2)宏定义.宏调 ...
- itpt_TCPL 第四章:函数和程序结构
2016.08.30 – 10.09 个人英文阅读练习笔记(极低水准). 08.30 第四章:函数和程序结构 函数能够将大型的计算任务分解为多个小型的计算任务,并且程序员还能够利用别人已经编写好的函数 ...
- 第四节 基本命令和程序结构控制(1)
第四节 基本命令和程序结构控制(1) 2010年06月22日 第四节 基本命令和程序结构控制(1) 前面几节我们讲解了ActionScript的基础知识,相信你已经对ActionScript的编程方法 ...
- 雨落C++小课堂第四课——C++程序结构(4)
hello,大家好,在下雨落,最近雨落正在疯狂补习C++啊,终于明白了为什么程序员一般会"秃头"啊,不说了,上标题-- C++程序结构(4) 接着上次地讲-- 嗯,这是为什么呢,我 ...
- python编程语法-Python学习笔记(Ⅰ)——Python程序结构与基础语法
作为微软的粉丝,最后终于向Python低头了,拖了两三个月终于下定决心学习Python了.不过由于之前受到C/C#等语言影响的思维定式,前期有些东西理解起来还是很费了些功夫的. 零.先抄书: 1.Py ...
- Python学习笔记(Ⅰ)——Python程序结构与基础语法
作为微软的粉丝,最后终于向Python低头了,拖了两三个月终于下定决心学习Python了.不过由于之前受到C/C#等语言影响的思维定式,前期有些东西理解起来还是很费了些功夫的. 零.先抄书: 1.Py ...
- python的类程序的结构_python(8)---程序结构
在计算机编程中,面向过程的编程中,程序结构分为三类:顺序结构.分支结构.循环结构. 一.顺序结构 顺序结构就是指程序一步一步按照顺序执行程序,顺序结构比较简单. 二.分支结构 分支结构主要就是逻辑判断 ...
最新文章
- qtablewidget 数据量大效率很低_让大牛带你走进大数据分析:R基础及应用的潮流尖端,享受RHadoop...
- Jquery-基础知识点
- 链表的数据域怎么使用结构体_一步一步教你从零开始写C语言链表
- java 读取 image_如何在java读取sql里头读取image格式的数据转换成图片格式
- mysql ==null_mysql = null 问题
- Proxy Hosted Virtual
- 智慧城市数据采集的四大难点分析及解决措施
- NYOJ813 - 对决
- SWIFT IOS开发 部分compile error
- 扇贝有道180917每日一句
- 皕杰报表使用技巧:竖排文字如何输入
- 软件工程之项目开发计划
- 数据库的备份与恢复技术
- Discuz门户模板乱码解决方案
- Django基础(29): select_related和prefetch_related的用法与区别
- 最优化理论与方法1--理论基础
- matlab等距偏置曲线,144 偏置曲线命令详解
- Echarts中国地图各省份区域设置不同的颜色
- 5、Dubbo-监控中心
- 用sealed修饰的类有什么特点