При печати строки символов из загрузочного сектора отображается только первый символ
Я разрабатываю код в загрузочном секторе 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