1. 预备知识
- call 标号 将当前 IP 的内容入栈,并且根据位移跳转到执行标号处;ret 将栈顶元素赋值为 IP 寄存器,二者都是段内转移。由此,call 和 ret 指令共同支持了汇编语言编程中的模块化设计,类似于高级语言中的函数机制。如计算 N 的 3 次方:
call cube ;调用子程序
...
cube:
mov ax,bx
mul bx
mul bx
ret ;返回
- 用寄存器来存储参数和结果是最常用的方法,对于存放参数的寄存器和存放结果的寄存器,调用者和子程序的读写操作相反:调用者将参数送入参数寄存器,从结果寄存器取返回值;子程序从参数寄存器取参数,将结果送入结果寄存器。
- 在使用寄存器时我们希望:调用子程序时不必关系程序使用了哪些寄存器,编写子程序时不必关心调用者使用了哪些寄存器,不会发生寄存器冲突。解决办法是在程序的开始将所有用到的寄存器中的内容使用栈保存,然后在子程序返回前恢复:
子程序开始:
子程序使用的寄存器入栈
子程序的内容
子程序使用的寄存器出栈
ret
- 汇编语言中的除法规则:如果除数为 8 位则被除数为 16 位,默认存放在 AX 中,且 AL 存放商、AH 存放余数;如果除数为 16 位则被除数为 32 位,且高 16 位存放在 DX 中、低 16 位存放在 AX 中,且 AX 存放商、DX 存放余数。
2. 实验任务 1:显示字符串
在指定的位置,用指定的颜色,显示一个用 0 结束的字符串。参数:(dh)=行号,(dl)=列号,(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指向数据段data
mov si,0
call show_str ;调用子程序
mov 4c00h
int 21h
show_str:
... ;待完成部分
code ends
end start
- 由于需要显示有颜色的字符串,所以使用 80×25 彩色模式。每个字符占用 2 个字节,低位存储 ASCII 码、高位存储属性。一屏幕共占用 4000 字节,可存储 2000 个字符,共 25 行,每行 80 个字符。
- 由于写入位置的行号为 DH 的内容、列号为 DL 的内容,且每行的字节数为 160,所以可以使用乘法定位写入位置的起始位置(列的索引类似)。这里,使用两个 8 位寄存器做乘法:
mov al,160 ;8位寄存器乘法,一个存在AL中,另一个存在寄存器或内存单元(DH)中
mul dh ;定位行的偏移,乘法结果存放在AX中
mov bx,ax ;以防被下一个乘法覆盖,这里需要保存寄存器AX的内容,如BX
mov al,2
mul dl ;定位列的偏移,乘法结果存放在AX中
add bx,ax ;最终的偏移
- 由于事先不知道 data 段中字符串的长度,题目给出字符串的用 0 结束。jcxz 标号的功能是当寄存器 CX 的内容为 0 时则跳转到标号执行。所以,我们可以使用寄存器 CX 来接收字符串中的内容,并使用 jcxz 指令来判断是否到达字符串结尾。
- 由于不知道循环次数,这里使用 jmp 指令配合 jcxz 来完成循环功能:
help:
mov cl,data:[] ;将data段字符串依次写入C

本文介绍了汇编语言编程中的模块化设计,通过call和ret指令实现子程序调用。实验涉及显示字符串、解决除法溢出问题以及将数值转换为十进制字符串并显示。在显示字符串任务中,详细阐述了如何在指定位置以指定颜色显示字符串。在解决除法溢出问题中,提出了一种避免16位除法溢出的算法。最后,展示了将16位数据转换为十进制字符串的实现过程。
《汇编语言(王爽)》 | 实验 10:编写子程序&spm=1001.2101.3001.5002&articleId=122230794&d=1&t=3&u=8d41994d4f2646518ff5927f48bf54a6)
1841

被折叠的 条评论
为什么被折叠?



