Энди Росс предлагает гораздо больше основополагающих рассуждений, но, к сожалению, ошибочен или, по крайней мере, сбивает с толку технические детали. Это правда, что эффективный адрес, равный всего (%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.