rbp не разрешен в качестве базы SIB?

Я совершенно новичок в двоичном кодировании x86-64. Я пытаюсь исправить старый код ассемблера.

В любом случае, я пытаюсь сделать что-то вроде этого (синтаксис Intel):

mov    [rbp+rcx], al

Ассемблер в настоящее время генерирует это:

88 04 0D

но это не похоже на правильную инструкцию. Если я изменю базу в SIB-байте из rbp в какой-то другой регистр он работает нормально. Еще один способ заставить его работать - добавить нулевое смещение в один байт (88 44 0D 00). Похоже, это происходит с другими подобными кодами операций.

Почему я не могу использовать rbp там с mod=00?

1 ответ

Решение

Кодировка, которая будет означать rbp является escape-кодом для отсутствия базового регистра (просто disp32 в SIB или RIP-относительный rel32 в ModRM). Большинство сборщиков собираются [rbp] в [rbp + disp8=0],


Поскольку вам не нужно масштабировать, используйте [rcx + rbp] вместо этого, чтобы избежать необходимости в disp8=0, потому что rbp может быть индексом.

(SS и DS всегда эквивалентны в длинном режиме, поэтому не имеет значения, что base=RBP подразумевает SS, а base=RCX подразумевает использование сегмента DS.)


x86 / x86-64 ModRM режим адресации, кодирование особых случаев

(из ответа, который я написал на " Почему rbp и rsp называются регистрами общего назначения?"). Этот вопрос выглядит как идеальное место для копирования или трансплантации этого раздела.

rbp / r13 не может быть базовым регистром без смещения: вместо этого эта кодировка означает: (в ModRM) rel32 (Относительно RIP) или (в SIB) disp32 без базового регистра. (r13 использует те же 3 бита в ModRM/SIB, поэтому этот выбор упрощает декодирование, поскольку не позволяет декодеру длины команды смотреть на бит REX.B для получения 4-го бита базового регистра). [r13] собирает в [r13 + disp8=0], [r13+rdx] собирает в [rdx+r13] (избежать проблемы путем замены базы / индекса, когда это возможно).

rsp / r12 в качестве базового регистра всегда нужен байт SIB. (Кодирование ModR/M base=RSP является escape-кодом для сигнализации байта SIB, и опять же, больше декодера должно заботиться о префиксе REX, если r12 был обработан по-другому).

rsp не может быть индексным регистром. Это позволяет кодировать [rsp], что более полезно, чем [rsp + rsp], (Intel могла бы разработать кодировки ModRM / SIB для 32-битных режимов адресации (впервые в 386), поэтому SIB без индекса был возможен только при base=ESP. [eax + esp*4] возможно и только исключает [esp + esp*1/2/4/8], Но это бесполезно, поэтому они упростили аппаратное обеспечение, сделав index=ESP кодом без индекса независимо от базы. Это позволяет использовать два избыточных способа кодирования любого режима адресации base или base+disp: с или без SIB.)

r12 может быть индексным регистром. В отличие от других случаев, это не влияет на декодирование длины команды. Кроме того, его нельзя обойти с помощью более длинной кодировки, как в других случаях. AMD хотела, чтобы регистр AMD64 был как можно более ортогональным, поэтому имеет смысл потратить несколько дополнительных транзисторов на проверку REX.X как часть декодирования индекса / без индекса. Например, [rsp + r12*4] требует index=r12, поэтому имея r12 не вполне общее назначение сделало бы AMD64 худшей целью компилятора.

   0:   41 8b 03                mov    eax,DWORD PTR [r11]
   3:   41 8b 04 24             mov    eax,DWORD PTR [r12]      # needs a SIB like RSP
   7:   41 8b 45 00             mov    eax,DWORD PTR [r13+0x0]  # needs a disp8 like RBP
   b:   41 8b 06                mov    eax,DWORD PTR [r14]
   e:   41 8b 07                mov    eax,DWORD PTR [r15]
  11:   43 8b 04 e3             mov    eax,DWORD PTR [r11+r12*8] # *can* be an index

Все это относится и к 32-битным режимам адресации; кодировка идентична, за исключением того, что нет EIP-относительного кодирования, только два избыточных способа кодирования disp32 без основы.

См. Также https://wiki.osdev.org/X86-64_Instruction_Encoding для таблиц, подобных таблицам в руководстве Intel vol.2.


Похоже, это происходит с другими подобными кодами операций.

Кодирование ModRM операндов r/m всегда одинаково. Некоторые коды операций требуют операнда регистра, а некоторые требуют памяти, но фактическое ModRM + необязательное смещение SIB + исправлено, поэтому одно и то же оборудование может декодировать его независимо от инструкции.

Есть несколько редких кодов операций, таких как mov al/ax/eax/rax, [qword absolute_address] которые вообще не используют кодирование ModRM для своих операндов, но те, которые используют тот же формат.

Другие вопросы по тегам