第十六章 直接定址表

检测点16.1

下面的程序将code段中a处的8个数据累加,结果存储到b处的双字中,补全程序。

assume cs:code

code segment
    a dw 1, 2, 3, 4, 5, 6, 7, 8
    b dd 0
start:  mov si,0
        mov cx,8
    s:  mov ax,a[si]           
        add word ptr b[0],ax ;低八位加加数ax
        adc word ptr b[2],0  ;高八位+CF进位值
        add si,2             ;si索引+2
        loop s
        mov ax,4c00H
        int 21H
code ends
end start

检测点16.2

下面的程序将code段中a处的8个数据累加,结果存储到b处的双字中,补全程序。

assume cs:code, ds:data

data segment
    a db 1,2,3,4,5,6,7,8
    b dw 0
data ends

code segment

start:  mov ax,data ;data段的地址值赋值给ax
        mov ds,ax   ;初始化ds数据段寄存器值
        mov si,0
        mov cx,8
    s:  mov al,a[si]
        mov ah,0
        add b,ax
        inc si
        loop s
        mov ax,4c00h
        int 21h
code ends
end start
  1. 如果程序段中使用了数据标号,那么就必须在assume中声明段与段寄存器的关联。不然编译器无法得知类似a、b、c这样的标号是什么。
  2. 无论是否使用数据标号,如果要使用数据段数据,都需要在程序段中初始化ds寄存器

实验16:编写包含多个功能子程序的中断例程

安装一个新的int 7ch中断例程,为显示输出提供如下功能子程序:

(1) 清屏。

(2) 设置前景色。

(3) 设置背景色。

(4) 向上滚动一行。

入口参数说明:

(1) 用 ah 寄存器传递功能号:0 表示清屏,1表示设置前景色,2 表示设置背景色,3 表示向上滚动一行;

(2) 对于2、3号功能,用 al 传送颜色值,(al) ∈{0,1,2,3,4,5,6,7}

实现代码

assume cs:code

code segment
start:
	push cs				;int 7ch中断例程的安装程序
	pop ds
	mov si, offset int7ch_setscreen ;ds:si指向源地址(int7c的机器码)
	mov ax, 0000H
	mov es, ax			;es:di指向目的地址(0:204H向量表中)
	mov di, 204H			;前2个字用来存储原来的例程的入口地址
	mov cx, offset int7ch_end - offset int7ch_setscreen
	cld
	rep movsb
	mov ax, 0000H
	mov es, ax
	;将原来的例程的入口地址保存在0:200H处,共2个字单元。
	push es:[7cH*4]		;将向量表中7ch号ip存储到0:200H处
	pop es:[200H]
	push es:[7cH*4+2]	;将向量表中7ch号cs存储到0:202H处
	pop es:[202H]
	;设置中断向量表,使7ch条目中断向量指向0000:204H
	cli
	mov word ptr es:[7cH*4], 204H
	mov word ptr es:[7cH*4+2], 0000H
	sti
	mov ax, 4c00H
	int 21H
;----
;中断程序名称:int7ch_setscreen
;功能:设置屏幕属性(1)清屏。(2) 设置前景色。(3) 设置背景色。(4) 向上滚动一行。
;入口参数:
;(1)ah寄存器传递功能号:0表示清屏,1表示设置前景色,2表示设置背景色,3表示向上滚动一行;
;   对于2、3号功能,用al传送颜色值,(al)∈{0,1,2,3,4,5,6,7}
;返回值:无
;----
int7ch_setscreen:
	jmp short set
	table dw clear - int7ch_setscreen + 204H, frontcolor - int7ch_setscreen + 204H, backcolor - int7ch_setscreen + 204H, roll - int7ch_setscreen + 204H
set:
	push bx
	cmp ah, 3	;判断功能编号是否大于3,是则退出
	ja sret
	
	mov bl, ah	;根据功能编号调用对应的功能子程序
	mov bh, 0
	add bx, bx  	;根据ah中的功能号计算对应子程序的地址在table表中的偏移
	mov si, offset start - offset int7ch_setscreen
	call word ptr table[bx+si+204H]
sret:
	pop bx
	iret
;----
;子程序名称:clear
;功能:清屏,利用屏幕写满空格。
;入口参数:无
;返回值:无
;----
clear:
	push bx 	;保护寄存值
	push cx
	push es
	mov bx, 0b800h	;es:bx指向显存缓冲区
	mov es, bx
	mov bx, 0
	mov cx, 2000	;满屏显示共80*25=2000字符
	
clearloop:
	mov byte ptr es:[bx], ' '	;显存缓冲区写满空格
	add bx, 2
	loop clearloop
	pop es				;恢复寄存器值
	pop cx
	pop bx
	ret
;----
;子程序名称:frontcolor
;功能:改变屏幕显示字符的前景色
;入口参数:al
;返回值:无
;----
frontcolor:
	push bx
	push cx
	push es
	mov bx, 0b800h
	mov es, bx
	mov bx,1
	mov cx,2000
f_color:
	and byte ptr es:[bx], 11111000b ;改变字符前景色
	or es:[bx], al
	add bx, 2
	loop f_color
	pop es
	pop cx
	pop bx
	ret
;----
;子程序名称:backcolor
;功能:改变屏幕显示字符的背景色
;入口参数:al
;返回值:无
;----
backcolor:
	push bx
	push cx
	push es
	mov bx, 0b800h
	mov es, bx
	mov bx,1
	mov cx,2000
b_color:and byte ptr es:[bx], 10001111b ;改变字符背景色
	or es:[bx], al
	add bx, 2
	loop b_color
	pop es
	pop cx
	pop bx
	ret
;----
;子程序名称:roll
;功能:向上滚动一行,依次将n+1行内容复制到n行,最后一行空。
;入口参数:无
;返回值:无
;----
roll:
	push cx
	push si
	push di
	push es
	push ds
	
	mov si,0b800h
	mov es, si
	mov ds, si
	mov si,160          ;ds:si指向第n+1行
	mov di,0            ;es:di指向第n行
	cld                 ;方向为正
	mov cx,24           ;共复制24行
copy_line:
	push cx
	mov cx,160
	rep movsb
	pop cx
	loop copy_line
	
	mov cx,80	    ;最后一行清空
	mov si,0
clear_lastline:
	mov byte ptr es:[160*24+si],' '
	add si,2
	loop clear_lastline
	pop ds
	pop es
	pop di
	pop si
	pop cx
	ret
int7ch_end: nop
code ends
end start

本次实验的功能性子程序教材已经给出了实现,重点我们应该放在子程序调用程序段:int7ch_setscreen,与装载程序中的指令:org 204H(意为:通知编译器从204H为基础,来计算标号)。

思考一个问题,如果装载程序段中没有org 204H,会发生什么?

会导致call word ptr table[bx]时,无法正确定位到子程序的内存地址。本质原因为我们将一段代码放入了特定内存空间中。
而标号在被编译器转为具体偏移值时采用的基准地址值,并不会考虑这个因素。例如在debug中,如果程序没有写org 204H,那么标号的偏移量就是从0开始推算,而我们需要的是从204H开始推算。(可以利用debug查看call word ptr table[bx]编译后的table[bx]的实际值来验证)
如我本地测试时,call word ptr table[bx]最终被转为了call[bx+0206],因为jmp指令占用了两个字节,故table从206H开始。

回顾以往的装载程序段中,由于我们并没有使用到标号,所以并没有添加org xxx。如果应用到了标号,那么程序实则是有问题的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值