Что такое регистр% eiz? - PullRequest
51 голосов
/ 31 марта 2010

В следующем коде сборки, который я выгрузил с помощью objdump:

lea    0x0(%esi,%eiz,1),%esi

Что такое регистр %eiz? Что означает предыдущий код?

Ответы [ 3 ]

54 голосов
/ 31 марта 2010

См. Почему GCC LEA EIZ? :

По-видимому, %eiz - это псевдорегистр, который всегда всегда равен нулю (например, r0 в MIPS).

...

В конце концов я нашел сообщение в списке рассылки от гуру binutils Яна Ланса Тейлора, в котором раскрывается ответ. Иногда GCC вставляет инструкции NOP в поток кода, чтобы обеспечить правильное выравнивание и тому подобное. Инструкция NOP занимает один байт, так что вы можете подумать, что можете просто добавить столько, сколько необходимо. Но, по словам Яна Ланса Тейлора, чип быстрее выполняет одну длинную инструкцию, чем множество коротких. Таким образом, вместо того, чтобы вставлять семь инструкций NOP, они вместо этого используют одну причудливую LEA, которая занимает семь байтов и семантически эквивалентна NOP.

23 голосов
/ 28 августа 2012

(Очень поздно для игры, но это показалось интересным дополнением): Это вовсе не регистр, это причуды кодировки инструкций Intel. При использовании байта ModRM для загрузки из памяти в поле регистров используется 3 бита для хранения 8 возможных регистров. Но место, где ESP (указатель стека) «будет», вместо этого интерпретируется процессором как «байт SIB следует этой инструкции» (т.е. это расширенный режим адресации, а не ссылка на ESP). По причинам, известным только авторам, ассемблер GNU всегда представлял этот «ноль, где регистр в противном случае был бы» как регистр «% eiz». Синтаксис Intel просто отбрасывает его.

14 голосов
/ 15 января 2014

Энди Росс предлагает гораздо больше основополагающих рассуждений, но, к сожалению, ошибочен или, по крайней мере, сбивает с толку технические детали. Это правда, что эффективный адрес, равный всего (%esp), не может быть закодирован только байтом ModR / M, поскольку вместо того, чтобы декодироваться как (%esp), он используется, чтобы сигнализировать о включении байта SIB. Однако псевдорегистр %eiz не всегда используется с байтом SIB для представления того, что использовался байт SIB.

Байт SIB (масштаб / индекс / основание) состоит из трех частей: индекс (регистр, такой как %eax или %ecx, к которому применяется шкала), масштаб (степень двух от С 1 по 8, на который умножается регистр индекса) и базовый (другой регистр, который добавляется к масштабированному индексу). Это то, что позволяет использовать такие инструкции, как add %al,(%ebx,%ecx,2) (машинный код: 00 04 4b - код операции, modr / m, sib (обратите внимание, нет регистра% eiz, даже если использовался байт SIB)) (или в синтаксисе Intel: BYTE PTR [ecx * 2 + ebx], al ").

Однако %esp нельзя использовать в качестве регистра индекса в байте SIB. Вместо того, чтобы разрешить эту опцию, Intel вместо этого добавляет опцию для использования базового регистра без изменения масштаба или индексации. Поэтому для устранения различий между регистром add %al,(%ecx) (машинный код: 00 01 - код операции, modr / m) и add %al,(%ecx) (машинный код: 00 04 21 - код операции, modr / m, sib) альтернативный синтаксис Вместо этого используется add %al,(%ecx,%eiz,1) (или для синтаксиса Intel: add BYTE PTR [ecx+eiz*1],al).

И, как объяснено в статье, на которую ссылается Синан, эта конкретная инструкция (lea 0x0(%esi,%eiz,1),%esi) просто используется как многобайтовый nop (эквивалентный esi = &*esi), так что должна выполняться только одна nop-подобная инструкция вместо нескольких инструкций nop.

...