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

实验

实验任务 1

录入 task1.asm

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

lined15-25 的功能为将 Nuist 字符串全部改为大写,写入显存并附上颜色。

逐行解释:

    mov cx, 5               做五次循环
    mov si, 0               初始化 si
    mov di, 0f00h           初始化 di
s:  mov al, [si]            取数据段内对应字符
    and al, 0dfh            改为大写
    mov es:[di], al         写入显存
    mov al, [5+si]          为 al 赋数据段内的值
    mov es:[di+1], al       为先前写入字符的字的高位赋值,以此附以字符颜色
    inc si                  si + 1,移向数据段下一字符
    add di, 2               di + 2,移向显存下一个字
    loop s                  循环

使用 masm、link 对 task1.asm 进行汇编、链接,得到可执行文件 task1.exe,运行并观察结果:

picture1

使用 debug 工具进行调试、反汇编,并使用 g 命令执行到程序返回前:

picture2

修改 line4 里 5 个字节单元的值:

db 5 dup(2)
--> 改成:
db 2,3,4,5,6

重新汇编、链接、运行,结果为:

picture3

由先前分析以及实验可知:

db 2, 3, 4, 5, 6

在此程序中的作用为,设置字符在显存中的颜色。

实验任务 2

编写 task2.asm

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 bx, 0
s:      mov al, byte ptr ds:[bx]
        mov ah, 0
        mov dl, 0AH
        div dl
        mov byte ptr ds:[bx+10], ah
        mov ah, 2
        mov dl, al
        add dl, 30h
        int 21h
        mov ah, 2
        mov dl, byte ptr ds:[bx+10]
        add dl, 30h
        int 21h
        mov ah, 2
        mov dl, " "
        int 21h
        add bx, 1
        loop s

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

使用 masm、link 对 task2.asm 进行汇编、链接,得到可执行文件 task2.exe,运行并观察结果:

picture4

实验任务 3

task3.asm:

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

问题 1:程序返回前,data 段中的数据为:

23 01 56 04 89 07 bc 0a ef 0d ed 0f ba 0c 87 09

反汇编以 076A:0 开始 16 个字的内容,可以观察到与推断一致。

picture5

问题 2:程序返回前,cs、ss、ds 的值为

cs = 076C ss = 076B ds = 076A

由最先的反汇编可知程序在 001D 返回,使用 g 命令执行到此之前,观察到 cs ss ds 的值与推断一致。

picture6

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

实验任务 4

task4.asm

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

问题 1:程序返回前,data 段中的数据为:

23 01 56 04 00 00 00 00 00 00 00 00 00 00 00 00

问题 2:程序返回前,cs、ss、ds 的值为

cs = 076C ss = 076B ds = 076A

由图可知与预测一致

picture7

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

问题 4:对如下定义的段:

name segment
···
name ends

如果段中的数据占 N 个字节,则程序加载后,该段实际占用的空间为

floor((N + 15) / 16)

由观察可知,程序以 16 个字为单位分段

实验任务 5

task5.asm

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

问题 1:程序返回前,data 段中的数据为:

23 01 56 04 00 00 00 00 00 00 00 00 00 00 00 00

问题 2:程序返回前,cs、ss、ds 的值为

cs = 076A ss = 076E ds = 076D

由图可得与推测一致:

picture8

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

实验任务 6

只有实验任务 5 的程序能够正常运行。若将 end start 改为 end,即不指明函数的入口,由于实验任务 3,4 的 data 段和 stack 段都处于 code 段之前,若不指明入口,会默认从 076A:0 开始执行,即将数据段与栈段的数据当作程序运行,会出错;实验任务 5 的 data 段与 stack 段处于 code 之后,默认执行的起点就是 code 段的内容,所以可以正确执行。

实验任务 7

task7.asm

assume cs:code
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

c1 segment   
  db 8 dup(0)
c1 ends

code segment
start:	mov ax, c1
	mov ds, ax
	mov cx,8 
	mov bx, 0	
	mov ax, a
	mov es, ax
s:  mov al, byte ptr es:[bx]
	mov byte ptr ds:[bx], al
	add bx, 1
	loop s
	mov bx, 0;
	mov cx, 8
	mov ax, b
	mov es, ax
s1:	mov al, byte ptr es:[bx]
	add byte ptr ds:[bx], al
	add bx, 1
	loop s1
	
	mov ax,4c00h
    int 21h
code ends
end start

反汇编后得知程序在 002F 处返回,使用 g 命令:

picture9

在程序中我将 c1 段的段地址赋予 ds,使用 d 命令查看可发现程序正确执行。

实验任务 8

task8.asm

assume cs:code
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, b;
	mov ss, ax
	mov sp, 10h
	mov ax, a
	mov ds, ax
	mov bx, 0
	mov cx, 8
s:	push ds:[bx]
	add bx, 2
	loop s

	mov ax,4c00h
	int 21h

code ends
end start

反汇编后得知程序在 001A 处返回,使用 g 命令:

picture10

d 段的段地址为 076C,由图可得成功地使用 push 指令将 a 段中地前 8 个字型数据存储到了 b 段。

实验总结

在本次实验中,以多个段地的汇编源程序编写与调式为中心,进行了多次实验。
在此次实验我了解到:

  • 使用伪指令 segment 和 ends 定义逻辑段后,究竟是用作代码段、数据段还是栈,由程序员指定。
  • 段名代表的是段地址,是常数。不能使用 mov 直接送入段寄存器。
  • 使用 assume 仅仅表示将某个逻辑段和某个段寄存器关联起来;真正当作特定的段使用,需要在代码段中设置相应的段寄存器值,如 ds, ss。
  • 各逻辑段在内存空间中依序排列,并以 16 个字为一个单元进行分配
  • 若 code 段前有自己设置的逻辑段,需要指明程序的入口,否则会将数据段内的内容当作代码来执行。
  • 了解到各寄存器都有其各自的功能,不可随意将数据附入。
posted @ 2020-11-21 21:37  maranlll  阅读(105)  评论(1)    收藏  举报