From 19fa2ff620ef31152f4449bb2ec1ef77a0e4b9c4 Mon Sep 17 00:00:00 2001 From: inglorion Date: Mon, 5 May 2008 17:00:12 +0200 Subject: [PATCH] Initial import. --- Makefile | 18 + Makefile.cfg | 1 + include/alchemist/x86.h | 227 +++++++ x86/Makefile | 17 + x86/Makefile.cfg | 1 + x86/lib/Makefile | 28 + x86/lib/x86.c | 1740 +++++++++++++++++++++++++++++++++++++++++++++++ x86/test/Makefile | 21 + x86/test/exit42.c | 43 ++ x86/test/test.c | 311 +++++++++ 10 files changed, 2407 insertions(+) create mode 100644 Makefile create mode 100644 Makefile.cfg create mode 100644 include/alchemist/x86.h create mode 100644 x86/Makefile create mode 100644 x86/Makefile.cfg create mode 100644 x86/lib/Makefile create mode 100644 x86/lib/x86.c create mode 100644 x86/test/Makefile create mode 100644 x86/test/exit42.c create mode 100644 x86/test/test.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dce0c3e --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +SUBDIRS = x86 + +lib : + for dir in $(SUBDIRS); do (cd "$$dir" && $(MAKE) lib); done + +all : + for dir in $(SUBDIRS); do (cd "$$dir" && $(MAKE) all); done + +clean : + for dir in $(SUBDIRS); do (cd "$$dir" && $(MAKE) clean); done + +distclean : + for dir in $(SUBDIRS); do (cd "$$dir" && $(MAKE) distclean); done + +test : + for dir in $(SUBDIRS); do (cd "$$dir" && $(MAKE) test); done + +.PHONY : all clean distclean lib test diff --git a/Makefile.cfg b/Makefile.cfg new file mode 100644 index 0000000..eef3e91 --- /dev/null +++ b/Makefile.cfg @@ -0,0 +1 @@ +VERSION = 0 diff --git a/include/alchemist/x86.h b/include/alchemist/x86.h new file mode 100644 index 0000000..8120e77 --- /dev/null +++ b/include/alchemist/x86.h @@ -0,0 +1,227 @@ +#include + +struct cg_x86_mem; +struct cg_x86_arg; +struct cg_x86_instr; + +#define CG_X86_ARGTYPE_IMM8 1 +#define CG_X86_ARGTYPE_IMM16 2 +#define CG_X86_ARGTYPE_IMM32 3 +#define CG_X86_ARGTYPE_REG8 4 +#define CG_X86_ARGTYPE_REG16 5 +#define CG_X86_ARGTYPE_REG32 6 +#define CG_X86_ARGTYPE_MEM8 7 +#define CG_X86_ARGTYPE_MEM16 8 +#define CG_X86_ARGTYPE_MEM32 9 + +#define CG_X86_OP_ADD 1 +#define CG_X86_OP_ADC 2 +#define CG_X86_OP_AND 3 +#define CG_X86_OP_CALL 4 +#define CG_X86_OP_CLC 5 +#define CG_X86_OP_CLD 6 +#define CG_X86_OP_CLI 7 +#define CG_X86_OP_CMP 8 +#define CG_X86_OP_DEC 9 +#define CG_X86_OP_DIV 10 +#define CG_X86_OP_HLT 11 +#define CG_X86_OP_IDIV 12 +#define CG_X86_OP_IMUL 13 +#define CG_X86_OP_IN 14 +#define CG_X86_OP_INC 15 +#define CG_X86_OP_INSB 16 +#define CG_X86_OP_INSD 17 +#define CG_X86_OP_INSW 18 +#define CG_X86_OP_INT 19 +#define CG_X86_OP_INT1 20 +#define CG_X86_OP_INT3 21 +#define CG_X86_OP_INTO 22 +#define CG_X86_OP_IRET 23 +#define CG_X86_OP_IRETD 24 +#define CG_X86_OP_IRETW 25 +#define CG_X86_OP_JA 26 +#define CG_X86_OP_JB 27 +#define CG_X86_OP_JCXZ 28 +#define CG_X86_OP_JECXZ 29 +#define CG_X86_OP_JG 30 +#define CG_X86_OP_JL 31 +#define CG_X86_OP_JNA 32 +#define CG_X86_OP_JNB 33 +#define CG_X86_OP_JNG 34 +#define CG_X86_OP_JNL 35 +#define CG_X86_OP_JNO 36 +#define CG_X86_OP_JNP 37 +#define CG_X86_OP_JNS 38 +#define CG_X86_OP_JNZ 39 +#define CG_X86_OP_JO 40 +#define CG_X86_OP_JP 41 +#define CG_X86_OP_JS 42 +#define CG_X86_OP_JZ 43 +#define CG_X86_OP_JMP 44 +#define CG_X86_OP_LDS 45 +#define CG_X86_OP_LES 46 +#define CG_X86_OP_LFS 47 +#define CG_X86_OP_LGS 48 +#define CG_X86_OP_LSS 49 +#define CG_X86_OP_LEA 50 +#define CG_X86_OP_LEAVE 51 +#define CG_X86_OP_LGDT 52 +#define CG_X86_OP_LIDT 53 +#define CG_X86_OP_LLDT 54 +#define CG_X86_OP_LMSW 55 +#define CG_X86_OP_LODSB 56 +#define CG_X86_OP_LODSD 57 +#define CG_X86_OP_LODSW 58 +#define CG_X86_OP_LOOP 59 +#define CG_X86_OP_LOOPNZ 60 +#define CG_X86_OP_LOOPZ 61 +#define CG_X86_OP_LSL 62 +#define CG_X86_OP_LTR 63 +#define CG_X86_OP_MOV 64 +#define CG_X86_OP_MOVSB 65 +#define CG_X86_OP_MOVSD 66 +#define CG_X86_OP_MOVSW 67 +#define CG_X86_OP_MUL 68 +#define CG_X86_OP_NEG 69 +#define CG_X86_OP_NOP 70 +#define CG_X86_OP_NOT 71 +#define CG_X86_OP_OR 72 +#define CG_X86_OP_OUT 73 +#define CG_X86_OP_PAUSE 74 +#define CG_X86_OP_POP 75 +#define CG_X86_OP_POPAD 76 +#define CG_X86_OP_POPAW 77 +#define CG_X86_OP_POPFD 78 +#define CG_X86_OP_POPFW 79 +#define CG_X86_OP_PUSH 80 +#define CG_X86_OP_PUSHAD 81 +#define CG_X86_OP_PUSHAW 82 +#define CG_X86_OP_PUSHFD 83 +#define CG_X86_OP_PUSHFW 84 +#define CG_X86_OP_RET 85 +#define CG_X86_OP_RETF 86 +#define CG_X86_OP_ROL 87 +#define CG_X86_OP_ROR 88 +#define CG_X86_OP_SHL 89 +#define CG_X86_OP_SHR 90 +#define CG_X86_OP_SUB 91 +#define CG_X86_OP_XCHG 92 +#define CG_X86_OP_XOR 93 + +#define CG_X86_REG_AX 1 +#define CG_X86_REG_BX 2 +#define CG_X86_REG_CX 3 +#define CG_X86_REG_DX 4 +#define CG_X86_REG_DI 5 +#define CG_X86_REG_SI 6 +#define CG_X86_REG_BP 7 +#define CG_X86_REG_SP 8 +#define CG_X86_REG_AL 9 +#define CG_X86_REG_BL 10 +#define CG_X86_REG_CL 11 +#define CG_X86_REG_DL 12 +#define CG_X86_REG_AH 13 +#define CG_X86_REG_BH 14 +#define CG_X86_REG_CH 15 +#define CG_X86_REG_DH 16 +#define CG_X86_REG_EAX 17 +#define CG_X86_REG_EBX 18 +#define CG_X86_REG_ECX 19 +#define CG_X86_REG_EDX 20 +#define CG_X86_REG_EDI 21 +#define CG_X86_REG_ESI 22 +#define CG_X86_REG_EBP 23 +#define CG_X86_REG_ESP 24 +#define CG_X86_REG_CS 25 +#define CG_X86_REG_DS 26 +#define CG_X86_REG_ES 27 +#define CG_X86_REG_FS 28 +#define CG_X86_REG_GS 29 + +#define CG_X86_MODE_32BIT 0 +#define CG_X86_MODE_16BIT 1 + +#define CG_X86_ERR_ARGA_MISSING "argument A required, but missing" +#define CG_X86_ERR_ARGB_MISSING "argument B required, but missing" +#define CG_X86_ERR_ARGA_NOT_NULL "argument A must not be specified" +#define CG_X86_ERR_ARGB_NOT_NULL "argument B must not be specified" +#define CG_X86_ERR_ARGA_NOT_IMM8 "argument A must be of type imm8" +#define CG_X86_ERR_ARGA_NOT_IMM16 "argument A must be of type imm16" +#define CG_X86_ERR_ARGA_NOT_IMM32 "argument A must be of type imm32" +#define CG_X86_ERR_ARGA_NOT_MEM8 "argument A must be of type mem8" +#define CG_X86_ERR_ARGA_NOT_MEM16 "argument A must be of type mem16" +#define CG_X86_ERR_ARGA_NOT_MEM32 "argument A must be of type mem32" +#define CG_X86_ERR_ARGA_NOT_REG8 "argument A must be of type reg8" +#define CG_X86_ERR_ARGA_NOT_REG16 "argument A must be of type reg16" +#define CG_X86_ERR_ARGA_NOT_REG32 "argument A must be of type reg32" +#define CG_X86_ERR_ARGB_NOT_IMM8 "argument B must be of type imm8" +#define CG_X86_ERR_ARGB_NOT_IMM16 "argument B must be of type imm16" +#define CG_X86_ERR_ARGB_NOT_IMM32 "argument B must be of type imm32" +#define CG_X86_ERR_ARGB_NOT_MEM8 "argument B must be of type mem8" +#define CG_X86_ERR_ARGB_NOT_MEM16 "argument B must be of type mem16" +#define CG_X86_ERR_ARGB_NOT_MEM32 "argument B must be of type mem32" +#define CG_X86_ERR_ARGB_NOT_REG8 "argument B must be of type reg8" +#define CG_X86_ERR_ARGB_NOT_REG16 "argument B must be of type reg16" +#define CG_X86_ERR_ARGB_NOT_REG32 "argument B must be of type reg32" +#define CG_X86_ERR_ARGA_ARGB_NOT_SAME_SIZE "argument A and argument B must be the same size" +#define CG_X86_ERR_INVALID_INSTRUCTION "invalid instruction" +#define CG_X86_ERR_INVALID_SCALE_FACTOR "invalid scale factor (must be 0, 1, 2, 4 or 8)" +#define CG_X86_ERR_UNKNOWN_OPCODE "unknown opcode" + +void cg_x86_free_mem(struct cg_x86_mem *mem); +void cg_x86_free_arg(struct cg_x86_arg *arg); +void cg_x86_free_instr(struct cg_x86_instr *instr); + +struct cg_x86_arg *cg_x86_make_imm_arg(int type, int imm); +struct cg_x86_arg *cg_x86_make_imm8_arg(int imm); +struct cg_x86_arg *cg_x86_make_imm16_arg(int imm); +struct cg_x86_arg *cg_x86_make_imm32_arg(int imm); +struct cg_x86_mem *cg_x86_make_mem(int base, int scale, int reg, int offset); +struct cg_x86_arg *cg_x86_make_mem_arg(int type, int base, int scale, int index, int displacement); +struct cg_x86_arg *cg_x86_make_mem8_arg(int base, int scale, int index, int displacement); +struct cg_x86_arg *cg_x86_make_mem16_arg(int base, int scale, int index, int displacement); +struct cg_x86_arg *cg_x86_make_mem32_arg(int base, int scale, int index, int displacement); +struct cg_x86_arg *cg_x86_make_reg_arg(int type, int reg); +struct cg_x86_arg *cg_x86_make_reg8_arg(int reg); +struct cg_x86_arg *cg_x86_make_reg16_arg(int reg); +struct cg_x86_arg *cg_x86_make_reg32_arg(int reg); +struct cg_x86_instr *cg_x86_make_instr(int opcode, + struct cg_x86_arg *arga, + struct cg_x86_arg *argb); + +int cg_x86_emit_nullary_instr(char *str, size_t size, int opcode); +int cg_x86_emit_imm8_instr(char *str, size_t size, int opcode, int imm); +int cg_x86_emit_mem16_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement); +int cg_x86_emit_mem32_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement); +int cg_x86_emit_mem8_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement); +int cg_x86_emit_mem16_imm16_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int imm); +int cg_x86_emit_mem32_imm32_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int imm); +int cg_x86_emit_mem8_imm8_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int imm); +int cg_x86_emit_mem16_reg16_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int reg); +int cg_x86_emit_mem32_reg32_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int reg); +int cg_x86_emit_mem8_reg8_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int reg); +int cg_x86_emit_reg16_instr(char *str, size_t size, int opcode, int reg); +int cg_x86_emit_reg32_instr(char *str, size_t size, int opcode, int reg); +int cg_x86_emit_reg8_instr(char *str, size_t size, int opcode, int reg); +int cg_x86_emit_reg16_imm16_instr(char *str, size_t size, int opcode, int reg, int imm); +int cg_x86_emit_reg16_imm8_instr(char *str, size_t size, int opcode, int reg, int imm); +int cg_x86_emit_reg32_imm32_instr(char *str, size_t size, int opcode, int reg, int imm); +int cg_x86_emit_reg32_imm8_instr(char *str, size_t size, int opcode, int reg, int imm); +int cg_x86_emit_reg8_imm8_instr(char *str, size_t size, int opcode, int reg, int imm); +int cg_x86_emit_reg16_reg16_instr(char *str, size_t size, int opcode, int rega, int regb); +int cg_x86_emit_reg32_reg32_instr(char *str, size_t size, int opcode, int rega, int regb); +int cg_x86_emit_reg8_reg8_instr(char *str, size_t size, int opcode, int rega, int regb); + +int cg_x86_emit_instr(char *str, size_t size, struct cg_x86_instr *instr); + +int cg_x86_snprint_mem(char *str, size_t size, struct cg_x86_mem *mem); +int cg_x86_snprint_reg(char *str, size_t size, int reg); +int cg_x86_snprint_arg(char *str, size_t size, struct cg_x86_arg *arg); +int cg_x86_snprint_instr(char *str, size_t size, struct cg_x86_instr *instr); +int cg_x86_snprint_instr_nl(char *str, size_t size, struct cg_x86_instr *instr); + +char *cg_x86_get_last_error(); +int cg_x86_get_mode(); +void cg_x86_set_mode(int mode); +void cg_x86_set_malloc(void *(*newmalloc) (size_t)); +void cg_x86_set_free(void (*newfree) (void*)); diff --git a/x86/Makefile b/x86/Makefile new file mode 100644 index 0000000..1c40271 --- /dev/null +++ b/x86/Makefile @@ -0,0 +1,17 @@ +SUBDIRS = lib test + +lib : + cd lib && $(MAKE) + +all : lib test + +clean : + for dir in $(SUBDIRS); do (cd "$$dir" && $(MAKE) clean); done + +distclean : + for dir in $(SUBDIRS); do (cd "$$dir" && $(MAKE) distclean); done + +test : + cd test && $(MAKE) + +.PHONY : all lib clean distclean test diff --git a/x86/Makefile.cfg b/x86/Makefile.cfg new file mode 100644 index 0000000..a3c6aa7 --- /dev/null +++ b/x86/Makefile.cfg @@ -0,0 +1 @@ +LIBTARGET = libalchemist_x86.so.$(VERSION) diff --git a/x86/lib/Makefile b/x86/lib/Makefile new file mode 100644 index 0000000..1815704 --- /dev/null +++ b/x86/lib/Makefile @@ -0,0 +1,28 @@ +include ../../Makefile.cfg +include ../Makefile.cfg + +TARGETS = libalchemist_x86.so $(LIBTARGET) +OBJECTS = x86.o + +all : $(TARGETS) + +clean : + -rm $(OBJECTS) + +distclean : clean + -rm $(TARGETS) + +lib : $(LIBTARGET) + +libalchemist_x86.so : $(LIBTARGET) + ln -fs $(LIBTARGET) libalchemist_x86.so + +$(LIBTARGET) : $(OBJECTS) + $(LD) -shared $(OBJECTS) -o $(LIBTARGET) $(LDFLAGS) + +.SUFFIXES : .c .o + +.c.o : + $(CC) -c $(CFLAGS) -I../../include $< + +.PHONY : all clean distclean lib diff --git a/x86/lib/x86.c b/x86/lib/x86.c new file mode 100644 index 0000000..448819c --- /dev/null +++ b/x86/lib/x86.c @@ -0,0 +1,1740 @@ +#include +#include +#include "alchemist/x86.h" + +#define NEW(T) (T*) my_malloc(sizeof(T)) +#define BYTE char + +#define NEED_ARGA if(!instr->arga) { error = CG_X86_ERR_ARGA_MISSING; return -1; } +#define NEED_ARGB if(!instr->arga) { error = CG_X86_ERR_ARGB_MISSING; return -1; } +#define ARGA_NULL if(instr->arga) { error = CG_X86_ERR_ARGA_NOT_NULL; return -1; } +#define ARGB_NULL if(instr->argb) { error = CG_X86_ERR_ARGB_NOT_NULL; return -1; } +#define ARGA_TYPE_IMM8 if(instr->arga->type != CG_X86_ARGTYPE_IMM8) {\ + error = CG_X86_ERR_ARGA_NOT_IMM8; return -1; } +#define ARGA_TYPE_IMM16 if(instr->arga->type != CG_X86_ARGTYPE_IMM16) {\ + error = CG_X86_ERR_ARGA_NOT_IMM16; return -1; } +#define ARGA_TYPE_IMM32 if(instr->arga->type != CG_X86_ARGTYPE_IMM32) {\ + error = CG_X86_ERR_ARGA_NOT_IMM32; return -1; } +#define ARGB_TYPE_IMM8 if(instr->argb->type != CG_X86_ARGTYPE_IMM8) {\ + error = CG_X86_ERR_ARGB_NOT_IMM8; return -1; } +#define ARGB_TYPE_IMM16 if(instr->argb->type != CG_X86_ARGTYPE_IMM16) {\ + error = CG_X86_ERR_ARGB_NOT_IMM16; return -1; } +#define ARGB_TYPE_IMM32 if(instr->argb->type != CG_X86_ARGTYPE_IMM32) {\ + error = CG_X86_ERR_ARGB_NOT_IMM32; return -1; } +#define ARGA_ARGB_SAME_SIZE if(argument_size(instr->arga) != argument_size(instr->argb)) {\ + error = CG_X86_ERR_ARGA_ARGB_NOT_SAME_SIZE; return -1; } +#define INVALID_INSTRUCTION { error = CG_X86_ERR_INVALID_INSTRUCTION; return -1; } +#define INVALID_SCALE_FACTOR { error = CG_X86_ERR_INVALID_SCALE_FACTOR; return -1; } + +#define EMIT_BYTE(X) { if(size > n) str[n] = (BYTE) (X); n++; } +#define EMIT_WORD(X) { EMIT_BYTE((X) & 0xff); EMIT_BYTE(((X) >> 8) & 0xff); } +#define EMIT_DWORD(X) { EMIT_BYTE((X) & 0xff); EMIT_BYTE(((X) >> 8) & 0xff); \ + EMIT_BYTE(((X) >> 16) & 0xff); EMIT_BYTE(((X) >> 24) & 0xff); } +#define EMIT_MR(X, Y) { m = cg_x86_emit_mem_or_reg_arg(str + n, size - n, X, Y); \ + if(m < 0) return m; else n += m; } +#define EMIT_REG_MODRM(REG, SPARE) { m = cg_x86_emit_reg_modrm(str + n, size - n, REG, SPARE); \ + if(m < 0) return m; else n+= m; } +#define EMIT_MEM_MODRM(BASE, SCALE, INDEX, DISPLACEMENT, SPARE) {\ + m = cg_x86_emit_mem_modrm(str + n, size - n, BASE, SCALE, INDEX, DISPLACEMENT, SPARE); \ + if(m < 0) return m; else n+= m; } + +#define EMIT_JCC16(CC) cg_x86_emit_jcc16(str, size, CC, imm); +#define EMIT_JCC32(CC) cg_x86_emit_jcc32(str, size, CC, imm); +#define EMIT_OP_IMM16(OP) cg_x86_emit_op_imm16(str, size, OP, imm) +#define EMIT_OP_IMM16_IMM16(OP) cg_x86_emit_op_imm16_imm16(str, size, OP, imma, immb) +#define EMIT_OP_IMM16_IMM32(OP) cg_x86_emit_op_imm16_imm32(str, size, OP, imma, immb) +#define EMIT_OP_IMM32(OP) cg_x86_emit_op_imm32(str, size, OP, imm) +#define EMIT_OP_IMM8(OP) cg_x86_emit_op_imm8(str, size, OP, imm) +#define EMIT_OP_MEM_REG16(OP) cg_x86_emit_op_mem_reg16(str, size, OP, base, scale, index, displacement, reg) +#define EMIT_OP_MEM_REG32(OP) cg_x86_emit_op_mem_reg32(str, size, OP, base, scale, index, displacement, reg) +#define EMIT_OP_MEM_REG8(OP) cg_x86_emit_op_mem_reg8(str, size, OP, base, scale, index, displacement, reg) +#define EMIT_OP_REG_MEM16(OP) cg_x86_emit_op_mem_reg16(str, size, OP, base, scale, index, displacement, reg) +#define EMIT_OP_REG_MEM32(OP) cg_x86_emit_op_mem_reg32(str, size, OP, base, scale, index, displacement, reg) +#define EMIT_OP_REG_MEM8(OP) cg_x86_emit_op_mem_reg8(str, size, OP, base, scale, index, displacement, reg) +#define EMIT_OP_REG_REG16(OP) cg_x86_emit_op_reg_reg16(str, size, OP, rega, regb) +#define EMIT_OP_REG_REG32(OP) cg_x86_emit_op_reg_reg32(str, size, OP, rega, regb) +#define EMIT_OP_REG_REG8(OP) cg_x86_emit_op_reg_reg8(str, size, OP, rega, regb) +#define EMIT_OP_SPARE_MEM16(OP, SPARE) cg_x86_emit_op_spare_mem16(str, size, OP, SPARE, base, scale, index, displacement) +#define EMIT_OP_SPARE_MEM32(OP, SPARE) cg_x86_emit_op_spare_mem32(str, size, OP, SPARE, base, scale, index, displacement) +#define EMIT_OP_SPARE_MEM8(OP, SPARE) cg_x86_emit_op_spare_mem8(str, size, OP, SPARE, base, scale, index, displacement) +#define EMIT_OP_SPARE_MEM_IMM16(OP, SPARE) cg_x86_emit_op_spare_mem_imm16(str, size, OP, SPARE, base, scale, index, displacement, imm) +#define EMIT_OP_SPARE_MEM_IMM32(OP, SPARE) cg_x86_emit_op_spare_mem_imm32(str, size, OP, SPARE, base, scale, index, displacement, imm) +#define EMIT_OP_SPARE_MEM_IMM8(OP, SPARE) cg_x86_emit_op_spare_mem_imm8(str, size, OP, SPARE, base, scale, index, displacement, imm) +#define EMIT_OP_SPARE_REG16(OP, SPARE) cg_x86_emit_op_spare_reg16(str, size, OP, SPARE, reg) +#define EMIT_OP_SPARE_REG32(OP, SPARE) cg_x86_emit_op_spare_reg32(str, size, OP, SPARE, reg) +#define EMIT_OP_SPARE_REG8(OP, SPARE) cg_x86_emit_op_spare_reg8(str, size, OP, SPARE, reg) +#define EMIT_OP_SPARE_REG_IMM16(OP, SPARE) cg_x86_emit_op_spare_reg_imm16(str, size, OP, SPARE, reg, imm) +#define EMIT_OP_SPARE_REG_IMM32(OP, SPARE) cg_x86_emit_op_spare_reg_imm32(str, size, OP, SPARE, reg, imm) +#define EMIT_OP_SPARE_REG_IMM8(OP, SPARE) cg_x86_emit_op_spare_reg_imm8(str, size, OP, SPARE, reg, imm) + +#define INSTR16 if(mode == CG_X86_MODE_32BIT) EMIT_BYTE('\x66') +#define INSTR32 if(mode == CG_X86_MODE_16BIT) EMIT_BYTE('\x66') +#define ADDRESS16 if(mode == CG_X86_MODE_32BIT) EMIT_BYTE('\x67') +#define ADDRESS32 if(mode == CG_X86_MODE_16BIT) EMIT_BYTE('\x67') + +static char *error = NULL; +static int mode = CG_X86_MODE_32BIT; + +static void *(*my_malloc) (size_t) = malloc; +static void (*my_free) (void*) = free; + +/* Address of the form base + scale * index + offset */ +struct cg_x86_mem { + int base; + int scale; + int index; + int displacement; +}; + +struct cg_x86_arg { + int type; + union { + int imm; + struct cg_x86_mem *mem; + int reg; + } value; +}; + +struct cg_x86_instr { + int opcode; + struct cg_x86_arg *arga; + struct cg_x86_arg *argb; +}; + +char *cg_x86_opcodes[] = { + NULL, + "add", + "adc", + "and", + "call", + "clc", + "cld", + "cli", + "cmp", + "dec", + "div", + "hlt", + "idiv", + "imul", + "in", + "inc", + "insb", + "insd", + "insw", + "int", + "int1", + "int3", + "into", + "iret", + "iretd", + "iretw", + "ja", + "jb", + "jcxz", + "jecxz", + "jg", + "jl", + "jna", + "jnb", + "jng", + "jnl", + "jno", + "jnp", + "jns", + "jnz", + "jo", + "jp", + "js", + "jz", + "jmp", + "lds", + "les", + "lfs", + "lgs", + "lss", + "lea", + "leave", + "lgdt", + "lidt", + "lldt", + "lmsw", + "lodsb", + "lodsd", + "lodsw", + "loop", + "loopnz", + "loopz", + "lsl", + "ltr", + "mov", + "movsb", + "movsd", + "movsw", + "mul", + "neg", + "nop", + "not", + "or", + "out", + "pause", + "pop", + "popad", + "popaw", + "popfd", + "popfw", + "push", + "pushad", + "pushaw", + "pushfd", + "pushfw", + "ret", + "retf", + "rol", + "ror", + "shl", + "shr", + "sub", + "xchg", + "xor", +}; + +char *cg_x86_registers[] = { + NULL, + "ax", + "bx", + "cx", + "dx", + "di", + "si", + "bp", + "sp", + "al", + "bl", + "cl", + "dl", + "ah", + "bh", + "ch", + "dh", + "eax", + "ebx", + "ecx", + "edx", + "edi", + "esi", + "ebp", + "esp", +}; + +static int register_code[] = { + -1, + 0, + 3, + 1, + 2, + 7, + 6, + 5, + 4, + 0, + 3, + 1, + 2, + 4, + 7, + 5, + 6, + 0, + 3, + 1, + 2, + 7, + 6, + 5, + 4, +}; + +static size_t atleast0(size_t n) { + return (n > 0) ? n : 0; +} + +static int argument_size(struct cg_x86_arg *arg) { + if(!arg) return 0; + switch(arg->type) { + case CG_X86_ARGTYPE_IMM8: + case CG_X86_ARGTYPE_MEM8: + case CG_X86_ARGTYPE_REG8: + return 8; + case CG_X86_ARGTYPE_IMM16: + case CG_X86_ARGTYPE_MEM16: + case CG_X86_ARGTYPE_REG16: + return 16; + case CG_X86_ARGTYPE_IMM32: + case CG_X86_ARGTYPE_MEM32: + case CG_X86_ARGTYPE_REG32: + return 32; + default: + return -1; + } +} + +void cg_x86_free_mem(struct cg_x86_mem *mem) { + if(mem) free(mem); +} + +void cg_x86_free_arg(struct cg_x86_arg *arg) { + if(arg) { + switch(arg->type) { + case CG_X86_ARGTYPE_MEM8: + case CG_X86_ARGTYPE_MEM16: + case CG_X86_ARGTYPE_MEM32: + cg_x86_free_mem(arg->value.mem); + break; + default: + ; /* do nothing */ + } + free(arg); + } +} + +void cg_x86_free_instr(struct cg_x86_instr *instr) { + if(instr) { + if(instr->arga) cg_x86_free_arg(instr->arga); + if(instr->argb) cg_x86_free_arg(instr->argb); + free(instr); + } +} + +char *cg_x86_get_last_error() { + return error; +} + +struct cg_x86_arg *cg_x86_make_imm_arg(int type, int imm) +{ + struct cg_x86_arg *arg = NEW(struct cg_x86_arg); + if(arg) { + arg->type = type; + arg->value.imm = imm; + } + return arg; +} + +struct cg_x86_arg *cg_x86_make_imm8_arg(int imm) +{ + return cg_x86_make_imm_arg(CG_X86_ARGTYPE_IMM8, imm); +} + +struct cg_x86_arg *cg_x86_make_imm16_arg(int imm) +{ + return cg_x86_make_imm_arg(CG_X86_ARGTYPE_IMM16, imm); +} + +struct cg_x86_arg *cg_x86_make_imm32_arg(int imm) +{ + return cg_x86_make_imm_arg(CG_X86_ARGTYPE_IMM32, imm); +} + +struct cg_x86_mem *cg_x86_make_mem(int base, int scale, int index, int displacement) { + struct cg_x86_mem *mem = NEW(struct cg_x86_mem); + if(mem) { + mem->base = base; + mem->scale = scale; + mem->index = index; + mem->displacement = displacement; + } + return mem; +} + +struct cg_x86_arg *cg_x86_make_mem_arg(int type, int base, int scale, int index, int displacement) { + struct cg_x86_arg *arg = NEW(struct cg_x86_arg); + if(arg) { + arg->value.mem = cg_x86_make_mem(base, scale, index, displacement); + if(!arg->value.mem) { + free(arg); + return NULL; + } + arg->type = type; + } + return arg; +} + +struct cg_x86_arg *cg_x86_make_mem8_arg(int base, int scale, int index, int displacement) { + return cg_x86_make_mem_arg(CG_X86_ARGTYPE_MEM8, + base, scale, index, displacement); +} + +struct cg_x86_arg *cg_x86_make_mem16_arg(int base, int scale, int index, int displacement) { + return cg_x86_make_mem_arg(CG_X86_ARGTYPE_MEM16, + base, scale, index, displacement); +} + +struct cg_x86_arg *cg_x86_make_mem32_arg(int base, int scale, int index, int displacement) { + return cg_x86_make_mem_arg(CG_X86_ARGTYPE_MEM32, + base, scale, index, displacement); +} + +struct cg_x86_arg *cg_x86_make_reg_arg(int type, int reg) { + struct cg_x86_arg *arg = NEW(struct cg_x86_arg); + if(arg) { + arg->type = type; + arg->value.reg = reg; + } + return arg; +} + +struct cg_x86_arg *cg_x86_make_reg8_arg(int reg) { + return cg_x86_make_reg_arg(CG_X86_ARGTYPE_REG8, reg); +} + +struct cg_x86_arg *cg_x86_make_reg16_arg(int reg) { + return cg_x86_make_reg_arg(CG_X86_ARGTYPE_REG16, reg); +} + +struct cg_x86_arg *cg_x86_make_reg32_arg(int reg) { + return cg_x86_make_reg_arg(CG_X86_ARGTYPE_REG32, reg); +} + +struct cg_x86_instr *cg_x86_make_instr(int opcode, + struct cg_x86_arg *arga, + struct cg_x86_arg *argb) +{ + struct cg_x86_instr *instr = NEW(struct cg_x86_instr); + if(instr) { + instr->opcode = opcode; + instr->arga = arga; + instr->argb = argb; + } + return instr; +} + +int cg_x86_emit_mem_modrm(char *str, size_t size, int base, int scale, int index, int displacement, int spare) { + BYTE modrm, sib; + int n = 0, address_mode = 0; + + modrm = spare << 3; + + /* Calculate the size of the displacement we need to use. */ + if(displacement == 0) { + /* No displacement. */ + /* modrm |= 0; */ + modrm |= 0x40; /* Put one anyway... */ + } else if((displacement & 0xffffff00) == 0) { + /* byte displacement. */ + modrm |= 0x40; + } else if((displacement & 0xffff0000) == 0) { + /* word displacement. */ + modrm |= 0x80; + address_mode = 16; + } else { + /* dword displacement. */ + modrm |= 0x80; + address_mode = 32; + } + + /* Calculate SIB byte. */ + /* Scale must be 1, 2, 4, or 8 */ + switch(scale) { + case 0: + case 1: + sib = 0x00; + break; + case 2: + sib = 0x40; + break; + case 4: + sib = 0x80; + break; + case 8: + sib = 0xc0; + break; + default: + /* No other values of scale are allowed. */ + INVALID_SCALE_FACTOR + } + + /* Index */ + /* If scale == 0, we don't have an index. In that case, + * the index code is 4 (so we or with 4 << 3, which is 0x20). */ + if(scale == 0) sib |= 0x20; + else { + /* ESP cannot be used as an index. */ + if(index == CG_X86_REG_ESP) INVALID_INSTRUCTION + sib |= register_code[index] << 3; + } + + /* Base */ + sib |= register_code[base]; + + /* For now, we only support addressing using the SIB byte. + That also means we must use 32-bit mode. */ + modrm |= 4; + ADDRESS32; + EMIT_BYTE(modrm); + EMIT_BYTE(sib); + switch(modrm & 0xc0) { + case 0: + break; + case 0x40: + EMIT_BYTE(displacement); + break; + case 0x80: + EMIT_DWORD(displacement); + break; + default: + /* Can't happen */ + return -1; + } + + return n; +} + +int cg_x86_emit_reg_modrm(char *str, size_t size, int reg, int spare) { + int n = 0; + EMIT_BYTE(0xc0 | (spare << 3) | register_code[reg]); + return n; +} + +int cg_x86_emit_mem_or_reg_arg(char *str, size_t size, struct cg_x86_arg *arg, int spare) { + /* A mem/reg argument consists of a modrm byte, an optional SIB + * byte, and an optional displacement value which may be a byte, + * word, or dword. The ModR/M byte is divided into 3 parts: + * - bits 0 .. 2: r/m field + * - bits 3 .. 5: reg field + * - bits 6 .. 7: mod field + * + * If mod is 3, the modrm byte encodes a register. reg holds the register code, + * and r/m will be 0. + * + * The rest of this comment only applies to the case where mod != 3. In + * this case, the mem/reg argument encodes a memory address. + * + * mod holds the width of the displacement field: + * - mod 0 means no displacement field + * - mod 1 means one byte displacement field + * - mod 2 means one word displacement field (in 16-bit address mode), + * or one dword displacement field (in 32-bit address mode) + * + * The r/m field gives the combination of registers to be used for calculating + * the address. + * - r/m 0 means bx + si + * - r/m 1 means bx + di + * - r/m 2 means bp + si + * - r/m 3 means bp + di + * - r/m 4 means si + * - r/m 5 means di + * - r/m 6 means bp + * - r/m 7 means bx + * + * The displacement field is a (0, 1, 2, or 4 bytes long) offset to be + * added to the address encoded by the modrm and SIB bytes. + * + */ + struct cg_x86_mem *mem; + + switch(arg->type) { + + case CG_X86_ARGTYPE_REG8: + case CG_X86_ARGTYPE_REG16: + case CG_X86_ARGTYPE_REG32: + return cg_x86_emit_reg_modrm(str, size, arg->value.reg, spare); + + case CG_X86_ARGTYPE_MEM8: + case CG_X86_ARGTYPE_MEM16: + case CG_X86_ARGTYPE_MEM32: + mem = arg->value.mem; + return cg_x86_emit_mem_modrm(str, size, mem->base, mem->scale, mem->index, mem->displacement, spare); + + default: + INVALID_INSTRUCTION + } +} + +int cg_x86_emit_jcc16(char *str, size_t size, int cc, int imm) { + int n = 0; + INSTR16 + EMIT_BYTE(0x0f); + EMIT_BYTE(0x80 + cc); + EMIT_WORD(imm); + return n; +} + +int cg_x86_emit_jcc32(char *str, size_t size, int cc, int imm) { + int n = 0; + INSTR32 + EMIT_BYTE(0x0f); + EMIT_BYTE(0x80 + cc); + EMIT_DWORD(imm); + return n; +} + +int cg_x86_emit_op_imm16(char *str, size_t size, char op, int imm) { + int n = 0; + INSTR16 + EMIT_BYTE(op); + EMIT_WORD(imm); + return n; +} + +int cg_x86_emit_op_imm16_imm16(char *str, size_t size, char op, int imma, int immb) { + int n = 0; + INSTR16 + EMIT_BYTE(op); + EMIT_WORD(imma); + EMIT_WORD(immb); + return n; +} + +int cg_x86_emit_op_imm16_imm32(char *str, size_t size, char op, int imma, int immb) { + int n = 0; + INSTR32 + EMIT_BYTE(op); + EMIT_WORD(imma); + EMIT_DWORD(immb); + return n; +} + +int cg_x86_emit_op_imm32(char *str, size_t size, char op, int imm) { + int n = 0; + INSTR32 + EMIT_BYTE(op); + EMIT_DWORD(imm); + return n; +} + +int cg_x86_emit_op_imm8(char *str, size_t size, char op, int imm) { + int n = 0; + EMIT_BYTE(op); + EMIT_BYTE(imm); + return n; +} + +int cg_x86_emit_op_mem_reg16(char *str, size_t size, char op, int base, int scale, int index, int displacement, int reg) { + int n = 0, m; + INSTR16 + EMIT_BYTE(op); + EMIT_MEM_MODRM(base, scale, index, displacement, register_code[reg]); + return n; +} + +int cg_x86_emit_op_mem_reg32(char *str, size_t size, char op, int base, int scale, int index, int displacement, int reg) { + int n = 0, m; + INSTR32 + EMIT_BYTE(op); + EMIT_MEM_MODRM(base, scale, index, displacement, register_code[reg]); + return n; +} + +int cg_x86_emit_op_mem_reg8(char *str, size_t size, char op, int base, int scale, int index, int displacement, int reg) { + int n = 0, m; + EMIT_BYTE(op); + EMIT_MEM_MODRM(base, scale, index, displacement, register_code[reg]); + return n; +} + +int cg_x86_emit_op_reg_reg16(char *str, size_t size, char op, int rega, int regb) { + int n = 0, m; + INSTR16 + EMIT_BYTE(op); + EMIT_REG_MODRM(regb, register_code[rega]); + return n; +} + +int cg_x86_emit_op_reg_reg32(char *str, size_t size, char op, int rega, int regb) { + int n = 0, m; + INSTR32 + EMIT_BYTE(op); + EMIT_REG_MODRM(regb, register_code[rega]); + return n; +} + +int cg_x86_emit_op_reg_reg8(char *str, size_t size, char op, int rega, int regb) { + int n = 0, m; + EMIT_BYTE(op); + EMIT_REG_MODRM(regb, register_code[rega]); + return n; +} + +int cg_x86_emit_op_spare_mem16(char *str, size_t size, char op, int spare, int base, int scale, int index, int displacement) { + int n = 0, m; + INSTR16 + EMIT_BYTE(op); + EMIT_MEM_MODRM(base, scale, index, displacement, spare); + return n; +} + +int cg_x86_emit_op_spare_mem32(char *str, size_t size, char op, int spare, int base, int scale, int index, int displacement) { + int n = 0, m; + INSTR32 + EMIT_BYTE(op); + EMIT_MEM_MODRM(base, scale, index, displacement, spare); + return n; +} + +int cg_x86_emit_op_spare_mem8(char *str, size_t size, char op, int spare, int base, int scale, int index, int displacement) { + int n = 0, m; + EMIT_BYTE(op); + EMIT_MEM_MODRM(base, scale, index, displacement, spare); + return n; +} + +int cg_x86_emit_op_spare_reg16(char *str, size_t size, char op, int spare, int reg) { + int n = 0, m; + INSTR16 + EMIT_BYTE(op); + EMIT_REG_MODRM(reg, spare); + return n; +} + +int cg_x86_emit_op_spare_reg32(char *str, size_t size, char op, int spare, int reg) { + int n = 0, m; + INSTR32 + EMIT_BYTE(op); + EMIT_REG_MODRM(reg, spare); + return n; +} + +int cg_x86_emit_op_spare_reg8(char *str, size_t size, char op, int spare, int reg) { + int n = 0, m; + EMIT_BYTE(op); + EMIT_REG_MODRM(reg, spare); + return n; +} + +int cg_x86_emit_op_spare_reg_imm16(char *str, size_t size, char op, int spare, int reg, int imm) { + int n = 0, m; + INSTR16 + EMIT_BYTE(op); + EMIT_REG_MODRM(reg, spare); + EMIT_WORD(imm); + return n; +} + +int cg_x86_emit_op_spare_reg_imm32(char *str, size_t size, char op, int spare, int reg, int imm) { + int n = 0, m; + INSTR32 + EMIT_BYTE(op); + EMIT_REG_MODRM(reg, spare); + EMIT_DWORD(imm); + return n; +} + +int cg_x86_emit_op_spare_reg_imm8(char *str, size_t size, char op, int spare, int reg, int imm) { + int n = 0, m; + EMIT_BYTE(op); + EMIT_REG_MODRM(reg, spare); + EMIT_BYTE(imm); + return n; +} + +int cg_x86_emit_op_spare_mem_imm16(char *str, size_t size, char op, int spare, int base, int scale, int index, int displacement, int imm) { + int n = 0, m; + INSTR16 + EMIT_BYTE(op); + EMIT_MEM_MODRM(base, scale, index, displacement, spare); + EMIT_WORD(imm); + return n; +} + +int cg_x86_emit_op_spare_mem_imm32(char *str, size_t size, char op, int spare, int base, int scale, int index, int displacement, int imm) { + int n = 0, m; + INSTR32 + EMIT_BYTE(op); + EMIT_MEM_MODRM(base, scale, index, displacement, spare); + EMIT_DWORD(imm); + return n; +} + +int cg_x86_emit_op_spare_mem_imm8(char *str, size_t size, char op, int spare, int base, int scale, int index, int displacement, int imm) { + int n = 0, m; + EMIT_BYTE(op); + EMIT_MEM_MODRM(base, scale, index, displacement, spare); + EMIT_BYTE(imm); + return n; +} + +int cg_x86_emit_nullary_instr(char *str, size_t size, int opcode) { + int n = 0; + switch(opcode) { + case CG_X86_OP_CLC: + EMIT_BYTE(0xf8); + break; + case CG_X86_OP_CLD: + EMIT_BYTE(0xfc); + break; + case CG_X86_OP_CLI: + EMIT_BYTE(0xfa); + break; + case CG_X86_OP_RET: + EMIT_BYTE(0xc3); + break; + case CG_X86_OP_RETF: + EMIT_BYTE(0xcb); + break; + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_imm16_instr(char *str, size_t size, int opcode, int imm) { + int n = 0; + switch(opcode) { + case CG_X86_OP_CALL: + return EMIT_OP_IMM16(0xe8); + case CG_X86_OP_JA: + return EMIT_JCC16(7); + case CG_X86_OP_JB: + return EMIT_JCC16(2); + case CG_X86_OP_JG: + return EMIT_JCC16(15); + case CG_X86_OP_JL: + return EMIT_JCC16(12); + case CG_X86_OP_JNA: + return EMIT_JCC16(6); + case CG_X86_OP_JNB: + return EMIT_JCC16(3); + case CG_X86_OP_JNG: + return EMIT_JCC16(14); + case CG_X86_OP_JNL: + return EMIT_JCC16(13); + case CG_X86_OP_JNO: + return EMIT_JCC16(1); + case CG_X86_OP_JNP: + return EMIT_JCC16(11); + case CG_X86_OP_JNS: + return EMIT_JCC16(9); + case CG_X86_OP_JNZ: + return EMIT_JCC16(5); + case CG_X86_OP_JO: + return EMIT_JCC16(0); + case CG_X86_OP_JP: + return EMIT_JCC16(10); + case CG_X86_OP_JS: + return EMIT_JCC16(8); + case CG_X86_OP_JZ: + return EMIT_JCC16(4); + case CG_X86_OP_JMP: + return EMIT_OP_IMM16(0xe9); + case CG_X86_OP_RET: + return EMIT_OP_IMM16(0xc2); + case CG_X86_OP_RETF: + return EMIT_OP_IMM16(0xca); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_imm16_imm16_instr(char *str, size_t size, int opcode, int imma, int immb) { + int n = 0; + switch(opcode) { + case CG_X86_OP_CALL: + return EMIT_OP_IMM16_IMM16(0x9a); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_imm16_imm32_instr(char *str, size_t size, int opcode, int imma, int immb) { + int n = 0; + switch(opcode) { + case CG_X86_OP_CALL: + return EMIT_OP_IMM16_IMM32(0x9a); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_imm32_instr(char *str, size_t size, int opcode, int imm) { + int n = 0; + switch(opcode) { + case CG_X86_OP_CALL: + return EMIT_OP_IMM32(0xe8); + case CG_X86_OP_JA: + return EMIT_JCC32(7); + case CG_X86_OP_JB: + return EMIT_JCC32(2); + case CG_X86_OP_JG: + return EMIT_JCC32(15); + case CG_X86_OP_JL: + return EMIT_JCC32(12); + case CG_X86_OP_JNA: + return EMIT_JCC32(6); + case CG_X86_OP_JNB: + return EMIT_JCC32(3); + case CG_X86_OP_JNG: + return EMIT_JCC32(14); + case CG_X86_OP_JNL: + return EMIT_JCC32(13); + case CG_X86_OP_JNO: + return EMIT_JCC32(1); + case CG_X86_OP_JNP: + return EMIT_JCC32(11); + case CG_X86_OP_JNS: + return EMIT_JCC32(9); + case CG_X86_OP_JNZ: + return EMIT_JCC32(5); + case CG_X86_OP_JO: + return EMIT_JCC32(0); + case CG_X86_OP_JP: + return EMIT_JCC32(10); + case CG_X86_OP_JS: + return EMIT_JCC32(8); + case CG_X86_OP_JZ: + return EMIT_JCC32(4); + case CG_X86_OP_JMP: + return EMIT_OP_IMM32(0xe9); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_imm8_instr(char *str, size_t size, int opcode, int imm) { + int n = 0; + switch(opcode) { + case CG_X86_OP_INT: + return EMIT_OP_IMM8(0xcd); + case CG_X86_OP_JA: + return EMIT_OP_IMM8(0x77); + case CG_X86_OP_JB: + return EMIT_OP_IMM8(0x72); + case CG_X86_OP_JCXZ: + return EMIT_OP_IMM8(0xe3); + case CG_X86_OP_JECXZ: + return EMIT_OP_IMM8(0xe3); + case CG_X86_OP_JG: + return EMIT_OP_IMM8(0x85); + case CG_X86_OP_JL: + return EMIT_OP_IMM8(0x82); + case CG_X86_OP_JNA: + return EMIT_OP_IMM8(0x76); + case CG_X86_OP_JNB: + return EMIT_OP_IMM8(0x73); + case CG_X86_OP_JNG: + return EMIT_OP_IMM8(0x84); + case CG_X86_OP_JNL: + return EMIT_OP_IMM8(0x83); + case CG_X86_OP_JNO: + return EMIT_OP_IMM8(0x71); + case CG_X86_OP_JNP: + return EMIT_OP_IMM8(0x81); + case CG_X86_OP_JNS: + return EMIT_OP_IMM8(0x79); + case CG_X86_OP_JNZ: + return EMIT_OP_IMM8(0x75); + case CG_X86_OP_JO: + return EMIT_OP_IMM8(0x70); + case CG_X86_OP_JP: + return EMIT_OP_IMM8(0x80); + case CG_X86_OP_JS: + return EMIT_OP_IMM8(0x78); + case CG_X86_OP_JZ: + return EMIT_OP_IMM8(0x74); + case CG_X86_OP_JMP: + return EMIT_OP_IMM8(0xeb); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_mem16_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement) { + int n = 0; + switch(opcode) { + case CG_X86_OP_CALL: + return EMIT_OP_SPARE_MEM16(0xff, 2); + case CG_X86_OP_INC: + return EMIT_OP_SPARE_MEM16(0xff, 0); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_mem16_imm16_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int imm) { + int n = 0, m, spare; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_SPARE_MEM_IMM16(0x81, 2); + case CG_X86_OP_ADD: + return EMIT_OP_SPARE_MEM_IMM16(0x81, 0); + case CG_X86_OP_AND: + return EMIT_OP_SPARE_MEM_IMM16(0x81, 4); + case CG_X86_OP_CMP: + return EMIT_OP_SPARE_MEM_IMM16(0x81, 7); + case CG_X86_OP_OR: + return EMIT_OP_SPARE_MEM_IMM16(0x81, 1); + case CG_X86_OP_MOV: + return EMIT_OP_SPARE_MEM_IMM16(0xc7, 0); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_mem16_reg16_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int reg) { + int n = 0, m; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_MEM_REG16(0x11); + case CG_X86_OP_ADD: + return EMIT_OP_MEM_REG16(0x01); + case CG_X86_OP_AND: + return EMIT_OP_MEM_REG16(0x23); + case CG_X86_OP_CMP: + return EMIT_OP_MEM_REG16(0x39); + case CG_X86_OP_OR: + return EMIT_OP_MEM_REG16(0x09); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_mem32_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement) { + int n = 0; + switch(opcode) { + case CG_X86_OP_CALL: + return EMIT_OP_SPARE_MEM32(0xff, 2); + case CG_X86_OP_INC: + return EMIT_OP_SPARE_MEM32(0xff, 0); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_mem32_imm32_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int imm) { + int n = 0, m, spare; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_SPARE_MEM_IMM32(0x81, 2); + case CG_X86_OP_ADD: + return EMIT_OP_SPARE_MEM_IMM32(0x81, 0); + case CG_X86_OP_AND: + return EMIT_OP_SPARE_MEM_IMM32(0x81, 4); + case CG_X86_OP_CMP: + return EMIT_OP_SPARE_MEM_IMM32(0x81, 7); + case CG_X86_OP_OR: + return EMIT_OP_SPARE_MEM_IMM32(0x81, 1); + case CG_X86_OP_MOV: + return EMIT_OP_SPARE_MEM_IMM32(0xc7, 0); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_mem32_reg32_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int reg) { + int n = 0, m; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_MEM_REG32(0x11); + case CG_X86_OP_ADD: + return EMIT_OP_MEM_REG32(0x01); + case CG_X86_OP_AND: + return EMIT_OP_MEM_REG32(0x23); + case CG_X86_OP_CMP: + return EMIT_OP_MEM_REG32(0x39); + case CG_X86_OP_OR: + return EMIT_OP_MEM_REG32(0x09); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_mem8_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement) { + int n = 0; + switch(opcode) { + case CG_X86_OP_INC: + return EMIT_OP_SPARE_MEM8(0xfe, 0); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_mem8_imm8_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int imm) { + int n = 0, m; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_SPARE_MEM_IMM8(0x80, 2); + case CG_X86_OP_ADD: + return EMIT_OP_SPARE_MEM_IMM8(0x80, 0); + case CG_X86_OP_AND: + return EMIT_OP_SPARE_MEM_IMM8(0x80, 4); + case CG_X86_OP_CMP: + return EMIT_OP_SPARE_MEM_IMM8(0x80, 7); + case CG_X86_OP_OR: + return EMIT_OP_SPARE_MEM_IMM8(0x80, 1); + case CG_X86_OP_MOV: + return EMIT_OP_SPARE_MEM_IMM8(0xc6, 0); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_mem8_reg8_instr(char *str, size_t size, int opcode, int base, int scale, int index, int displacement, int reg) { + int n = 0, m; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_MEM_REG8(0x10); + case CG_X86_OP_ADD: + return EMIT_OP_MEM_REG8(0x00); + case CG_X86_OP_AND: + return EMIT_OP_MEM_REG8(0x20); + case CG_X86_OP_CMP: + return EMIT_OP_MEM_REG8(0x38); + case CG_X86_OP_OR: + return EMIT_OP_MEM_REG8(0x08); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg16_instr(char *str, size_t size, int opcode, int reg) { + int n = 0; + switch(opcode) { + case CG_X86_OP_CALL: + return EMIT_OP_SPARE_REG16(0xff, 2); + case CG_X86_OP_DEC: + INSTR16 + EMIT_BYTE(0x48 + register_code[reg]); + break; + case CG_X86_OP_DIV: + return EMIT_OP_SPARE_REG16(0xf7, 6); + case CG_X86_OP_IDIV: + return EMIT_OP_SPARE_REG16(0xf7, 7); + case CG_X86_OP_IMUL: + return EMIT_OP_SPARE_REG16(0xf7, 5); + case CG_X86_OP_INC: + INSTR16 + EMIT_BYTE(0x40 + register_code[reg]); + break; + case CG_X86_OP_MUL: + return EMIT_OP_SPARE_REG16(0xf7, 4); + case CG_X86_OP_NEG: + return EMIT_OP_SPARE_REG16(0xf7, 3); + case CG_X86_OP_NOT: + return EMIT_OP_SPARE_REG16(0xf7, 2); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg16_imm16_instr(char *str, size_t size, int opcode, int reg, int imm) { + int n = 0, m, spare; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + if(reg == CG_X86_REG_AX) { + return EMIT_OP_IMM16(0x15); + } else { + return EMIT_OP_SPARE_REG_IMM16(0x81, 2); + } + case CG_X86_OP_ADD: + if(reg == CG_X86_REG_AX) { + return EMIT_OP_IMM16(0x05); + } else { + return EMIT_OP_SPARE_REG_IMM16(0x81, 0); + } + case CG_X86_OP_AND: + if(reg == CG_X86_REG_AX) { + return EMIT_OP_IMM16(0x25); + } else { + return EMIT_OP_SPARE_REG_IMM16(0x81, 4); + } + case CG_X86_OP_CMP: + if(reg == CG_X86_REG_AX) { + return EMIT_OP_IMM16(0x3d); + } else { + return EMIT_OP_SPARE_REG_IMM16(0x81, 7); + } + case CG_X86_OP_OR: + if(reg == CG_X86_REG_AX) { + return EMIT_OP_IMM16(0x0d); + } else { + return EMIT_OP_SPARE_REG_IMM16(0x81, 1); + } + case CG_X86_OP_XOR: + if(reg == CG_X86_REG_AX) { + return EMIT_OP_IMM16(0x35); + } else { + return EMIT_OP_SPARE_REG_IMM16(0x81, 6); + } + case CG_X86_OP_MOV: + return EMIT_OP_IMM16(0xb8 + register_code[reg]); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg16_imm8_instr(char *str, size_t size, int opcode, int reg, int imm) { + int n = 0, m, spare; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_SPARE_REG_IMM8(0x83, 2); + case CG_X86_OP_ADD: + return EMIT_OP_SPARE_REG_IMM8(0x83, 0); + case CG_X86_OP_AND: + return EMIT_OP_SPARE_REG_IMM8(0x83, 4); + case CG_X86_OP_CMP: + return EMIT_OP_SPARE_REG_IMM8(0x83, 7); + case CG_X86_OP_OR: + return EMIT_OP_SPARE_REG_IMM8(0x83, 1); + case CG_X86_OP_XOR: + return EMIT_OP_SPARE_REG_IMM8(0x83, 6); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg16_mem16_instr(char *str, size_t size, int opcode, int reg, int base, int scale, int index, int displacement) { + int n = 0, m; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_REG_MEM16(0x13); + case CG_X86_OP_ADD: + return EMIT_OP_REG_MEM16(0x03); + case CG_X86_OP_AND: + return EMIT_OP_REG_MEM16(0x23); + case CG_X86_OP_CMP: + return EMIT_OP_REG_MEM16(0x3b); + case CG_X86_OP_OR: + return EMIT_OP_REG_MEM16(0x0b); + case CG_X86_OP_XOR: + return EMIT_OP_REG_MEM16(0x33); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg16_reg16_instr(char *str, size_t size, int opcode, int rega, int regb) { + int n = 0, m; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_REG_REG16(0x13); + case CG_X86_OP_ADD: + return EMIT_OP_REG_REG16(0x03); + case CG_X86_OP_AND: + return EMIT_OP_REG_REG16(0x23); + case CG_X86_OP_CMP: + return EMIT_OP_REG_REG16(0x3b); + case CG_X86_OP_OR: + return EMIT_OP_REG_REG16(0x0b); + case CG_X86_OP_XOR: + return EMIT_OP_REG_REG16(0x33); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg32_instr(char *str, size_t size, int opcode, int reg) { + int n = 0; + switch(opcode) { + case CG_X86_OP_CALL: + return EMIT_OP_SPARE_REG32(0xff, 2); + case CG_X86_OP_DEC: + INSTR32 + EMIT_BYTE(0x48 + register_code[reg]); + break; + case CG_X86_OP_DIV: + return EMIT_OP_SPARE_REG32(0xf7, 6); + case CG_X86_OP_IDIV: + return EMIT_OP_SPARE_REG32(0xf7, 7); + case CG_X86_OP_IMUL: + return EMIT_OP_SPARE_REG32(0xf7, 5); + case CG_X86_OP_INC: + INSTR32 + EMIT_BYTE(0x40 + register_code[reg]); + break; + case CG_X86_OP_MUL: + return EMIT_OP_SPARE_REG32(0xf7, 4); + case CG_X86_OP_NEG: + return EMIT_OP_SPARE_REG32(0xf7, 3); + case CG_X86_OP_NOT: + return EMIT_OP_SPARE_REG32(0xf7, 2); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg32_imm32_instr(char *str, size_t size, int opcode, int reg, int imm) { + int n = 0, m, spare; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + if(reg == CG_X86_REG_EAX) { + return EMIT_OP_IMM32(0x15); + } else { + return EMIT_OP_SPARE_REG_IMM32(0x81, 2); + } + case CG_X86_OP_ADD: + if(reg == CG_X86_REG_EAX) { + return EMIT_OP_IMM32(0x05); + } else { + return EMIT_OP_SPARE_REG_IMM32(0x81, 0); + } + case CG_X86_OP_AND: + if(reg == CG_X86_REG_EAX) { + return EMIT_OP_IMM32(0x25); + } else { + return EMIT_OP_SPARE_REG_IMM32(0x81, 4); + } + case CG_X86_OP_CMP: + if(reg == CG_X86_REG_EAX) { + return EMIT_OP_IMM32(0x3d); + } else { + return EMIT_OP_SPARE_REG_IMM32(0x81, 7); + } + case CG_X86_OP_OR: + if(reg == CG_X86_REG_EAX) { + return EMIT_OP_IMM32(0x0d); + } else { + return EMIT_OP_SPARE_REG_IMM32(0x81, 1); + } + case CG_X86_OP_XOR: + if(reg == CG_X86_REG_EAX) { + return EMIT_OP_IMM32(0x35); + } else { + return EMIT_OP_SPARE_REG_IMM32(0x81, 6); + } + case CG_X86_OP_MOV: + return EMIT_OP_IMM32(0xb8 + register_code[reg]); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg32_imm8_instr(char *str, size_t size, int opcode, int reg, int imm) { + int n = 0, m, spare; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_SPARE_REG_IMM8(0x83, 2); + case CG_X86_OP_ADD: + return EMIT_OP_SPARE_REG_IMM8(0x83, 0); + case CG_X86_OP_AND: + return EMIT_OP_SPARE_REG_IMM8(0x83, 4); + case CG_X86_OP_CMP: + return EMIT_OP_SPARE_REG_IMM8(0x83, 7); + case CG_X86_OP_OR: + return EMIT_OP_SPARE_REG_IMM8(0x83, 1); + case CG_X86_OP_XOR: + return EMIT_OP_SPARE_REG_IMM8(0x83, 6); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg32_mem32_instr(char *str, size_t size, int opcode, int reg, int base, int scale, int index, int displacement) { + int n = 0, m; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_REG_MEM32(0x13); + case CG_X86_OP_ADD: + return EMIT_OP_REG_MEM32(0x03); + case CG_X86_OP_AND: + return EMIT_OP_REG_MEM32(0x23); + case CG_X86_OP_CMP: + return EMIT_OP_REG_MEM32(0x3b); + case CG_X86_OP_OR: + return EMIT_OP_REG_MEM32(0x0b); + case CG_X86_OP_XOR: + return EMIT_OP_REG_MEM32(0x33); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg32_reg32_instr(char *str, size_t size, int opcode, int rega, int regb) { + int n = 0, m; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_REG_REG32(0x13); + case CG_X86_OP_ADD: + return EMIT_OP_REG_REG32(0x03); + case CG_X86_OP_AND: + return EMIT_OP_REG_REG32(0x23); + case CG_X86_OP_CMP: + return EMIT_OP_REG_REG32(0x3b); + case CG_X86_OP_OR: + return EMIT_OP_REG_REG32(0x0b); + case CG_X86_OP_XOR: + return EMIT_OP_REG_REG32(0x33); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg8_instr(char *str, size_t size, int opcode, int reg) { + int n = 0; + switch(opcode) { + case CG_X86_OP_DEC: + return EMIT_OP_SPARE_REG8(0xfe, 1); + case CG_X86_OP_DIV: + return EMIT_OP_SPARE_REG8(0xf6, 6); + case CG_X86_OP_IDIV: + return EMIT_OP_SPARE_REG8(0xf6, 7); + case CG_X86_OP_IMUL: + return EMIT_OP_SPARE_REG8(0xf6, 5); + case CG_X86_OP_INC: + return EMIT_OP_SPARE_REG8(0xfe, 0); + case CG_X86_OP_MUL: + return EMIT_OP_SPARE_REG8(0xf6, 4); + case CG_X86_OP_NEG: + return EMIT_OP_SPARE_REG8(0xf6, 3); + case CG_X86_OP_NOT: + return EMIT_OP_SPARE_REG8(0xf6, 2); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg8_imm8_instr(char *str, size_t size, int opcode, int reg, int imm) { + int n = 0, m, spare; + char op; + switch(opcode) { + case CG_X86_OP_ADC: + if(reg == CG_X86_REG_AL) { + return EMIT_OP_IMM8(0x14); + } else { + return EMIT_OP_SPARE_REG_IMM8(0x80, 2); + } + case CG_X86_OP_ADD: + if(reg == CG_X86_REG_AL) { + return EMIT_OP_IMM8(0x04); + } else { + return EMIT_OP_SPARE_REG_IMM8(0x80, 0); + } + case CG_X86_OP_AND: + if(reg == CG_X86_REG_AL) { + return EMIT_OP_IMM8(0x24); + } else { + return EMIT_OP_SPARE_REG_IMM8(0x80, 4); + } + case CG_X86_OP_CMP: + if(reg == CG_X86_REG_AL) { + return EMIT_OP_IMM8(0x3c); + } else { + return EMIT_OP_SPARE_REG_IMM8(0x80, 7); + } + case CG_X86_OP_OR: + if(reg == CG_X86_REG_AL) { + return EMIT_OP_IMM8(0x0c); + } else { + return EMIT_OP_SPARE_REG_IMM8(0x80, 1); + } + case CG_X86_OP_XOR: + if(reg == CG_X86_REG_AL) { + return EMIT_OP_IMM8(0x34); + } else { + return EMIT_OP_SPARE_REG_IMM8(0x80, 6); + } + case CG_X86_OP_MOV: + return EMIT_OP_IMM8(0xb0 + register_code[reg]); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg8_mem8_instr(char *str, size_t size, int opcode, int reg, int base, int scale, int index, int displacement) { + int n = 0, m; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_MEM_REG8(0x12); + case CG_X86_OP_ADD: + return EMIT_OP_MEM_REG8(0x02); + case CG_X86_OP_AND: + return EMIT_OP_MEM_REG8(0x22); + case CG_X86_OP_CMP: + return EMIT_OP_MEM_REG8(0x3a); + case CG_X86_OP_OR: + return EMIT_OP_MEM_REG8(0x0a); + case CG_X86_OP_XOR: + return EMIT_OP_MEM_REG8(0x32); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_reg8_reg8_instr(char *str, size_t size, int opcode, int rega, int regb) { + int n = 0, m; + switch(opcode) { + case CG_X86_OP_ADC: + return EMIT_OP_REG_REG8(0x12); + case CG_X86_OP_ADD: + return EMIT_OP_REG_REG8(0x02); + case CG_X86_OP_AND: + return EMIT_OP_REG_REG8(0x22); + case CG_X86_OP_CMP: + return EMIT_OP_REG_REG8(0x3a); + case CG_X86_OP_OR: + return EMIT_OP_REG_REG8(0x0a); + case CG_X86_OP_XOR: + return EMIT_OP_REG_REG8(0x32); + default: + INVALID_INSTRUCTION + } + return n; +} + +int cg_x86_emit_instr(char *str, size_t size, struct cg_x86_instr *instr) { + int opcode = instr->opcode; + int rega, regb, imm; + struct cg_x86_mem *mem; + + /* Dispatch based on instruction format. */ + switch(instr->arga ? instr->arga->type : 0) { + case 0: + /* No arga */ + return cg_x86_emit_nullary_instr(str, size, opcode); + + case CG_X86_ARGTYPE_IMM8: + /* Arga is imm8 */ + imm = instr->arga->value.imm; + switch(instr->argb ? instr->argb->type : 0) { + case 0: + return cg_x86_emit_imm8_instr(str, size, opcode, imm); + default: + INVALID_INSTRUCTION + } + + case CG_X86_ARGTYPE_REG8: + /* Arga is reg8 */ + rega = instr->arga->value.reg; + switch(instr->argb ? instr->argb->type : 0) { + case 0: + return cg_x86_emit_reg8_instr(str, size, opcode, rega); + case CG_X86_ARGTYPE_IMM8: + return cg_x86_emit_reg8_imm8_instr(str, size, opcode, rega, instr->argb->value.imm); + case CG_X86_ARGTYPE_REG8: + return cg_x86_emit_reg8_reg8_instr(str, size, opcode, rega, instr->argb->value.reg); + case CG_X86_ARGTYPE_MEM8: + mem = instr->argb->value.mem; + return cg_x86_emit_reg8_mem8_instr(str, size, opcode, rega, mem->base, mem->scale, mem->index, mem->displacement); + default: + INVALID_INSTRUCTION + } + + case CG_X86_ARGTYPE_REG16: + /* Arga is reg16 */ + rega = instr->arga->value.reg; + switch(instr->argb ? instr->argb->type : 0) { + case 0: + return cg_x86_emit_reg16_instr(str, size, opcode, rega); + case CG_X86_ARGTYPE_IMM16: + return cg_x86_emit_reg16_imm16_instr(str, size, opcode, rega, instr->argb->value.imm); + case CG_X86_ARGTYPE_MEM16: + mem = instr->argb->value.mem; + return cg_x86_emit_reg16_mem16_instr(str, size, opcode, rega, mem->base, mem->scale, mem->index, mem->displacement); + case CG_X86_ARGTYPE_REG16: + return cg_x86_emit_reg16_reg16_instr(str, size, opcode, rega, instr->argb->value.reg); + default: + INVALID_INSTRUCTION + } + + case CG_X86_ARGTYPE_REG32: + /* Arga is reg32 */ + rega = instr->arga->value.reg; + switch(instr->argb ? instr->argb->type : 0) { + case 0: + return cg_x86_emit_reg32_instr(str, size, opcode, rega); + case CG_X86_ARGTYPE_IMM32: + return cg_x86_emit_reg32_imm32_instr(str, size, opcode, rega, instr->argb->value.imm); + case CG_X86_ARGTYPE_MEM32: + mem = instr->argb->value.mem; + return cg_x86_emit_reg32_mem32_instr(str, size, opcode, rega, mem->base, mem->scale, mem->index, mem->displacement); + case CG_X86_ARGTYPE_REG32: + return cg_x86_emit_reg32_reg32_instr(str, size, opcode, rega, instr->argb->value.reg); + default: + INVALID_INSTRUCTION + } + + case CG_X86_ARGTYPE_MEM8: + /* Arga is mem8 */ + mem = instr->arga->value.mem; + switch(instr->argb ? instr->argb->type : 0) { + case 0: + return cg_x86_emit_mem8_instr(str, size, opcode, mem->base, mem->scale, mem->index, mem->displacement); + case CG_X86_ARGTYPE_IMM8: + return cg_x86_emit_mem8_imm8_instr(str, size, opcode, mem->base, mem->scale, + mem->index, mem->displacement, instr->argb->value.imm); + case CG_X86_ARGTYPE_REG8: + return cg_x86_emit_mem8_reg8_instr(str, size, opcode, mem->base, mem->scale, mem->index, mem->displacement, + instr->argb->value.reg); + default: + INVALID_INSTRUCTION + } + + case CG_X86_ARGTYPE_MEM16: + /* Arga is mem16 */ + mem = instr->arga->value.mem; + switch(instr->argb ? instr->argb->type : 0) { + case 0: + return cg_x86_emit_mem16_instr(str, size, opcode, mem->base, mem->scale, mem->index, mem->displacement); + case CG_X86_ARGTYPE_IMM16: + return cg_x86_emit_mem16_imm16_instr(str, size, opcode, mem->base, mem->scale, + mem->index, mem->displacement, instr->argb->value.imm); + default: + INVALID_INSTRUCTION + } + + case CG_X86_ARGTYPE_MEM32: + /* Arga is mem32 */ + mem = instr->arga->value.mem; + switch(instr->argb ? instr->argb->type : 0) { + case 0: + return cg_x86_emit_mem32_instr(str, size, opcode, mem->base, mem->scale, mem->index, mem->displacement); + case CG_X86_ARGTYPE_IMM32: + return cg_x86_emit_mem32_imm32_instr(str, size, opcode, mem->base, mem->scale, + mem->index, mem->displacement, instr->argb->value.imm); + default: + INVALID_INSTRUCTION + } + + default: + INVALID_INSTRUCTION + } +} + +int cg_x86_snprint_mem(char *str, size_t size, struct cg_x86_mem *mem) { + if(mem) { + if(mem->scale) { + if(mem->displacement) { + return snprintf(str, size, "[%s + %d * %s + %d]", + cg_x86_registers[mem->base], + mem->scale, + cg_x86_registers[mem->index], + mem->displacement); + } else { + return snprintf(str, size, "[%s + %d * %s]", + cg_x86_registers[mem->base], + mem->scale, + cg_x86_registers[mem->index]); + } + } else { + if(mem->displacement) { + return snprintf(str, size, "[%s + %d]", + cg_x86_registers[mem->base], + mem->displacement); + } else { + return snprintf(str, size, "[%s]", + cg_x86_registers[mem->base]); + } + } + } else { + return snprintf(str, size, "#"); + } +} + +int cg_x86_snprint_reg(char *str, size_t size, int reg) { + return snprintf(str, size, cg_x86_registers[reg]); +} + +int cg_x86_snprint_arg(char *str, size_t size, struct cg_x86_arg *arg) { + int n; + if(arg) { + switch(arg->type) { + case CG_X86_ARGTYPE_IMM8: + n = snprintf(str, size, "(byte) %d", arg->value.imm); + break; + case CG_X86_ARGTYPE_IMM16: + n = snprintf(str, size, "(word) %d", arg->value.imm); + break; + case CG_X86_ARGTYPE_IMM32: + n = snprintf(str, size, "(dword) %d", arg->value.imm); + break; + case CG_X86_ARGTYPE_MEM8: + n = snprintf(str, size, "(byte) "); + n += cg_x86_snprint_mem(str + n, atleast0(size - n), arg->value.mem); + break; + case CG_X86_ARGTYPE_MEM16: + n = snprintf(str, size, "(word) "); + n += cg_x86_snprint_mem(str + n, atleast0(size - n), arg->value.mem); + break; + case CG_X86_ARGTYPE_MEM32: + n = snprintf(str, size, "(dword) "); + n += cg_x86_snprint_mem(str + n, atleast0(size - n), arg->value.mem); + break; + case CG_X86_ARGTYPE_REG8: + case CG_X86_ARGTYPE_REG16: + case CG_X86_ARGTYPE_REG32: + n = cg_x86_snprint_reg(str, size, arg->value.reg); + break; + default: + n = snprintf(str, size, "#", arg->type); + } + } else { + n = snprintf(str, size, "#"); + } + return n; +} + +int cg_x86_snprint_instr(char *str, size_t size, struct cg_x86_instr *instr) { + int n; + if(instr) { + n = snprintf(str, size, "%s", cg_x86_opcodes[instr->opcode]); + if(instr->arga) { + if(n < size) str[n] = ' '; + n++; + n += cg_x86_snprint_arg(str + n, atleast0(size - n), instr->arga); + } + if(instr->argb) { + if(n < size) str[n] = ','; + n++; + if(n < size) str[n] = ' '; + n++; + n += cg_x86_snprint_arg(str + n, atleast0(size - n), instr->argb); + } + } else { + n = snprintf(str, size, "#"); + } + return n; +} + +int cg_x86_snprint_instr_nl(char *str, size_t size, struct cg_x86_instr *instr) { + int n = cg_x86_snprint_instr(str, size, instr); + if(n < size) str[n] = '\n'; + return n + 1; +} + +int cg_x86_get_mode() { return mode; } +void cg_x86_set_mode(int newmode) { mode = newmode; } + +void cg_x86_set_malloc(void *(*newmalloc) (size_t)) { + my_malloc = newmalloc; +} + +void cg_x86_set_free(void (*newfree) (void*)) { + my_free = newfree; +} diff --git a/x86/test/Makefile b/x86/test/Makefile new file mode 100644 index 0000000..ad24c6b --- /dev/null +++ b/x86/test/Makefile @@ -0,0 +1,21 @@ +include ../Makefile.cfg + +TARGETS = exit42 +OBJECTS = + +all : test + +clean : + -rm $(OBJECTS) + +distclean : clean + -rm $(TARGETS) + +test : $(TARGETS) + +.SUFFIXES : .c .o + +.c : $(LIBTARGET) + $(CC) $(CFLAGS) -I../../include $< -o $@ $(LDFLAGS) -L../lib -lalchemist_x86 + +.PHONY : all clean distclean test diff --git a/x86/test/exit42.c b/x86/test/exit42.c new file mode 100644 index 0000000..8850e01 --- /dev/null +++ b/x86/test/exit42.c @@ -0,0 +1,43 @@ +#include "alchemist/x86.h" + +int main(int argc, char **argv) { + char code[0x10000]; + int n = 0; + + /*** write code ***/ + + /* xor eax, eax */ + n += cg_x86_emit_reg32_reg32_instr(code + n, + sizeof(code - n), + CG_X86_OP_XOR, + CG_X86_REG_EAX, + CG_X86_REG_EAX); + /* inc eax */ + n += cg_x86_emit_reg32_instr(code + n, + sizeof(code) - n, + CG_X86_OP_INC, + CG_X86_REG_EAX); + /* xor ebx, ebx */ + n += cg_x86_emit_reg32_reg32_instr(code + n, + sizeof(code) - n, + CG_X86_OP_XOR, + CG_X86_REG_EBX, + CG_X86_REG_EBX); + /* or ebx, 42 */ + n += cg_x86_emit_reg32_imm8_instr(code + n, + sizeof(code) - n, + CG_X86_OP_OR, + CG_X86_REG_EBX, + 42); + /* int 0x80 */ + n += cg_x86_emit_imm8_instr(code + n, + sizeof(code) - n, + CG_X86_OP_INT, + 0x80); + + /*** invoke code ***/ + ((void (*) ()) code)(); + + /*** should not be reached ***/ + return 0; +} diff --git a/x86/test/test.c b/x86/test/test.c new file mode 100644 index 0000000..074b173 --- /dev/null +++ b/x86/test/test.c @@ -0,0 +1,311 @@ +#include +#include +#include "x86.h" + +#define AL CG_X86_REG_AL +#define AH CG_X86_REG_AH +#define BL CG_X86_REG_BL +#define BH CG_X86_REG_BH +#define CL CG_X86_REG_CL +#define CH CG_X86_REG_CH +#define DL CG_X86_REG_DL +#define DH CG_X86_REG_DH +#define AX CG_X86_REG_AX +#define BX CG_X86_REG_BX +#define CX CG_X86_REG_CX +#define DX CG_X86_REG_DX +#define SI CG_X86_REG_SI +#define DI CG_X86_REG_DI +#define BP CG_X86_REG_BP +#define SP CG_X86_REG_SP +#define EAX CG_X86_REG_EAX +#define EBX CG_X86_REG_EBX +#define ECX CG_X86_REG_ECX +#define EDX CG_X86_REG_EDX +#define ESI CG_X86_REG_ESI +#define EDI CG_X86_REG_EDI +#define EBP CG_X86_REG_EBP +#define ESP CG_X86_REG_ESP + +#define ADC CG_X86_OP_ADC +#define ADD CG_X86_OP_ADD +#define INC CG_X86_OP_INC +#define INT CG_X86_OP_INT +#define OR CG_X86_OP_OR +#define XOR CG_X86_OP_XOR + +#define EMIT write_code(stdout, buffer, n) +#define EMIT_IMM8(OPCODE, IMM) \ + n = cg_x86_emit_imm8_instr(buffer, sizeof(buffer), OPCODE, IMM); EMIT +#define EMIT_MEM8_REG8(OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, REG) \ + n = cg_x86_emit_mem8_reg8_instr(buffer, sizeof(buffer), OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, REG); EMIT +#define EMIT_MEM16_REG16(OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, REG) \ + n = cg_x86_emit_mem16_reg16_instr(buffer, sizeof(buffer), OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, REG); EMIT +#define EMIT_MEM32_REG32(OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, REG) \ + n = cg_x86_emit_mem32_reg32_instr(buffer, sizeof(buffer), OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, REG); EMIT +#define EMIT_MEM8_IMM8(OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, IMM) \ + n = cg_x86_emit_mem8_imm8_instr(buffer, sizeof(buffer), OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, IMM); EMIT +#define EMIT_MEM16_IMM16(OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, IMM) \ + n = cg_x86_emit_mem16_imm16_instr(buffer, sizeof(buffer), OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, IMM); EMIT +#define EMIT_MEM32_IMM32(OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, IMM) \ + n = cg_x86_emit_mem32_imm32_instr(buffer, sizeof(buffer), OPCODE, BASE, SCALE, INDEX, DISPLACEMENT, IMM); EMIT +#define EMIT_REG8_IMM8(OPCODE, REG, IMM) \ + n = cg_x86_emit_reg8_imm8_instr(buffer, sizeof(buffer), OPCODE, REG, IMM); EMIT +#define EMIT_REG16_IMM16(OPCODE, REG, IMM) \ + n = cg_x86_emit_reg16_imm16_instr(buffer, sizeof(buffer), OPCODE, REG, IMM); EMIT +#define EMIT_REG16_IMM8(OPCODE, REG, IMM) \ + n = cg_x86_emit_reg16_imm8_instr(buffer, sizeof(buffer), OPCODE, REG, IMM); EMIT +#define EMIT_REG32(OPCODE, REG) \ + n = cg_x86_emit_reg32_instr(buffer, sizeof(buffer), OPCODE, REG); EMIT +#define EMIT_REG32_IMM32(OPCODE, REG, IMM) \ + n = cg_x86_emit_reg32_imm32_instr(buffer, sizeof(buffer), OPCODE, REG, IMM); EMIT +#define EMIT_REG32_IMM8(OPCODE, REG, IMM) \ + n = cg_x86_emit_reg32_imm8_instr(buffer, sizeof(buffer), OPCODE, REG, IMM); EMIT +#define EMIT_REG8_REG8(OPCODE, REGA, REGB) \ + n = cg_x86_emit_reg8_reg8_instr(buffer, sizeof(buffer), OPCODE, REGA, REGB); EMIT +#define EMIT_REG16_REG16(OPCODE, REGA, REGB) \ + n = cg_x86_emit_reg16_reg16_instr(buffer, sizeof(buffer), OPCODE, REGA, REGB); EMIT +#define EMIT_REG32_REG32(OPCODE, REGA, REGB) \ + n = cg_x86_emit_reg32_reg32_instr(buffer, sizeof(buffer), OPCODE, REGA, REGB); EMIT +#define EMIT_REG8_MEM8(OPCODE, REG, BASE, SCALE, INDEX, DISPLACEMENT) \ + n = cg_x86_emit_reg8_mem8_instr(buffer, sizeof(buffer), OPCODE, REG, BASE, SCALE, INDEX, DISPLACEMENT); EMIT +#define EMIT_REG16_MEM16(OPCODE, REG, BASE, SCALE, INDEX, DISPLACEMENT) \ + n = cg_x86_emit_reg16_mem16_instr(buffer, sizeof(buffer), OPCODE, REG, BASE, SCALE, INDEX, DISPLACEMENT); EMIT +#define EMIT_REG32_MEM32(OPCODE, REG, BASE, SCALE, INDEX, DISPLACEMENT) \ + n = cg_x86_emit_reg32_mem32_instr(buffer, sizeof(buffer), OPCODE, REG, BASE, SCALE, INDEX, DISPLACEMENT); EMIT + +static void log(const char *str) { + fprintf(stderr, "%s\n", str); +} + +static void *my_malloc(size_t n) { + /* fprintf(stderr, "Allocating %d bytes\n", n); */ + return malloc(n); +} + +static write_code(FILE *stream, char *buffer, int n) { + if(n < 0) { + fputs(cg_x86_get_last_error(), stderr); + exit(1); + } + return fwrite(buffer, 1, n, stream); +} + +int main(int argc, char **argv) { + int n; + char *buffer[1024]; + struct cg_x86_instr *instr; + + log("adc al, dl"); + EMIT_REG8_REG8(ADC, + AL, + DL); + + log("adc bx, cx"); + EMIT_REG16_REG16(ADC, + BX, + CX); + + log("adc eax, esi"); + EMIT_REG32_REG32(ADC, + EAX, + ESI); + + log("adc [ebp + 1 * esi], al"); + EMIT_MEM8_REG8(ADC, + EBP, 1, ESI, 0, + AL); + + log("adc [ebp + 2 * esi + 2], ax"); + EMIT_MEM16_REG16(ADC, + EBP, 2, ESI, 2, + AX); + + log("adc [ebp + 4 * esi - 4], eax"); + EMIT_MEM32_REG32(ADC, + EBP, 4, ESI, -4, + EAX); + + log("adc byte [ebp + esi], 0"); + EMIT_MEM8_IMM8(ADC, + EBP, 1, ESI, 0, + 0); + + log("adc word [ebp + 2 * esi + 2], 0xffff"); + EMIT_MEM16_IMM16(ADC, + EBP, 2, ESI, 2, + 0xffff); + + log("adc dword [ebp + 4 * esi - 4], 0xfafafafa"); + EMIT_MEM32_IMM32(ADC, + EBP, 4, ESI, -4, + 0xfafafafa); + + log("adc ah, [ebx + 12]"); + EMIT_REG8_MEM8(ADC, + AH, + EBX, 0, 0, 12); + + log("adc di, [ebp + 4 * ecx + 12]"); + EMIT_REG16_MEM16(ADC, + DI, + EBP, 4, ECX, 12); + + log("adc edx, [ebp]"); + EMIT_REG32_MEM32(ADC, + EDX, + EBP, 0, 0, 0); + + log("adc bh, 42"); + EMIT_REG8_IMM8(ADC, + BH, + 42); + + log("adc cx, 0x4242"); + EMIT_REG16_IMM16(ADC, + CX, + 0x4242); + + log("adc edi, 0xdeadbeef"); + EMIT_REG32_IMM32(ADC, + EDI, + 0xdeadbeef); + + log("adc cx, byte 42"); + EMIT_REG16_IMM8(ADC, + CX, + 42); + + log("adc edi, byte 42"); + EMIT_REG32_IMM8(ADC, + EDI, + 42); + + log("adc al, 0x66"); + EMIT_REG8_IMM8(ADC, + AL, + 0x66); + + log("adc ax, 0x6666"); + EMIT_REG16_IMM16(ADC, + AX, + 0x6666); + + log("adc eax, 0x66666666"); + EMIT_REG32_IMM32(ADC, + EAX, + 0x66666666); + + log("add al, dl"); + EMIT_REG8_REG8(ADD, + AL, + DL); + + log("add bx, cx"); + EMIT_REG16_REG16(ADD, + BX, + CX); + + log("add eax, esi"); + EMIT_REG32_REG32(ADD, + EAX, + ESI); + + log("add [ebp + 1 * esi], al"); + EMIT_MEM8_REG8(ADD, + EBP, 1, ESI, 0, + AL); + + log("add [ebp + 2 * esi + 2], ax"); + EMIT_MEM16_REG16(ADD, + EBP, 2, ESI, 2, + AX); + + log("add [ebp + 4 * esi - 4], eax"); + EMIT_MEM32_REG32(ADD, + EBP, 4, ESI, -4, + EAX); + + log("add byte [ebp + esi], 0"); + EMIT_MEM8_IMM8(ADD, + EBP, 1, ESI, 0, + 0); + + log("add word [ebp + 2 * esi + 2], 0xffff"); + EMIT_MEM16_IMM16(ADD, + EBP, 2, ESI, 2, + 0xffff); + + log("add dword [ebp + 4 * esi - 4], 0xfafafafa"); + EMIT_MEM32_IMM32(ADD, + EBP, 4, ESI, -4, + 0xfafafafa); + + log("add ah, [ebx + 12]"); + EMIT_REG8_MEM8(ADD, + AH, + EBX, 0, 0, 12); + + log("add di, [ebp + 4 * ecx + 12]"); + EMIT_REG16_MEM16(ADD, + DI, + EBP, 4, ECX, 12); + + log("add edx, [ebp]"); + EMIT_REG32_MEM32(ADD, + EDX, + EBP, 0, 0, 0); + + log("add bh, 42"); + EMIT_REG8_IMM8(ADD, + BH, + 42); + + log("add cx, 0x4242"); + EMIT_REG16_IMM16(ADD, + CX, + 0x4242); + + log("add edi, 0xdeadbeef"); + EMIT_REG32_IMM32(ADD, + EDI, + 0xdeadbeef); + + log("add cx, byte 42"); + EMIT_REG16_IMM8(ADD, + CX, + 42); + + log("add edi, byte 42"); + EMIT_REG32_IMM8(ADD, + EDI, + 42); + + log("add al, 0x66"); + EMIT_REG8_IMM8(ADD, + AL, + 0x66); + + log("add ax, 0x6666"); + EMIT_REG16_IMM16(ADD, + AX, + 0x6666); + + log("add eax, 0x66666666"); + EMIT_REG32_IMM32(ADD, + EAX, + 0x66666666); + + log("xor eax, eax"); + EMIT_REG32_REG32(XOR, EAX, EAX); + log("inc eax"); + EMIT_REG32(INC, EAX); + log("xor ebx, ebx"); + EMIT_REG32_REG32(XOR, EBX, EBX); + log("or ebx, byte 42"); + EMIT_REG32_IMM8(OR, EBX, 42); + log("int 0x80"); + EMIT_IMM8(INT, 0x80); + + return 0; +} -- 2.11.4.GIT