TL: DR: вы все равно находите конец инструкции во время декодирования и настраиваете декодирование следующей инструкции. Для процессоров вполне нормально выполнять относительную адресацию относительно end текущей инструкции, хотя некоторые процессоры делают разные выборы, например, относительно конца следующей инструкции (для ARM-относительной адресации памяти в ПК).
См. Содержит ли счетчик программ текущий адрес или адрес следующей инструкции?
x86 Дизайн машинного кода был установлен в камне вв конце 70-х годов с 8086, за исключением вещей (таких как 32/64-битные режимы адресации ModRM + SIB), которые были переработаны при расширении ISA.
Оригинальные 8086 байты декодированной инструкции последовательно (не обязательно целая инструкция сразу)и не имеет верхнего предела числа байтов префикса или общей длины инструкции.
I думаю, 8086 избегает когда-либо необходимости сохранять начальный адресинструкция, даже для исключений. Например, на современном x86 #DE
(исключение деления) выдвигает адрес ошибочной инструкции. Но на 8086 фрейм исключений имеет адрес следующей инструкции .
8086 даже имеет «ошибку» (или задокументированный недостаток проекта), когда прерывания, поступающие во времявыполнение cs rep movsb
(например) выдвигает адрес конечного префикса в качестве адреса возврата исключения, делая переопределение сегмента для инструкций rep
-строки практически непригодным для использования с включенными прерываниями. (Потому что выполнение будет возобновлено либо без rep
, либо без переопределения сегмента, которое вы указали первым). См. x86 Счетчик программ, абстрагированный от микроархитектуры? и комментарии.
Когда 8086 заканчивает декодировать инструкцию call
, он не знает, где она началась. Единственная контрольная точка, которую он имеет, - это конец инструкции call
. Так что, если они захотят провести эту оптимизацию в аппаратном обеспечении (нигде не сохраняя адрес начала декодирования), у них даже не будет выбора. Хотя теоретически они могли бы использовать адрес кода операции E8 call
(после любых префиксов) в качестве привязки, вероятно, для записи этого отдельно потребовался бы дополнительный сумматор или дополнительное оборудование.
Уже извлекает / декодируетдолжен найти конец команды во время декодирования (при этом выясняя, что это call
или jmp
), поэтому конец инструкции / адрес следующей инструкции уже доступен внутри. call
даже нужно поместить это значение в стек в качестве адреса возврата.
Конвейерная RISC или полностью непайпированный ЦП также будет использовать этот адрес следующей инструкции для извлечения следующей инструкции из памяти илиI-кэш. Но на практике предварительная выборка 8086 асинхронна в небольшой буфер предварительной выборки. Формат машинного кода разрабатывался на бумаге в основном до проектирования реализации, поэтому эта общая причина для создания вещей относительно конца инструкции, возможно, была тем, что имел в виду архитектор.
Это общий выбор дизайнадля многих ISA сделать ветки относительно конца инструкции.
Просто повторюсь, причина, о которой я говорю, только около 8086 (что внутренне очень отличается от современногоx86), это был первый ген, и понимание этого помогает объяснить некоторые решения по проектированию машинного кода. (например, почему x86 тратит 8 опкодов на однобайтовый xchg [e/r]ax, reg
: потому что 8086 не имел movsx
или 2-операнд imul
, и требовал или хотел AX для многих вещей. Также этот размер кода былглавное узкое место в производительности.)
Современный x86 просто отслеживает адрес каждой инструкции и может использовать его при декодировании call rel32
. Не ахти какое дело. Почему команды перехода / вызова x86 используют относительные смещения вместо абсолютных пунктов назначения?