任务1
task1.asm
assume cs:code, ds:data
data segment
x db 1, 9, 3
len1 equ $ - x ; 符号常量, $指下一个数据项的偏移地址,这个示例中,是3
y dw 1, 9, 3
len2 equ $ - y ; 符号常量, $指下一个数据项的偏移地址,这个示例中,是9
data ends
code segment
start:
mov ax, data
mov ds, ax
mov si, offset x ; 取符号x对应的偏移地址0 -> si
mov cx, len1 ; 从符号x开始的连续字节数据项个数 -> cx
mov ah, 2
s1: mov dl, [si]
or dl, 30h ; 数值转为字符
int 21h
mov dl, ' '
int 21h ; 输出空格
inc si
loop s1
mov ah, 2
mov dl, 0ah
int 21h ; 换行
mov si, offset y ; 取符号y对应的偏移地址3 -> si
mov cx, len2/2 ; 从符号y开始的连续字数据项个数 -> cx
mov ah, 2
s2: mov dx, [si]
or dl, 30h
int 21h
mov dl, ' '
int 21h ; 输出空格
add si, 2
loop s2
mov ah, 4ch
int 21h
code ends
end start
int 21h
功能2:在标准输出上显示一个字符并将光标前进一个位置。
接收参数:AH=2
DL=字符值
返回值: 无
-
理解运算符offset、伪指令equ、预定义符号$的灵活使用。通过line4、line6,以及数据项的数据属性(字节、字、双字,等),可以方便计算出连续数据项的个数,而无需人工计数。
注*: 符号常量len1, len2不占用数据段内存空间 -
回答问题
① line26, 汇编指令 loop s1 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明是如何计算得到跳转后标号s1其后指令的偏移地址的。
E2F2
中 位移量: F2(h) --> 11110010(b) --> 00001110(b) --> -12(d) (补码-->原码)
位移量的计算: d(h) - 19(h) --> -12(d)
CPU根据目标偏移地址减去当前偏移地址得到位移量② line44,汇编指令 loop s2 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明是如何计算得到跳转后标号s2其后指令的偏移地址的。
分析同上, 跳转的位移量为 FO(h).
任务2
task2.asm
assume cs:code, ds:data
data segment
dw 200h, 0h, 230h, 0h
data ends
stack segment
db 16 dup(0)
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov word ptr ds:[0], offset s1
mov word ptr ds:[2], offset s2
mov ds:[4], cs
mov ax, stack
mov ss, ax
mov sp, 16
call word ptr ds:[0]
s1: pop ax
call dword ptr ds:[2]
s2: pop bx
pop cx
mov ah, 4ch
int 21h
code ends
end start
根据call指令的跳转原理,先从理论上分析,程序执行到退出(line31)之前,寄存器(ax) = ? 寄存器(bx) = ? 寄存器(cx) = ?
分析:
call word ptr ds:[0] 短转移, 将下一条指令偏移地址(ip)压入栈, 并转移至 ds:[0]地址即 s1 处, 此后的 pop ax 将该内容出栈给ax;
call dword ptr ds:[2] 段间转移, 将下一条指令基址和偏移地址(cs 和 ip)压入栈, 并转移至 ds:[2] 起始的双字指向的地址即 s2 处, 此后的 pop bx 将ip出栈给ax, pop cx 将 cs 出栈给 cx.
即:
ax = s1 bx = s2 cx = s2行所在段基址
任务3
针对8086CPU,已知逻辑段定义如下:
data segment
x db 99, 72, 85, 63, 89, 97, 55
len equ $- x
data ends
编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据之间以空格间隔。
要求:
- 编写子程序printNumber
功能:以十进制形式输出一个两位数
入口参数:寄存器ax(待输出的数据 --> ax)
出口参数:无 - 编写子程序printSpace
功能:打印一个空格
入口参数:无
出口参数:无
在主体代码中,综合应用寻址方式和循环,调用printNumber和printSpace, 实现题目要求。
task3.asm
assume cs:code, ds:data
data segment
x db 99, 72, 85, 63, 89, 97, 55
len equ $- x
data ends
code segment
main:
mov ax, data
mov ds, ax
mov cx, len
mov si, offset x
print:
mov al, [si]
mov ah, 0
call printNumber
call printSpace
inc si
loop print
mov ah, 4ch
int 21h
;功能:以十进制形式输出一个两位数
;入口参数:寄存器ax(待输出的数据 --> ax)
;出口参数:无
printNumber:
mov bl, 10
div bl
mov bx, ax
mov ah, 2
mov dl, bl ; 打印商(10位)
or dl, 30h
int 21h
mov dl, bh ; 打印余数(个位)
or dl, 30h
int 21h
ret
printSpace:
mov ah, 2
mov dl, ' '
int 21h
ret
code ends
end main
运行结果:
任务4
针对8086CPU,已知逻辑段定义如下:
data segment
str db 'try'
len equ $ - str
data ends
编写8086汇编源程序task4.asm,在屏幕上以指定颜色、指定行,在屏幕上输出字符串。
要求:
- 编写子程序printStr
- 功能:在指定行、以指定颜色,在屏幕上显示字符串
- 入口参数
- 字符串首字符地址 --> ds:si(其中,字符串所在段的段地址—> ds, 字符串起始地址的偏移地址—> si)
- 字符串长度 --> cx
- 字符串颜色 --> bl
- 指定行 --> bh (取值:0 ~24)
- 出口参数:无
- 在主体代码中,两次调用printStr,使得在屏幕最上方以黑底绿字显示字符串,在屏幕最下方以黑
底红色显示字符串
task4.asm
assume cs:code
data segment
str db 'try'
len equ $ - str
data ends
code segment
main:
mov ax, 0b800h
mov es, ax
first_print:
mov ax, data
mov ds, ax
mov si, offset str
mov cx, len
mov bl, 00000010b ; 黑底绿字
mov bh, 0 ; 第0行
call printStr
second_print:
mov si, offset str
mov cx, len
mov bl, 00000100b ; 黑底红字
mov bh, 24 ; 第24行
call printStr
mov ah, 4ch
int 21h
; 入口参数:
; 字符串首字符地址 --> ds:si(其中,字符串所在段的段地址—> ds, 字符串起始地址的偏移地址—> si)
; 字符串长度 --> cx
; 字符串颜色 --> bl
; 指定行 --> bh (取值:0 ~24)
printStr:
push bp ; 因为要用到bp和di, 先保存现场
push di
mov ah, 0
mov al, 160
mul bh
mov bp, ax ; 计算行数偏移地址存储在bp
mov di, si ; di存储显存中每个字符偏移地址
printChar:
mov al, ds:[si]
mov es:[bp+di], al ; 字符
mov es:[bp+di+1], bl ; 颜色
inc si
inc di
inc di ; di要加两次
loop printChar
pop bp ; 还原现场
pop di
ret
code ends
end main
运行结果:
任务5
针对8086CPU,针对8086CPU,已知逻辑段定义如下:
data segment
stu_no db '20498329042'
len = $ - stu_no
data ends
在80×25彩色字符模式下,在屏幕最后一行正中间显示学号。要求输出窗口蓝底,学号和两侧折线,以
白色前景色显示。
task5.asm
assume cs:code, ds:data
data segment
stu_no db '201983300514'
len = $ - stu_no
data ends
code segment
main:
call print_blue_screen
call print_stu_no
mov ah, 4ch
int 21h
print_blue_screen:
push ax ; 保存现场
push es
push si
mov ax, 0b800h
mov es, ax
mov cx, 2000
mov si, 1
single_blue:
mov byte ptr es:[si], 00010000b
inc si
inc si
loop single_blue
pop si ; 还原现场
pop es
pop ax
ret
print_stu_no:
push ax
push es
push si
push ds
push di
prefix:
mov ax, 0b800h
mov es, ax
mov cx, 34
mov si, 3840 ; si存放每次显存输出的偏移地址
call print_dash
content:
mov ax, data
mov ds, ax
mov cx, len
mov di, 0 ; di存放data中每个字符的偏移地址
single_no:
mov al, ds:[di]
inc di
mov byte ptr es:[si], al
inc si
mov byte ptr es:[si], 00010111b
inc si
loop single_no
postfix:
mov cx, 34
call print_dash
pop di
pop ds
pop si
pop es
pop ax
ret
; 输入参数:
; 显示的基地址si
; 输出长度cx
; 输出:
; 迭代后的基地址si
print_dash:
single_dash:
mov byte ptr es:[si], '-'
inc si
mov byte ptr es:[si], 00010111b
inc si
loop single_dash
ret
code ends
end main
运行结果: