При печати строки символов из загрузочного сектора отображается только первый символ

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

Привет

Я получаю это вместо этого:

ЧАС

Почему печатается только один символ, а не вся строка? Как я могу это исправить?

Это фрагмент моего кода:

mov ah, 0x0e
mov bx, string_p
add bx, 0x7c00
mov al, [bx]
int 0x10
 jmp $
string_p:
       db 'Hello',0
"then padding and magic number"

2 ответа

Прерывание 10H с регистрацией AH установлен в 0EH ( INT 21h/AH=0eh), напечатает текущий символ в регистре AL, Список прерываний Ральфа Брауна считается библией прерываний DOS и BIOS. Это ценный источник информации о том, какие прерывания доступны, как они работают и каковы их побочные эффекты.

Если вы используете INT 21h/AH=0eh, вам нужно вручную перемещать указатель строки для каждого символа и печатать их по одному за раз. Код, подобный этому, должен работать:

org 0x7c00             ; starting address
bits 16                ; 16-Bit mode

main:
  cli                  ; disable interrupts
  cld                  ; clear direction flags
  xor ax, ax           ; set AX to 0
  mov ds, ax           ; set DS to 0
  mov ah, 0x0e         ; call 0EH bios call
  mov si, string       ; move starting address of `string` into SI

loop:
  lodsb                ; load byte at DS into AL, update (increment) SI
  or al, al            ; check if AL is 0 (ORing will do nothing, but set the right flags
  jz hltloop           ; if zero jump to end
  int 0x10             ; do the print call
  jmp loop             ; jump back to loop start

hltloop:
  hlt                  ; halt and catch fire
  jmp hltloop          ; jump back to halt, if an interrupt occurred anyway

string:
       db 'Hello',0

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

В этом примере используется инструкция LODSB для чтения каждого символа строки. Инструкции LODS документированы как:

Загружает байт, слово или двойное слово из исходного операнда в регистр AL, AX или EAX соответственно. Операндом-источником является ячейка памяти, адрес которой считывается из регистров DS:ESI или DS:SI (в зависимости от атрибута address-size инструкции, 32 или 16 соответственно). Сегмент DS может быть переопределен префиксом переопределения сегмента.

Уже поздно, но может кому-то помочь. У меня возникла та же проблема, связанная с разработкой ОС на Ubuntu. Вот что сработало для меня. Я создал функцию печати и вызвал ее после перемещения адреса моей строки в bx:

print_function:
pusha
mov ah, 0x0e
mov al, [bx]
int 0x10
cmp al, 0
jne increment
jmp the_end

increment:  
add bx , 1
mov al, [bx]    
int 0x10
cmp al, 0
jne increment
jmp the_end 

the_end:    
popa    
ret
Другие вопросы по тегам