summaryrefslogtreecommitdiff
path: root/instructions.h
diff options
context:
space:
mode:
authoronelin <oscar@nelin.dk>2026-06-13 00:01:19 +0000
committeronelin <oscar@nelin.dk>2026-06-13 00:01:19 +0000
commit1c31d1024c227979d5e4df7dd555fa866562c044 (patch)
tree5f00d4f4311f48ad814616c89e2732f57fadbffe /instructions.h
parent9f871ef0e0f27f795f5df7d842c7c205b6faa05f (diff)
Add mov src, dst instructionHEADmaster
Diffstat (limited to 'instructions.h')
-rw-r--r--instructions.h120
1 files changed, 94 insertions, 26 deletions
diff --git a/instructions.h b/instructions.h
index 1623ff0..04f35a3 100644
--- a/instructions.h
+++ b/instructions.h
@@ -23,43 +23,113 @@
#define PREFIX_BRANCH_TAKEN PREFIX_OVERRIDE_SEGMENT_DS
// Prefix group 3
+// sets opsize to 16 bit,
+// if combined with REX.w, set opsize to 64,
+// if only REX.w, then both opsize and address is 64 bit.
#define PREFIX_OVERRIDE_OPSIZE 0x66
// Prefix group 4
+// sets address size to 32 bit.
#define PREFIX_OVERRIDE_ADDRESSSIZE 0x67
-// Instructions
-// Move double-word immediate
-#define MOVBI(reg, imm) (0xb0 + reg), (imm & 0xff)
-#define MOVWI(reg, imm) \
- (0xb8 + reg), (imm & 0xff), ((imm >> 8) & 0xff), ((imm >> 16) & 0xff)
-#define MOVDI(reg, imm) \
- (0xb8 + reg), (imm & 0xff), ((imm >> 8) & 0xff), ((imm >> 16) & 0xff), \
- ((imm >> 24) & 0xff)
-// TODO replace 0x48 with encoding,
-// | 0 1 0 0 | W R X B |
+// Rex prefixes are used when
+// - Using 64-bit operand sizes when default is not 64 bit (eg. rax as opposed
+// to eax),
+// - Using extended registers (R8 to R15, XMM8 to XMM15, YMM8 to YMM15, CR8 to
+// CR15 and DR8 to DR15),
+// - Using one of the uniform byte registers: SPL, BPL, SIL or DIL.
+// Rex prefix
+// [ 0 1 0 0 | W R X B ]
+// W changes operand size to 64 bits
+// R Extension to MODRM.reg field
+// X Extension SIB.index field, 64-bit addressing
+// B Extension to MODRM.rm or SIB.base fields, 64-bit addressing
+#define REX(mode) (0b01000000 | mode)
+#define REX_W 0b1000
+#define REX_R 0b0100
+#define REX_X 0b0010
+#define REX_B 0b0001
+
+// Rex2 prefix (2 bytes
+// [ 1 1 0 1 | 0 1 0 1 ]
+// [ M₀ R₄ X₄ B₄ | W R₃ X₃ B₃ ]
+// W, R₃, X₃, and B₃ are the same as in REX
+// R₄, X₄, and B₄ are used to encode 32 EGPR registers.
+// M0 selects between legacy map 0 (1-byte opcodes, no escape) and legacy
+// map 1 (2-byte opcodes, escape 0x0F).
//
-// 0 1 0 0 -- fixed pattern
-// W -- Set to use 64-bit operands,
-// R -- extension to MODRM.reg field, registers
-// X -- extension to SIB.index field, 64-bit addressing
-// B -- extension to MODRM.rm or SIB.base field, 64-bit addressing
-#define MOVABS(reg, imm) 0x48, MOVD(reg, imm)
-#define MOVQ(reg, imm) 0x48, 89 c8
+// Opcodes that default to 64bit in long mode (and does therefore not need REX
+// prefixes) are:
+// CALL (near), ENTER, Jcc, JrCXZ, JMP (near), LEAVE, LGDT, LIDT, LLDT, LOOP,
+// LOOPcc, LTR, MOV CR(n), MOV DR(n), POP reg/mem, POP reg, POP FS, POP GS,
+// POPFQ, PUSH imm8, PUSH imm32, PUSH reg/mem, PUSH reg, PUSH FS, PUSH GS,
+// PUSHFQ, and RET (near).
+#define REX2(mode) REX(REX_R | REX_B), mode
+#define REX2_W REX_W
+#define REX2_R REX_R
+#define REX2_R3 REX_R
+#define REX2_X REX_X
+#define REX2_X3 REX_X
+#define REX2_B REX_B
+#define REX2_B3 REX_B
+#define REX2_M 0b10000000
+#define REX2_R4 0b01000000
+#define REX2_X4 0b00100000
+#define REX2_B4 0b00010000
-#define MODRM(mod, reg, rm) (((mod & 3) << 6) | ((reg & 7) << 3) | (rm & 3))
-// MOD REG RM (r/m = register/memory)
-// 1 1 | 1 0 1 | 1 0 1
+// MODR/M
+// MOD REG RM (r/m = register/memory)
+// [ 1 1 | 1 0 1 | 1 0 1 ]
// if mod == 0b11, then treat r/m as register,
// (examples in OP SRC DST ordering (same as the reg-rm order)
-// gas/at&t ASM => op reg-idx reg-idx => MOD | REG | RM
+// gas/at&t ASM => op reg-idx reg-idx => MOD | REG | RM
// --------------------+----------------------+---------------------
-// ie "xor %rcx, %rcx" => XOR 1 1 => 1 1 | 0 0 1 | 0 0 1
-// ie "xor %rsi, %rbp" => XOR 6 5 => 1 1 | 1 0 1 | 1 1 0
+// ie "xor %rcx, %rcx" => XOR 1 1 => [ 1 1 | 0 0 1 | 0 0 1 ]
+// ie "xor %rsi, %rbp" => XOR 6 5 => [ 1 1 | 1 0 1 | 1 1 0 ]
//
// Other combinations of MOD means RM specifies an addressing mode.
// For 64bit systems:
//
+// "disp" is displacement specified in `mod` bits.
+#define MODRM(mod, reg, rm) (((mod & 3) << 6) | ((reg & 7) << 3) | (rm & 7))
+
+// SIB (Scale, Index, Base)
+// [ S S | I I I | B B B ]
+// S S: equals 2^SIB.index, eg. 1, 2, 4, 8
+// I I I: index register to use. REX.X, VEX.~X, and XOP.~X expands this with 1
+// most significant bit. B B B: base register to use. REX.B, VEX.~B, and XOP.~B
+// expands this with 1 most significant bit. Same layout as MODRM, could as well
+// as define it as MODRM(scale, index, base)
+#define SIB(scale, index, base) \
+ (((scale & 3) << 6) | ((index & 7) << 3) | (base & 7))
+
+// Opcode encoding
+// <op>
+// 0x0F <op>
+// 0x0F 0x38 <op>
+// 0x0F 0x3A <op>
+
+// Instructions
+// Move immediates
+#define MOVBI(reg, imm) (0xb0 + reg), (imm & 0xff)
+#define MOVWI(reg, imm) \
+ PREFIX_OVERRIDE_OPSIZE, (0xb8 + reg), (imm & 0xff), ((imm >> 8) & 0xff)
+#define MOVDI(reg, imm) \
+ (0xb8 + reg), (imm & 0xff), ((imm >> 8) & 0xff), ((imm >> 16) & 0xff), \
+ ((imm >> 24) & 0xff)
+#define MOVQI(reg, imm) \
+ REX(REX_W), MOVDI(reg, imm), ((imm >> 32) & 0xff), ((imm >> 40) & 0xff), \
+ ((imm >> 48) & 0xff), ((imm >> 56) & 0xff)
+#define MOVABS(reg, imm) MOVQI(reg, imm)
+
+// Move registers
+#define MOVB(src, dst) (0x88), MODRM(0b11, src, dst)
+#define MOVW(src, dst) PREFIX_OVERRIDE_OPSIZE, (0x89), MODRM(0b11, src, dst)
+#define MOVD(src, dst) (0x89), MODRM(0b11, src, dst)
+#define MOVQ(src, dst) REX(REX_W), MOVD(src, dst)
+
+#define ADDBIC(reg, imm) (0x10 + reg), (imm & 0xff)
+#define ADDBIC(reg, imm) (0x10 + reg), (imm & 0xff)
#define ADD
#define CALL
@@ -78,13 +148,11 @@
#define LEA
#define POP
#define PUSH
-#define RET 0xc3
+#define RET 0xc3
#define RETN
#define SUB
#define XOR /*TODO*/
#define SYSCALL 0x0f, 0x05
-#define REX(mode) (0b01000000 | mode)
-
#endif