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]