22

The general form for memory addressing in Intel and AT&T Syntax is the following:

[base + index*scale + disp]      # Intel, including GAS .intel_syntax noprefix
disp(base, index, scale)         # AT&T

My questions are the following:

  • Can base and index be any register?
  • What values can scale take, is it 1, 2, 4 and 8 (with 1 being the default)?
  • Are index and disp interchangeable (with the only difference being that index is a register while disp is an immediate value)?
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    Related: [What is the meaning of MOV (%r11,%r12,1), %edx?](//stackoverflow.com/q/2883850) – Peter Cordes Feb 07 '20 at 05:54
  • 2
    Also some AT&T addressing mode examples in https://stackoverflow.com/tags/att/info – Peter Cordes Apr 11 '20 at 15:01
  • Somewhat related: [Referencing the contents of a memory location. (x86 addressing modes)](https://stackoverflow.com/q/34058101) for more about different subsets of the general form and when you might use them. – Peter Cordes Aug 25 '20 at 04:29

1 Answers1

17

This is described in Intel's manual:

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.
  • Base — The value in a general-purpose register.
  • Index — The value in a general-purpose register. [can't be ESP/RSP]
  • Scale factor — A value of 2, 4, or 8 that is multiplied by the index value.

The offset which results from adding these components is called an effective address.

The scale-factor is encoded as a 2-bit shift count (0,1,2,3), for scale factors of 1, 2, 4, or 8. And yes, *1 (shift count = 0) is the default if you write (%edi, %edx); that's equivalent to (%edi, %edx, 1)


In AT&T syntax, it's disp(base, index, scale) - constants go outside the parens. Some Intel-syntax assemblers also allow syntax like 1234[ebx], others don't. But AT&T syntax is rigid; every component of the addressing mode can only go in its proper place. For example:

movzwl  foo-0x10(,%edx,2), %eax

does a zero-extending 16-bit ("word") load into EAX, from the address foo-0x10 + edx*2. EDX is the index register, with scale-factor 2. There is no base register. foo and -0x10 are both part of the displacement, both link-time constants. foo is a symbol address that the linker will fill in and subtract 0x10 from (because of the -0x10 assemble-time offset).

If you have the choice, use just a base instead of an index with a scale of 1. An index requires a SIB byte to encode, making the instruction longer. That's why compilers choose addressing modes like 8(%ebp) to access stack memory, not 8(,%ebp).

See also Referencing the contents of a memory location. (x86 addressing modes) for more about when you might use a base, and/or index, and/or displacement.


A 16-bit displacement is only encodeable in a 16-bit addressing mode, which uses a different format that can't include a scale factor, and has a very limited selection of which registers can be a base or index.

So a mode like 1234(%edx) would have to encode the 1234 as a 32-bit disp32 in 32-bit machine code.

Byte offsets from -128 .. +127 can use a short-form 8-bit encoding. Your assembler will take care of this for you, using the shortest valid encoding for the displacement.


All of this is identical in 64-bit mode for 64-bit addressing modes, with disp32 also being sign-extended to 64-bit just like disp8.

64-bit mode does add a new different addressing mode, symbol(%rip) which doesn't work with any general-purpose registers, only a 32-bit offset from RIP. See How do RIP-relative variable references like "[RIP + _a]" in x86-64 GAS Intel-syntax work? which also covers AT&T syntax.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Michael
  • 57,169
  • 9
  • 80
  • 125
  • I'm still not exactly sure what is a general purpose register, are all of the following considered to be general purpose registers: EAX, EBX, ECX, EDX, ESI, EDI, EBP, and ESP? –  Jan 14 '15 at 07:03
  • Yes (except `ESP` is excluded from the Index part). See figure 3-11 (_"Offset (or Effective Address) Computation"_) in the manual. – Michael Jan 14 '15 at 07:04
  • 4
    Let's mention one more minor difference between *base* and *index*: when EBP or ESP is used as *base* register, default segment is SS, otherwise it is DS. MOV EAX,[EDI+EBP] loads EAX from data segment but MOV EAX,[EBP+EDI] from stack segment. Nevertheless, in Window flat model it doesn't matter, as both DS and SS contain the same segment descriptor. – vitsoft Jan 14 '15 at 11:34
  • In Long mode, what differences are there? – Paul Stelian Jan 24 '18 at 14:37
  • @PaulStelian: See [Referencing the contents of a memory location. (x86 addressing modes)](https://stackoverflow.com/questions/34058101/referencing-the-contents-of-a-memory-location-x86-addressing-modes/34058400#34058400) for how addressing modes work, including 64-bit mode. – Peter Cordes Mar 24 '18 at 20:36