实验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,运行并观察结果:

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

修改 line4 里 5 个字节单元的值:
db 5 dup(2)
--> 改成:
db 2,3,4,5,6
重新汇编、链接、运行,结果为:

由先前分析以及实验可知:
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,运行并观察结果:

实验任务 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 个字的内容,可以观察到与推断一致。

问题 2:程序返回前,cs、ss、ds 的值为
cs = 076C ss = 076B ds = 076A
由最先的反汇编可知程序在 001D 返回,使用 g 命令执行到此之前,观察到 cs ss ds 的值与推断一致。

问题 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
由图可知与预测一致

问题 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
由图可得与推测一致:

问题 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 命令:

在程序中我将 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 命令:

d 段的段地址为 076C,由图可得成功地使用 push 指令将 a 段中地前 8 个字型数据存储到了 b 段。
实验总结
在本次实验中,以多个段地的汇编源程序编写与调式为中心,进行了多次实验。
在此次实验我了解到:
- 使用伪指令 segment 和 ends 定义逻辑段后,究竟是用作代码段、数据段还是栈,由程序员指定。
- 段名代表的是段地址,是常数。不能使用 mov 直接送入段寄存器。
- 使用 assume 仅仅表示将某个逻辑段和某个段寄存器关联起来;真正当作特定的段使用,需要在代码段中设置相应的段寄存器值,如 ds, ss。
- 各逻辑段在内存空间中依序排列,并以 16 个字为一个单元进行分配
- 若 code 段前有自己设置的逻辑段,需要指明程序的入口,否则会将数据段内的内容当作代码来执行。
- 了解到各寄存器都有其各自的功能,不可随意将数据附入。

浙公网安备 33010602011771号