2017-01-04 12 views
6

Причина моего вопроса в том, что Starman seems to believe the GRUB Legacy author's explanation (см следующий необъяснимого код:Не является 07C0: 0000, тот же физический адрес на машинах x86, что и 0000: 7C00?

7C4B EA507C0000 JMP  0000:7C50 ; Long Jump to the next instruction 
             ; because some bogus BIOSes jump to 
             ; 07C0:0000 instead of 0000:7C00. 

Когда я выполняю Intel-заданный алгоритм для построения эффективных адресов на первой ссылки памяти, я умножать 07C0: на 16 (эффективно левый сдвиг его на четыре бита или один полубайт). Затем я добавляю смещение: 0000 и получаю десятичный адрес 31,744.

Если я оставил смену сегмента второй записи памяти четыре бита, у меня все еще есть 0000: и смещение: 7C00 по-прежнему относится к местоположению 31,744. Так что моя реакция кишки является автором этого кода загрузочного сектора GRUB Legacy, тянет нашу ногу. Regardl эссе формы ссылки на память, сделанной любым BIOS, если эффективный адрес вычисляется до десятичного числа 31 744, то, похоже, нет проблем в том, что этот длинный прыжок решается.

В предположении, что автор кода просто выразил ложную физическую ячейку памяти таким образом, что, похоже, было то же физическое местоположение, что и было правильно, я начал думать о том, как можно было бы обращаться с BIOS, который отправил его на неправильный адрес. Пятибайтовый длинный прыжок, похоже, не является решением чего-либо. Пять NOP будут выполнять одну и ту же цель (на самом деле, просто , начав код загрузочного сектора на пять байт раньше, и исключение Long Jump будет иметь тот же эффект, что и Long Jump к следующей команде).

Если BIOS переместится в нужное место (7C00), никаких проблем. Если BIOS переместится в положение выше 7C00, тогда никакой код, загруженный на 7C00, не сможет исправить эту проблему. Если BIOS переместится в местоположение между 7C00 и 7C4B, тогда данные, хранящиеся в этой области (или ошибки, интерпретируемые с отсутствующими байтами), скорее всего, вызовут сбой. Если BIOS скачет точно на 7C4B, инструкция TEST будет переписана (с помощью Long Jump), а JNZ - 7C54 будет выполнена на основе последней математики, выполняемой в BIOS.

Для того, чтобы BIOS перепрыгнул ниже 7C4B, снова неправильные инструкции могут вызвать сбой. С удачей, часть кода загрузочного сектора будет выполнена. Результаты такого выполнения будут зависеть от того, к чему именно «фиктивный» адрес памяти загружается BIOS. Так автор этого кода загрузочного сектора вытягивает нашу ногу с рассказом о «фиктивных BIOS, которые переходят в неправильное место»?

Я отмечаю в BLOG Luke Luo, что загрузочный сектор GRUB2, хотя и отличается от загрузочного сектора GRUB Legacy, retains this inexplicable Long Jump. Поэтому, если оригинальный автор загрузочного сектора GRUB Legacy играет в нас шутку, это довольно удачная шутка (она пережила полную перезапись GRUB). Я остался с выбором, полагая невероятное утверждение о некотором неименованном BIOS и решении такой проблемы, которая, по-видимому, ничего не делает или, полагая, что автор исходного загрузочного сектора играл в нас шутку.

Люк Ло, похоже, согласен с написанием инструкций NOP к 7C66 и 7C67, что свидетельствует о том, что у него нет BIOS, который перескакивает в неправильное место. Загрузочный сектор GRUB2, который был записан на мой Flash-накопитель Linux Mint 13, имеет те же NOP. Однако загрузочный сектор GRUB2, записанный на жесткий диск моего ноутбука (Debian Etch), имеет короткий переход к следующей инструкции, написанной на 7C66 и 7C67 (обратите внимание, что Luke Luo показывает нам, что исходный загрузочный сектор, хранящийся в/usr/lib/grub/i386-pc/boot.img имеет значение Debian). Обе альтернативы имеют одинаковый эффект (выполняют инструкцию, которая следует за ними), поэтому работают оба загрузочных сектора. Также не будет такой эффективности, которую я ожидал бы в загрузочном секторе, где доступно всего около 450 байт для кода, который должен загружать другой сектор и выполнять его (включая сообщения об ошибках, если что-то пойдет не так с этой простой операцией и восьмибайтовым адресом самого сектора).

Так что я что-то упускаю, или я определил kludge, который должен быть удален из загрузочного сектора GRUB (чтобы освободить место для более значимого кода)?

+2

Некоторое время назад я написал [Stackoverflow Q & A] (http://stackoverflow.com/questions/34548325/near-call-jump-tables-dont-always-work-in-a-bootloader) о ситуации, когда не имея этого даун-прыжка, могут привести к неправильным результатам в загрузчике. Это действительно зависит от того, как написан код загрузчика. Некоторые разработчики загрузочных загрузчиков из избытка осторожности добавляют FAR JMP к явным установкам _CS_ к значению, которое они хотят, чтобы они не сталкивались с проблемами, но это может быть необязательно, если их код никогда не полагается на определенное значение в _CS_ –

+0

Подумайте, «изобилие осторожности» покрывает его. Без дальнейшей идентификации BIOS с этой проблемой нельзя даже проверить, что он все еще существует. В те дни, когда у нас не было выбора, кроме как получить наш BIOS с нашим оборудованием, это было бы решением поставщика BIOS, который не знает, как закодировать. Сегодня я надеюсь, что решение будет состоять в замене BIOS. –

+1

Когда изменилась ситуация, что BIOS не пришел с аппаратным обеспечением? Каждая материнская плата, которую я купил за последние несколько лет, поставляется со встроенным BIOS. И даже с виртуальными машинами поставщик VM все еще записывает реализацию BIOS. –

ответ

6

Вам не хватает разницы в фактическом состоянии ЦП (в то время как физический адрес - тот же, это верно).

Когда BIOS делает JMP 0000:7C00:

ваша первая команда находится в cs=0000, ip=7C00, и ваш машинный код должен быть скомпилирован для такого рода перемещения, всякий раз, когда это делает какой-либо абсолютной адресации, как, например mov ax,cs:[myTable] (тогда myTable может что-то вроде 0x7F00).

Когда BIOS делает JMP 07C0:0000:

ваша первая команда находится в cs=07C0, ip=0000, поэтому такие вещи, как myTable будет больше походить на 0x0300.

Таким образом, первый длинный прыжок в начале кода «нормализует» тот же физический адрес 31,744 в ожидаемую форму cs:ip, делая остальную часть абсолютных адресов в коде загрузчика правильно.

+1

Вот что я подумал, но я не нашел префикса переопределения сегмента в коде сборки. Следующие команды инициализируют DS до [0000]. Вы заметили, где в коде это имеет значение? Возможно, это просто предыдущий код ... – fjardon

+0

@fjardon Я не проверял конкретный источник, так как даже если конкретный загрузчик будет работать только с 'ds:' и относительными прыжками, это все еще немного «токсичная» ловушка для любого в будущем, кто попытается изменить его. Поэтому я по-прежнему рекомендую эту практику даже для кода, который не полагается на значение 'cs'. – Ped7g

+0

@fjardon, и теперь я посмотрел и не нашел проблем. Таким образом, похоже, что прыжок действительно является только предосторожностью в этом случае (я взял только быстрый просмотр ~ 5 мин, никакого серьезного пересмотра кода). Опять же, я не уверен, что дополнительные 5B стоят * любого * риска. В каком-то конкретном случае наверняка да, но, скорее всего, нет. – Ped7g