Может кто-нибудь объяснить этот непосредственно собранный код операции x86 JMP? - PullRequest
8 голосов
/ 13 февраля 2009

В школе мы использовали программу начальной загрузки для запуска автономных программ без операционной системы. Я изучал эту программу, и когда включен защищенный режим, происходит большой переход, который выполняется путем непосредственной сборки кода операции и операндов в качестве данных в программе. Это было для ассемблера GNU:


         /* this code immediately follows the setting of the PE flag in CR0 */</p>

<pre><code>.byte   0x66, 0xEA
.long   TARGET_ADDRESS
.word   0x0010          /* descriptor #2, GDT, RPL=0 */

Прежде всего, зачем делать это (вместо мнемоники инструкции)?

Я просматривал руководства Intel, но код все еще немного сбит с толку. В частности, в томе 2А, ​​стр. 3-549, есть таблица кодов операций. Соответствующая запись:

EA *cp* JMP ptr16:32  Inv.  Valid  Jump far, absolute, address given in
operand

Фактический код операции очевиден, но первый байт, 0x66, сбил меня с толку. Ссылаясь на таблицу в руководстве Intel, cp, очевидно, означает, что последует 6-байтовый операнд. И, очевидно, 6 байтов следуют в следующих двух строках. 0x66 кодирует «Префикс переопределения размера операнда». Какое это имеет отношение к cp в таблице? Я ожидал, что для cp будет какое-то шестнадцатеричное значение, но вместо этого есть префикс переопределения. Может кто-нибудь прояснить это для меня?

Вот дамп из od:

c022    **ea66    0000    0001    0010**    ba52    03f2    c030

TARGET_ADDRESS был определен как 0x00010000.

Меня также немного смущает значение двух последних байтов. Тем не менее, это, кажется, совсем другой вопрос. Становится довольно поздно, и я часами смотрю на код и руководства Intel, поэтому я надеюсь, что понял свою точку зрения.

Спасибо за внимание!

Ответы [ 3 ]

12 голосов
/ 13 февраля 2009

0x66 указывает, что JMP (0xEA) ссылается на шесть байтов. По умолчанию используется значение 64 КБ (16 бит) в реальном режиме или до 32 бит в защищенном режиме (если я хорошо помню). Увеличив его, он также включает дескриптор сегмента, индекс сегмента в GDT или LDT, что означает, что этот код выполняет то, что традиционно называется «длинным прыжком»: прыжок, который пересекает сегменты в архитектура x86. В этом случае сегмент указывает на вторую запись в GDT. Если вы посмотрите ранее в этой программе, вы, скорее всего, увидите, как определяется GDT с точки зрения начального адреса и длины сегмента (см. Руководство Intel для изучения таблиц GDT и LDT, 32-битная запись, описывающая каждый сегмент).

2 голосов
/ 14 мая 2009

Я сталкиваюсь с этим немного. Некоторые сборщики прыгнут только на ЭТИКЕТКУ. В этом случае человек хочет совершить абсолютный переход к конкретному жестко закодированному смещению. Я предполагаю, что jmp TARGET_ADDRESS не будет работать, поэтому они просто указали его в байтах, чтобы обойти эту проблему.

0 голосов
/ 19 августа 2014

0x66 определяет переопределение размера операнда текущего размера сегмента кода. Предполагая, что текущий размер кода является 16-разрядным, указатель новой инструкции будет 32-разрядным, а не 16-разрядным. Если текущий размер сегмента кода 32-битный, 0x66 будет отображать целевой указатель инструкции как 16-битный. Текущий атрибут размера кода зависит от используемого селектора CS и его атрибутов, загруженных из таблицы GDT / LDT. В реальном режиме размер сегмента кода обычно составляет 16 бит, за исключением особых случаев «нереального» режима.

...