使用int 0x20和int 0x21 / ah = 0x4C退出16位汇编程序有什么区别?

7

我曾经在不同的时间使用过两种

int 0x20

并且

mov ah, 0x4c
int 0x21

作为结束16位汇编程序的方式,有两种方法。
但是这两种方法之间有什么区别呢?
编辑:感谢大家的评论。根据Alexey提到的PSP(程序段前缀)进行跟进,得到了来自Microsoft MASM支持的这篇文章
该文章似乎表明,两者之间的区别不仅仅是返回代码。
如果有人能更明确地将它们联系在一起,我很乐意授予接受答案的人。

1
https://retrocomputing.stackexchange.com/questions/16891/difference-between-int-0x20-and-int-0x21-0x4c - ninjalj
3个回答

17
首先,一些背景知识。DOS使用中断21h进行系统调用。AH用于解复用INT 21h提供的各种功能。当程序被执行时,DOS会在其前面放置256字节,称为PSP(程序段前缀),其中包含有关进程的信息。
DOS中最初的退出函数是INT 21/AH=00。现在,显然DOS开发人员决定从程序返回应该是退出程序的一种方式(这是来自CP/M吗?)。RET(near)从堆栈弹出一个字并跳转到它。因此,当创建程序时,其堆栈以单词0000开始。这是PSP的开始。因此,在PSP的开头有终止程序的代码。为了使该代码保持小巧,INT 20h充当MOV AH,00h ; INT 21h的别名。
[编辑:可以在下面的屏幕截图中看到这一点。]
DOS 2.0从Unix中借鉴了许多东西,包括返回代码。因此,一个新的INT 21h函数出现了,INT 21h / AH = 4ch,它接受返回代码并将其返回给操作系统。该函数还设计用于与EXE文件一起使用(在DOS 2.0中也是新功能),这些文件可以有多个段。以前的退出函数(INT 20h和INT 21h / 00)假定CS与COM程序启动时相同,即它指向程序之前的PSP 256字节。

历史注释:在CP/M上,有3种退出程序的方式:

  • 调用BDOS函数0(等同于INT 21 AH = 00h,DOS函数0)
  • 跳转到0000h处的WBOOTF位置(等同于PSP偏移量000h)
  • 返回
"The WBOOTF位置由3个字节组成:1个字节用于跳转,2个字节用于跳转目标(BDOS中的WBOOT函数)。
在早期版本的CP/M中,调用BDOS功能0或跳转到WBOOT会导致从磁盘重新加载CP/M的某些部分(热启动),然后运行一些操作系统初始化;而直接返回则返回到CCP(控制台命令处理器,相当于COMMAND.COM),然后提示输入下一个命令行。据我所知,CP/M 3通常被加载到ROM中,返回到WBOOT位置会导致从ROM重新加载操作系统的部分内容。"

如果您允许的话,我想插入一个带注释的截图来验证您所描述的内容。我会编辑您的回复并将其粘贴进去--看看您的想法。(如果您不想这样做,我不会感到冒犯!)请告诉我。 - Assad Ebrahim

7

2
在一个.COM程序中,你也可以执行RET来退出(前提是你没有任何未弹出的堆栈内容并且没有破坏任何结构)。这个RET会将控制权转移到int 0x20 - Alexey Frunze
@AlexeyFrunze: RET -- 我不知道。你所说的损坏结构是指寄存器bxdsbpss吗?还是其他什么? - Assad Ebrahim
2
@AKE:你刚才写的是 mov ah, 0x09 吗?也许你想写的是 mov ah, 0x4c,或者更好的选择是 mov ax,0x4c00 - ninjalj
1
请注意,区别在于DOS最初没有使用返回代码,然后从Unix中借鉴了返回代码的思想用于DOS 2.0。 - ninjalj
@AlexeyFrunze:我对你提到的PSP进行了跟进,似乎这是差异的核心所在。我已经编辑了问题以反映这一点 - 如果你能再多解释一下,我会非常感激。 - Assad Ebrahim
显示剩余9条评论

2
这是我所知道的。
MOV AH, 0x4C
INT 0x21

结束当前运行的EXE文件,必须以这种方式结束EXE文件,因为代码段寄存器CS。如果您以这种方式结束COM文件,则可能会出现意外结果(崩溃、挂起、重新启动等)。因此,请使用正确的方式来结束EXE文件。

INT 0x20

结束一个COM文件。

在COM程序中,CS与程序启动时相同,即它指向程序之前256字节的PSP。(CodeSegment InstructionPointer CS:IP,CS包含代码段)。是的,我们谈论寄存器,变量就像一个衣柜,我能像你正确地放置东西在抽屉里一样工作。 AX = 0000 BX = 0000 CX = 0000(CX由CL和CH组成)等。

我认为COM文件通常限制为64K ALWAYS。我认为第二个原因是COM文件没有数据段,它们确实具有数据,但它们驻留在与代码相同的段中。我认为它们除了CODE外没有任何段,COM文件中的所有数据都存储在64K内。EXE文件确实有一个段,当使用正确的内存模型(请参见Intel Memory Model)时,某些EXE文件可以具有更多的段(CS:IP)。

  • Tiny* CS=DS=SS
  • Small DS=SS
  • Medium DS=SS,多个代码段
  • Compact 单个代码段,多个数据段
  • Large 多个代码和数据段
  • Huge 多个代码和数据段;单个数组可能>64 KB

使用内存模型SMALL时,EXE文件的限制为64K。当使用更大的内存模型和远32位指针时,您可以寻址超过64K(仍受限制)。我认为这就是“诀窍”。

现在每个人都在抱怨我为什么要使用EXE文件。以上是原因。内存模型来自维基百科。对于那些不关心的人,我从专业人士那里艰难地学到了这一点。彼得·诺顿和约翰·索查。来自Norton Utilities(DOS Norton Commander背后的人)。他有一本关于汇编语言的书,类似于“IBM-PC的汇编语言”。你应该阅读它,他解释得最好。他就像我的好老师。微软CodeView让我很清楚。在DOS C中编程? Turbo C 2.0是您能够获得的最好的东西。哦,我不再编程了。


2
如果你能削减一些态度,这将是一个非常有帮助的答案。 - APC
1
AH=0x4c / INT 0x21 同样可以安全地退出 .com 文件,参见其他答案。如果你想设置程序的退出状态,就必须使用它而不是 int 0x20。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接