实验任务:
(1)将下面的程序保存为t1.asm文件,将其生产可执行文件t1.exe。
assume cs:codesg
codesg segment
mov ax, 2000H
mov ss, ax
mov sp, 0
add sp, 10
pop ax
pop bx
push ax
push bx
pop ax
pop bx
mov ax, 4C00H
int 21H
codesg ends
end
步骤:
1、进入dos,打开edit
注意,本实验用的是dosbox系统,但是这个系统操作其实比较繁琐,以后实验操作熟练度上升,可以使用masm集成实验环境。
-----------------------------------------------------------------------------------------------------
2、输入代码,如图:
注意倒数第二行的“ends”和最后一行的“end”不要写错。
-------------------------------------------------------------------------------------------------------------------------------------
3、保存文件
截图:
因为笔者之前设置过默认保存路径,因此保存时不必选择路径。
注意:文件扩展名为.asm
--------------------------------------------------------------------------------------
4、编译
①进入dos,进入d:\masm(保存路径为d:\masm\1.asm),运行masm.exe
②在文件源后面(source filename 【.ASM】)后面直接输入文件名即可,如本实验的1.asm即可,不必详细输入文件路径
③【1.boj】文件名默认为1.boj,不必另行指定文件名,直接enter跳过
④source listing 编译程序提示输入列表文件的名称,enter跳过即可
⑤corss-reference 编译程序提示出入交叉引用文件的名称,enter跳过即可
⑥忽略交叉引用文件的生成后,屏幕显示如图:
通过对1.asm的编译,masm目录下生产了新文件1.boj。当然,这是在没有出现错误的情况下。错误大概有两类:1、程序中有“Service Erroes”;2、找不到所给出的源程序文件
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
5、连接
①进入dos方式,进入d:\masm,运行link.exe
输入:d:\link 1(连接1.obj)
注意:输入d:\masm\link 无效,d:\masm\link 1也无效
------------------------------------------------------------------
②
②run file生成文件,程序默认输出可执行文件1.exe,enter跳过指定命名,生成1.exe
------------------------------------------
③list file:连接程序提示输入映像文件,enter跳过即可
---------------------------------------------------------------------------------------
④ libraries 连接程序提示输入库文件的名称,enter跳过即可
--------------------------------------------------------------------------------------
⑤忽略库文件的连接后,屏幕显示如图:
警告错误“没有栈段”,这里不必理会
------------------------------------------------------------------------------------------
【2】用debug跟踪t1.exe的执行过程
①在命令提示符下输入:debug 1.exe
②用r查看寄存器信息:
d cs:0
u cs:0
③执行代码:
mov ax,2000
mov ss,ax
mov sp,0
解释:将2000H段开始的内存单元创建一个栈结构。栈顶指针ss:sp指向00H 如图:
——————————————————————————————————————————————————————————————
add sp,10
解释:使sp指向10h,即栈结构分配空间为10个字节,如图:
——————————————————————————————————————————————————————————————
pop ax -------------------------->弹出栈顶元素赋给ax;sp=sp+2=000A+2=000CH
pop bx -------------------------->弹出栈顶元素赋给bx;sp=sp+2=000C+2=000EH
注意:此时栈顶为000E,已经越界,触发中断机制 如图:
———————————————————————————————————————————————————————————————
push ax -------------------------->将ax压入栈中;sp=sp-2=000EH-2=000CH
push bx -------------------------->将bx压入栈中;sp=sp-2=000CH-2=000AH
————————————————————————————————————————————————————————————————————
pop ax -------------------------->弹出栈顶元素赋给ax;sp=sp+2=000A+2=000CH
pop bx -------------------------->弹出栈顶元素赋给ax;sp=sp+2=000A+2=000EH
总结:在这个栈结构中,栈内存没有使用,可以随意越界,但是如果栈内有数据,越界将会破坏数据,因此一定要注意栈的空间分配
(3)PSP的头两个字节是CD 20,用debug加载t1.exe,查看PSP的内容。
书上p92提到:PSP存放在ds:0的前256个字节中,从ds中可以得到PSP的段地址SA,PSP的偏移地址为0.则物理地址为SA*16+0,因为PSP占256(100h)个字节,所以程序的物理地址为 SA*16+0+256=SA*16+16+16+0=(SA+16)*16+0
可用段地址和偏移地址表示为SA+10H:0,即cs=ds+10h(如ds=129E,cs=12AE)