第十六章 直接定址表
16.1 描述了单元长度的标号
使用一种标号不但表示内存单元的地址,还表示了内存单元的长度,即表示了内存单元的长度,即表示次数标号处的单元是一个字单元还是一个字节单元,还是双字单元。
assume cs:code
code segment
a db 1, 2, 3, 4, 5, 6, 7, 8
b dw 0
start: 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
例如 b dw 0
指令 mov ax, b
等价于 mov ax, cs:[8]
mov b, 2
; mov word ptr cs:[8], 2
inc b
; inc word ptr cs:[8]
以下指令会引起编译错误
mov al, b
因为b代表了字单元,而al是8位寄存器。
称为数据标号。
注: ADD 指令 的两个操作数 ,op1 和 op2 两个都为寄存器, 一个内存地址 一个寄存器 一个内存地址 一个 立即数
一个寄存器 一个立即数 都是合法的。
两个都是内存地址 或者两个都是 立即数 非法 参考 x86 ADD指令
参考:http://x86.renejeschke.de/html/file_module_x86_id_5.html?spm=5176.100239.blogcont59019.4.e4ptjf
Description |
---|
Adds the first operand (destination operand) and the second operand (source operand) and stores the result in the destination operand. The destination operand can be a register or a memory location; the source operand can be an immediate, a register, or a memory location. (However, two memory operands cannot be used in one instruction.) When an immediate value is used as an operand, it is sign-extended to the length of the destination operand format. The ADD instruction performs integer addition. It evaluates the result for both signed and unsigned integer operands and sets the OF and CF flags to indicate a carry (overflow) in the signed or unsigned result, respectively. The SF flag indicates the sign of the signed result. This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically. |
16.2 在其他段中使用数据标号
注意带 : 的地址标号只能使用在代码段中,不能再其他段中使用。
以下程序将data段中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
mov ds, ax
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
要使用data段中的数据标号需要
1)assume中关联data段和ds
2)程序顶部设置ds为data段的段地址
3)在汇编源码中直接使用标号会翻译成对应的寻址指令
可以直接使用标号来当作数据定义
data segment
a db 1, 2, 3, 4, 5, 6, 7, 8
b dw 0
c dw a, b
data ends
相当于
data segment
a db 1, 2, 3, 4, 5, 6, 7, 8
b dw 0
c dw offset a, offset b
data ends
还有一种定义
data segment
a db 1, 2, 3, 4, 5, 6, 7, 8
b dw 0
c dd a, b
data ends
相当于
data segment
a db 1, 2, 3, 4, 5, 6, 7, 8
b dw 0
c dw offset a, seg a, offset b, seg b
data ends
seg操作符用于取某一标号的段地址
检测点16.2=
注意:这里assume关联来es寄存器 所有对a的访问会被解释成es:[...]
查看编译后的机器码
源代码:
assume cs:code, es:data
data segment
a db 1, 2, 3, 4, 5, 6, 7, 8
b dw 0
data ends
code segment
start: mov ax, data
mov es, ax
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
16.3 直接定址表
使用一种映射关系来对应数据(表结构法的思想)
建立一张表直接存放字符 '0'~'F'
通过数值索引来直接查找到相关值进行字符显示。
子程序如下
showbyte:jmp short show
table db '0123456789ABCDEF'
show:push bx
push es
mov ah, al; store the whole number
shr ah, 1
shr ah, 1
shr ah, 1
shr ah, 1; ah store the high 4bit value
and al, 00001111b; al store the low 4bit value
mov bl, ah
mov bh, 0
mov ah, table[bx];; ah store the ascii value for high 4bit
mov bx, 0b800h
mov es, bx
mov es:[160 * 12 + 40 * 2], ah ; show the high 4bit ascii char
mov bl, al
mov bh, 0
mov al, table[bx];; al store the ascii value for low 4bit
mov es:[160 * 12 + 40 * 2 + 2], al ; show the low
pop es
pop bx
ret
运算速度而采用查表法
; in al store the angle value
showsin:jmp short show
tabledw ag0, ag30, ag60, ag90, ag120, ag150, ag180;
ag0db '0', 0
ag30 db '0.5', 0
ag60db '0.866', 0
ag90db '1', 0
ag120db '0.866', 0
ag150db '0.5', 0
ag180db '0', 0
show:push bx
push es
push si
mov bx, 0b800h
mov es, bx
;angle /30
mov ah, 0
mov bl, 30
div bl
mov bl, al
mov bh, 0
;add bx, bx
mov bx, table[bx]
; show the result of sin(x) as ascii characters
mov si, 160*120 + 40*2
shows: mov ah, cs:[bx]
cmp ah, 0
je showret
mov es:[si], ah
inc bx
add si, 2
jmp short shows
showret: pop si
pop es
pop bx
ret
16.4 程序入口地址的直接定址表
可以将子程序的入口地址存储在表中,方便各种子程序的调用。
例子 实现一个子程序setscreen,为显示输出提供如下功能
1)清屏
2)设置前景色
3)设置背景色
4)向上滚动一行
入口参数说明
1)用ah寄存器传递功能号:0 清屏,1 设置前景色, 2 设置背景色,3 向上滚动一行
2)对于1,2号功能,用al传递颜色值 (al) = (0, 1, 2, 3, 4, 5, 6, 7}
; clean screen
assume cs:code
code segment
start:mov ah, 3
mov al, 0
call setscreen
mov ax, 4c00h
int 21h
; set the screen
; in ah = command 0, 1, 2, 3
; in al = color
setscreen: jmp short set
table dw sub1, sub2, sub3, sub4
set: push bx
cmp ah, 3
ja sret
mov bl, ah
mov bh, 0
add bx, bx ; equal bx * 2 to address the offset in the table of words
call word ptr table[bx]
sret:pop bx
ret
; sub1 :for clean screen
sub1:push bx
push cx
push es
mov bx, 0b800h
mov es, bx
mov bx, 0
mov cx, 2000
sub1s:mov byte ptr es:[bx], ' '
add bx, 2
loop sub1s
pop es
pop cx
pop bx
ret
; sub2 set foreground color
; in al = color
sub2:push bx
push cx
push es
mov bx, 0b800h
mov es, bx
mov bx, 1
mov cx, 2000
sub2s:and byte ptr es:[bx], 11111000b ; clear the current color
or es:[bx], al; set the color
add bx, 2
loop sub2s
pop es
pop cx
pop bx
ret
; sub3 set bgcolor
; in al = color
sub3:push bx
push cx
push es
mov cl, 4
shl al, cl; left shift al to 0XXX0000b
mov bx, 0b800h
mov es, bx
mov bx, 1
mov cx, 2000
sub3s:and byte ptr es:[bx], 10001111b ; clear the current color
or es:[bx], al; set the color
add bx, 2
loop sub3s
pop es
pop cx
pop bx
ret
;sub4 scrollup 1line.
sub4:push cx
push si
push di
push es
push ds
mov si, 0b800h
mov es, si
mov ds, si
mov si, 160; ds:si point to #N+1 line
mov di, 0; es:di point to #N line
cld; df = 0
mov cx, 24; copy 24 times
sub4s:push cx
mov cx, 160
rep movsb; copy the whole line
pop cx
loop sub4s
; clear the last line
mov cx, 80
mov si, 0
sub4s1: mov byte ptr [160 * 24 + si], ' ' ;clear the last line
add si, 2
loop sub4s1
pop ds
pop es
pop di
pop si
pop cx
ret
setscreene: nop
code ends
end start
实验16 编写包含多个功能子程序的中断例程
内容和上一样,
新增需求 增加中断int 7ch, 为显示输出提供如下功能的子程序。
由于需要将程序安装到0:200处 使用表查询到地址不准确必须使用间接位移。
assume cs:code
code segment
start:; set es:di as target address 0000:0200h
mov ax, 0
mov es, ax
mov di, 200h
; set ds:si as source address cs:sqr
mov ax, cs
mov ds, ax
mov si, offset setscreen
; set cx as the data length
mov cx, offset setscreene - offset setscreen
; set the transport directive DF = 0 cld
cld
rep movsb
; set the IRQ table 1F0 = 200h(IP) 1F2 = 0(CS)
mov ax, 0
mov es, ax
mov word ptr es:[7ch * 4], 200h; install IRQ7ch
mov word ptr es:[7ch * 4 + 2], 0
mov ax, 4c00h
int 21h
; set the screen
; in ah = command 0, 1, 2, 3
; in al = color
setscreen: cmp ah, 0
je do1
cmp ah, 1
je do2
cmp ah, 2
je do3
cmp ah, 3
je do4
jmp short sret
do1:call sub1
jmp short sret
do2:call sub2
jmp short sret
do3:call sub3
jmp short sret
do4:call sub4
jmp short sret
sret:iret
; sub1 :for clean screen
sub1:push bx
push cx
push es
mov bx, 0b800h
mov es, bx
mov bx, 0
mov cx, 2000
sub1s:mov byte ptr es:[bx], ' '
add bx, 2
loop sub1s
pop es
pop cx
pop bx
ret
; sub2 set foreground color
; in al = color
sub2:push bx
push cx
push es
mov bx, 0b800h
mov es, bx
mov bx, 1
mov cx, 2000
sub2s:and byte ptr es:[bx], 11111000b ; clear the current color
or es:[bx], al; set the color
add bx, 2
loop sub2s
pop es
pop cx
pop bx
ret
; sub3 set bgcolor
; in al = color
sub3:push bx
push cx
push es
mov cl, 4
shl al, cl; left shift al to 0XXX0000b
mov bx, 0b800h
mov es, bx
mov bx, 1
mov cx, 2000
sub3s:and byte ptr es:[bx], 10001111b ; clear the current color
or es:[bx], al; set the color
add bx, 2
loop sub3s
pop es
pop cx
pop bx
ret
;sub4 scrollup 1line.
sub4:push cx
push si
push di
push es
push ds
mov si, 0b800h
mov es, si
mov ds, si
mov si, 160; ds:si point to #N+1 line
mov di, 0; es:di point to #N line
cld; df = 0
mov cx, 24; copy 24 times
sub4s:push cx
mov cx, 160
rep movsb; copy the whole line
pop cx
loop sub4s
; clear the last line
mov cx, 80
mov si, 0
sub4s1: mov byte ptr [160 * 24 + si], ' ' ;clear the last line
add si, 2
loop sub4s1
pop ds
pop es
pop di
pop si
pop cx
ret
setscreene: nop
code ends
end start
后来查询资料在网上找到了另外一种方法,使用为指令ORG 200H
意思是这条指令之后的所有标号和代码以200H开始编译。这样便一起就会把setscreen标号开始的代码和标号当作是偏移地址200H开始进行处理。
org 200h; let the masm to compile the code start with offset 200h
; set the screen
; in ah = command 0, 1, 2, 3
; in al = color
setscreen: jmp short set
table dw sub1, sub2, sub3, sub4
set: push bx
cmp ah, 3
ja sret
mov bl, ah
mov bh, 0
add bx, bx ; equal bx * 2 to address the offset in the table of words
call word ptr table[bx]
sret:pop bx
iret