(2011.11.02)汇编_王爽_第10章_学习小结
本章内容:
1. call 与 ret指令的使用
2.使用call 和ret 对子程序的编写
3. mul指令(乘法)的使用
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
知识点归纳:
现在,个人根据段内转移和段间转移,在程序中调用方法的对应将其归纳为两类,主要功能是实现程序中子程序的编写,相当于高级语言中的函数调用,知识点如下:
一. 段内转移 (仅改IP)
-> 指令:call 标号 \ call word ptr [内存单元地址]
原理:实现段内转移原理相当于以下2个步骤
第1步: push IP
第2步: jmp near ptr 标号 \ jmp word ptr [内存地址]
-> 指令:ret
原理:改IP, 实现段内转移跳出,执行指令完毕后,让IP指向ret指令后的内存单元
第1步: pop IP
二. 段间转移 (改CS:IP)
-> 指令:call far ptr 标号 \ call dword ptr [内存单元地址]
原理:实现段间转移原理相当于以下3个步骤
第1步: push CS
第2步: push IP
第3步: jmp far ptr 标号 \ jmp dword ptr [内存单元地址]
-> 指令:retf
原理:实观段间转移跳出原理相当于以下2个步骤
第1步:pop IP
第2步:pop CS
三:具有子程序的源程序的框架
assume cs:code
code segment
main: ; 这个程序,两个子程序嵌套了
: ; 一个子程序运行完后,接着会跳到另一个子程序运行
: ; 最后都运行完后,会逐步跳出子程序,回到主程序
call sub1 ; 现开始调用子程序
:
:
mov ax, 4c00h
int 21h
sub1 : ; 子程序sub1开始
:
:
call far ptr sub2 ; 将子程序嵌套在sub1中,调用子程序sub2
:
ret ; 子程序返回
sub2: ; 子程序sub2开始
: ; 为了不使寄存器发生冲突,还可以按以下方法编写子程序
: ; 子程序中使用的寄存器入栈
: ; 子程序内容
: ; 子程序中使用的寄存器出栈
retf ; 子程序返回
code ends
end main
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
; 程序名称:1009_模块化程序设计_乘法的使用.asm
; 程序功能:计算data段中第一组数据的3次方,结果保存在后面一组dword单元中。
assume cs:code
data segment
dw 1, 2, 3, 4, 5, 6, 7, 8 ; 即求这一行的每一个数的三次方,结果放入下一行中
dd 0, 0, 0, 0, 0, 0, 0, 0
data ends
code segment
start:
mov ax, data
mov ds, ax
mov si, 0 ; ds:si 指向第一组word单元 (原数字)
mov di, 16 ; ds:di 指向第二组dword单元 (计算结果)
mov cx, 8
s:
mov bx, [si]
call cube ; 调用子程序(功能:计算三次方)
mov [di], ax ; 存放计算结果的低位
mov [di].2, dx ; 存放计算结果的高位
add si, 2 ; ds:si指向下一个word单元
add di, 4 ; ds:di指向下一个dword单元
loop s
mov ax, 4c00h
int 21h
cube: ; 子程序cube(功能:计算三次方)
mov ax, bx
mul bx
mul bx
ret ; 乘法:mul指令 8位(数值小于255) 16位(数值大于等于255)
; 乘数1 al ax
; 乘数2 8位(内存单元)或(reg) 16位(内存单元)或(reg)
; 结果 ax dx:[ax]
code ends
end start
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
; 程序名称:1012_模块化程序设计_大小写转换_解决寄存器冲突的问题.asm
; 程序功能:将一个全是字母,以零结尾的字符串,转化为大写。
assume cs:code
data segment
db 'word', 0
db 'unix', 0
db 'wind', 0
db 'good', 0
data ends
code segment
start:
mov ax, data
mov ds, ax
mov bx, 0
mov cx, 4 ; 共有四组长度相同的单词
s:
mov si, bx
call capital ; 调用功能函数
add bx, 5 ; 每组单词的长度为5
loop s
mov ax, 4c00h
int 21h
; 子程序说明:将一个全是字母,以零结尾的字符串,转化为大写
; 子程序参数:ds:si指向字符串的首地址
; 子程序结果:没有返回值
capital: ; 子程序中使用的寄存器入栈
push cx ; 这是为了防止影响主程序
push si
change:
mov cl, [si]
mov ch, 0
jcxz ok ; jcxz 当cx为零时,跳至标号
; 此处巧妙地利用了cl作为数据结束标记
and byte ptr [si], 11011111b
inc si
jmp short change
ok:
pop si ; 寄存器按相应的顺序出栈,数值还原到主程序中。
pop cx
ret ; 跳出子程序
code ends
end start
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
; 程序名称:实验10_编写子程序_显示字符串.asm
; 程序功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串
; 子程序描述:
; 名称:show_str
; 功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串
; 参数:(dh) = 行号(取值范围0~24),(dl) = 列号(取值范围 0~79),
; (cl) = 颜色, ds:si指向字符串的首地址
; 返回: 无
; 应用举例:在屏幕的8行3列,用绿色显示data段中的字符串
assume cs:code
data segment
db 'Welcome to masm!', 0
data ends
code segment
start:
mov dh, 8 ; 行号
mov dl, 3 ; 列号
mov cl, 2 ; 颜色
mov ax, data
mov ds, ax ; 将数据段地址放入至ds中
mov si, 0 ; 将si设置为数据段的偏移地址
call show_str
mov ax, 4c00h
int 21h
; 程序分析:
; 此处要实现显示功能,实际上就是要将ds:[si]的数据搬到B8000H - BFFFFH中
; 而现在,段地址我将其设为es = B8000, 偏移地址[bx = dh].[di = dl],循环时,di递增
show_str:
mov al, dh ; 令[bx = dh]
mov ah, 160 ; 每行160个字节
mul ah
sub ax, 160
mov bx, ax
mov al, dl ; 令[di = dl]
mov ah, 0
mov di, ax
mov ax, 0B800H ; 设置目的地址
mov es, ax
s:
mov ch, [si] ; 判断si中的数据是否为零
mov cl, 0
jcxz ok
mov al, ds:[si]
mov es:[bx+di], al
inc di
mov ah, 2 ; 颜色
mov es:[bx+di],ah
inc di
inc si
jmp short s
ok:
ret
code ends
end start