проблема языка ассемблера в связи между BIOS и старой ОС MSDOS - PullRequest
0 голосов
/ 04 января 2019

У меня есть немного длинноватый код, но очень маленькая проблема в строке, которая явно упоминается как «ПРОБЛЕМА В ЭТОЙ ЛИНИИ». Почему мы добавляем 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 голосов
/ 07 января 2019

Я просто хочу знать, почему мы добавляем AX в SI.

В отличие от какого-то другого способа вычисления того же самого? Непонятно, о чем вы все еще удивляетесь после того, как комментарий Шута ответил на вопрос сразу. Если это не имеет смысла для вас, возможно, вам нужно начать писать код самостоятельно и / или смотреть на вывод компилятора для C, который вы понимаете, чтобы освоиться с x86 и asm, чтобы вы могли читать код других людей .


Позже JMP [SI] отправляется к коду обработчика для этой команды, поэтому они вычисляют адрес в SI. (Он индексирует таблицу слов, поэтому добавление дважды преобразует индекс слова в смещение байта. X86-16 не имеет режимов адресации с масштабированным индексом.)

Разные заглушки обертки перед общим ENTRY устанавливают SI в основу разных таблиц. Очевидно, вы удалили все из них, кроме CONSOLE_INT: из кода (вот почему есть явно бесполезный jmp short ENTRY, который собирался бы здесь jmp +0), но у того, который вы оставили, есть MOV SI,OFFSET CONSOLE_TABLE.

Если бы не необходимость поддержки нескольких таблиц, они могли бы рассчитать только смещение байтов в SI или DI и использовать jmp [CONSOLE_TABLE + DI]. Но расширение нуля до байта в SI или DI неудобно на pre-386 без MOVZX, потому что нет никаких отдельно доступных регистров верхней половины / нижней половины.

Если бы они хотели уничтожить BX, они могли бы сделать следующее, чтобы сохранить инструкцию. Но, вероятно, им нужно сохранить указатель на структуру, чтобы позже получить доступ к другим членам.

 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, чтобы удвоить его до добавления к SI, они могли бы сделать CMP AL,11 раньше, до вычисления окончательного указателя, или просто сделать cmp al, 22 после удвоение AX.

0 голосов
/ 07 января 2019

CONSOLE_TABLE заполнено размером около 1003 * word рядом с указателями. Если вы хотите использовать, например, CON_READ , который является 5-м элементом и имеет CommandType aka 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.
...