6

I am reading the Intel x86_64 guide vol.1 to refresh how memory addressing works.

Still,

3.7.5 Specifying an Offset

The offset part of a memory address can be specified directly as a static value (called a displacement) or through an address computation made up of one or more of the following components:

• Displacement — An 8-, 16-, or 32-bit value.

I read in Agner Fog's assembly guide that 64-bit absolute addressing was possible when used with (r/e)ax register.

So..

Is it possible, or not, to use absolute addressing with 64 bits addresses to jmp, mov and call (with all the registers), or will I have to keep using the Base + displacement combo?

Kroma
  • 1,109
  • 9
  • 18

3 Answers3

4

Note that mov absolute_addr64, %rax is only available with rax as the target.
mov $imm64, %reg is available for any register.
See Load from a 64-bit address into other register than rax, and why we can't move a 64-bit immediate value to memory?

When AMD designed the AMD64 architecture, they basically said 2GB of code should be enough for everyone. (Per executable and per shared library; calls between things that aren't statically linked together typically need indirection through a full 64-bit address anyway.)

https://gitlab.com/x86-psABIs/x86-64-ABI describes the small, medium, and large code models for the x86-64 System V ABI (used on everything non-Windows.)

  • small: normal 32bit relative displacements for every jump, call, and memory displacement. (All symbols are known to be located between 0 and 2^31 - 2^24 - 1).

  • medium: small code, but the data section is split into two parts: regular and large (.ldata, lrodata, .lbss).

This model requires the compiler to use movabs instructions to access large static data and to load addresses into registers, but keeps the advantages of the small code model for manipulation of addresses in the small data and text sections (specially needed for branches)

By default only data larger than 65535 bytes will be placed in the large data section

  • large:

The compiler is required to use the movabs instruction, as in the medium code model, even for dealing with addresses inside the text section. Additionally, indirect branches are needed when branching to addresses whose offset from the current instruction pointer is unknown.

It is possible to avoid the limitation on the text section in the small and medium models by breaking up the program into multiple shared libraries, so this model is strictly only required if the text of a single function becomes larger than what the medium model allows.

Medium PIC needs to movabs / lea / add to generate RIP-relative addresses with larger than 32bit displacements.

Large PIC needs that for addressing the global offset table and procedure linkage table, too.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
3

Only the move to and from accumulator has a 64 bit absolute address variant.
All other moves are limited to the 32 bit displacement methods.

Fifoernik
  • 9,779
  • 1
  • 21
  • 27
  • The `mov , rax` and `mov rax, ` are not really _displacements_ like the other addressing modes. It is absolute within the specified segment. It is used in Linux to access data in the `FS` segment. For the data segment, your program needs a relocation (i.e. it is not PIC compatible). Actually, the GNU disassembler uses the `movabs` instruction (i.e. move absolute—not relative). – Alexis Wilke Mar 12 '23 at 15:22
1

I don't think the x86 architectures have 64 bit displacements or offsets.

The reason is simple: the "ease" of programming these provide, doesn't occur often enough to matter. Statistically, most of the offsets you need are pretty small. When you need the 64 bit offset (very rarely) you can always simulated with an ADD instruction at virtually no performance penalty. The transistors to do 64 bit offsets, are better spent doing something else.

Ira Baxter
  • 93,541
  • 22
  • 172
  • 341
  • An add instruction? Interesting, how would you do that? I doubt I will do it because it incurs another instruction, even a 1 cpu cycle one, which is a waste. – Kroma Aug 06 '15 at 11:25
  • 1
    If you want to do an indexed operation with a 64 bit displacement, you have to add the displacement to the base. So, base in a register, add 64 bit constant, followed by indirect load or store of the target address. In more specialized cases where the 64 bit value is a direct address, you can simply load it into a register and then do the indirection. Yes, it costs an extra instruction to do the ADD. In practice, you won't do this very often so it doesn't matter. – Ira Baxter Aug 06 '15 at 13:03
  • Ok, Thanks a lot for your precision – Kroma Aug 06 '15 at 14:18
  • 1
    I don't think you can add a 64 bit immediate value, but you could add a 64 bit value stored in memory, or move a 64 bit immediate value into a register, then use that register as part of the address. I'm wondering about the offsets when segments are used, such as FS or GS for accessing "per thread" variables. The seed value for rand is one of these. – rcgldr Aug 07 '15 at 07:21
  • 1
    @rcgldr: that's correct, even `add $immediate, %rax` is only available with a sign-extended `imm32`. If you want your constant inline in the instruction stream, rather than loaded as data, you can `movabs $imm64, %rax`. (http://stackoverflow.com/questions/19415184/load-from-a-64-bit-address-into-other-register-than-rax). Best plan: keep your 64b displacement in a register, calculate an index in another reg, and use the index as the dest / 1st src for an `add`. – Peter Cordes Aug 09 '15 at 07:01