Okay so I have been studying Chapter 2 of Volume 2 of the Intel Manuals.
I have as best an understanding as I can get of the ModR/M byte, the REX byte, the SIB byte, and the general instruction encoding (by just reading with no practice or practical tinkering yet). Now, from my understanding, the "instruction" encoding is different from the whole "call" encoding (as I would call it): that is, the instruction plus the operands. That took me days to realize, and I'm still not certain of it.
So I am going to try to apply my knowledge now on these 4 types of calls.
opcode instruction operand encoding
04 ib ADD AL, imm8 I
REX + 80 /0 ib ADD r/m8*, imm8 MI
00 /r ADD r/m8, r8 MR
REX.W + 03 /r ADD r64, r/m64 RM
First some background:
ib
is an unsigned byte- imm[digit] is an immediate value
- capital letters in the instruction are registers
- the operand encoding letters are for referencing the lookup table in the docs, that's it.
- r/m[digit] means register or memory bytes
- r[digit] means only register bytes
Looking at the "Instruction Operand Encoding" table, I see this:
operand encoding operand 1 operand 2
RM ModRM:reg (r, w) ModRM:r/m (r)
MR ModRM:r/m (r, w) ModRM:reg (r)
MI ModRM:r/m (r, w) imm8
I AL/AX/EAX/RAX imm8
- The (r) means the operand is read.
- The (w) means the operand is written to.
So I see those "operand encoding" strings like MR
. That gives me 00 /r
from the example instructions. So we have two hex values, 00
, and then there's the /r
. I have re-read it's meaning a dozen times but still don't know what it means.
I have thought a lot about all of the above parts, but it just feels like something is missing. I can't piece it together to apply this knowledge yet.
So already I am lost. I just studied the ModRM, reg, and r/m stuff, but I don't know what they mean here. Going back and rereading.
The ModR/M byte is an addressing-form specifier byte. It is divided into 3 parts or "fields".
- The mod field combines with the r/m field to form 32 possible values: eight registers and 24 addressing modes.
- The reg/opcode field specifies either a register number or three more bits of opcode information. The purpose of the reg/opcode field is specified in the primary opcode.
- The r/m field can specify a register as an operand or it can be combined with the mod field to encode an addressing mode.
We don't have to deal with the SIB codes in this question.
That doesn't really give me any actionable information. Then there are the rich tables of every value the ModR/M byte takes up in tables 2-1 through 2-3. I am not really sure how the columns and rows line up and what they mean yet.
So, I don't know how to write down those 4 examples of instructions into opcodes, even if I were to select registers or memory addresses for them at random.
Skipping to section 3.1.1.1, I have studied all of the keywords there too.
- REX.W — Indicates the use of a REX prefix that affects operand size or instruction semantics.
- /digit — A digit between 0 and 7 indicates that the ModR/M byte of the instruction uses only the r/m (register or memory) operand. The reg field contains the digit that provides an extension to the instruction's opcode.
- /r — Indicates that the ModR/M byte of the instruction contains a register operand and an r/m operand.
Those 3 are relevant for the instructions above.
Then there is "Table 3-1. Register Codes", which I think shows you something about what the decimal/binary value is of each register, which is useful somewhere in this equation.
That's pretty much it on what I need to know. Everything else in this book seems to be the individual instruction details, or the advanced instruction info which I don't care about yet (like VEX
).
But I've read this stuff about 5 times through so far and I still don't have a solid understanding of how to write 1 instruction call yet, for the goal of writing a machine code generator without using gcc/clang/llvm/etc..
I see this image too, but don't know what to do with it entirely yet.
How do you write these 4 example x86 assembly instructions in opcodes, according to the Intel docs? How do I interpret the "operand encoding" values in the table above? Say we select some random registers or slots of memory that fit the instruction type constraints above, then how do you figure out how to write it down into hex code using the Intel Manuals?