Почему использование переопределения сегмента 'DS:' недопустимо в 64-битном режиме? - PullRequest
0 голосов
/ 17 мая 2018

У меня есть несколько простых строк кода сборки, которые перемещаются по некоторым данным, например:

mov rax,qword ptr gs:[60]                         
mov rcx,qword ptr ds:[rax+20]                                         
mov rax,qword ptr gs:[60]                         
mov rcx,qword ptr ds:[rax+20]                     
mov rbx,qword ptr ds:[rcx+28] 

Однако компилятор возвращает

Ошибка A2202: недопустимоиспользование сегментного регистра

У меня такое чувство, что это может быть проблемой с моим компилятором или версией, любые указатели были бы полезны

1 Ответ

0 голосов
/ 18 мая 2018

cs / ds / es / ss Префиксы переопределения сегментов разрешены в машинном коде в 64-битном режиме, но они буквально не влияют на инструкции с операндами памяти.(например, если mov eax, ds:[rbp] сбои из неканонического адреса (старшие 16 бит не являются расширением знака младших 48), это все равно ошибка #SS (потому что базовый регистр - RBP или RSP), а не #GPПрефикс DS действительно игнорируется, а не просто эквивалентен, потому что все эти сегменты имеют одинаковый фиксированный базовый адрес = 0. Руководство Intel vol.1 3.3.7.1 Каноническая адресация.

Если в инструкции используются базовые регистрыRSP / RBP и использует префикс переопределения сегмента для указания сегмента не-SS, канонический сбой генерирует #GP (вместо #SS). В 64-битном режиме применимы только переопределения сегментов FS и GSв этой ситуации. Другие префиксы переопределения сегмента (CS, DS, ES и SS) игнорируются . Обратите внимание, что это также означает, что переопределение сегмента SS, примененное к «не-стековой» ссылке на регистр, игнорируется. Такая последовательностьпо-прежнему создает #GP для канонического сбоя (а не #SS).

Формулировка в этом разделе может означать, что они игнорируются только для целей типов исключений в tего случай.

Единственное, как вы могли бы заметить разницу, было бы, если бы можно было дать DS селектор сегмента, который выйдет из строя, если какая-либо нагрузка или хранилище попытается его использовать, затем запустите mov eax, ds:[rbp].Но я не уверен, что это возможно;Я сразу получил сообщение об ошибке на mov ds, eax при попытке установить ненулевое значение в Linux.Селекторы NULL сегмента «работают» для DS и ES.Учитывая предупреждения ассемблера / поведение NASM и FASM, разработчики этих ассемблеров, по крайней мере, думают, что префиксы сегментов действительно бессмысленны.


fs и gs являются единственными переопределениями сегментовкоторые делают что-либо в 64-битном режиме. Они могут иметь ненулевые базовые адреса.

CS / DS / ES / SS полезны только для заполнения, чтобы сделать инструкции длиннее (по причинам выравнивания) . Какие методы могут быть использованы для эффективного расширения длины инструкций на современном x86?

Обратите внимание, что ds уже является сегментом по умолчанию для всех базовых регистров, кроме rbp / rsp,таким образом, явный префикс ds не изменит значения инструкции вообще , даже если она не будет проигнорирована.Если ваш ассемблер отказывается принимать mov rcx,qword ptr ds:[rax+20], было бы разумно также отказаться принять mov ecx, dword ptr ds:[eax+20] в 32-битном режиме.

Для некоторых ассемблеров (например, NASM), упомянув сегмент явно висходная строка asm выдает префикс сегмента в инструкции, даже если это уже значение по умолчанию. Если так работает MASM, то не рекомендуется использовать его в целях «документирования».

Есливы хотите испустить префиксы DS для заполнения, просто закодируйте их явно:

mov   rax, gs:[60]
db    3Eh   ; ds prefix
mov   rcx, [rax+20]

Интересно, что в .intel_syntax noprefix GAS (который похож на MASM), ds:[rax+20] собирается без явного префикса (потому что этоуже по умолчанию), но ss:[rax+20] выдает префикс.Поэтому GAS не предполагает, что cs / ds / es / ss эквивалентны даже в 64-битном коде.

NASM предупреждает: segments.asm:5: warning: ds segment base generated, but will be ignored in 64-bit mode

mov rax, [gs: 60]
mov rcx, [ds: rax+20]
mov rcx, [rax+20]

собирается с NASM для этого (objdump -drwC -Mintel вывод):

  4000b0:       65 48 8b 04 25 3c 00 00 00      mov    rax,QWORD PTR gs:0x3c
  4000b9:       3e 48 8b 48 14          mov    rcx,QWORD PTR ds:[rax+0x14]
  4000be:       48 8b 48 14             mov    rcx,QWORD PTR [rax+0x14]
...