#ifndef INSTRUCTIONS_H #define INSTRUCTIONS_H // Prefixes // Prefix groups are mutually exclusive // Prefix group 1 #define PREFIX_LOCK 0xf0 #define PREFIX_REPNE 0xf2 #define PREFIX_REPNZ PREFIX_REPNE #define PREFIX_REP 0xf3 #define PREFIX_REPE PREFIX_REP #define PREFIX_REPZ PREFIX_REP // Prefix group 2 #define PREFIX_OVERRIDE_SEGMENT_CS 0x2e #define PREFIX_OVERRIDE_SEGMENT_SS 0x36 #define PREFIX_OVERRIDE_SEGMENT_DS 0x3e #define PREFIX_OVERRIDE_SEGMENT_ES 0x26 #define PREFIX_OVERRIDE_SEGMENT_FS 0x64 #define PREFIX_OVERRIDE_SEGMENT_GS 0x65 #define PREFIX_BRANCH_NOT_TAKEN PREFIX_OVERRIDE_SEGMENT_CS #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 // 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). // // 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 // 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 // --------------------+----------------------+--------------------- // 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 // // 0x0F // 0x0F 0x38 // 0x0F 0x3A // 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 #define CMP #define DEC #define DIV #define HLT #define IDIV #define IMUL #define INC #define INT #define INTO #define IRET #define JNZ #define JMP #define LEA #define POP #define PUSH #define RET 0xc3 #define RETN #define SUB #define XOR /*TODO*/ #define SYSCALL 0x0f, 0x05 #endif