x86/x64 Add Displacement addressing

11,200

Solution 1

There are a few different forms of indirect operands in x86:

  1. [reg]
  2. [reg + displacement]
  3. [displacement]
  4. [reg * constant + reg]
  5. [reg * constant + reg + displacement]

The "displacement" is just a constant that gets added to the rest of the address. In cases where there is no component of the address other than the constant, it is still called a "displacement". This is mainly for consistency with the other addressing forms.

Another way to look at it is that all addresses are of the form

[reg * constant + reg + displacement]

With each of the components allowing a value of 0.

The [displacement] form is just the encoding where all components other than the displacement are zero.

As a compiler writer the last 2 forms are particularly interesting. They make it easy to encode things like pArray[index]->field + 1in a single instruction.

Solution 2

There is no "special add that takes a displacement", that page is being unnecessarily confusing - this is just part of the normal memory operand encoding.

add is a fairly standard instruction that is encoded the same way as all the alu-ops are: there is a special case for using al as destination and an immediate as the source (04 ib), using ax/eax/rax as the destination and an immediate as the source (+ 05 imm), three versions of add r/m, imm (one for 8bit destinations, one for wider destinations and a sign-extended 8bit source, one for wider destinations and a wide source), and of course an add r, r/m and add r/m, r.

This is just a special case of add r, r/m, where the r/m takes the form of a displacement: see note #1 of ModRM encoding.

So they just mean add edx, [sdword]. (but they misencoded the reg field, edx corresponds to 010, not 011)

Solution 3

That page is not accurate. The "add that takes a displacement" which it's talking about refers to the form add r[16|32], r/m[16|32] or add edx, [0xdisp] as you might see it in a disassembler's output. Assuming it's talking about the ADD instruction with opcode 0x03,

  • Encoding the edx register destination and specifying a 32-bit displacement as effective address in the ModR/M byte would give it the value of 0x15 (refer to the Intel® 64 and IA-32 Architectures Software Developer’s Manual Vol. 2, page 41, table 2-2).
  • The effect of this instruction is to add the dword at the memory address disp to the contents of edx.
  • The actual encoding of the instruction would thus be: \x03\x15\x00\x00\x00\x01, for a displacement of 1 byte.
Share:
11,200
Ryan Brown
Author by

Ryan Brown

Updated on July 29, 2022

Comments

  • Ryan Brown
    Ryan Brown almost 2 years

    I'm writing a compiler for x86/x64 CPU instructions and I can't seem to figure out what people mean by 'displacement' address. For example the Add instruction is detailed here: http://www.c-jump.com/CIS77/CPU/x86/X77_0150_encoding_add_edx_displacement.htm

    I'm just trying to implement the add instruction where a register is added to a normal memory address. The problem is, the address is a 'displacement address'. Does that mean the address is a signed value that's the offset from the instruction location?

  • Ryan Brown
    Ryan Brown over 11 years
    So to add say AL (8 bit register 0) to the memory location 0x00000000, the CPU would accept (in hex) 00 05 00000000?
  • Ryan Brown
    Ryan Brown over 11 years
    Ok so how does [reg * constant + reg + displacement] get encoded into a machine instruction? Say I have an array at memory location 0x00000001 and I want to access the index of it which is AL. I guess I want to use the move instruction and do MOV AH 0x00000001[AL]. I think that's just [reg+displacement]. Section 6 of this page shows encoding the R/M byte but it's really confusing: c-jump.com/CIS77/CPU/x86/lecture.html
  • Scott Wisniewski
    Scott Wisniewski over 11 years
    Take a look at volume 2 of the intel manual. Each instruction specifies its encoding forms. Encoding forms that list r/m operands accept register or memory operands in the mod/rm byte.
  • Scott Wisniewski
    Scott Wisniewski over 11 years
    Take a look at volume 2 of the intel manual. Each instruction specifies its encoding forms. Encoding forms that list r/m operands accept register or memory operands in the mod/rm byte. In chapter 2 of volume 2, section 2.1 there is a table that shows the meaning of the mod r/m byte. The forms that have [--][--] listed denote an encoding that uses the SIB byte. SIB addressing is of the form regconstant + reg. Some forms of the mod/rm byte indicate that the SIB byte is followed by a displacement. Those gives the regconstant + reg + constant forms. There is a table explaining SIB as well.
  • Ryan Brown
    Ryan Brown over 11 years
    Oh ok thanks! I'm also reading that on 64-bit processors the displacement address is still 32 bits?? So on anything larger you have to load it into a register to read it?
  • Bulat M.
    Bulat M. over 7 years
    @Scott, Could one use register as a displacement? While assembling lea %rax(%r12), %r14 gcc spits Error: junk (%r12) after register.
  • Scott Wisniewski
    Scott Wisniewski over 7 years
    No. It wouldn't be a "displacement" if it was a register. The displacement is a constant that follows the modrm byte. You can use the sum of 2 registers though. Take a look at the intel manual.