1

I'm am trying to understand machine code memory addressing for x86, and I've encountered two opposing general forms for addressing (using the ModRM and SIB bytes).

Most unofficial resources I consult suggest memory addressing is done in a subset of the general form [register1 + scale * register2 + displacement]. An example would be [EAX+disp8] for some 8 bit displacement. Example resources are:

https://cs.nyu.edu/courses/fall10/V22.0201-002/addressing_modes.pdf

http://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing

But consulting the intel manual (Vol.2A, 2.1.5) it looks like the general form is instead [register1] + [scale * register2] + displacement. For example, in the left column of Table 2-2, it shows [EAX]+disp8. The notes at the bottom of the table suggest the same.

So which general form is correct? The first form yields an value in memory. The second form yields a memory address, but does so by first accessing other values in memory.

Keeping it mind that the [] operator is not distributive, that is [register1 + register2] !== [register1]+[register2], the two general forms are not identical. I imagine the first form is correct and I am not interpreting intel's manual correctly.

1

I'm looking at the addressing mode table, and it says ~:

[register1] + [register2*scale] + [displacement]

Despite the usual meaning of []s, there is no way that the above means the memory contents addressed individually by each of

  • register1
  • register2 * scale
  • displacement

Ok, register1 may hold a valid memory address, but register2 * scale (in general) doesn't make a valid memory address, nor does displacement (if it is a small displacement, like 8 or 16 bits).

So, within this particular text, we have to assume the []s don't mean memory references, and are just like regular parenthesis.

The processor offers a memory address computed by r1 + r2 * scale-constant + disp-constant. The computation of the address does not involve reading/writing (data) memory, it is just using the values within the registers (and using values of instruction bytes for the displacement).

That computed memory address is then dereferenced according to the instruction opcode — that address may be read from, written to, or both (though for LEA (Load Effective Address), only the address is used, not the memory contents there).

4
  • Your logic of assumption makes sense. I'm still surprised intel would choose this misleading notation. Thanks. – Joseph Johnston Jun 6 '17 at 17:47
  • Intel's syntax in their manuals has always been a little off-the-wall. This is why I've always preferred working from the manuals provided with assemblers, as they can generally be relied on to provide consistent explanations of everything. – Jules Jun 7 '17 at 1:14
  • Also, note that [...] doesn't consistently mean memory dereferencing in any case, due to the special case of the LEA instruction: for example, LEA eax, [eax + 4*ecx] means to multiply ecx by 4, add eax to it, and store the resulting value in eax... no memory access is performed at all. – Jules Jun 7 '17 at 1:18
  • True. Though the notation [] would actually be consistent with LEA, as this opcode, Load Effective Address, is like taking the address in C/C++ (say as in: p = & a[i], where we compute a[i] and then take its address not its value). In other words, the operand of LEA is a memory location just like for MOV, the difference being that for any other opcode the memory would be accessed (read or written or both) to make the resulting value, whereas for LEA just the memory address itself is the result. I have updated my answer at the end for this! – Erik Eidt Jun 7 '17 at 1:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.