Доброе утро. Я в ассемблере, можно сказать, новичок и хочу освоить низкоуровневое программирование на примере своего загрузчика. Схема примерно такова: в MBR диска садится код, проверяющий наличие диска с определённым ID, а оригинальная MBR сохраняется в другой сектор и потом подгружается. Дабы не плодить множество файлов, я хотел код, который будет записан в MBR, записать, скажем, в инсталляторе, в отдельной секции, а потом просто скопировать на место MBR. Но инсталлятор на MASM32, поэтому вопрос такой: будет ли код, написанный под Win32 без использования 32-разрядных регистров, работать на таком уровне? Т.е. будет ли он тем же, как если бы я собирал его в отдельном com-файле под досом? Сам код для MBR: Код (Text): org 7C00h ; Загрузим себя по другому адресу ; Но не весь код, а только с ; метки payload cld mov si, (payload + 7C00h) mov di, 7D00h mov cx, 200h rep movsb jmp 0000:7D00h ; far jump на копию нашего кода payload: ; Чтение старой MBR из 8 сектора ; в режиме CHS mov ax, 0201h ; Номер функции & номер сектора mov dl, 80h ; С первого диска xor dh, dh ; Нулевой головки mov cx, 0008h ; Восьмой сектор нулевого ; цилиндра mov bx, 7C00h ; Читаем по смещению бывшего ; загрузчика int 13h ; Тут рабочий код, не забываем о 446 б. Мэйби есть смысл подгрузить ещё ; кода ; Прыгаем на оригинальную ; загрузочную запись jmp 0000:7C00h
Ты должен вставить бинарник в инсталлятор в каком-либо виде (например, как байтовый массив констант). То, о чем ты говоришь, возможно, но не целесообразно и потребует весьма специфических действий по пересчету смещений и т.п. Хотя в fasm'е это сделать не сложно: Код (Text): mbr: org 7C00h use16 ... rb 7DB8h-$ org mbr+($-$$) use32
Дело не в регистрах. А в системах декодирования команд 16 битной схемы и 32 битной. Но это легко решается используя управляющие слова "use16" и "use32" подробнее зависит от компилятора. Вторая проблема это смещения. Надо чтобы компилятор и правильно выставил или твой инсталятор. Это нетрудно.
Компилятор - masm32, который, кажется, 16-битный код уже не поддерживает. Хм. Понятно, спасибо. Тут нарисовалась другая проблема - вышеуказанный код я собрал фасмом и записал в MBR, сохранив старую в нужный сектор. VirtualBox при запуске выдало примерно следующее: "int13_harddisk: function 42. Can't use 64bits lba", и это притом, что я читаю в CHS, а функция 02, а не 42. Я подозреваю, что я где-то натупил со смещениями на этапе переноса тела загрузчика в другую область памяти, и он прыгнул не в то место. В какую сторону нужно копать?
drunken_cowboy Код (Text): mov si, (payload + 7C00h) Здесь неверно, т.к. согласно вышестоящему org 7C00h отсчёт адресов всех меток, включая payload, уже идёт начиная с базы 7C00h.
Чёёрт, точно, прошляпил. После редактирования: Код (Text): use16 org 7C00h ; Загрузим себя по другому адресу ; Но не весь код, а только с ; метки payload xor ax,ax mov ds,ax mov es,ax mov ss,ax mov sp,7B00h cld mov si, payload mov di, 7D00h mov cx, 200h rep movsb jmp 0000:7D00h ; far jump на копию нашего кода payload: ... При загрузке это дело намертво зависает, а толкового мана по отладке загрузчиков я так и не нашёл. Вообще, вот такой трюк сработал: Код (Text): org 0600h use16 xor ax,ax mov ds,ax mov es,ax mov ss,ax mov sp,7C00h cld mov si, 7C00h mov di, 600h mov cx, 200h rep movsb jmp 0000:payload payload: ... Вроде схема примерно одинаковая, где тут может быть загвоздка? Обидно, что ошибся в десяти строчках, а не знаю, где. Вроде и
Я думал, мы не обсуждаем код... Твои 7B00h, 7D00h меня пугают. Действительно на ровном месте столько неоднозначных вещей понаделал... Если чЁ, то вершину стека можно устанавливать на 7С00h, а 7C00h+512 = 7E00h. Твое желание перемещать только полезный код похвально, но если это делать необдуманно, то опять можно наломать дров со смещениями. fasm в отличие от нек. др. компиляторов позволяет делать такие вещи достаточно элегантно. Вот немного обобщенный вариант разметки, используемый в моих MBR-загрузчиках. Код (Text): org 7C00h start: xor cx,cx cli mov ss,cx mov sp,$$ sti mov ds,cx mov si,old_base - old_base mod 2 mov es,cx mov di,new_base - old_base mod 2 cld mov cl,(size+1)/2 rep movsw jmp 0:new_base rb 440-($-$$)-size old_base: org 600h ; 7E00h new_base: ... ; необязательно, просто четный размер гарантирует ; выравнивание перемещаемого кода на четную границу, ; что улучшит эффективность при перемещении словами align 2 label size at $-$$ Это не самая простая разметка. Можно проще: Код (Text): org 7C00h ... align 2 old_base: org 600h new_base: ... org old_base+($-$$) ; old_base+size db 7C00h+440-$ dup 0
Да, забыл сказать, что сложность первой разметки вызвана тем, что я перемещаемый код обычно размещаю под верхней границей доступной области MBR.
Однако да. Читая сектор по адресу 7C00h, я затирал скопированный код, поэтому там и творилось нечто невообразимое. Спасибо. Приму к сведению, в т.ч. и код.
drunken_cowboy запретов-то нет... хоть 64-битный. Только тогда там же надо размещать загрузку чего-то еще, и переход в PM, и минимальные драйвера для продолжения работы с диском, и ... Где-то поблизости и недавно была тема похожая, с мудрым советом "не надо впихивать невпихуемое". Пусть МБР делает свою часть - читает в память некий лоадер и передает ему управление. Лоадер может быть бОльшего размера, не ограничен в 1-2 сектора. Впихнуть в МБР инициализацию защищенного режима, драйвер диска, обработчики аппаратных прерываний и исключений - не буду говорить "невозможно", хз, Левши имеются, и блоху подкуют. Но не нужно - и сложно - и при этом чем-то придется пожертвовать (например, проверками на успех дисковых операций, или совместимостью с железом).