汇编语言学习-直接定位表


直接定址表

描述了单元长度的标号

以前我们多采用后面不带冒号的形式进行编程

assume:code

code segment

    a: db 1,2,3,4,5,6,7,8
    b: dw 0

start:
    mov si,offset a
    mov bx,offset b
    mov cx,8
s:
    mov al,cs:[si]
    mov ah,0
    add cs:[bx],ax
    inc si
    loop s

    mov ax,4c00h
    int 21h
code ends
end start

But the mark only represent the address of the memory. We still have another form of the mark that does not have the colon. For example.

assume:code

code segment

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

start:
    mov si,offset a
    mov bx,offset b
    mov cx,8
s:
    mov al,a:[si]
    mov ah,0
    add bs,ax
    inc si
    loop s

    mov ax,4c00h
    int 21h
code ends
end start

mov al,a[si] equal to mov al,cs:0[si]

So, we could find the way helps us access the address of memory in a neat form. We call it data-mark.他标记了存储数据的单元的地址和长度,它不同于仅仅表示地址的标号。

在其他段使用数据标号

一般来说,我们不在代码段中定义数据,而是将数据定义到其他段中,在其他段中,我们也可以使用数据标号来描述数据单元的地址和长度。

注意:在后面加有‘:’的地址只能在代码段中使用,不能在其他段使用。

实验

安装一个新的int 7ch中断例程

功能: 1.clear the screen
2.set the foreground
3.set the background
4.move up one row

思路

  • 编写新的int 7ch 中断例程
  • 安装新的int 7ch 中断例程

这个实验过程的代码出了很多问题,到最后终于改好了。

初期的改错思路

the major problem 是中断例程中table dw sub1,sub2,sub3,sub4无法正常运作。
给人的感觉好像,不能在程序中用一样.按照这种形式写的话,后面的set标号无法被正确的编译。不知道为什么都变成了table标号下面的??

问题1

改成这种形式之后,才能在debug中的cpu看到正确的汇编代码,虽然代码段中把它们这些地址解析成了汇编指令

问题2

通过后续的观察发现,其实代码是被正确解析了的,只是在cpu版块的显示上table段中的存放的数据被当作了指令。但是为什么程序不执行呢?

这也是为什么要把jmp命令放在前面的原因,就是为了不让table段存放的数据被当作指令执行,这样的话,肯定有问题的

改变写法后的对比图

后期的改错思路

先整理一下初期思路中出错的原因,再分析一下是哪些基础的知识没有掌握好,导致我们这么长时间一直在纠错

初期思路:

  • 1.jmp命令放在前面的原因,就是为了防止我们存储的数据被当作指令执行,这也是为什么你在debug模块中的cpu看汇编代码的时候,看起来好像很奇怪。但是它们都是正常的指令。
    cpu视角下的汇编代码

  • 2.tabledata dw sub1,sub2,sub3,sub4;无论是tabledata 还是 sub1,sub2 这些地址都是相对于最开始运行的CS段而言的,而我们想要的是中断例程,也就是执行中断例程的时候的CS段。这样去调用的话,肯定会出错。说成白话的话就是,本来一棵树距离图书馆35米,但是现在要问你,这棵树举例教学楼多少米,你要是还说35米。那是不是有点刻舟求剑的意思了。所以,真正要采用的是相对地址,还得加上0200h才行! 这样才行tabledata dw offset sub1 - offset interupt + 0200h,offset sub2 - offset interupt+0200h,offset sub3 - offset interupt+0200h,offset sub4 - offset interupt+0200h

    1. call word ptr [bx]这样默认的访问地址是 ds+bx,而你想要的是cs:[bx]所以要把寄存器显式的标注出来啊
    1. 虽然中断例程处,确实没有办法通过F7进入,但是可以通过看0000:0200h内存中代码,就可以发现到底是不是你想要的了。
      0000:0200处的代码
    1. int指令和iret指令的作用,如果真的能很好的掌握这两个指令,也犯不着这么长时间才找到问题的源头。

代码

assume cs:code

code segment

start:

    mov ax,cs
    mov ds,ax
    mov si,offset interupt; set the ds:si point to the source address
    mov ax,0
    mov es,ax
    mov di,0200h; set the es:di point to the destination address
    mov cx,offset interuptend-offset interupt; cx the length of transmisson
    cld ; the sequence of the transmit
    rep movsb

    mov ax,0
    mov es,ax

    cli
    mov word ptr es:[7ch*4],0200h
    mov word ptr es:[7ch*4+2],0
    sti

    ;调用之前的设置你需要再看一下要求是怎么设置的
    mov ah,2
    mov al,3
    
    int 7ch; 这里怎么跳到了4002h
    ; call interupt

    mov ax,4c00h
    int 21h

;所以程序大体上是没有问题的
;但是加上table sub1,sub2,sub3,sub4之后就显的怪怪的
;通过调试程序来看的话,只有mov bl,ah之后的程序是正常的
;前面的程序好像都是错的一样,--通过CPU反汇编的指令来看的话,前面的几句都不对

;我如果去掉table直接调用函数的话,就不会出现上述问题
;对前面的简单程序进行操作后发现,这个table dw sub1,sub2,sub3,sub4不能在标号里面

;也不是因为jmp short set语句和tabledata dw......两个语句的顺序问题
;书上说
interupt:
    jmp short set

    ;并不是写法是错的,而是你用错了
    ;按道理来说,程序的执行CS IP 本来在code段
    ;现在你引发了中断以后就跑到 中断例程中的CS IP了,但是此时 tabledata中保存的仍然是最开始的CS IP 这样一跳转的话,z
    ; tabledata dw sub1,sub2,sub3,sub4;这种写法是错误的
    ;写成下面这种形式的话,set标号就会重新显示出来
    tabledata dw offset sub1 - offset interupt + 0200h,offset sub2 - offset interupt+0200h,offset sub3 - offset interupt+0200h,offset sub4 - offset interupt+0200h
    ; tabledata dw offset sub1 - offset interupt + 0200h,offset sub2 - offset interupt + 0200h,offset sub3 - offset interupt + 0200h,offset sub4 - offset interupt + 0200h

set:
    push bx
    push es
    push cx
    cmp ah,3;判读功能号是否大于3
    ja sret
    mov bl,ah
    mov bh,0
    add bx,bx;根据ah中的功能号计算对应子程序在table表中的偏移
    add bx,offset tabledata-offset interupt + 0200h
    ; call word ptr (offset tabledata-offset interupt)[bx+0200h];调用对应的功能子程序这句话有问题 
    ; 上面这条指令错就错在 这样隐含的寄存器是ds 也就是 访问的是ds:[...]但是我们想要的是cs:[bx]
    call word ptr cs:[bx]
    ; add bx,7e02h
    ; jmp cs:[bx]

sret:
    pop cx
    pop es
    pop bx
    ; ret
    iret

;make the screen empty
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
    ; jmp sret

; set the foreground
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
    or es:[bx],al
    add bx,2
    loop sub2s

    pop es
    pop cx
    pop bx
    ret
;set the background color
sub3:
    push bx
    push cx
    push es

    mov cl,4
    shl al,cl
    mov bx,0b800h
    mov es,bx
    mov bx,1
    mov cx,2000
sub3s:
    and byte ptr es:[bx],10001111B
    or es:[bx],al
    add bx,2
    loop sub3s

    pop es
    pop cx
    pop bx
    ret
;scroll up one line
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指向第n+1行
    mov di,0;es:di指向第n行
    cld
    mov cx,24;共复制24行
sub4s:
    push cx
    mov cx,160
    rep movsb
    pop cx
    loop sub4s

    mov cx,80
    mov si,0
sub4s1:
    mov byte ptr [160*24+si],' ';最后一行清空
    add si,2
    loop sub4s1

    pop ds
    pop es
    pop di
    pop si
    pop cx
    ret

interuptend:
    nop
code ends
end start

效果

清屏

设置前景色

设置背景色

向上滚动一行


文章作者: 美食家李老叭
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 美食家李老叭 !
评论
  目录