From 79f5ba0237426b3fd40c82308140940e88ba7b16 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Wed, 13 Apr 2011 16:08:51 +0000 Subject: [PATCH] More improvements to the support for the i386 architecture --- include/Asm/arch.h | 1 + src/arch.c | 39 ++++++++++++++++++++++++++++++++++++++- src/arch/i386.c | 2 ++ src/arch/i386.ins | 4 ++++ src/arch/i386.reg | 26 +++++++++++++------------- src/code.c | 31 ++++++++++++++++++++++++++++++- test/i386.S | 4 ++++ 7 files changed, 92 insertions(+), 15 deletions(-) diff --git a/include/Asm/arch.h b/include/Asm/arch.h index c8520c7..9d70499 100644 --- a/include/Asm/arch.h +++ b/include/Asm/arch.h @@ -65,6 +65,7 @@ typedef uint32_t ArchOperand; # define AOF_IMPLICIT 0x1 /* for registers */ # define AOF_SIGNED 0x2 /* for immediate */ # define AOF_SOFFSET 0x3 +# define AOF_OFFSETSIZE 0x4 /* for registers */ /* macros */ # define AO_GET_FLAGS(operand) ((operand & AOM_FLAGS) >> AOD_FLAGS) diff --git a/src/arch.c b/src/arch.c index 36de4ab..a896117 100644 --- a/src/arch.c +++ b/src/arch.c @@ -165,6 +165,7 @@ ArchInstruction * arch_get_instruction_by_opcode(Arch * arch, uint8_t size, /* arch_get_instruction_by_operands */ static int _operands_operands(Arch * arch, ArchInstruction * ai, AsOperand ** operands, size_t operands_cnt); +static int _operands_operands_immediate(uint32_t operand, AsOperand * aso); ArchInstruction * arch_get_instruction_by_operands(Arch * arch, char const * name, AsOperand ** operands, size_t operands_cnt) @@ -212,6 +213,19 @@ static int _operands_operands(Arch * arch, ArchInstruction * ai, return -1; switch(AO_GET_TYPE(operand)) { + case AOT_IMMEDIATE: + if(_operands_operands_immediate(operand, + operands[i]) != 0) + return -1; + break; + case AOT_DREGISTER: + /* check if it exists */ + ar = arch_get_register_by_name(arch, + operands[i]->value); + if(ar == NULL) + return -1; + /* FIXME implement the rest */ + break; case AOT_REGISTER: /* check if it exists */ ar = arch_get_register_by_name(arch, @@ -228,11 +242,34 @@ static int _operands_operands(Arch * arch, ArchInstruction * ai, } break; } - /* FIXME check AOF_SIGNED */ } return 0; } +static int _operands_operands_immediate(uint32_t operand, AsOperand * aso) +{ + unsigned long value; + long lvalue; + unsigned long max; + + /* check if the size fits */ + if(AO_GET_FLAGS(operand) & AOF_SIGNED) + { + lvalue = *(unsigned long*)aso->value; + value = (lvalue >= 0) ? lvalue : -lvalue; + } + else + value = *(unsigned long*)aso->value; + /* apply negative offset */ + if(AO_GET_FLAGS(operand) & AOF_SOFFSET) + value >>= AO_GET_OFFSET(operand); + max = 1; + max <<= AO_GET_SIZE(operand) + 1; + if(value > max - 1) + return -1; + return 0; +} + /* arch_get_name */ char const * arch_get_name(Arch * arch) diff --git a/src/arch/i386.c b/src/arch/i386.c index 10920f6..17ce3ae 100644 --- a/src/arch/i386.c +++ b/src/arch/i386.c @@ -27,6 +27,7 @@ enum { #include "i386.reg" + REG_size_count }; #undef REG @@ -35,6 +36,7 @@ enum enum { #include "i386.reg" + REG_id_count }; #undef REG diff --git a/src/arch/i386.ins b/src/arch/i386.ins index 64c7ccd..fa8bd32 100644 --- a/src/arch/i386.ins +++ b/src/arch/i386.ins @@ -14,6 +14,8 @@ /* helpers */ #define OP1F (1 << AOD_SIZE) #define OP2F (2 << AOD_SIZE) +#define OP_RM8 AO_DREGISTER(AOF_OFFSETSIZE, 8, 8) +#define OP_RMW AO_DREGISTER(AOF_OFFSETSIZE, 8, W) #define OP_U8 AO_IMMEDIATE(0, 0, 8) #define OP_UW AO_IMMEDIATE(0, 0, W) @@ -23,6 +25,8 @@ { "aam", 0xd40a, OP2F, AOT_NONE, AOT_NONE, AOT_NONE }, { "aam", 0xd4, OP1F, OP_U8, AOT_NONE, AOT_NONE }, { "aas", 0x3f, OP1F, AOT_NONE, AOT_NONE, AOT_NONE }, +{ "adc", 0x80, OP1F, OP_RM8, OP_U8, AOT_NONE }, +{ "adc", 0x81, OP1F, OP_RMW, OP_UW, AOT_NONE }, { "adc", 0x14, OP1F, OP_U8, OP_al, AOT_NONE }, { "adc", 0x15, OP1F, OP_UW, OP_AX, AOT_NONE }, { "nop", 0x90, OP1F, AOT_NONE, AOT_NONE, AOT_NONE }, diff --git a/src/arch/i386.reg b/src/arch/i386.reg index 171bcb0..5724685 100644 --- a/src/arch/i386.reg +++ b/src/arch/i386.reg @@ -1,15 +1,15 @@ -REG(ah, 8, 0x00) -REG(al, 8, 0x01) -REG(bh, 8, 0x02) +REG(al, 8, 0x00) +REG(cl, 8, 0x01) +REG(dl, 8, 0x02) REG(bl, 8, 0x03) -REG(ch, 8, 0x04) -REG(cl, 8, 0x05) -REG(dh, 8, 0x06) -REG(dl, 8, 0x07) +REG(ah, 8, 0x04) +REG(bh, 8, 0x05) +REG(ch, 8, 0x06) +REG(dh, 8, 0x07) REG(ax, 16, 0x00) -REG(bx, 16, 0x01) -REG(cx, 16, 0x02) -REG(dx, 16, 0x03) +REG(cx, 16, 0x01) +REG(dx, 16, 0x02) +REG(bx, 16, 0x03) REG(sp, 16, 0x04) REG(bp, 16, 0x05) REG(si, 16, 0x06) @@ -22,9 +22,9 @@ REG(fs, 16, 0x0c) REG(gs, 16, 0x0d) #ifndef ARCH_i386_real REG(eax,32, 0x00) -REG(ebx,32, 0x01) -REG(ecx,32, 0x02) -REG(edx,32, 0x03) +REG(ecx,32, 0x01) +REG(edx,32, 0x02) +REG(ebx,32, 0x03) REG(esi,32, 0x04) REG(edi,32, 0x05) REG(esp,32, 0x06) diff --git a/src/code.c b/src/code.c index 8cacfe1..148a3a0 100644 --- a/src/code.c +++ b/src/code.c @@ -185,6 +185,8 @@ static int _instruction_fixed_register(Code * code, ArchOperand operand, AsOperand * aso, uint32_t * pu); static int _instruction_variable(Code * code, ArchInstruction * ai, AsOperand ** operands, size_t operands_cnt); +static int _instruction_variable_dregister(Code * code, ArchOperand operand, + char const * name); static int _instruction_variable_immediate(Code * code, ArchOperand operand, void * value); static int _instruction_variable_opcode(Code * code, ArchInstruction * ai); @@ -316,6 +318,30 @@ static int _instruction_variable(Code * code, ArchInstruction * ai, return 0; } +static int _instruction_variable_dregister(Code * code, ArchOperand operand, + char const * name) +{ + ArchRegister * ar; + uint32_t value; + uint32_t offset; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, name); +#endif + if((ar = arch_get_register_by_name(code->arch, name)) == NULL) + return -1; + value = ar->id; + if(AO_GET_FLAGS(operand) & AOF_OFFSETSIZE) + { + offset = AO_GET_OFFSET(operand); + operand &= ~(AOM_OFFSET | AOM_SIZE); + operand |= (offset << AOD_SIZE); + } + else + value <<= AO_GET_OFFSET(operand); + return _instruction_variable_immediate(code, operand, &value); +} + static int _instruction_variable_immediate(Code * code, ArchOperand operand, void * value) { @@ -329,7 +355,7 @@ static int _instruction_variable_immediate(Code * code, ArchOperand operand, fprintf(stderr, "DEBUG: %s()\n", __func__); #endif if((size = AO_GET_SIZE(operand)) == 0) - return -error_set_code("%s", "Empty immediate value"); + return -error_set_code(1, "%s", "Empty immediate value"); else if(size <= 8) { u8 = *(uint8_t*)value; @@ -378,6 +404,9 @@ static int _instruction_variable_operand(Code * code, ArchInstruction * ai, case AOT_IMMEDIATE: return _instruction_variable_immediate(code, operand, aso->value); + case AOT_DREGISTER: + return _instruction_variable_dregister(code, operand, + aso->value); case AOT_REGISTER: return _instruction_variable_register(code, operand, aso->value); diff --git a/test/i386.S b/test/i386.S index c8457ba..a2720db 100644 --- a/test/i386.S +++ b/test/i386.S @@ -7,4 +7,8 @@ aas adc $0x42, %al adc $0x42, %eax + adc [%eax], $0x42 + adc [%ecx], $0x42 + adc [%eax], $0x42434445 + adc [%ecx], $0x42434445 nop