实验3 多个段的汇编源程序编写与调试

实验3

一、实验结论

1、实验任务1

代码如下:

assume cs:code, ds:data
data segment
        db 'Nuist'
        db 5 dup(2)
data ends

code segment
start:
        mov ax, data
        mov ds, ax

        mov ax, 0b800H
        mov es, ax

        mov cx, 5
        mov si, 0
        mov di, 0f00h
s:      mov al, [si]
        and al, 0dfh
        mov es:[di], al
        mov al, [5+si]
        mov es:[di+1], al
        inc si
        add di, 2
        loop s

        mov ah, 4ch
        int 21h
code ends
end start

运行结果如下图:

调试过程如下图:

将db 5 dup(2)改成db 2,3,4,5,6后,代码如下:

assume cs:code, ds:data
data segment
        db 'Nuist'
        db 2,3,4,5,6
data ends

code segment
start:
        mov ax, data
        mov ds, ax

        mov ax, 0b800H
        mov es, ax

        mov cx, 5
        mov si, 0
        mov di, 0f00h
s:      mov al, [si]
        and al, 0dfh
        mov es:[di], al
        mov al, [5+si]
        mov es:[di+1], al
        inc si
        add di, 2
        loop s

        mov ah, 4ch
        int 21h
code ends
end start

运行结果如下图:

调试过程如下图:

  源代码中line4的字节数据写入了B800:0F00后5个字的高位字节中,即写入了显存单元中决定色彩的字节,改变它们将改变现实内容的色彩。故该数值的作用为决定字符的色彩。

 

2、实验任务2

源代码如下:

assume cs:code, ds:data

data segment
    db 23, 50, 66, 71, 35
data ends

code segment
start:    
    mov ax,data
    mov ds,ax

    mov cx,5
    mov si,0
    mov bl,0ah

s:  mov al,ds:[si]
    mov ah,0
    div bl
    add ah,030h
    add al,030h
    mov bx,ax
    mov ah,2
    mov dl,bl
    int 21h
    mov dl,bh
    int 21h
    mov bl,0ah
    inc si
    loop s

    mov ah,4ch
    int 21h
code ends
end start

运行结果如下:

 

3、实验任务3

源代码如下:

assume cs:code, ds:data, ss:stack
data segment
  dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
data ends

stack segment
  dw 0, 0, 0, 0, 0, 0, 0, 0
stack ends

code segment
start:  mov ax,stack
        mov ss, ax
        mov sp,16
        
        mov ax, data
        mov ds, ax
        
        push ds:[0]
        push ds:[2]
        pop ds:[2]
        pop ds:[0]
        
        mov ax,4c00h
        int 21h

code ends
end start

使用debug执行至返回前,此时各寄存器状态如下图:

使用d命令查看数据段中数据,如下图:

故:

①data段中的数据为23 01 56 04 89 07 BC 0A EF 0D ED 0F BA 0C 87 09

②程序返回前,cs=076C,ss=076B,ds=076A。

③设程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。

 

4、实验任务4

源代码如下:

assume cs:code, ds:data, ss:stack
data segment
  dw 0123h, 0456h
data ends

stack segment
  dw 0, 0
stack ends

code segment
start:  mov ax,stack
        mov ss, ax
        mov sp,16
        
        mov ax, data
        mov ds, ax
        
        push ds:[0]
        push ds:[2]
        pop ds:[2]
        pop ds:[0]
        
        mov ax,4c00h
        int 21h

code ends
end start

使用debug执行至返回前,此时各寄存器状态如下图:

使用d命令查看数据段中数据,如下图:

故:

①data段中的数据为23 01 56 04

②程序返回前,cs=076C,ss=076B,ds=076A。

③设程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。

④如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为⌈N/16⌉*16。

 

5、实验任务5

源代码如下:

assume cs:code, ds:data, ss:stack

code segment
start:  mov ax,stack
        mov ss, ax
        mov sp,16
        
        mov ax, data
        mov ds, ax
        
        push ds:[0]
        push ds:[2]
        pop ds:[2]
        pop ds:[0]
        
        mov ax,4c00h
        int 21h

code ends
data segment
  dw 0123h, 0456h
data ends

stack segment
  dw 0,0
stack ends
end start

使用debug执行至返回前,此时各寄存器状态如下图:

使用d命令查看数据段中数据,如下图:

故:

①data段中的数据为23 01 56 04

②程序返回前,cs=076A,ss=076E,ds=076D。

③设程序加载后,code段的段地址为X,则data段的段地址为X+3,stack段的段地址为X+4。

 

6、实验任务6

  如果将“end start”改为“end”,则task5.exe依然可以正常运行,其它两个不能。这是由于task5.exe中段的排列顺序为代码段——数据段——栈段,加载入内存后CS:IP默认指向程序开头,即代码段开头,故能正常运行。其它两个程序中段的排列顺序为数据段——栈段——代码段,加载入内存后CS:IP默认指向程序开头,即数据段开头,CPU将会把数据段中的数据解释为指定运行,引发错误。

 

7、实验任务7

源代码如下:

assume cs:code, ds:a, ss:b ,es:c
a segment
  db 1,2,3,4,5,6,7,8
a ends

b segment
  db 1,2,3,4,5,6,7,8
b ends

c segment   ; 在集成软件环境中,请将此处的段名称由c→改为c1或其它名称
  db 8 dup(0)
c ends

code segment
start:
    mov ax,a
    mov ds,ax
    
    mov ax,b
    mov ss,ax

    mov ax,c
    mov es,ax

    mov si,0
    mov cx,8

s:  mov al,ds:[si]
    add al,ss:[si]
    mov es:[si],al
    inc si
    loop s

    mov ah,4ch
    int 21h
code ends
end start

使用debug运行至返回前,查看逻辑段C中内容,如下图:

可见,程序实现了要求。

 

8、实验任务8

源代码如下:

assume cs:code, ds:a, ss:b
a segment
  dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
a ends

b segment
  dw 8 dup(0)
b ends

code segment
start: 
    mov ax,a
    mov ds,ax
    
    mov ax,b
    mov ss,ax
    mov sp,010h
    
    mov si,0
    mov cx,8

s:    push [si]
    add si,2
    loop s

    mov ah,4ch
    int 21h
    
code ends
end start

使用debug运行至返回前,查看逻辑段B中内容,如下图:

可见,程序实现了要求。

 

二、实验总结

  在编写实验任务2的程序时,一开始,运行编写完成的程序后将会陷入死机无法退出,只能重启dosbox。使用debug单步执行发现执行除法指令后,CPU执行的下一条指令不再是预期的add ah,030h,而是??? [bx+si],且CS、IP等寄存器的数值均发生了变化。显然,这一命令是错误的,是死机的源头。查询资料发现,这是除法溢出导致的。检查代码后,发现原因为我将mov al,ds:[si] mov ah,0误写为mov ax,ds[si]。关于除法溢出的具体解释如下:

  x86的除法指令正确执行是有条件的。这个条件是:被除数的高位寄存器数值,必须小于除数。如果数据不满足这样的条件,被除数的高位寄存器数值大于或者等于除数(相当于除法运算后产生的商会是个跟被除数大小一样的数值级别,但是实际上用来存放商的实际寄存器数值级别只有被除数的一半大小),就会产生除法溢出。此时,将会自动触发触发溢出中断。

  通过该问题,我学到了x86汇编语言中并非语法检查无错误程序就能正常运行。部分指令的执行是有额外的限制条件的。

posted @ 2020-11-26 22:02  SpeakLessPoiMore  阅读(102)  评论(1编辑  收藏  举报