本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
学习教材:《汇编语言(第4版)》王爽著 此笔记是书中内容+自我总结,方便查阅和复习 请支持原著
call和ret是两个转移指令,只修改IP或同时修改CS和IP @[toc]
一、call和ret的理解——模块化
在主函数内调用子函数,就要用到call和ret,这样就可以实现模块化
call会转移到标号(位移量)/详细偏移地址处运行,当运行结束后使用ret返回到call的下一行继续执行
code segment
...
child:add ax,bx ;子函数
ret ;转移到call的下一行代码
main:mov ax,0 ;主函数
mov bx,1
call child ;转移到标号处
...
mov ax,4c00h
int 21h
code ends
end main
二、ret和retf
- ret将出栈的数据传送给IP,实现近转移
- retf将出栈的数据传送给IP和CS,实现远转移
Ⅰ、ret的具体操作
- IP=ss*16+sp
- sp+=2
相当于执行pop IP
Ⅱ、retf的具体操作
- IP=ss*16+sp
- sp+=2
- CS=ss*16+sp
- sp+=2
相当于执行pop IP,再执行pop CS,后进先出为IP的值
三、call
与ret相反:call将当前的IP或CS和IP先后入栈,再转移到指定的标号(位移量)/地址处
注意:读取call后,IP会指向下一行代码,才会进行call的操作,因此此时入栈的IP指向call的下一行
Ⅰ、转移到标号处——call 标号
call 标号
这是16位位移,操作和注意事项同jmp near ptr,属于段内近转移
- sp-=2
- ss*16+sp=IP
- IP+=16位位移
相当于执行push IP,再执行jmp near ptr 标号
Ⅱ、转移地址在寄存器中——call reg
call 16位reg
- sp-=2
- ss*16+sp=IP
- IP+=reg
相当于执行push IP,再执行jmp 16位reg
转移地址在内存中——call X ptr
分为两种word和dword型,其中:
call word ptr 内存单元地址相当于执行push IP,再执行jmp word ptrcall dword ptr 内存单元地址相当于执行push CS、push IP,再执行jmp dword ptr,后进先出为IP的值
检测点10.5
(1) 下面的程序执行后,ax中的数值为多少?
assume cs:code
stack segment
dw 8 dup (0)
stack ends
code segment
start:mov ax,stack
mov ss,ax
mov sp,16
mov ds,ax
mov ax,0
call word ptr ds:[0eh]
inc ax
inc ax
inc ax
mov ax,4c00h
int 21h
code ends
end start
答案:ax=3
- 构造16B空栈,地址[0-0FH],ds指向栈段,ax置零
- 第一次到字型call时,IP指向第一个inc入栈。转移到栈空间[0EH-0FH](栈底字单元)所指位置,由于是空栈,即转移到第一行
mov ax,stack - 第二次到字型call时,IP指向第一个inc入栈。转移到栈空间[0EH-0FH](栈底字单元)所指位置,由于栈底有第一个inc的地址,转移到第一个inc
- 依次执行三个inc后程序结束
(2) 下面的程序执行后,ax和bx中的数值为多少?
assume cs:code
data segment
dw 8 dup(0)
data ends
code segment
start:mov ax,data
mov ss,ax
mov sp,16
mov word ptr ss:[0],offset s
mov ss:[2],cs
call dword ptr ss:[0]
nop
s: mov ax,offset s
sub ax,ss:[0ch]
mov bx,cs
sub bx,ss:[0eh]
mov ax,4c00h
int 21h
code ends
end start
答案:ax=1,bx=0
- 构造16B空栈,地址[0-0FH]
- 栈顶[0-1]存入s的偏移地址(严格来说不是一个栈结构)
- 栈空间[2-3]存入CS
- 到双字型call时,CS入栈底[0EH-0FH],IP指向
nop入栈[0CH-0DH]。转移到栈空间[0-4]所指位置,此处为远转移,转移到CS:offset s(即标号s)处 - ax=offset s
- 对于第一个sub :由于[0CH-0DH]存
nop的偏移地址,而nop是s的下一行,因此有offsetnop=offset s+1,此处即为sub ax,offset s+1,即ax=offset s-(offset s+1)=1 - bx=cs
- 对于第二个sub :由于[0EH-0FH]存CS,此处即为
sub bx,cs,即bx=CS-CS=0
四、mul乘法
Ⅰ、乘法的二要素
类比div除法
- 两个相乘的数:要么全是8位要么全是16位。8位乘法存在al和8位寄存器或内存中;16位乘法存在ax和16位寄存器或内存中
- 积:8位乘法存在ax,16位乘法高位在dx低位在ax
积位数是乘数位数的2倍
Ⅱ、mul计算
mul regmul SA:EA
例:计算100*10和100*10000
前者结果小于255,后者结果大于255,前者8位乘法后者16位乘法 实现代码分别如下:
mov al,100
mov bl,10
mul bl
mov ax,100
mov bx,10000
mul bx
运算后查看ax或ax和dx以获得积
五、模块化参数传递
当模块化时,不可避免地会复用寄存器,因此避免寄存器内的值混乱,在进入子程序前应先将寄存器的内容全都入栈,在结束子程序之前将内容出栈,以保存值
后记
- call和ret可以设计子程序
- mul支持两种位数
- 运行子程序之前先将寄存器的值全部保存起来
- 书上关于多个单词转大写的程序(P204)是子程序的典型例子,应多理解其过程