программа сборки для вывода строки на экран - PullRequest
0 голосов
/ 22 апреля 2020

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

[org 0x7c00] ; Tell the assember the place to load this code

    mov bx, HELLO_MSG ; move the data to the bx register
    pusha             ; push all register values to stack?
    call printstr     ; call printstr routine

printstr:
    mov ah, 0x0e ; BIOS teletype output
    pop bx       ; pop to bx
    mov al, bl   ; put low byte of bx to al
    int 0x10     ; print it.
    cmp al, 0    ; Compare if its a string termination character?
    jne printstr ; if not go back to top
    ret          ; return to the caller?


; Data
HELLO_MSG:
    db 'Hello world!', 0

jmp $

times  510-($-$$) db 0
dw  0xaa55

Я запускаю эту программу из загрузочного сектора диск в qemu, эмулирующий AT-совместимый компьютер на базе x86.

Ответы [ 2 ]

3 голосов
/ 22 апреля 2020

1) Регистр BX не содержит символ, который вы хотите напечатать, но содержит адрес памяти, где находится символ, который вы хотите напечатать (@HELLO_MSG). Таким образом, вы действительно хотите сказать не «mov al, bl», а «mov al, [bx]», то есть

«Установить AL в байт, хранящийся по адресу памяти BX» (mov AL , [BX])

2) Регистр BX используется B IOS для цветового компонента, с которым он телетипируется. Вы не можете использовать этот регистр в качестве индекса для памяти в HELLO_MSG. Вместо этого попробуйте использовать регистр SI - "mov al, [SI]".

3) Для каждого l oop вам необходимо, чтобы программа переместилась к следующему символу в строке, чтобы он одновременно печатал следующий символ и сравнил следующий символ с «0», так что вам нужно увеличить регистр индексации (SI, как я предлагаю в пункте 2). Поэтому вам нужно поместить инструкцию "in c si" где-то после установки al и перед переходом jne.

4) Вы также неправильно используете стек. Инструкция pusha поместит все регистры в стек sh, и они будут помещены в стек в определенном порядке c. Лучший способ получить обратно из пуша - это попа. Если вы вставите bx, вы будете вставлять в стек то, что было по оси на оси, и указатель стека будет не синхронизирован c примерно на 10 байтов или около того. Я бы даже не использовал стек.

Вот как я буду делать то, что вы пытаетесь сделать:

    pusha             ; save all the registers to the stack
    mov si, HELLO_MSG ; set SI to to the address of the message
printstr:
    mov ah, 0x0e ; BIOS teletype output
    mov bh, 00h  ; teletyping to the default page at B800h (IBM PC)
    mov bl, 07h  ; the CGA colour white
    mov al,[si]  ; put byte of memory address si into al
    int 0x10     ; print it.
    inc si
    cmp al, 0    ; Compare if its a string termination character?
    jne printstr ; if not go back to top
    popa         ; retrieve all the registers from the stack
    ret          ; return to the caller?


; Data
HELLO_MSG:
    db 'Hello world!', 0

Обратите внимание, что я использую pusha и popa просто для демонстрации их использования. Поскольку я использую только ax, bx и si, было бы дешевле сделать три нажатия этих регистров и три всплывающих окна в конце, если бы действительно было необходимо сохранить эти регистры в контексте полной программы. Я стараюсь писать так, чтобы регистры могли быть немедленно сброшены, если сохранение их содержимого не является неизбежной необходимостью.

2 голосов
/ 22 апреля 2020

Инструкция POP BX не делает то, что вы, похоже, предполагаете. Он берет значение из стека и сохраняет его в BX. Он не обращается к памяти, на которую указывает BX. Вам нужно что-то вроде MOV AL, [BX], чтобы получить символ, на который указывает BX, и затем инструкцию, чтобы BX указывал на следующий символ.

Кроме того, вы не правильно завершаете свою программу. CALL сохраняет текущую позицию и затем начинает печатать строку. Когда вы RET urn, процессор продолжает выполнение после инструкции CALL. Вам нужно что-то сказать процессору прекратить выполнение чего-либо, или он может попытаться напечатать еще несколько вещей, которые он не должен печатать.

Как вы упомянули в комментарии, вы используете загрузочный сектор в qemu. Кажется, нет никакой концепции сообщать qemu о выходе, поэтому вы должны заблокировать свою программу. Типичным способом достижения этого является последовательность инструкции CLI, указывающей процессору, что он не должен обрабатывать какие-либо прерывания, после чего следует инструкция HLT, которая указывает процессору ничего не делать, пока он не обработает прерывание. Когда вы блокируете прерывания, инструкция HLT будет ждать вечно.

...