BIOS和旧的MSDOS OS之间的通信中的汇编语言问题

时间:2019-01-04 12:33:13

标签: assembly x86-16 bios

我有一些冗长的代码,但是一行中的问题非常小,明确地称为“此行中的问题”。为什么我们要两次(而不是一次)添加SI和AX。代码,您将可以非常准确地找到它。

DEVSTART LABEL WORD
CONSOLE_DEV:                ;Header for device CON
    DW      AUXDEV,BIOSSEG  ;Link to next device
    DW      8003H           ;Attributes - console input, 
                            ;output device
    DW      STRATEGY        ;Srategy entry point
    DW      CON_INT         ;Interrupt entry point
    DB      "CON     "      ;Device name
;-------------------------------------------------
CONSOLE_TABLE: DW      EXIT ;0  - Init. (Not used)
    DW      EXIT            ;1  - Media check (Not used)
    DW      EXIT            ;2  - Get Bios Parameter Block 
                            ;(Not used)
    DW      CMDERR          ;3  - Reserved. (Currently 
                            ;returns error)
    DW      CON_READ        ;4  - Character read. 
                            ;(Destructive)
    DW      CON_RDND        ;5  - Character read. (Non- 
                            ;destructive)
    DW      EXIT            ;6  - Return status. (Not used)
    DW      CON_FLSH        ;7  - Flush Input buffer.
    DW      CON_WRIT        ;8  - Character write.
    DW      CON_WRIT        ;9  - Character write with 
                            ;Verify.
    DW      CON_WRST        ;10 - Character write status.
    DW      EXIT            ;11 - Flush output buffer. (Not 
                            ;used.)
    DW      EXIT            ;12 - IO Control.
;-----------------------------------------------
    PAGE
    SUBTTL  Strategy and Software Interrupt routines.

    ;Define offsets for io data packet

IODAT   STRUC
CMDLEN  DB      ?               ;LENGTH OF THIS COMMAND
UNIT    DB      ?               ;SUB UNIT SPECIFIER
CMD     DB      ?               ;COMMAND CODE
STATUS  DW      ?               ;STATUS
    DB      8 DUP (?)
MEDIA   DB      ?               ;MEDIA DESCRIPTOR
TRANS   DD      ?               ;TRANSFER ADDRESS
COUNT   DW      ?               ;COUNT OF BLOCKS OR 
CHARACTERS
START   DW      ?               ;FIRST BLOCK TO TRANSFER
IODAT   ENDS

PTRSAV  DD      0               ;Strategy pointer save.

;
; Simplistic Strategy routine for non-multi-Tasking system.
;
;   Currently just saves I/O packet pointers in PTRSAV for
;   later processing by the individual interrupt routines.
;

STRATP  PROC    FAR

STRATEGY:
    MOV     WORD PTR CS:[PTRSAV],BX
    MOV     WORD PTR CS:[PTRSAV+2],ES
    RET

STRATP  ENDP

;
; Console interrupt routine for processing I/O packets.
;

CONSOLE_INT:
    PUSH    SI
    MOV     SI,OFFSET CONSOLE_TABLE
    JMP     SHORT ENTRY
;-------------------------------------------
;
; Common program for handling the simplistic I/O packet
;   processing scheme in MSDOS 2.0
;

ENTRY:  PUSH    AX              ;Save all nessacary 
                                ;registers.
    PUSH    CX
    PUSH    DX
    PUSH    DI
    PUSH    BP
    PUSH    DS
    PUSH    ES
    PUSH    BX

    LDS     BX,CS:[PTRSAV]  ;Retrieve pointer to I/O Packet.

    MOV     AL,[BX.UNIT]    ;AL = Unit code.
    MOV     AH,[BX.MEDIA]   ;AH = Media descriptor.
    MOV     CX,[BX.COUNT]   ;CX = Contains byte/sector 
                            ;count.
    MOV     DX,[BX.START]   ;DX = Starting Logical sector.

    XCHG    DI,AX           ;Move Unit & Media into DI 
                            ;temporarily.
    MOV     AL,[BX.CMD]     ;Retrieve Command type. (1 => 
                            ;11)
    XOR     AH,AH           ;Clear upper half of AX for 
                            ;calculation.

    ADD     SI,AX           ;"PROBLEM IN THIS LINE"
                            ;(Compute entry pointer in dispatch table).
    ADD     SI,AX           ;"PROBLEM IN THIS LINE".

    CMP     AL,11           ;Verify that not more than 11 
                            ;commands.
    JA      CMDERR          ;Ah, well, error out.
    XCHG    AX,DI           ;Move Unit & Media back where 
                            ;they belong.
    LES     DI,[BX.TRANS]   ;DI contains addess of Transfer 
                            ;address.
                            ;ES contains segment.
    PUSH    CS
    POP     DS              ;Data segment same as Code 
                            ;segment.
    JMP     [SI]            ;Perform I/O packet command.

CODE CONTINUES..............

请帮助,如果您觉得很奇怪,我深表遗憾。但我确信我在这篇文章中添加了足够的信息。请参阅提到的“此行中的问题”行。如果您需要更多详细信息,请告诉我。

2 个答案:

答案 0 :(得分:3)

CONSOLE_TABLE word 大小的近指针填充。如果您想使用例如 CON_READ 是第5项,并且具有 CommandType FunctionNumber 4,您必须在此表中使用8的偏移量。

  

这恰好是功能编号的两倍!

因此两次添加功能编号将产生正确的地址。

MOV     AL,[BX.CMD]     ;Retrieve Command type. (1 => 11)
XOR     AH,AH           ;Clear upper half of AX for calculation.

非常重要!此时,SI已经保存了 CONSOLE_TABLE 的地址。

ADD     SI,AX           ; Add function number once
ADD     SI,AX           ; Add function number twice

加倍功能编号的替代解决方案也很简单。

MOV     AL,[BX.CMD]     ;Retrieve Command type. (1 => 11)
XOR     AH,AH           ;Clear upper half of AX for calculation.

非常重要!此时,SI已经保存了 CONSOLE_TABLE 的地址。

SHL     AX,1            ; Doubling the function number gives offset
ADD     SI,AX           ; Add full offset

该程序中最容易引起误解的元素是名称过于通用的标签 ENTRY 。真正的入口点当然是 CONSOLE_INT ,其中保留SI,然后设置为指向 CONSOLE_TABLE 的开始。

原始软件程序员可能在软件中有更多这些PUSH SI MOV SI, ... JMP ENTRY片段。

CONSOLE_TABLE:
+0  == 0*2   EXIT       ;0  - Init. (Not used)
+2  == 1*2   EXIT       ;1  - Media check (Not used)
+4  == 2*2   EXIT       ;2  - Get Bios Parameter Block (Not used)
+6  == 3*2   CMDERR     ;3  - Reserved. (Currently returns error)
+8  == 4*2   CON_READ   ;4  - Character read. (Destructive)
+10 == 5*2   CON_RDND   ;5  - Character read. (Non-destructive)
+12 == 6*2   EXIT       ;6  - Return status. (Not used)
+14 == 7*2   CON_FLSH   ;7  - Flush Input buffer.
+16 == 8*2   CON_WRIT   ;8  - Character write.
+18 == 9*2   CON_WRIT   ;9  - Character write with Verify.
+20 == 10*2  CON_WRST   ;10 - Character write status.
+22 == 11*2  EXIT       ;11 - Flush output buffer. (Not used.)
+24 == 12*2  EXIT       ;12 - IO Control.

答案 1 :(得分:2)

  

我只想知道为什么我们要向SI添加AX。

相对于其他计算同一事物的方式?在不清楚Jester的评论后,您仍然想知道什么。如果这对您没有意义,也许您需要自己开始编写一些代码和/或查看您了解的C的编译器输出,以适应x86和asm,以便能够阅读其他人的代码。


稍后有JMP [SI]会分派给该命令的处理程序代码,因此他们正在SI中计算地址。 (它正在索引一个单词表,因此加两次将单词索引转换为字节偏移。x86-16没有缩放索引寻址模式。)

公共ENTRY之前的不同包装器存根将SI设置为不同表的基础。显然,您从代码中删除了除CONSOLE_INT:以外的所有代码(这就是为什么这里似乎有无用的jmp short ENTRY会在此处汇编为jmp +0的原因),但是您留下的那个有{{1} }。

如果不需要支持多个表,则可以只计算SI或DI中的字节偏移量,并使用MOV SI,OFFSET CONSOLE_TABLE。但是在没有MOVZX的386之前的版本中,将字节零扩展到SI或DI是不方便的,因为没有上半部/下半部可单独访问的寄存器。

如果他们愿意销毁BX,则可以执行以下操作来保存指令。但是大概他们需要保留指向该结构的指针,以便以后访问其他成员。

jmp [CONSOLE_TABLE + DI]

如果他们想在添加到SI之前在{em> 之前将 MOV bl, [BX.CMD] xor bh, bh add bx, bx ; word index -> byte offset ... jmp [bx+si] ; BX can be a base register, unlike AX 加倍,则可以在计算最终指针之前完成add ax,ax,或者只是在将AX加倍后完成CMP AL,11