From a38d6d7fde92c0697c3ec349865e39800a7a001e Mon Sep 17 00:00:00 2001 From: inglorion Date: Wed, 7 May 2008 06:30:36 +0200 Subject: [PATCH] Added some documentation to x86.c. Added doc target to x86/Makefile. --- x86/Makefile | 9 +- x86/lib/x86.c | 333 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 338 insertions(+), 4 deletions(-) diff --git a/x86/Makefile b/x86/Makefile index 1c40271..73cdaaf 100644 --- a/x86/Makefile +++ b/x86/Makefile @@ -1,9 +1,9 @@ -SUBDIRS = lib test +SUBDIRS = doc lib test lib : cd lib && $(MAKE) -all : lib test +all : doc lib test clean : for dir in $(SUBDIRS); do (cd "$$dir" && $(MAKE) clean); done @@ -11,7 +11,10 @@ clean : distclean : for dir in $(SUBDIRS); do (cd "$$dir" && $(MAKE) distclean); done +doc : + cd doc && $(MAKE) + test : cd test && $(MAKE) -.PHONY : all lib clean distclean test +.PHONY : all lib clean distclean doc test diff --git a/x86/lib/x86.c b/x86/lib/x86.c index 448819c..52e24ee 100644 --- a/x86/lib/x86.c +++ b/x86/lib/x86.c @@ -2,6 +2,46 @@ #include #include "alchemist/x86.h" +/** \file + * + * \section concepts Concepts + * + * This library is used to emit instructions. + * + * Instructions consist of an opcode and + * zero, one, or two arguments. + * + * Arguments can be immediate values, + * registers, or memory locations. + * + * An immediate value can be 8, 16, or 32 bits (immediate + * values of these sizes are abbreviated imm8, + * imm16 and imm32, respectively). + * Whichever the size of the immediate value, its value is + * always given as an int in the API. + * + * Registers are specified using integers. The + * CG_X86_REG_* macros can be used to designate specific + * registers (the name of the register is used in place of + * the *). In the emitted instructions, registers are + * designated by their code, which can be obtained by + * using the int used by this API as an index in the + * array register_code. + * + * Memory addresses are specified using a base, a scale + * factor, and index, and a displacement. Base and + * index are registers, whereas scale factor and displacement + * are integers. The scale factor must be 0, 1, 2, 4, or 8. + * The actual address is given by + * value_of_base_register + scale_factor * value_of_index_register + * + displacement. + */ + +/** Allocate memory for a value. + * Allocates memory for a single value of a given type. + * @param T The type of value to allocate memory for. + * @return A pointer to the newly allocated memory, or NULL on error. + */ #define NEW(T) (T*) my_malloc(sizeof(T)) #define BYTE char @@ -78,7 +118,7 @@ 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 */ +/** Address of the form base + scale * index + offset */ struct cg_x86_mem { int base; int scale; @@ -86,6 +126,12 @@ struct cg_x86_mem { int displacement; }; +/** Argument to an instruction. + * There are three types of argument: + * 1. immediate + * 2. memory address + * 3. register + */ struct cg_x86_arg { int type; union { @@ -95,12 +141,17 @@ struct cg_x86_arg { } value; }; +/** An x86 instruction. + * An unstruction consists of an opcode and two arguments, + * which can be NULL. + */ struct cg_x86_instr { int opcode; struct cg_x86_arg *arga; struct cg_x86_arg *argb; }; +/** Table translating CG_X86_OP_* macros to operation names. */ char *cg_x86_opcodes[] = { NULL, "add", @@ -198,6 +249,7 @@ char *cg_x86_opcodes[] = { "xor", }; +/** Table translating CG_X86_REG_* macros to register names. */ char *cg_x86_registers[] = { NULL, "ax", @@ -226,6 +278,7 @@ char *cg_x86_registers[] = { "esp", }; +/** Table translating CG_X86_REG_* macros to register codes. */ static int register_code[] = { -1, 0, @@ -254,10 +307,18 @@ static int register_code[] = { 4, }; +/** Given a number, returs that number if it is greater than 0, + * else returns 0. + */ static size_t atleast0(size_t n) { return (n > 0) ? n : 0; } +/** Return the size, in bits, of the argument. + * @param arg The argument whose size to determine. + * @return The size of the argument in bits (8, 16, or 32), + * 0 if arg was NULL, or -1 if an error occurred. + */ static int argument_size(struct cg_x86_arg *arg) { if(!arg) return 0; switch(arg->type) { @@ -278,10 +339,16 @@ static int argument_size(struct cg_x86_arg *arg) { } } +/** Free a cg_x86_mem structure. + * @param mem The structure to free. + */ void cg_x86_free_mem(struct cg_x86_mem *mem) { if(mem) free(mem); } +/** Free an cg_x86_arg structure and its children. + * @param arg The structure to free. + */ void cg_x86_free_arg(struct cg_x86_arg *arg) { if(arg) { switch(arg->type) { @@ -297,6 +364,9 @@ void cg_x86_free_arg(struct cg_x86_arg *arg) { } } +/** Free an cg_x86_instr structure and its children. + * @param instr The structure to free. + */ void cg_x86_free_instr(struct cg_x86_instr *instr) { if(instr) { if(instr->arga) cg_x86_free_arg(instr->arga); @@ -305,6 +375,7 @@ void cg_x86_free_instr(struct cg_x86_instr *instr) { } } +/** Get the last error. */ char *cg_x86_get_last_error() { return error; } @@ -407,6 +478,17 @@ struct cg_x86_instr *cg_x86_make_instr(int opcode, return instr; } +/** Emits a modrm parameter that refers to a memory location. + * @param str The buffer to store the modrm in. + * @param size The size of the buffer. + * @param base The register that holds the base of the memory location. + * @param scale The scale factor (must be 0, 1, 2, 4, or 8). + * @param index The register that holds the index (ignored if scale == 0). + * @param displacement The displacement of the memory location. + * @param spare The value to store in the spare bits of the modrm. + * + * @return The number of bytes needed to store the modrm. + */ 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; @@ -488,6 +570,14 @@ int cg_x86_emit_mem_modrm(char *str, size_t size, int base, int scale, int index return n; } +/** Emits a modrm that refers to a register. + * @param str The buffer to store the emitted code in. + * @param size The size of the buffer. + * @param reg The register to encode in the modrm. + * @param spare The value to encode in the spare of the modrm. + * + * @return The number of bytes needed to store the emitted modrm. + */ 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]); @@ -549,6 +639,13 @@ int cg_x86_emit_mem_or_reg_arg(char *str, size_t size, struct cg_x86_arg *arg, i } } +/** Emits a conditional jump instruction with a 16-bit offset. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param cc The condition code. + * @param imm The offset. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_jcc16(char *str, size_t size, int cc, int imm) { int n = 0; INSTR16 @@ -558,6 +655,13 @@ int cg_x86_emit_jcc16(char *str, size_t size, int cc, int imm) { return n; } +/** Emits a conditional jump instruction with a 32-bit offset. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param cc The condition code. + * @param imm The offset. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_jcc32(char *str, size_t size, int cc, int imm) { int n = 0; INSTR32 @@ -567,6 +671,13 @@ int cg_x86_emit_jcc32(char *str, size_t size, int cc, int imm) { return n; } +/** Emits an instruction consisting of an opcode and a 16-bit immediate argument. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param imm The immediate value. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_op_imm16(char *str, size_t size, char op, int imm) { int n = 0; INSTR16 @@ -575,6 +686,14 @@ int cg_x86_emit_op_imm16(char *str, size_t size, char op, int imm) { return n; } +/** Emits an instruction consisting of an opcode and two 16-bit immediate arguments. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param imma The first immediate value. + * @param immb The second immediate value. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_op_imm16_imm16(char *str, size_t size, char op, int imma, int immb) { int n = 0; INSTR16 @@ -584,6 +703,15 @@ int cg_x86_emit_op_imm16_imm16(char *str, size_t size, char op, int imma, int im return n; } +/** Emits an instruction consisting of an opcode, one 16-bit immediate argument, + * and one 32-bit immediate argument. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param imma The 16-bit immediate value. + * @param immb The 32-bit immediate value. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_op_imm16_imm32(char *str, size_t size, char op, int imma, int immb) { int n = 0; INSTR32 @@ -593,6 +721,13 @@ int cg_x86_emit_op_imm16_imm32(char *str, size_t size, char op, int imma, int im return n; } +/** Emits an instruction consisting of an opcode and a 32-bit immediate argument. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param imm The immediate value. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_op_imm32(char *str, size_t size, char op, int imm) { int n = 0; INSTR32 @@ -601,6 +736,13 @@ int cg_x86_emit_op_imm32(char *str, size_t size, char op, int imm) { return n; } +/** Emits an instruction consisting of an opcode and a 8-bit immediate argument. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param imm The immediate value. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_op_imm8(char *str, size_t size, char op, int imm) { int n = 0; EMIT_BYTE(op); @@ -608,6 +750,18 @@ int cg_x86_emit_op_imm8(char *str, size_t size, char op, int imm) { return n; } +/** Emits an instruction consisting of an opcode and a modrm encoding a memory + * address and a 16-bit register. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param base The base of the memory address. + * @param scale The scale of the memory address. + * @param index The index of the memory address. + * @param displacement The displacement of the memory address. + * @param reg The register. + * @return The number of bytes needed to store the instruction. + */ 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 @@ -616,6 +770,18 @@ int cg_x86_emit_op_mem_reg16(char *str, size_t size, char op, int base, int scal return n; } +/** Emits an instruction consisting of an opcode and a modrm encoding a memory + * address and a 32-bit register. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param base The base of the memory address. + * @param scale The scale of the memory address. + * @param index The index of the memory address. + * @param displacement The displacement of the memory address. + * @param reg The register. + * @return The number of bytes needed to store the instruction. + */ 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 @@ -624,6 +790,18 @@ int cg_x86_emit_op_mem_reg32(char *str, size_t size, char op, int base, int scal return n; } +/** Emits an instruction consisting of an opcode and a modrm encoding a memory + * address and an 8-bit register. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param base The base of the memory address. + * @param scale The scale of the memory address. + * @param index The index of the memory address. + * @param displacement The displacement of the memory address. + * @param reg The register. + * @return The number of bytes needed to store the instruction. + */ 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); @@ -631,6 +809,14 @@ int cg_x86_emit_op_mem_reg8(char *str, size_t size, char op, int base, int scale return n; } +/** Emits an instruction consisting of an opcode and a modrm encoding two 16-bit registers. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param rega The first register. + * @param regb The second register. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_op_reg_reg16(char *str, size_t size, char op, int rega, int regb) { int n = 0, m; INSTR16 @@ -639,6 +825,14 @@ int cg_x86_emit_op_reg_reg16(char *str, size_t size, char op, int rega, int regb return n; } +/** Emits an instruction consisting of an opcode and a modrm encoding two 32-bit registers. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param rega The first register. + * @param regb The second register. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_op_reg_reg32(char *str, size_t size, char op, int rega, int regb) { int n = 0, m; INSTR32 @@ -647,6 +841,14 @@ int cg_x86_emit_op_reg_reg32(char *str, size_t size, char op, int rega, int regb return n; } +/** Emits an instruction consisting of an opcode and a modrm encoding two 8-bit registers. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param rega The first register. + * @param regb The second register. + * @return The number of bytes needed to store the instruction. + */ 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); @@ -654,6 +856,18 @@ int cg_x86_emit_op_reg_reg8(char *str, size_t size, char op, int rega, int regb) return n; } +/** Emits an instruction consisting of an opcode, a spare, and a memory address + * referring to a 16-bit value. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param base The base of the memory address. + * @param scale The scale of the memory address. + * @param index The index of the memory address. + * @param displacement The displacement of the memory address. + * @return The number of bytes needed to store the instruction. + */ 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 @@ -662,6 +876,18 @@ int cg_x86_emit_op_spare_mem16(char *str, size_t size, char op, int spare, int b return n; } +/** Emits an instruction consisting of an opcode, a spare, and a memory address + * referring to a 32-bit value. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param base The base of the memory address. + * @param scale The scale of the memory address. + * @param index The index of the memory address. + * @param displacement The displacement of the memory address. + * @return The number of bytes needed to store the instruction. + */ 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 @@ -670,6 +896,18 @@ int cg_x86_emit_op_spare_mem32(char *str, size_t size, char op, int spare, int b return n; } +/** Emits an instruction consisting of an opcode, a spare, and a memory address + * referring to a 8-bit value. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param base The base of the memory address. + * @param scale The scale of the memory address. + * @param index The index of the memory address. + * @param displacement The displacement of the memory address. + * @return The number of bytes needed to store the instruction. + */ 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); @@ -677,6 +915,14 @@ int cg_x86_emit_op_spare_mem8(char *str, size_t size, char op, int spare, int ba return n; } +/** Emits an instruction consisting of an opcode, a spare, and a 16-bit register. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param reg The register. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_op_spare_reg16(char *str, size_t size, char op, int spare, int reg) { int n = 0, m; INSTR16 @@ -685,6 +931,14 @@ int cg_x86_emit_op_spare_reg16(char *str, size_t size, char op, int spare, int r return n; } +/** Emits an instruction consisting of an opcode, a spare, and a 32-bit register. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param reg The register. + * @return The number of bytes needed to store the instruction. + */ int cg_x86_emit_op_spare_reg32(char *str, size_t size, char op, int spare, int reg) { int n = 0, m; INSTR32 @@ -693,6 +947,14 @@ int cg_x86_emit_op_spare_reg32(char *str, size_t size, char op, int spare, int r return n; } +/** Emits an instruction consisting of an opcode, a spare, and a 8-bit register. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param reg The register. + * @return The number of bytes needed to store the instruction. + */ 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); @@ -700,6 +962,16 @@ int cg_x86_emit_op_spare_reg8(char *str, size_t size, char op, int spare, int re return n; } +/** Emits an instruction consisting of an opcode, a spare, a register, + * and a 16-bit immediate value. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param reg The register. + * @param imm The immediate value. + * @return The number of bytes needed to store the instruction. + */ 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 @@ -709,6 +981,16 @@ int cg_x86_emit_op_spare_reg_imm16(char *str, size_t size, char op, int spare, i return n; } +/** Emits an instruction consisting of an opcode, a spare, a register, + * and a 32-bit immediate value. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param reg The register. + * @param imm The immediate value. + * @return The number of bytes needed to store the instruction. + */ 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 @@ -718,6 +1000,16 @@ int cg_x86_emit_op_spare_reg_imm32(char *str, size_t size, char op, int spare, i return n; } +/** Emits an instruction consisting of an opcode, a spare, a register, + * and an 8-bit immediate value. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param reg The register. + * @param imm The immediate value. + * @return The number of bytes needed to store the instruction. + */ 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); @@ -726,6 +1018,19 @@ int cg_x86_emit_op_spare_reg_imm8(char *str, size_t size, char op, int spare, in return n; } +/** Emits an instruction consiting of an opcode, a spare, a memory address, + * and a 16-bit immediate value. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param base The base of the memory address. + * @param scale The scale of the memory address. + * @param index The index of the memory address. + * @param displacement The displacement of the memory address. + * @param imm The immediate value. + * @return The number of bytes needed to store the instruction. + */ 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 @@ -735,6 +1040,19 @@ int cg_x86_emit_op_spare_mem_imm16(char *str, size_t size, char op, int spare, i return n; } +/** Emits an instruction consiting of an opcode, a spare, a memory address, + * and a 32-bit immediate value. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param base The base of the memory address. + * @param scale The scale of the memory address. + * @param index The index of the memory address. + * @param displacement The displacement of the memory address. + * @param imm The immediate value. + * @return The number of bytes needed to store the instruction. + */ 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 @@ -744,6 +1062,19 @@ int cg_x86_emit_op_spare_mem_imm32(char *str, size_t size, char op, int spare, i return n; } +/** Emits an instruction consiting of an opcode, a spare, a memory address, + * and a 8-bit immediate value. + * @param str The buffer to emit the instruction to. + * @param size The size of the buffer. + * @param op The opcode. + * @param spare The spare. + * @param base The base of the memory address. + * @param scale The scale of the memory address. + * @param index The index of the memory address. + * @param displacement The displacement of the memory address. + * @param imm The immediate value. + * @return The number of bytes needed to store the instruction. + */ 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); -- 2.11.4.GIT