r/m32
and reg32
are operand specifications. The first means a 32-bit register or memory operand, the second is a 32-bit register. Section B.1 Key to operand specifications
of that page you link to explains this:
Registers: reg8 denotes an 8-bit general purpose register, reg16 denotes a 16-bit general purpose register, and reg32 a 32-bit one. fpureg denotes one of the eight FPU stack registers, mmxreg denotes one of the eight 64-bit MMX registers, and segreg denotes a segment register. In addition, some registers (such as AL, DX or ECX) may be specified explicitly.
Memory references: mem denotes a generic memory reference; mem8, mem16, mem32, mem64 and mem80 are used when the operand needs to be a specific size. Again, a specifier is needed in some cases: DEC [address] is ambiguous and will be rejected by NASM. You must specify DEC BYTE [address], DEC WORD [address] or DEC DWORD [address] instead.
Register or memory choices: many instructions can accept either a register or a memory reference as an operand. r/m8 is a shorthand for reg8/mem8; similarly r/m16 and r/m32. r/m64 is MMX-related, and is a shorthand for mmxreg/mem64.
Similarly, section B.2 Key to opcode descriptions
shows how the opcode/operands are encoded:
The codes o16 and o32 indicate that the given form of the instruction should be assembled with operand size 16 or 32 bits. In other words, o16 indicates a 66 prefix in BITS 32 state, but generates no code in BITS 16 state; and o32 indicates a 66 prefix in BITS 16 state but generates nothing in BITS 32.
That explains the o32
.
A hex number, such as 3F, indicates a fixed byte containing that number.
That covers the 39
, a fixed opcode.
The code /r ... indicates that one of the operands is a memory address or r/m, and another is a register, and that an effective address should be generated with the spare (register) field in the ModR/M byte being equal to the `register value' of the register operand.
And that details how the other operands are stored, though it's not a simple process since there's usually some bit fiddling required. I'd suggest following the links given in that section to the sections detailing how effective addresses and registers are encoded.
The [386]
is the level at which the opcode/operand set was introduced.
If you really want to understand the encoding, assemble a few different variations of the cmp
statement, and have a look at the machine code they generate. Then try to disassemble them back into source code using sections B.1
, B.2
, B.2.1
and B.2.5
.
That will hopefully greatly speed your understanding of how it works.