【问题标题】:What's the difference between using int 0x20 and int 0x21 / ah=0x4C to exit a 16-bit assembly program?使用 int 0x20 和 int 0x21 / ah=0x4C 退出 16 位汇编程序有什么区别?
【发布时间】:2012-09-17 11:39:00
【问题描述】:

在不同的时候,我都用过

int 0x20

mov ah, 0x4c
int 0x21

作为结束 16 位汇编程序的方法。

但这两者有什么区别呢?


编辑:感谢大家的 cmets。跟进 Alexey 对 PSP(程序段前缀)的引用,得到了this nugget from Microsoft MASM support

这篇文章似乎表明,除了返回码之外,还有更多的区别。

很高兴将公认的答案授予能够更明确地将两者联系在一起的任何人。

【问题讨论】:

标签: assembly x86 dos


【解决方案1】:

后面的 int 0x21 允许您指定返回码。

返回码放在寄存器AL中。

http://spike.scu.edu.au/~barry/interrupts.html#ah4c

【讨论】:

  • 这是唯一的区别吗?我注意到在某些环境中(例如 DOSbox,int 0x20 工作正常,而 int 0x21 出现问题。)
  • 定义“乱码”。例如,如果您在 AL 中有一个不确定的值,并且后续步骤会检查返回码,那么您返回的返回码很可能是非零。按照惯例,这通常被解释为某种程序故障。
  • @AKE 在 .COM 程序中,您也可以执行 RET 退出(前提是您的任何东西都没有从堆栈中弹出,并且您没有损坏任何结构)。 RET 将控制权转移给 int 0x20
  • @AKE:你刚刚写的是mov ah, 0x09吗?也许您的意思是mov ah, 0x4c,或者更好的是mov ax,0x4c00
  • 请注意,差异来自于 DOS 最初不使用返回码,然后在 DOS 2.0 中采用了来自 Unix 的返回码的想法。
【解决方案2】:

首先,一些背景。 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 文件(AFAIR 也是 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)
  • 返回

WBOOTF 位置由 3 个字节组成:1 个字节用于跳转,2 个字节用于跳转目标(BDOS 中的 WBOOT 函数)。

在 CP/M 的早期版本中,调用 BDOS 函数 0 或跳转到 WBOOT 会导致部分 CP/M 从磁盘重新加载(热启动),并且随后运行一些操作系统初始化;而 RETurning 则直接返回到 CCP(Console Command Processor,相当于 COMMAND.COM),然后提示输入下一个命令行。 AFAIU, CP/M 3 通常被加载到 ROM 中,并且返回返回到 WBOOT 位置,导致从 ROM 重新加载部分操作系统。

【讨论】:

  • 在您允许的情况下,我想插入一个带注释的屏幕截图,以验证您所描述的内容。我将编辑您的回复并将其粘贴进去——看看您的想法。 (如果您不愿意,也不会被冒犯!)请告诉我。
【解决方案3】:

这是我所知道的。

MOV AH, 0x4C
INT 0x21

结束正在运行的EXE文件,EXE文件必须这样结束,因为codesegment register CS.如果我错了,请纠正我,但如果你以这种方式结束 COM 文件,你会得到意想不到的结果(崩溃、挂起、重新启动等)。因此

INT 0x20

结束一个 COM 文件。

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

我认为 COM 文件通常总是限制为 64K。我认为的第二个原因是 COM 文件没有数据段,它们确实有数据,但它与代码位于同一段中。我以为他们除了 CODE 没有任何段,COM 文件中的所有数据都存储在 64K 内。 EXE 文件确实有一个段,某些 EXE 文件在使用正确的内存模型时可以有更多的段 (CS:IP)(请参阅英特尔内存模型)。

  • 小* CS=DS=SS
  • 小号DS=SS
  • 中等DS=SS,多个代码段
  • 紧凑的单个代码段,多个数据段
  • 大型多个代码和数据段
  • 巨大的多个代码和数据段;单个数组可能 >64 KB

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

现在每个人都在抱怨我为什么要使用 EXE 文件。以上是原因。内存模型来自维基百科。对于那些不在乎的人,我从专业人士那里学到了这一点。彼得诺顿和约翰索查。来自 Norton Utilities(The Norton Commander for DOS 背后的人)。他有一本关于组装的书,例如“IBM-PC 的组装”。你应该读它,他解释得最好。他对我来说就像一个好老师。 Microsoft CodeView 澄清了我很多。在 DOS C 中编程? Turbo C 2.0 是你能得到的最好的。哦,我不再编程了。

【讨论】:

  • 如果你去掉一些态度,这可能是一个非常有帮助的答案。
  • AH=0x4c / INT 0x21 也将安全地退出 .com 文件;查看其他答案。如果你想设置程序的退出状态,你必须使用它而不是int 0x20
猜你喜欢
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-12
  • 2020-05-05
  • 2015-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多