diff options
| -rw-r--r-- | instructions.h | 120 | ||||
| -rw-r--r-- | main.c | 5 | ||||
| -rw-r--r-- | tiny.s | 5 |
3 files changed, 100 insertions, 30 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 @@ -2,8 +2,9 @@ #include "registers.h" #include "write_elf.c" -static const unsigned char some_opcodes[] = {MOVDI(REG_EAX, 0x3c), - MOVDI(REG_EDI, 0x41), SYSCALL}; +static const unsigned char some_opcodes[] = { + MOVWI(REG_EAX, (long)0x41), MOVQ(REG_EAX, REG_EDI), + MOVDI(REG_EAX, (long)0x3c), SYSCALL}; static const unsigned int some_opcodes_len = sizeof(some_opcodes) / sizeof(some_opcodes[0]); @@ -4,8 +4,9 @@ section .text _start: ; 60 = syscall exit - mov eax, ecx + xor rax, rax + mov ax, 0x1 ; rdi is exit code - mov rdi, 0x41 + mov edi, 0x41 syscall |
