|
30鱼币
本帖最后由 SKY_DOR/cy 于 2022-7-14 22:39 编辑
assume cs:code,ss:c,ds:b,es:a
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
db 0,0,0,0 , 0,0,0,0
c ends
code segment
start: mov ax,a
mov es,ax
mov ax,c
mov ss,ax
mov sp,30h
mov bx,0
mov cx,8
mov ax,02h
mov ax,4c00h
int 21h
code ends
end start
上面是我写的汇编代码
编译出来的结果 076D:0016处的指令是:mov ax,4c00h
最开始的编译结果
ss段赋值前的指令
我执行完下面的代码段之后
mov ss,ax
mov sp,30h
076D:0016处的指令变为:ADD al,[BX+SI]
ss段赋值后的指令
想了很久一直想不通是什么原因,想向大家请教一下
本帖最后由 jackz007 于 2022-7-15 17:31 编辑
根据调试信息,不难获取代码段与堆栈段所占用内存情况如下: 堆栈区域:076C0 ~ 076F0 长度 30H
代码区域: 076D0 ~ 076EB 长度 1BH
这里的内存地址是 20 位绝对地址
对于 exe 文件而言,其各个段所属的内存空间是不可以发生重叠的,不难看出,在本例中,堆栈段完全覆盖了代码段,整个代码段全部位于堆栈段内,这样,当堆栈中有数据存入时,就很容易破坏代码段的数据,这就是本例代码存在的问题。
又是 X 爽教的,赶快换教材吧,其实,assume 伪指令一般是不需要声明堆栈段的,在程序代码中也无需为 ss、sp 赋初值,因为 exe 文件头中有专门的字段记载它们的数值,一个 exe 在加载进内存的时候,操作系统会根据文件头的信息自动设置这些寄存器的初始数值,根本不需要用代码去设置,我们要做的,是告诉编译程序,哪个是堆栈段就可以了。
assume cs:code , ds:b , es:a
a segment para public 'data'
db 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8
a ends
b segment para public 'data'
db 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8
b ends
c segment para stack 'stack' ; 这样定义的堆栈段可以被编译器自动识别
400h db dup(0) ; 定义 400h 个字节的堆栈空间,并全部初始化为字节 00
c ends
code segment para public 'code'
start: mov ax,c ; 多余指令,可以删除
mov ss,ax ; debug 时看看 ss 在被赋值前是否已经与 ax 相同?多余指令,可以删除
mov sp,400h ; debug 时看看 sp 在被赋值前其值是否已经是 400h?多余指令,可以删除
mov ax,a ; 这里应该成为第一条指令
mov es,ax
mov bx,0
mov cx,8
mov ax,02h
mov ax,4c00h
int 21h
code ends
end start
这样定义堆栈段,编译的时候,就不会再出现没有堆栈的警告信息,在跟踪的时候,也不会再出现代码被修改的问题了。
堆栈必须定义足够大,因为不止我们自己的代码在用,调用 DOS、BIOS 功能时,操作系统也在使用,定义小了会给程序埋下隐患,可能危害程序的正常运行。你的程序在为 sp 赋值后,代码被改变,可是,代码却并没有使用堆栈,是不是很奇怪?这是因为堆栈在我们并不知情的情况下,已经被操作系统使用,由于被使用的堆栈区域与代码区域重合,从而,造成代码莫名其妙被修改的后果。
|
最佳答案
查看完整内容
根据调试信息,不难获取代码段与堆栈段所占用内存情况如下:
这里的内存地址是 20 位绝对地址
对于 exe 文件而言,其各个段所属的内存空间是不可以发生重叠的,不难看出,在本例中,堆栈段完全覆盖了代码段,整个代码段全部位于堆栈段内,这样,当堆栈中有数据存入时,就很容易破坏代码段的数据,这就是本例代码存在的问题。
又是 X 爽教的,赶快换教材吧,其实,assume 伪指令一 ...
|