4 ms·
> There’s one exception to this: x86_64 allows for a 64-bit displacement with the a* registers. I don't think the example for this (https://gcc.godbolt.org/z/3
by haberman 6y ago
> There’s one exception to this: x86_64 allows for a 64-bit displacement with the a* registers.
I don't think the example for this (https://gcc.godbolt.org/z/35ytYW https://gcc.godbolt.org/z/35ytYW) is correct.
The highlighted instruction ("movabs rax, offset x") is not a load, it's just moving the address of x into rax. The "offset x" operand is a 64-bit immediate (not a displacement). It will be resolved to the address of x with a relocation.
Indeed, you can get the compiler to emit this form of "movabs" into other registers, which contradicts the point that 64-bit displacements are a* specific: https://godbolt.org/z/3MYTUC https://godbolt.org/z/3MYTUC
To get a load or store to a 64-bit displacement, I think you want something like this: https://godbolt.org/z/4QMtpo https://godbolt.org/z/4QMtpo
- woodruffw 6y agoWhoops! You’re absolutely right. I’ll fix that in a bit.
- haberman 6y agoCool. :) Nice article btw. I noticed a few other things in the section about segments: > The good news is that caring about them isn’t too bad: they essentially boil down to adding the value in the segment register to the rest of the address calculation. Surprisingly, the segment register's value isn't added directly (my coworker and I discovered this recently). The segment bases are stored in model-specific registers, and I don't believe these are readable from user-space. https://en.wikipedia.org/wiki/X86_memory_segmentation#Later_developments https://en.wikipedia.org/wiki/X86_memory_segmentation#Later_... If you try to read %fs directly, you'll get a completely unrelated value (an offset into table I think?) Another surprising and unfortunate thing is that segment-qualified addresses don't work with lea. That means getting the address of a thread-local unfortunately is not as simple as "lea rax, fs:[var]." You actually have to do a load to get the base address of the thread-local block (eg. fs:0). The first pointer in the thread-local block is reserved for this. That's why this function has to do a load before the lea: https://godbolt.org/z/jkt28n https://godbolt.org/z/jkt28n
- woodruffw 6y agoThanks for the kind words! And yep! I need to make the language around the segment registers more precise: if I'm remembering right, the segment value itself gives you the GDT index (maybe only in 32-bit mode?), which you can then pull from. For 64-bit modes I think those values essentially become nonsense because of the fsbase/gsbase MSRs, as you mentioned :-)
- cesarb 6y agoIf I recall correctly, at least on 32-bit mode the segment registers were a 13-bit offset into either the GDT or the LDT (so a maximum of 8192 entries on each), 1 bit to choose between the GDT and the LDT, and 2 bits for the protection ring. The base and limit (and other details) were loaded from the GDT/LDT when the segment register was loaded; the undocumented SAVEALL/LOADALL instructions could save and load the "hidden" base/limit/etc directly, leading to tricks like the "unreal mode".