多个段的汇编源程序的编写与调试
实验任务1:
task1.asm源代码:

assume cs:code, ds:data data segment db 'Nuist' db 5 dup(2) ;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

1、编译、连接:
masm task1.asm; link task1.obj;
2、运行结果:屏幕上显示出绿色的全为大写的’NUIST’

3、代码分析:
①运行前查看内存中数据段的内容:
d 076a:0 9 ;DS+10h=076a:代码开始的段地址,0~9数据长度为ah

由结果可知,数据与代码中预存的数据完全一致;
②反汇编查看:
1)理论上:代码长度(CX = 003B)= 数据段(db ‘NUIST’ :5Byte;db 5 dup(2) :5字节)+ 程序段(3b – a = 31)
代码中用end start指定了程序入口,CS:IP理论上应该是:076A:000A,而实际为076B:0000,不一致;

原因:当程序段不足16字节时,将会补足16字节进行存储;所以实际代码段长度为(3B-1)h=2bh;
查看数据:

反汇编指令:
u 0 2a
结果:

反汇编正确;
其中,源代码中的data被编译器处理为一个表示段地址的值,因此也无法直接赋给段寄存器;
③执行到程序返回之前:

④代码理解:

1 assume cs:code, ds:data 2 data segment 3 db 'Nuist' 4 db 5 dup(2) 5 data ends 6 7 code segment 8 start: ;标号start 9 mov ax, data 10 mov ds, ax 11 12 mov ax, 0b800H ;目标段地址设置为显存段地址 13 mov es, ax 14 15 mov cx, 5 ;设置循环次数5 16 mov si, 0 17 mov di, 0f00h 18 s: mov al, [si] ;每次循环将Nuist中的字符放入al 19 and al, 0dfh ;转换为大写:与11011111 标绿位置0,其余位不变 20 mov es:[di], al ;转换后的字符放入目标地址 21 mov al, [5+si] ;字符串循环的同时可以依次将取偏移地址为5~9的数据;预设dup(2)对应显示均为绿色 22 mov es:[di+1], al ;复制入控制颜色的位置;预设dup(2)对应显示均为绿色 23 inc si 24 add di, 2 25 loop s 26 27 mov ah, 4ch 28 int 21h 29 code ends 30 end start ;用“end标号”指明源程序中指明程序的入口

⑤改变第4行代码:
db 2,3,4,5,6 ;db 5 dup(2)
编译、连接,运行结果:

结果:颜色改变了;猜测:这里的数值控制显示的颜色。
实验任务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 si,0
s: mov bl,10 mov ah,0 ;ah要恢复0,否则影响ax作为被除数 mov al,[si] div bl add al,30h add ah,30h mov bx,ax ;由于输出字符需要访问ah,ah中的结果应先转移 mov ah,2 mov dl,bl int 21h mov dl,bh int 21h inc si loop s mov ah,4ch int 21h code ends end start

实验结果截图:

成功输出。
实验任务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

问题:
① CPU执行程序,程序返回前,data段中数据: 23 01 56 04 ………………执行前后数据段中数据不变 ②CPU执行程序,程序返回前,(SA为代码段起始段地址) cs = ss+1h ss = ds+1h ds = SA+10h ③设程序加载后,code段的段地址为X,则data段的段地址为:X-2h,stack段的段地址为:X-1h
1、查看初始时各个段地址:

SA = 075A
2、反汇编:程序段长:42h-10h-10h = 22h
u 0 21

问题①执行前后数据段内容未发生改变,结论正确:

问题②:实际运行中参照量SA = 075Ah


CS = 076Ch = SS + 1h;SS = 076Bh = DS + 1h;DS = 076Ah = SA + 10h 与理论一致;
问题③:
CS = 076Ch = X;SS = 076Bh = CS - 1h;DS = 076Ah = CS - 2h 与理论一致。
实验任务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

问题:

① CPU执行程序,程序返回前,data段中数据: 23 01 56 04 ②CPU执行程序,程序返回前,(SA为代码段起始段地址) cs = ss+1h ss = ds+1h ds = SA+10h ③设程序加载后,code段的段地址为X,则data段的段地址为:X-2h,stack段的段地址为:X-1h
④如果段中数据占N个字节,程序加载后,该段实际占有的空间:若N%16==0 实际N字节;否则,实际存储(N/16+1)*16字节。

前三个问题:同实验3:
由task4的运行截图可知:



结论完全一致;
问题④:task4代码中data段和stack段均不足16个字节,实际加载时,每段都补足了16字节;
将代码改变如下:
assume cs:code, ds:data, ss:stack data segment dw 0123h, 0456h,0123h, 0456h,0123h, 0456h,0123h, 0456h,0123h, 0456h ;data段设置20个字节 data ends
………………………… ;其余均不变
运行结果对比:

data段数据20字节,实际存储却为2H(32字节);

结论:段的存储长度为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

问题:
① CPU执行程序,程序返回前,data段中数据: 23 01 56 04不变 ②CPU执行程序,程序返回前,(SA为代码段起始段地址) cs = SA+10H ss = DS+1H ds = CS+3H ③设程序加载后,code段的段地址为X,则data段的段地址为:X+3,stack段的段地址为:X+4
运行结果:

反汇编:

CS = 076A DS = 076D = CS + 3H :意味着代码段实际存储内存为30H,而反汇编依然是22H字节即为完整代码,可以推测,代码段中不足16个字节的部分补足16字节进行存储;
SS = DS + 1H :data段数据实际存储为10H个字节;
且由运行结果可知:CX = 0042H–》CX = 0044H,则栈段实际存储 44H – 30H – 10H = 4H 为源代码中预留栈段的实际长度,并未补齐16字节存储;
由实验结果可以推测,源代码在程序加载后,只有最后一个程序段不进行补齐16字节存储的操作。
执行:

实验结果与理论一致。
实验任务6:
问题:
实验任务5中代码仍然可以正确执行,因为默认CS = SA + 10H,只有实验任务5中的代码此时的CS为程序段正确的起始段地址;
实验结果:
task3,删去代码最后的start后编译、连接追踪运行结果:

CS未指向正确的程序开始,第一条代码也错误,代码中也没有重定向CS的代码;
task4,删去代码最后的start后编译、连接追踪运行结果:

结果同上;
task5,删去代码最后的start后编译、连接追踪运行结果:

CS指向程序入口,反汇编成功,仍然可以执行;
实验结果与理论猜测一致。
实验任务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 c segment ; 在集成软件环境中,请将此处的段名称由c→改为c1或其它名称 db 8 dup(0) c ends code segment start: mov ax,a mov ds,ax mov ax,c mov es,ax mov cx,8 mov si,0 s: mov al,ds:[si] add al,ds:[si+16] mov es:[si],al inc si mov al,0 loop s mov ax,4c00h int 21h code ends end start

运行结果:
①编译、连接,跟踪运行、反汇编:

②在运行前查看3段数据,g命令运行到返回前,查看运行后结果:

实验成功。
实验任务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,a mov ds,ax mov ax,b mov ss,ax mov sp,10h mov cx,8 mov si,0eh s: mov ax,ds:[si] push ax dec si dec si loop s mov ax,4c00h int 21h code ends end start

编译、连接、跟踪运行,反汇编查看:

运行前后查看内存内容:

实验成功。