Qemu и Raw Binary File - PullRequest
       91

Qemu и Raw Binary File

3 голосов
/ 26 июня 2019

Я собираю и запускаю двоичные файлы (загрузочный сектор, этап 1, этап 2) для практики. Загрузочный сектор - asm, и первый этап - asm, который работает нормально. Второй этап загружается в 0x1000, и у меня есть некоторый asm, который переходит к началу моего кода C. Мои прыжки и вызовы кажутся отключенными (короткими) на два байта.

Я пробовал код в Bochs и Qemu (шагая по нему). Весь код выглядит хорошо. Я даже разобрал его в МАР, и все выглядит хорошо. Я предполагаю, что это может быть моим недостатком знаний о выравнивании кода.

2-й этап начинается с 0x1000:

0x1000: cli    
0x1001: xor    eax,eax
0x1003: mov    eax,0x1f1a
0x1008: mov    esp,eax
0x100a: sti    
0x100b: jmp    0x1010

Первый прыжок приземляется в 0x1010 (это разобранный код C):

0x1010: push   0x16b4
0x1015: call   0x14ca   <---
0x101a: add    esp,0x4
0x101d: jmp    0x101d

Вызов выше 0x14CA фактически достигает 0x000014c9, два байта короче.

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

1 Ответ

3 голосов
/ 26 июня 2019

Это дикое предположение, которое на самом деле может быть неверным.Он основан на том факте, что в 32-битном коде относительные кодированные вами команды JMP и CALL имеют размер 5 байтов, а в 16-битном коде - 3 байта.5 байтов - 3 байта = 2 байта.Учитывая, что относительные цели JMP и CALL основаны на расстоянии от начала следующей инструкции, он может подсказать, что могло пойти не так.

Если я возьму этот код:

bits 32
org 0x1000

    cli
    xor    eax,eax
    mov    eax,0x1f1a
    mov    esp,eax
    sti
    jmp    0x1010
    push   0x16b4
    call   0x14ca
    add    esp,0x4
    jmp    0x101d

И соберите его с:

nasm -f bin stage2.asm -o stage2.bin

И просмотрите 32-битное декодирование с:

ndisasm -b32 -o 0x1000 stage2.bin

Я получу:

00001000  FA                cli
00001001  31C0              xor eax,eax
00001003  B81A1F0000        mov eax,0x1f1a
00001008  89C4              mov esp,eax
0000100A  FB                sti
0000100B  E900000000        jmp dword 0x1010
00001010  68B4160000        push dword 0x16b4
00001015  E8B0040000        call dword 0x14ca
0000101A  83C404            add esp,byte +0x4
0000101D  E9FBFFFFFF        jmp dword 0x101d

Это выглядит правильно.Однако, если я декодирую тот же код, что и 16-битный, с помощью:

ndisasm -b16 -o 0x1000 stage2.bin

я получаю:

00001000  FA                cli
00001001  31C0              xor ax,ax
00001003  B81A1F            mov ax,0x1f1a
00001006  0000              add [bx+si],al
00001008  89C4              mov sp,ax
0000100A  FB                sti
0000100B  E90000            jmp word 0x100e
0000100E  0000              add [bx+si],al
00001010  68B416            push word 0x16b4
00001013  0000              add [bx+si],al
00001015  E8B004            call word 0x14c8
00001018  0000              add [bx+si],al
0000101A  83C404            add sp,byte +0x4
0000101D  E9FBFF            jmp word 0x101b
00001020  FF                db 0xff
00001021  FF                db 0xff

Декодирование инструкций неверно, однако JMP и CALLsприсутствуют и идут в неправильные места памяти.Это ужасно похоже на наблюдения, которые вы видите.

Не видя ваш код, я надеюсь, что к тому моменту, когда вы начнете выполнять этап 2 с 0x1000, вы перейдете в 32-битный защищенный режим.Если нет, то я подозреваю, что это корень ваших проблем.Я считаю, что 32-битные закодированные инструкции выполняются в 16-битном реальном режиме.


Обновление

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

Вы переходите в нереальный режим, входя в 32-битный защищенный режим и возвращаетесь в 16-битный реальный режим.Нереальный режим по-прежнему является 16-битным реальным режимом, за исключением того, что ограничения в кэше скрытых дескрипторов установлены в 0xffffffff (предел 4 ГБ).Вернувшись в 16-битный реальный режим, вы сможете напрямую обращаться к памяти в сегментах за пределами 64 КБ, используя 32-битную адресацию, но код все еще работает в 16-битном реальном режиме.

Если вы пишетекод для 16-битного нереального режима ваш компилятор и ассемблер все еще должны генерировать 16-битный код.Если вы намереваетесь написать / сгенерировать 32-битный код, тогда нереальный режим не подходит, и вам потребуется войти в 32-битный защищенный режим для выполнения 32-битного кода.

...