Привет Мировой загрузчик, не работающий

Я работал через учебные руководства над этой веб-страницей, которая прогрессивно создает загрузчик, который отображает Привет Мир.

2-е учебное руководство (где мы пытаемся заставить быть произведенными) работы отлично и все же 1-е учебное руководство не работает на меня вообще! (BIOS полностью игнорирует гибкий диск и загружается прямо в Windows). Это - меньше проблемы, хотя любые объяснения ценились бы.

Настоящая проблема состоит в том, что я не могу заставить 3-е учебное руководство работать. Вместо этого при выводе "Привет Мир", я получаю необычный символ (и мерцающий курсор) в нижнем левом углу экрана. Это немного походит на улыбающуюся поверхность в скругленном прямоугольнике. Кто-либо знает, как заставить Привет Мир отображаться, как он должен?

5
задан Ry- 1 December 2012 в 17:52
поделиться

2 ответа

Вы говорите "загрузиться прямо в windows", поэтому я предполагаю, что вы используете физический ПК. Заметка на будущее: Всегда используйте эмулятор для разработки! Это просто проще. Мне нравится Bochs для OSDeving, потому что он имеет хорошие функции отладки. Теперь о возможных решениях.

Существует множество глючных BIOS, которые нарушают неофициальные спецификации IBM PC для адреса загрузки 0x7C00.

Это может вызвать множество проблем с адресами памяти и тому подобным при сборке. Поэтому сделайте начало следующим образом:

[BITS 16] ;tell the assembler that its a 16 bit code
[ORG 0x7C00] ;this tells the assembler where the code will be loaded at when it runs on your machine. It uses this to compute the absolute addresses of labels and such.

jmp word 0:flush ;#FAR jump so that you set CS to 0. (the first argument is what segment to jump to. The argument(after the `:`) is what offset to jump to)
;# Without the far jmp, CS could be `0x7C0` or something similar, which will means that where the assembler thinks the code is loaded and where your computer loaded the code is different. Which in turn messes up the absolute addresses of labels.
flush: ;#We go to here, but we do it ABSOLUTE. So with this, we can reset the segment and offset of where our code is loaded.
mov BP,0 ;#use BP as a temp register
mov DS,BP ;#can not assign segment registers a literal number. You have to assign to a register first.
mov ES,BP ;#do the same here too
;#without setting DS and ES, they could have been loaded with the old 0x7C0, which would mess up absolute address calculations for data. 

Смотрите, некоторые загружают по адресу 0x07C0:0000, а большинство загружают (и считается, что это правильно) по адресу 0x0000:7C00. Это один и тот же адрес, но различные настройки сегментов могут действительно испортить абсолютные адреса памяти. Итак, давайте уберем "магию" ассемблера и посмотрим, как это выглядит (обратите внимание, я не гарантирую, что адреса будут полностью правильными. Я не знаю размер всех опкодов)

jmp word 0:0x7C04 ;# 0x7C04 is the address of the `flush` label 
...

Итак, мы переходим к абсолютному адресу.

Теперь. Что происходит, когда мы этого не делаем?

Возьмем, к примеру, эту программу:

mov ax,[mydata]
hlt

mydata: dw 500 ;#just some data

Она дизассемблируется на что-то вроде

mov ax,[0x7C06] 

О, ну она использует абсолютную адресацию, так как это может пойти не так? А что если DS на самом деле 0x7C0? Тогда вместо ожидаемого ассемблером 0:0x7C06 он получит 0x7C0:0x7C06, что не один и тот же плоский адрес.

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

7
ответ дан 14 December 2019 в 04:33
поделиться

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

[ORG 0x7C00]    ;Origin, tell the assembler that where the code will

Исходя из разговора, который мы вели, похоже, что адрес в чем-то не соответствует предсказанному. Возможно, просто регистр сегмента данных DS - это не то, что вы ожидаете. Возможно, вам действительно удастся заставить работать оригинальный листинг с веб-страницы, добавив push и pop из ds перед вызовом для отображения строки, как показано здесь

 push cs
 pop ds

Если нет, то следующий код работает.

 [ORG 0x000]    ; switched to 0 since we are going to try to correct it ourself

 call nextinstruction
 nextinstruction:    ; get the return address of the call into dx
 pop dx              ; which is essentially the start of the code + 3 (3 bytes for the call instruction)
 MOV SI, HelloString ;Store string pointer to SI
 add si, dx          ; add IP from start of program
 sub si, 3           ; subtract the 3 the call instruction probably took
 push cs
 pop ds              ; make ds the same as cs.  
 CALL PrintString   ;Call print string procedure
 JMP $      ;Infinite loop, hang it here.

Этот код определяет смещение во время выполнения выполняемого кода, а также убеждается, что DS указывает на тот же сегмент. Если не указано иное, инструкции, включающие SI, обычно также используют DS в качестве сегмента кода для обращения к памяти.

DS - это сегментный регистр, и вы можете прочитать что-нибудь вроде Искусство ассемблера, чтобы узнать больше.

Earlz делает то же самое, просто проверяет правильность регистров, чтобы адрес памяти ссылался правильно. Просто он знает больше о специфике загрузочного сектора, чем я.

1
ответ дан 14 December 2019 в 04:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: