Search code examples
assemblyx86dos

What's the difference between using int 0x20 and int 0x21 / ah=0x4C to exit a 16-bit assembly program?


At various times, I've used both

int 0x20

and

mov ah, 0x4c
int 0x21

as ways of ending a 16-bit assembly program.

But what is the difference between the two?


EDIT: Thanks for your comments everyone. Following up on Alexey's reference to the PSP (program segment prefix), yielded this nugget from Microsoft MASM support.

The article seems to suggest there's more to the difference than just return codes.

Happy to award the accepted answer to anyone who can tie the two together a bit more definitively.


Solution

  • First, some background. DOS uses interrupt 21h for its system calls. AH is used to demultiplex the various functions INT 21h provides. When a program is executed, DOS puts before it 256 bytes known as the PSP (Program Segment Prefix), which contain information about the process.

    The original exit function in DOS is INT 21/AH=00. Now, apparently DOS developers decided that returning from a program should be a way to exit the program (did this come from CP/M?). RET (near) pops a word from the stack and jumps to it. So, when a program is created, its stack starts with a word 0000. This is the start of the PSP. So, at the start of the PSP there is code to terminate the program. To keep that code small, INT 20h acts as an alias to MOV AH,00h ; INT 21h.

    [Edit: This can be seen in the screenshot below.]

    DOS 2.0 took many things from Unix, including return codes. So, a new INT 21h function appeared, INT 21h/AH=4ch, which takes a return code to return it to the OS. This function is also designed to work with EXE files (AFAIR also new in DOS 2.0), which can have several segments. The previous exit functions (INT 20h and INT 21h/00) assume CS is the same as it was at program startup on a COM program, that is, it points to the PSP 256 bytes before the program.

    [Edit: Illustration of DOS program structure, using <code>debug</code>

    Historical note: on CP/M, there were 3 ways to exit a program:

    • Calling BDOS function 0 (the equivalent of INT 21 AH=00h, DOS function 0)
    • Jumping to the WBOOTF location at 0000h (the equivalent of PSP offset 000h)
    • RETurning

    The WBOOTF location consisted of 3 bytes: 1 byte for a jump, 2 bytes for the jump target (the WBOOT function in BDOS).

    In early versions of CP/M, calling BDOS function 0 or jumping to WBOOT caused parts of CP/M to be reloaded from disk (warm boot), and some OS initialization to be subsequently run; while RETurning directly returned to the CCP (Console Command Processor, the equivalent of COMMAND.COM), which then prompted for the next command line. AFAIU, CP/M 3 was usually loaded in ROM, and returning returned to the WBOOT location, causing a reload of parts of the OS from ROM.