Х86-16 письменном виде ASCIIZ строки прямо к видео


При разработке своей операционной системы, я решил, что существует необходимость более подробную информацию о том, что происходит в реальном режиме. Идею включения непечатаемых символов в ASCII-строку родился из знания ВТ100 управляющие коды, но я хотел сделать это немного проще и более полную функциональность в то же время.

На машине с Win7, блокнот++ и NASM 2.11.08 используются для создания двоичных файлов. Когда это возможно, DOSBox и отладки или DEBUGX используются для тестирования кода, который в конечном итоге скопированы изображения для бох и, наконец, с загрузочных носителей.

Мой код является полностью независимым и не должен соответствовать какому-либо конкретному или интерфейс Аби с установленными библиотеками. Любое соответствие cdecl или АЗЬСАИ чисто случайно, как я выбрать то, что служит цели.


В командной строке или в режиме отладки, это позволяет проверить каждую строку и ждет ввода пользователя после каждого дисплея. Я выбрал 1000:0, потому что код может быть изменен, перезагрузка и прыгать туда и обратно из командной строки, не затрагивая строку для отображения.

    BDA     equ     40H

    VIDEO       equ     10H
      SAP       equ     05H         ; BIOS function, change displayed page
 KEYBOARD       equ     16H

            org     0x100           ; Origin for DOS .com files

; =============================================================================================
;   This benchmark will display or at least process successive NULL terminated strings, wait
;   for user response and then continue unless beginning of next string is NULL.
; ---------------------------------------------------------------------------------------------

            enter   8, 0            ; So stack will be page aligned entering ShowS.

    ; As ShowS is an integral part of real mode startup code in my OS, DOSBOX is used as
    ; a convenient means of testing code, so this mimics required functionality.

            push    0x1000          ; Segment where ASCIIZ string lives
            push    0               ; Offset from segment

    Read:   call    ShowS           ; SP = FFE0
            jz      .done           ; ZF = 1 if byte pointed to by SI is NULL.

            push    ax              ; This is the pointer to next string.

            xor     ax, ax          ; This allows me to single step through each string
            int     KEYBOARD
            cmp     al, ESC         ; Did operator press escape?
            jnz     Read

    .done:  leave                   ; Kill procedure frame so RET will go to proper place
            ret                     ; Essentially does an INT 20H @ CS:0000

Размеры рамки и выравнивание стека используются только для облегчения визуализации в режиме отладки.


; ____________________________________________________________________________________________

     Params:    dw      0           ; Offset into page in bytes
            db      0           ; Page to write too (0 - 7)
            db      0           ; Characters attribute

  %define   TxtPntr BP + 4      ; ARG0 = Far pointer to ASCIIZ string.
  %define   SafeStk BP - (FrmSize +  7 * 2)

    Cursors     equ     50H     ; Base of array of WORDS for cursor postion of each page.
      DispPg        equ     62H     ; Page currently being displayed
              EOS       equ       0H        ; End Of String
    FrmSize     equ       4H        ; Bytes reserved for local data

            ESC     equ       0H            
; =============================================================================================
;   Display ASCIIZ text on an 80 x 25 x 16 color console. This can be a single or an array
;   of strings, but must be terminated with DOUBLE NULL.

;   ENTER:  ARG1 = Segment portion of far pointer to string
;           ARG0 = Offset and ultimately loaded into DS:SI

;   LEAVE:    AX = Offset to next string (Only if ZF = 0)
;             CX = -1 if there was a buffer overrun (string larger than 128 bytes)
;             DX = Size of memory leak on stack in bytes

;   FLAGS:    ZF = 1 if at end of array of strings, otherwise there is another string.
; ---------------------------------------------------------------------------------------------

    ShowS:  enter   FrmSize, 0          ; ARGS begin @ SS:FFF0

    ; NOTE: Any changes in this prologue must be representative in SafeStk definition.

            push    es                  ; 1
            push    ds                  ; 2
            push    di                  ; 3
            push    si                  ; 4
            push    fs                  ; 5

            push    BDA
            pop     fs                  ; Establish segment into BDA

            push    cs                  ; As it is a far call into this procedure, DS might
            pop     ds                  ; not be pointing to CS
            mov     si, Params          ; DS:SI points to the two DWORD parameters

            push    ds                  ; 6
            push    si                  ; 7  SafeStk points here

    ; At each iteration it is assumed to continue from last position in same page. To 
    ; override this, use whatever control characters at beginning of string to achieve desired
    ; results.

        ; In all probability, writes will be to the same page as previous, but for the sake
        ; of 12 bytes of code, this is as practical as conditionals to check BDA (active page)

            lodsw                       ; Get 16 bit offset into desired page.
            mov     di, ax
            lodsw                       ; AH = Attribute, AL = Page #
            push    ax
            add     al, 0B8H                ; Segments being @ 80x25 16 color
            shl     ax, 8
            mov     es, ax              ; ES:DI setup for STOSB or STOSW
            pop     ax                  ; Retrieve AH = characters attribute

            lds     si, [TxtPntr]       ; Grab far pointer to ASCIIZ string
            mov     cx, 128             ; Overflow count

    .next:  lodsb                       ; Read next or first char
            cmp     al, EOS
            jz      .done
            cmp     al, ' '
            jb      DoCtl               ; Execute handler for control character

; Write character to next location pointed to by ES:DI

    .post:  or      ah, ah              ; Has an attribute been defined
            jnz     .attr
            stosb
            inc     di
            jmp     .attr + 1           ; Do overrun check

    .attr:  stosw
            dec     cx                  ; Decrement displayable character count.
            jnc     .next               ; Return CX = -1 for overflow

    ; Until algorithm has been proven, this will give an indication of stack corruption.

    .done:  mov     dx, sp
            lea     sp, [SafeStk]       ; Changes in prologue affects this
            sub     dx, sp
            neg     dx                  ; CX = Difference in pointers

            shr     ax, 8               ; Move characters attribute into low nibble
            push    ax
            push    es
            mov     ax, di              ; Save copy of offset
            les     di, [SafeStk]
            stosw                       ; Save location of next write

    ; Skewing SP by one, forces attribute back into AH & MSB of video segment into AL

            inc     sp
            pop     ax
            inc     sp
            and     al, 7               ; Converts MSB of segment into page # (0-7)
            stosw
            add     sp, 4               ; Waste far pointer to procedures parameters

    ; Test character after this strings terminator to set ZF appropriately.

            test    byte [si], 0FFH     ; Test if there is another string.
            mov     ax, si              ; Return offset to next string in AX

            pop     fs
            pop     si
            pop     di
            pop     ds
            pop     es

            leave                       ; Kill procedure frame
            ret     2                   ; Only waste far pointers offset

    ; To avoid conditional jump of more than 128 bytes, this allows ret to branch back
    ; to DoCtl from a place than will definitely be more than 128 bytes away. It also serves
    ; as a convenient entry point for things that apply to each handler such as preserving AX

    DoCtl:  push    ax                  ; Need to preserve attribute
            push    .done               ; Set to return address
            jmp     .exe                ; First function in list
    .done:  pop     ax
            jmp     ShowS.next          ; Continue reading string

    ; Handlers should start here, but if not, suitable code should be implemented

        .exe:


103
2
задан 6 февраля 2018 в 06:02 Источник Поделиться
Комментарии