Segments are still used on 64 bit long mode and are still set up, except the CPU treats their bases to be 0 (except for gs and fs), and does not perform a limit check. The default segment for rax is indeed ds
, but this can be changed with a segment override. lea rdx, ds:0[rax*4]
is lea rdx, ds:[rax*4 + 0]
, which is lea rdx, ds:[rax*4]
, which is the same as lea rdx, [rax*4]
in that when that instruction is executed, the AGU uses the ds
segment descriptor by default for rax
to perform privilege checks, but not limit or base checks. This segment descriptor is either renamed and is placed in the reservation station (and hence it is the job of the decoder and allocator to use the correct segment descriptor based on the prefix override or lack thereof) or is internal to the AGU and the AGU uses the uop opcode which might encode the segment to use. I have also seen lea rdx, [ds:rax]
notation, which is the same thing as lea rdx, ds:[rax]
, but the problem is lea rdx, [ds:rax*4]
would be semantically misleading, as on x86 you can only do lea rdx, ds:[rax*4]
. I believe that gs:[0x32]
, gs:0x32
and [gs:0x32]
all represent the same thing in x86 assemblies / disassemblies, for instance gs:0x32
does not mean 'get the calculated linear address of gs:0x32
', because we have lea
for that, and gs:[0x32]
does not mean 'get the address at value at ds:[0x32]
and then use that as an offset into gs and get the calculated linear address', therefore the other 2 forms can safely represent [gs:0x32]
, and as mentioned gs:[...]
is more clear as it acts as precedence demarcation when a scale or index is involved