assembly IBM 5150 - int 21 h损坏段寄存器

kkih6yb8  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(130)

我一直在模拟的IBM 5150、PC-DOS 1.0、IBM Macro Assembler 1.0上玩汇编。
我从一个简单的“Hello World”开始:

stack    segment   stack                                                        
         db        80h dup(?)                                                   
stack    ends                                                                   
                                                                                
data     segment                                                                
msg      db        'Hello World!',13,10,'$'                                     
data     ends                                                                   
                                                                                
code     segment                                                                
         assume    cs:code,ds:data                                              
         mov       dx, seg msg                                                  
         mov       ds, dx                                                       
         mov       dx, offset msg                                               
         mov       ah, 09h                                                      
         int       21h                                             
         int       20h                                                          
code     ends                                                                   
                                                                                
         end

可悲的是,程序在输出后崩溃。通过 debug 我发现,在21 h中断后,DS,CS和IP寄存器被损坏。

a:debug hello.exe
-r
AX=0000  BX=0000  CX=0000  DX=0000  SP=0080  BP=0000  SI=0000  DI=0000  
DS=049F  ES=049F  SS=04B1  CS=04AF  IP=0000   NV UP DI PL NZ NA PO NC 
04AF:0000 BAB004        MOV     DX,04B0                 
-t

AX=0000  BX=0000  CX=0000  DX=04B0  SP=0080  BP=0000  SI=0000  DI=0000  
DS=049F  ES=049F  SS=04B1  CS=04AF  IP=0003   NV UP DI PL NZ NA PO NC 
04AF:0003 8EDA          MOV     DS,DX                   
-t

AX=0000  BX=0000  CX=0000  DX=04B0  SP=0080  BP=0000  SI=0000  DI=0000  
DS=04B0  ES=049F  SS=04B1  CS=04AF  IP=0005   NV UP DI PL NZ NA PO NC 
04AF:0005 BA0000        MOV     DX,0000                 
-t

AX=0000  BX=0000  CX=0000  DX=0000  SP=0080  BP=0000  SI=0000  DI=0000  
DS=04B0  ES=049F  SS=04B1  CS=04AF  IP=0008   NV UP DI PL NZ NA PO NC 
04AF:0008 B409          MOV     AH,09                   
-t

AX=0900  BX=0000  CX=0000  DX=0000  SP=0080  BP=0000  SI=0000  DI=0000  
DS=04B0  ES=049F  SS=04B1  CS=04AF  IP=000A   NV UP DI PL NZ NA PO NC 
04AF:000A CD21          INT     21                      
-t
Hello World!

AX=0040  BX=0000  CX=0000  DX=0000  SP=FD24  BP=0000  SI=0000  DI=0000  
DS=0040  ES=049F  SS=04B1  CS=FFFF  IP=FFFF   OV DN EI NG ZR AC PE CY 
FFFF:FFFF 00EA          ADD     21

有人能解释一下为什么吗?
我为PC-DOS 2.0写了一个类似的程序,它工作了。(只是用21 h,4Ch来终止,PC-DOS 1.0不支持)
PS:我这样做是出于对历史的好奇,所以...

sdnqo3pr

sdnqo3pr1#

我可以肯定地回答你问题的一部分:当Int 21h/AH=4Ch在DOS1.0中不可用时,如何正确地退出DOS.EXE程序?
主要的方法是使用Int 20h,但是有一个警告。当你使用Int 20h时,你必须将 CS 设置为Program Segment Prefix (PSP)所在的段。问题是在EXE程序中,CS 不指向PSP段,而是指向一个单独的代码段!
一般的解决方法是利用 DS(和 ES)在启动时指向一个EXE程序的PSP段。你也可以利用PSP的第一个字中有一条Int 20h指令。我们可以使用一个FAR Return to PSP_Segment:0000 h来执行PSP中的Int 20h来退出程序。
终止DOS.EXE程序的代码可能如下所示:

stack    segment   stack
         db        80h dup(?)
stack    ends

data     segment
data     ends

code     segment

main     proc far                ; Marking this `far` will make the
                                 ; assembler convert RET to a FAR RETURN

         push ds                 ; DS = PSP, save PSP segment on stack

         ; Insert program code here. 
         ; Make sure the stack is balanced when finished         
         ; -----------------
         assume cs:code,ds:data
         mov dx, data
         mov ds, dx
         ; -----------------

         ; Exit EXE program with FAR Return to PSP_Segment:0000h where
         ; an Into 20h resides in the word at offset 0000h in the PSP

         xor ax, ax              ; AX = 0
         push ax                 ; Push 0 on the stack
                                 ; Note: `PUSH` with an immediate value 
                                 ; wasn't a valid instruction on 
                                 ; Intel 8088/8086 processors

         ; At this point the DS (PSP) pushed at the beginning of the program
         ; and the value 0000h forms a CS:IP FAR pointer on the stack

                                 ; A FAR return is done since
                                 ; procedure main was declared as FAR

         ret                     ; Return to PSP_Segment:0000h via FAR pointer
                                 ; on the stack and execute
                                 ; the Int 20h at that address
main     endp                    ; End of procedure main
code     ends

         end

我相信在DEBUG的原始版本中可能存在一个bug,但我不能确定,而且我手边没有PC-DOS 1. 0环境来试用它。我开始认为trace正在跟踪多条指令,可能会同时执行Int 21hInt 20hint 20h由于上一节中给出的原因而失败。

备注

在COM程序中,CS 是包含PSP和您的代码的段。PSP是段的前256个字节,也是COM程序的起点(ORG)为100 h的原因。这就是为什么Int 20h在这种环境下工作,前提是您自己在代码中不更改 CS

相关问题