При сборке моего ассемблера для платформы x86 я столкнулся с некоторыми проблемами при кодировании инструкции JMP
:
OPCODE INSTRUCTION SIZE
EB cb JMP rel8 2
E9 cw JMP rel16 4 (because of 0x66 16-bit prefix)
E9 cd JMP rel32 5
...
( с моего любимого сайта инструкций x86, http://siyobik.info/index.php?module=x86&id=147)
Все это относительные переходы, где размер каждой кодировки (операция + операнд) находится в третьем столбце.
Теперь мой оригинальный (и, следовательно, неисправный из-за этого) дизайн зарезервировал максимальное (5 байт) пространство для каждой инструкции. Операнд еще не известен, потому что это прыжок в неизвестное место. Поэтому я реализовал механизм «перезаписи», который переписывает операнды в правильном месте в памяти, если местоположение перехода известно, и заполняет остальное NOP
с. Это несколько серьезная проблема в петлях.
Теперь моя проблема в следующей ситуации:
b: XXX
c: JMP a
e: XXX
...
XXX
d: JMP b
a: XXX (where XXX is any instruction, depending
on the to-be assembled program)
Проблема в том, что я хочу наименьшее возможное кодирование для инструкции JMP
(без заполнения NOP
).
Мне нужно знать размер инструкции в c
, прежде чем я смогу вычислить относительное расстояние между a
и b
для операнда в d
. То же самое относится к JMP
в c
: ему нужно знать размер d
, прежде чем он сможет рассчитать относительное расстояние между e
и a
.
Как существующие ассемблеры решают эту проблему или как вы это сделаете?
Вот что я думаю, что решает проблему:
Сначала закодируйте все инструкции для кодов операций между JMP
и его целью, если этот регион содержит код операции переменного размера, используйте максимальный размер, например, 5
для JMP
. Затем закодируйте относительный JMP
к своей цели, выбрав наименьший возможный размер кодировки (3, 4 или 5) и рассчитайте расстояние. Если какой-либо код операции переменного размера закодирован, измените все абсолютные операнды и все относительные инструкции, которые пропускают эту закодированную инструкцию: они перекодируются, когда их операнд изменяется, чтобы выбрать наименьший возможный размер. Этот метод гарантированно завершится, поскольку только коды операций переменного размера могут уменьшаться (поскольку он использует их максимальный размер).
Интересно, возможно, это слишком спроектированное решение , поэтому я задаю этот вопрос.