Проблема сегмента данных с x86 Ассемблер (nasm) для функции печати - PullRequest
0 голосов
/ 29 января 2012

В настоящее время я играю с ассемблером x86, так как я хотел обновить свои навыки для программирования низкого уровня :-).В целях тестирования я попытался написать функцию, которая просто печатает заданную строку.Сама функция печати работает нормально.На следующем шаге я хотел загрузить вторую ассемблерную программу с диска, перейти к ней и просто распечатать текст.Загрузка с диска при переходе по адресу работает нормально.

Вот такой сценарий:

[... loading from disk etc ... program is loaded to 0x7e0:0001]

jmp 0x7e0:0001

[... context of other asm ...]

jmp Start
;data fields
msg db "Hello World!",0

Start:
     xor si, si     ; clear SI register
     mov si, msg    ; load message to SI register

     call Print

     cli
     hlt            ; halt the system

Print:
     .PrintLoop:
         lodsb                ; load byte from SI register
         or al, al            ; check if 0 byte
         jz short .PrintDone  ; if so - stop
         mov ah, 0Ah          ; function - print text to cursor
         int 0x10             ; BIOS interrupt

         jmp .PrintLoop       ; continue with next char
     .PrintDone:
         ret

Вся эта программа работает нормально.Единственная проблема, с которой я сталкиваюсь, заключается в том, что текст не печатается.Во время отладки я увидел, что функция печати сразу переходит на метку .PrintDone, поскольку в SI нет данных, и поэтому lodsb ничего не загружает в al (кроме нулевого байта).

Я думал о том,что может быть что-то не так с сегментом данных.

Таким образом, я добавил следующую строку в начале Start-Routine:

xor ax, ax    ; clear ax register
mov ax, cs    
mov ds, ax    ; set data segment pointer

Но это ничего не изменило в отношении поведения программ,Ничего не печатается.

Проверка регистров ЦП, когда выполнение достигает команды остановки, дает следующее:

EAX=00000a00 EBX=00000000 ECX=00000002 EDX=00000000
ESI=00000026 EDI=00000000 EBP=00000000 ESP=0000ffff
EIP=00000036 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=1
ES =07e0 00007e00 0000ffff 00009300
CS =07e0 00007e00 0000ffff 00009b00
SS =9000 00090000 0000ffff 00009300
DS =07e0 00007e00 0000ffff 00009300

Есть ли у вас какие-либо подсказки, что здесь происходит?

[РЕДАКТИРОВАТЬ - РЕШЕНИЕ ПРОБЛЕМЫ]

Замена:

mov ah, 0Ah -> mov ah, 0xE

устраняет проблему!

Лучший Себастьян

1 Ответ

2 голосов
/ 29 января 2012

Есть несколько проблем.

Во-первых, вы неправильно установили регистры для функции 0Ah. Вы должны установить bh для номера страницы (0) и cx для счетчика повторов (1).

Во-вторых, эта функция BIOS не продвигает позицию курсора, и все символы печатаются в одном и том же месте на экране, перезаписывая друг друга, что должно приводить только к «!» видимый, так как это последний символ.

Советую вместо этого использовать функцию 0Eh.

В-третьих, вы не инициализируете флаг направления (flags.df), на который lodsb полагается. Вы должны использовать cld для сброса df.

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

Кроме того, NMIs и SMIs вызовут завершение hlt, и код, который следует за ним, будет выполнен (и то, что следует за вами, Print). Вы хотите выполнить hlt в цикле.

С этими исправлениями мы получаем:

bits 16
org 1

jmp Start
;data fields
msg db "Hello World!",0

Start:
     mov ax, cs    
     mov ds, ax    ; set data segment pointer
     cld

     mov si, msg    ; load message to SI register

     call Print

     cli
.halt:
     hlt            ; halt the system
     jmp .halt

Print:
     .PrintLoop:
         lodsb                ; load byte from SI register
         or al, al            ; check if 0 byte
         jz short .PrintDone  ; if so - stop
;         mov ah, 0Ah          ; function - print text to cursor
;         xor bh, bh
;         mov cx, 1
         mov ah, 0Eh          ; function - print text tty

         int 0x10             ; BIOS interrupt

         jmp .PrintLoop       ; continue with next char
     .PrintDone:
         ret

Двоичный файл, который вы получите, скомпилировав вышеприведенное с nasm blah.asm -f bin -o blah.bin, должен затем быть загружен в 0x7e0:0001 и перейти к jmp 0x7e0:0001.

...