注册 登录
编程论坛 汇编论坛

为什么这段代码在debug中结束后通过t指令可以回到最开始的指令啊

oped02 发布于 2022-10-21 20:45, 3212 次点击
程序代码:

data segment
    num    db    -9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10
    fu    db    20 dup(?)    ;存放负数
    zheng    db    20 dup(?)    ;存放正数
    noff    db    0    ;负数数目
    nofz    db    0    ;正数数目
data ends

code segment
    assume    cs:code,ds:data,es:data
codestart proc far
    push    ds
    xor    ax,ax
    push    ax

    mov    ax,data
    mov    ds,ax
    mov    es,ax

start:
    lea    si,fu
    lea    di,zheng
    lea    bx,num

    mov    cx,20

compare:
    mov    al,[bx]
    inc    bx
    cmp    al,0
    jg    positive
    inc    noff
    mov    [si],al
    inc    si
    jmp    transfer


positive:
    inc    nofz
    mov    [di],al
    inc    di

transfer:
    loop    compare
   
exit:
    ret

code ends
end    start
7 回复
#2
oped022022-10-21 20:46
只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录
只有本站会员才能查看附件,请 登录
#3
oped022022-10-21 20:48
回复 2楼 oped02
第一张是刚运行,我用t命令单步走了两次,因为里面有循环,所以用p指令直接清空cx,那么到了结尾的ret应该直接退出,为什么再执行一次后就又重新开始了呢
#4
oped022022-10-21 20:51
而且如果把代码尾部的ret更改为mov al,4ch    int 21h后就不会这样了,只不过会进入另一段代码,这段奇怪的代码貌似是我写的其它程序
只有本站会员才能查看附件,请 登录
#5
Valenciax2022-10-23 12:44
回复 3楼 oped02
为什么再执行一次后就又重新开始了呢 ?

答:
1.
将 codestart proc far 这一句改为
main proc far

2.

code ends
end    start
改为
main endp
code ends
end    main


这里解释一下,早期的dos版本为程式提供了3种离开程式返回dos的方法.
1.
mov ah,0 ;返回dos的函式
int 21h

2.
int 20h ;dos的返回中断

3.
在程式本身和dos间有一个二者沟通的界面段,叫psp,大小100h,位处于代码之前,而程式开始时的ds和es都会指向这个psp段,
所以程式须要在开始时
mov ax,data
mov ds,ax
用以取得资料段地址放入ds,否则ds就会一直=psp段.
在这个psp段的首两个字节是cd 20,cd 20 就是int 20h 的机器码.
于是有了楼主的代码
push ds
xor ax,ax
push ax
这里是把ds和0压入栈,然后若程式要结束时,只要一条指令retf就可以返回dos
ret是近程返回,由sp弹出一个word值入ip,新的ip就相当于返回父程序.cs不变
retf是远程返回,由sp弹出第一个word值入ip,然后sp+2,弹出第2个word值入cs,新的cs:ip就相当于远程返回父程序
程式之初已经把psp:0入栈,所以retf时,新的cs:ip = psp:0, 也就是直接运行int 20h
没错,就是这么迂回.....

好了,要实现上面的方法,须要的框架如下:

程序代码:

main proc far     ;远程程序

push ds     ;psp 入栈
xor ax,ax    ;ax=0
push ax        ;0入栈
...
...
...
ret         ;返回dos

main endp    ;程序结束

end main    ;程式结束,并以main作为入口





但为什么是ret不是retf?
因为既然是proc far,聪明的编译器知道是远程程序,会'自动'把你写的ret改为retf,当然写retf也可以.

[此贴子已经被作者于2022-10-23 12:51编辑过]

#6
Valenciax2022-10-23 12:46
回复 4楼 oped02
而且如果把代码尾部的ret更改为mov al,4ch    int 21h后就不会这样了,只不过会进入另一段代码,这段奇怪的代码貌似是我写的其它程序


答:
应该是mov ah,4ch

上面说过,早期的dos版本为程式提供了3种离开程式返回dos的方法,之后dos版本更新,有了第4程方法,就是

mov ah,4ch
int 21h

[此贴子已经被作者于2022-10-23 12:53编辑过]

#7
Valenciax2022-10-23 13:15
顺带一提,既然已经有了3种方式离开,为什么又捣搞一个ah=4ch的返回方式,是不是太无聊?

这里涉及dos扩充功能,我们都知道有batch批次档(windows之下是cmd),
当bat档运行完毕某一程式时,是可以透过errorlevel来判断程式的流程,比如

abcd.bat

程序代码:

@echo off
dosomething.exe
if errorlevel 3 goto do3
if errorlevel 2 goto do2
if errorlevel 1 goto do1
goto end

....
....
do1:
....
....

end:


好了,要实现errorlevel, 这个dosomething.exe必须要以ah=4ch离开,方法是
mov ah,4ch
mov al,errorcode
int 21h

这个errorcode就是程式完结后的errorlevel值.


再顺带说一下,其实离开dos的方法,还有int 27h, int 21h,ah=31h.......这是后话......
#8
oped022022-10-23 23:07
回复 7楼 Valenciax
感谢版主大大的详细解答
1