When I run mov ds,rax
, it will throw error Program terminated with signal SIGSEGV, Segmentation fault
What's wrong with the assembly code?
global main
main:
mov rax,0ffffH
mov ds,rax
mov rbx,6
ret
mov
to a segment register loads the internal segment base/limit / permissions stuff from the GDT (Global Descriptor Table). (The base and limit are treated as 0 / -1 respectively in 64-bit mode, but mov
to a segment register still has a real effect and still checks stuff. You can't just expect arbitrary values to not cause problems.)
According to Intel's manual for mov
, mov Sreg, r/m
faults with #GP(selector)
if the "segment selector index" (index into the GDT or LDT) "is outside the descriptor table limits".
Linux delivers SIGSEGV if user-space causes an invalid page fault, or any kind of #GP
exception.
Since bit 2 is set (1<<2
), this is indexing into the LDT (Local Descriptor Table), not GDT. There probably isn't an LDT at all for your process if you didn't ask your OS (Linux?) to create one, e.g. with a modify_ldt()
system call.
If you cleared that bit (mov eax, 0xfffb
), it still faults on my Linux desktop. From that we can infer that Linux didn't configure a GDT that large. There's no reason to expect it would; it only needs a handful of segment descriptors for normal operation. e.g. if you use info reg
, you can see the segment register values are:
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(0
works as a "null selector" that has a special meaning of keeping x86-64's minimal remnants of segmentation happy; it's not actually descriptor privilege level 0 (a kernel-only data segment) even though the low 2 bits are 00
. The low bits of cs
are the expected 11
(ring 3 = user-space).)
Other possible reasons for exceptions include: "If the DS, ES, FS, or GS register is being loaded and the segment pointed to is not a data or readable code segment."
I'm assuming you don't actually know much about segmentation, and I'm not trying to explain how to actually use segment registers. The point I'm trying to make is that you can't just use ds
as 16 bits of scratch space for arbitrary integer data.
If you want to know in more detail exactly what you can and can't put in ds
, read Intel's manuals. And the kernel source to see how it configures its GDT and LDT, or make a modify_ldt()
system call.