汇编语言流程转移与子程序篇--05
- “转移”综述
- 操作符offset
- 用操作符offset取得标号的偏移地址
- 练习
- jmp指令
- jmp指令——无条件转移
- jmp指令:依据位移进行转移
- 两种段内转移
- 远转移:jmp far ptr 标号
- 转移地址在寄存器中的jmp指令
- 转移地址在内存中的jmp指令
- jmp指令小结
- 其他转移指令
- jcxz指令
- loop指令
- 根据位移进行“相对”转移的意义
- call指令和ret指令
- 模块化程序设计
- call 指令
- 指令“call far ptr 标号”实现的是段间转移
- 转移地址在寄存器中的call指令
- 转移地址在内存中的call指令
- 返回指令:ret 和 retf
- call 和 ret 的配合使用
- 具有子程序的源程序的框架
- call 和 ret 的配合使用
- 例:为call和ret指令设置栈
- 乘法:mul 指令
- 回顾:除法div 指令
- 用 mul 指令做乘法
- 应用实例
- 汇编语言的模块化程序设计
- 模块化程序设计
- 参数和结果传递的问题
- 用寄存器来存储参数和结果是最常使用的方法
- 用内存单元批量传递数据
- 用栈传递参数
- 程序的执行过程中栈的变化
- 小结:参数和结果传递的问题
- 寄存器冲突问题
- 引子
- 代码:编程将data段中的字符串转化为大写
- 寄存器冲突问题的解决
- 寄存器冲突问题的解决示例
- 标志寄存器
- 认识标志寄存器的特殊之处
- ZF-零标志(Zero Flag)
- PF-奇偶标志(Parity Flag)
- SF-符号标志(Sign Flag)
- CF-进位标志(Carry Flag)
- OF-溢出标志(Overflow Flag)
- 认识标志寄存器的特殊之处
- 带进(借)位的加减法
- adc-带进位加法指令
- adc指令应用:大数相加
- 128位数据的相加
- sbb指令
- cmp与条件转移指令
- cmp指令
- 无符号数比较与标志位取值
- 有符号数比较与标志位取值
- 条件转移指令
- 条件转移指令的使用
- 条件转移指令应用
- 应用示例
- DF标志和串传送指令
- 问题的提出
- DF标志和串传送指令
- rep指令
- 应用实例
本系列文章参考汇编语言第四版和汇编语言程序设计 贺利坚主讲整理而成
“转移”综述
操作符offset
用操作符offset取得标号的偏移地址
练习
jmp指令
jmp指令——无条件转移
jmp指令的功能 : 无条件转移,可以只修改IP,也可以同时修改CS和IP
jmp指令要给出两种信息:
- 转移的目的地址
- 转移的距离
- 段间转移(远转移): jmp 2000:1000
- 段内短转移: jmp short 标号 ; IP的修改范围为 -128~127,8位的位移
- 段内近转移: jmp near ptr 标号 ; IP的修改范围为 -32768~32767,16位的位移
jmp指令:依据位移进行转移
代码语言:javascript复制076A:0003 EB03 JMP 0008
076A:0005 050100 ADD AX,0001
076A:0008 40 INC AX
- 当JMP指令被读入指令缓冲器后,IP=IP 所读取的指令长度=0005
- CPU执行指令缓冲器中的指令EB03
- IP=IP 3=0005 0003=0008
JMP short s : 对应的机器指令中,包含的是当前指令下一条指令开始位置处,到段内目标地址的位移
两种段内转移
远转移:jmp far ptr 标号
远转移(跨段转移)中,转移机器指令中包含的是目标地址,而不是相对位移
转移地址在寄存器中的jmp指令
转移地址在内存中的jmp指令
jmp指令小结
其他转移指令
jcxz指令
loop指令
根据位移进行“相对”转移的意义
call指令和ret指令
模块化程序设计
call 指令
将当前IP或CS和IP压栈,是为了子程序调用结束后,程序能够回到原来的位置,继续往下面执行
指令“call far ptr 标号”实现的是段间转移
转移地址在寄存器中的call指令
转移地址在内存中的call指令
返回指令:ret 和 retf
设计用来回到子程序调用结束后,源程序继续运行的地址处
call 和 ret 的配合使用
具有子程序的源程序的框架
call 和 ret 的配合使用
注意观察在调用call指令和ret指令时,sp栈顶寄存器值的变化
call需要使用栈,但是这里程序没有分配栈空间,是默认给出的栈空间,因此这是非常危险的,鬼知道默认的空间,是不是在别的啥子地方被占用了
例:为call和ret指令设置栈
乘法:mul 指令
回顾:除法div 指令
用 mul 指令做乘法
应用实例
汇编语言的模块化程序设计
模块化程序设计
参数和结果传递的问题
用寄存器来存储参数和结果是最常使用的方法
用内存单元批量传递数据
用栈传递参数
保存BP寄存器旧值的原因,在于子程序中需要使用到BP寄存器,而BP寄存器可能在主程序或者其他程序中被使用中,因此当前子程序用完BP寄存器后,需要恢复其旧值才可以。
ret 4是先恢复IP寄存器原先值,然后再讲SP栈顶地址寄存器的偏移值 4,这里是跳过a和b两个数据,因为这两个值没用了,不需要继续占据着栈空间
程序的执行过程中栈的变化
小结:参数和结果传递的问题
问题:根据提供的N,计算N的3次方。
考虑
- (1)我们将参数N存储在什么地方?
- (2)计算得到的数值,存储在什么地方?
方案:
- 用寄存器传递参数
- 用内存单元进行参数传递
- 用栈传递参数
寄存器冲突问题
引子
之前我们每次循环时,都是提前将要循环的次数保存在了cx寄存器中,但是有没有办法不提前写好循环次数,而在合适的时机结束循环呢?
- 在处理字符串问题时,可以模仿c语言的 结束符号
代码:编程将data段中的字符串转化为大写
cx寄存器使用的冲突,会导致程序运行的奔溃,这是个大问题,怎么解决呢?
寄存器冲突问题的解决
寄存器冲突问题的解决示例
标志寄存器
认识标志寄存器的特殊之处
ZF-零标志(Zero Flag)
PF-奇偶标志(Parity Flag)
SF-符号标志(Sign Flag)
CF-进位标志(Carry Flag)
OF-溢出标志(Overflow Flag)
带进(借)位的加减法
adc-带进位加法指令
对于最后一种因为减法产生借位而导致CF=1的情况,显然不是我们期望的样子,因此是存在问题的,但是这种问题的解决需要程序员自己去控制
adc指令应用:大数相加
128位数据的相加
- sub ax,ax不可以替换为mov ax,0 ,因为sub ax,ax算出来ax=0后,因为没有产生借位,因此CF=0,确保能够清空CF之前的状态,确保不会影响下面的adc操作
- inc di不会影响进位标志位CF,但是add di 2会影响CF标记位,如果发生溢出了,CF会被设置为1
sbb指令
- 低十六位相减,如果产生了借位,那么高16位就需要处理低十六位产生的借位