Why is the use of the 'DS:' segment override illegal in 64-bit mode?
Asked Answered
D

1

3

I have a pretty simple few lines of assembly code, which moves around some data, like this:

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] 

However, the compiler returns

error A2202:illegal use of segment register

I have a feeling this may be an issue with my compiler or version, any pointers would be helpful

Demott answered 17/5, 2018 at 20:47 Comment(9)
What assembler are you using?Rog
using ml64 assemblerDemott
Which line is indicated by the error?Cleanly
the second, fourth, and fifth ones.Demott
The lines with 'gs' in themDemott
@DanielPahor You mean the lines with ds in them, I think? In 64 bit mode, the only segment overrides that do anything are fs and gs, which is why your assembler might complain. Just leave out the ds: and it should just work.Cleanly
I'd say MASM is being overly aggressive in flagging this as a hard error. Fuz is correct. In 64-bit mode FS and GS overrides are the only ones that have any effect. DS and ES segment overrides can be generated, the processor will still decode them but they are effectively ignored. I'd consider this more of a situation where I'd warn the developer without a hard error.Toscano
something is wrong with yous assembler, try fasm (a bit different syntax: mov rax, qword [ ds:rax+60 ])Liminal
@Liminal : Nothing wrong with MASM interpreting it as a hard error (that's up to the assembler developers - I may not agree with it though). FASM goes to the other extreme. It quietly drops the ES, DS, CS overrides and pretends they were never part of the instruction specified (and thus doesn't generate them at all). Not anything wrong with that either but I think they should warn the user that the segment overrides were not generated.Toscano
P
6

cs/ds/es/ss segment override prefixes are allowed in machine code in 64-bit mode. But some assemblers choose not to allow them.

But note that they have literally no effect on instructions with memory operands. This might be why masm apparently chooses not to allow it, to save you from the "mistake" of wasting space on such prefixes. Other assemblers, like NASM, do allow it.

All those segments have the same fixed base address=0, and don't even change which exception would be raised.

Intel manual vol.1 3.3.7.1 Canonical Addressing:

If an instruction uses base registers RSP/RBP and uses a segment override prefix to specify a non-SS segment, a canonical fault generates a #GP (instead of an #SS). In 64-bit mode, only FS and GS segment-overrides are applicable in this situation. Other segment override prefixes (CS, DS, ES and SS) are ignored. Note that this also means that an SS segment-override applied to a “non-stack” register reference is ignored. Such a sequence still produces a #GP for a canonical fault (and not an #SS).

e.g. if mov eax, ds:[rbp] faults from a non-canonical address (high 16 bits aren't the sign-extension of the low 48), it's still a #SS fault (because the base register is RBP or RSP), not #GP. The DS prefix is really ignored.

The only other way you could tell the difference would be if it's possible to give DS a segment selector that will fault if any load or store tries to use it, then run mov eax, [ds:rbp]. But I'm not sure that's possible; I was getting a segfault right away on mov ds, eax when trying to set a non-zero value in Linux. NULL segment selectors "work" for DS and ES. Given the assembler warnings / behaviour of NASM and FASM, the developers of those assemblers at least think the segment prefixes truly are meaningless.


fs and gs are the only segment overrides that do anything in 64-bit mode.

They can have non-zero base addresses.

CS/DS/ES/SS are only useful for padding to make instructions longer (for alignment reasons). What methods can be used to efficiently extend instruction length on modern x86?

Note that ds is already the default segment for all base registers other than rbp / rsp, so an explicit ds prefix wouldn't change the meaning of the instruction at all even if it wasn't ignored. If your assembler refuses to accept mov rcx,qword ptr ds:[rax+20], it would be reasonable to also refuse to accept mov ecx, dword ptr ds:[eax+20] in 32-bit mode.


For some assemblers (e.g. NASM), mentioning a segment explicitly in an asm source line emits a segment prefix on the instruction, even if it's already the default. If that's how MASM works, then it's not a good idea to use it for "documentation" purposes.

If you do want to emit DS prefixes for padding, just encode them explicitly:

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

Other assemblers (GAS, NASM)

Interestingly, in GAS's .intel_syntax noprefix (which is MASM-like), ds:[rax+20] assembles without an explicit prefix (because it's already the default), but ss:[rax+20] does emit a prefix. So GAS doesn't assume that cs/ds/es/ss are equivalent even in 64-bit code.

NASM warns: segments.asm:5: warning: ds segment base generated, but will be ignored in 64-bit mode

mov rax, [gs: 60]             ; NASM requires the seg: to be
mov rcx, [ds: rax+20]         ;  inside the [] if present
mov rcx, [rax+20]

assembles with NASM to this (objdump -drwC -Mintel output):

  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]
Pleonasm answered 18/5, 2018 at 8:37 Comment(2)
Can a segment override be used with moffs32 instead of an m32. It doesn't appear to with moffs64. What happens?Maura
@LewisKelsey: moffs absolute addresses are still an "offset" part of a full seg:off address, hence the name. Yes, you could use NASM mov eax, [fs: qword 0x12345678abc] (64-bit absolute address referencing a 32-bit dword = moffs32). It works normally, fs_base + 0x12345678abc. (I haven't tried it, but I'd be shocked if it wasn't like this. I'm not sure what happens with a 32-bit address-size override; I think only the offset part is truncated to 32-bit, then added to the full 64-bit segment base).Pleonasm

© 2022 - 2024 — McMap. All rights reserved.