王爽 《汇编语言》 读书笔记 十六 直接定址表

时间:2022-06-16 01:12:55

第十六章  直接定址表


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