《汇编语言》第十六章 直接定位表

本文详细介绍了汇编语言中的直接定位表,包括描述了单元长度的标号、在其他段中使用数据标号、直接定址表以及程序入口地址的直接定址表的应用。通过实例解释了如何利用标号进行数据操作,并展示了如何通过直接定址表方便地调用子程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第16章 直接定位表

16.1 描述了单元长度的标号

我们常用offset来获取标号的内存地址。

offset a,reg a,前者是获取a的偏移地址,后者是获取a的段地址。

将它们放在相关寄存器当中,进行数据转移等有关操作。

现在,我们有了另一种写法:

assume cs:code
code segment
    a db 1,2,3,4,5,6,7,8
    b dw 0

start:  mov si,0
        mov cx,0
    s:  mov al,a[si]
        mov ah,0
        add b,ax
        inc si
        loop s
        mov ax,4c00h
        int 21h
code ends
end start

这样,我们的标号就相当于数组名,然后之后就是后面的元素,a[si],这种写法是你应该要明确的。
而标号b描述的地址是 code:8,和从这个地址开始,以后的内存单元都是字单元。

mov b,2 相当于 mov word ptr cs:[8],2,都是进行字操作的。

下面的指令则会引起编译错误:
mov al,b

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

注意,如果想在代码段中直接用数据标号访问数据,则需要用伪指令 assume 将标号所在的段和一个段寄存器联系起来。否则编译器在编译的时候,无法确定标号的段地址在哪一个寄存器。当然,这种联系是编译器需要的,但不是说,之后就不用操作了,你必须再手动将它们联系起来。

mov al,a[si],其实质就是 mov al,[si+0],因为a的地址为0.这种数组的思想你应该很明确的。

可以将标号当作数据来定义,此时,编译器将标号所表示的地址当做数据的值。
比如:

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

数据标号c处存储的两个字型数据为标号a,b的偏移地址。相当于:
c dw offset a,offset b

我们可以在c段中存储其段地址和偏移地址,相关操作如下:
c dw offset a,seg a,offset b,seg b

就是这个样子。

16.3 直接定址表

现在,我们讨论用查表的方法编写相关程序的技巧。

编程以十六进制的形式在屏幕中间显示给定的字节型数据。

注意,一个字节8位,而十六进制为4位,故一个字节应该分别表示两个数据。

利用移位等原理,可以将一个十六进制相关位数拆开。

这里直接使用字母表的形式,不多做介绍,看过之后就自然会明白。

子程序如下:

showbyte:   jmp short show

            table db '0123456789ABCDEF'
    show:   push bx
            push es
            push cx

            mov ah,al
            mov cx,4
            shr ah,cx   ;右移4位,ah中得到高4位的值
            and al,00001111b    ;al中为低4位的值

            mov bl,ah
            mov bh,0
            mov ah,table[bx];高4位的值作为相对table的偏移,取得对一个的字符

            mov bx,0b800h
            mov es,bx
            mov es:[160*12+40*2],ah

            mov bl,al
            mov bh,0
            mov al,table[bx];用低4位的值作为相对于table的偏移,取得对应的字符

            mov es:[160*120+40*2+2],al

            pop es
            pop bx

            ret

这个就是数组模型的利用,知道这么回事,利用偏移地址来实现,就是这个样子,很简单。

16.4 程序入口地址的直接定址表

我们可以在直接定址表中存储子程序的地址,从而方便地实现不同子程序的调用。

我们看下面的问题:

实现一个子程序setscreen,为显示输出提供如下功能。

  1. 清屏;
  2. 设置前景色;
  3. 设置背景色;
  4. 向上滚动一行。

我们现在要在一个程序中,顺序调用这四个字程序,我们现在不去纠结其如何实现的,这些内容前面我们都实现过了,最后一个向上滚动一行就是把下面的数据全部复制到显示缓冲区,就是这个样子。

我们可以将这些功能字程序的入口地址存储在一个表中,它们在表中的位置和功能号相对应。对应关系位:功能号*2=对应的功能子程序在地址表中的偏移。程序如下:

setscreen:  jmp short set
    table dw sub1,sub2,sub3,sub4

    set:    push bx

    ;判断功能号是否大于3,如果大于3则进行退出,这种操作是你需要明确的。
    cmp ah,3
    ja sret
    mov bl,ah
    mov bl,0

    add bx,bx   ;根据ah中的功能号计算对应子程序在table表中的偏移

    call word ptr table[bx]

sret:   pop bx
        ret

当然,我们可以用一下程序来实现:

setcreen:   cmp ah,0
            je do1
            cmp ah,2
            je do2
            cmp ah,3
            je do3
            cmp ah,4
            je do4
            jmp shor sret
    do1:    call sub1
            jmp short sret
    do2:    call sub2
            jmp short sret
    do3:    call sub3
            jmp short sret
    do4:    call sub4
            jmp shoer sret

    sret:   ret

这种方式,在我们之后编写子程序时,将会大大地节省我们的时间和精力,这种操作是你要明确的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值