Improved support for the i386 architecture
This commit is contained in:
parent
a0f0317e3b
commit
7809f589b4
@ -67,7 +67,6 @@ typedef uint32_t ArchOperand;
|
||||
# define AOF_SIGNED 0x4
|
||||
/* for registers */
|
||||
# define AOF_IMPLICIT 0x4
|
||||
# define AOF_OFFSETSIZE 0x8
|
||||
|
||||
/* macros */
|
||||
# define AO_GET_FLAGS(operand) ((operand & AOM_FLAGS) >> AOD_FLAGS)
|
||||
@ -77,11 +76,11 @@ typedef uint32_t ArchOperand;
|
||||
# define AO_GET_VALUE(operand) ((operand & AOM_VALUE) >> AOD_VALUE)
|
||||
|
||||
# define AO_IMMEDIATE(flags, offset, size) ((AOT_IMMEDIATE << AOD_TYPE) \
|
||||
| (flags << AOD_FLAGS) | (offset << AOD_OFFSET) \
|
||||
| (size << AOD_SIZE))
|
||||
| ((flags) << AOD_FLAGS) | ((offset) << AOD_OFFSET) \
|
||||
| ((size) << AOD_SIZE))
|
||||
# define AO_REGISTER(flags, offset, size, id) ((AOT_REGISTER << AOD_TYPE) \
|
||||
| (flags << AOD_FLAGS) | (offset << AOD_OFFSET) \
|
||||
| (size << AOD_SIZE) | (id << AOD_VALUE))
|
||||
| ((flags) << AOD_FLAGS) | ((offset) << AOD_OFFSET) \
|
||||
| ((size) << AOD_SIZE) | ((id) << AOD_VALUE))
|
||||
# define AO_DREGISTER(flags, offset, dsize) ((AOT_DREGISTER << AOD_TYPE) \
|
||||
| (flags << AOD_FLAGS) | (offset << AOD_OFFSET) \
|
||||
| (dsize << AOD_SIZE))
|
||||
@ -114,7 +113,8 @@ struct _ArchPlugin
|
||||
ArchDescription * description;
|
||||
ArchRegister * registers;
|
||||
ArchInstruction * instructions;
|
||||
int (*filter)(ArchPlugin * arch, ArchInstruction * instruction);
|
||||
int (*filter)(ArchPlugin * arch, ArchInstruction * instruction,
|
||||
unsigned char * buf, size_t size);
|
||||
};
|
||||
|
||||
#endif /* !DEVEL_ASM_ARCH_H */
|
||||
|
81
src/arch.c
81
src/arch.c
@ -166,6 +166,8 @@ ArchInstruction * arch_get_instruction_by_opcode(Arch * arch, uint8_t size,
|
||||
static int _operands_operands(Arch * arch, ArchInstruction * ai,
|
||||
AsOperand ** operands, size_t operands_cnt);
|
||||
static int _operands_operands_immediate(uint32_t operand, AsOperand * aso);
|
||||
static int _operands_operands_register(Arch * arch, uint32_t operand,
|
||||
AsOperand * aso);
|
||||
|
||||
ArchInstruction * arch_get_instruction_by_operands(Arch * arch,
|
||||
char const * name, AsOperand ** operands, size_t operands_cnt)
|
||||
@ -197,7 +199,6 @@ static int _operands_operands(Arch * arch, ArchInstruction * ai,
|
||||
{
|
||||
size_t i;
|
||||
uint32_t operand;
|
||||
ArchRegister * ar;
|
||||
|
||||
for(i = 0; i < operands_cnt; i++)
|
||||
{
|
||||
@ -219,27 +220,10 @@ static int _operands_operands(Arch * arch, ArchInstruction * ai,
|
||||
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,
|
||||
operands[i]->value);
|
||||
if(ar == NULL)
|
||||
if(_operands_operands_register(arch, operand,
|
||||
operands[i]) != 0)
|
||||
return -1;
|
||||
/* for implicit instructions it must match */
|
||||
if(AO_GET_FLAGS(operand) & AOF_IMPLICIT)
|
||||
{
|
||||
if(AO_GET_SIZE(operand) != ar->size)
|
||||
return -1;
|
||||
if(AO_GET_VALUE(operand) != ar->id)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -270,6 +254,30 @@ static int _operands_operands_immediate(uint32_t operand, AsOperand * aso)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _operands_operands_register(Arch * arch, uint32_t operand,
|
||||
AsOperand * aso)
|
||||
{
|
||||
ArchRegister * ar;
|
||||
ArchDescription * desc;
|
||||
|
||||
/* check if it exists */
|
||||
ar = arch_get_register_by_name(arch, aso->value);
|
||||
if(ar == NULL)
|
||||
return -1;
|
||||
/* check the size only for variable-length opcode encoding */
|
||||
desc = arch->plugin->description;
|
||||
if((desc == NULL || desc->instruction_size == 0)
|
||||
&& AO_GET_SIZE(operand) != ar->size)
|
||||
return -1;
|
||||
/* for implicit instructions it must match */
|
||||
if(AO_GET_FLAGS(operand) & AOF_IMPLICIT)
|
||||
{
|
||||
if(AO_GET_VALUE(operand) != ar->id)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* arch_get_name */
|
||||
char const * arch_get_name(Arch * arch)
|
||||
@ -312,3 +320,36 @@ ArchRegister * arch_get_register_by_name(Arch * arch, char const * name)
|
||||
return &arch->plugin->registers[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* arch_get_register_by_name_size */
|
||||
ArchRegister * arch_get_register_by_name_size(Arch * arch, char const * name,
|
||||
uint32_t size)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\", %u)\n", __func__, name, size);
|
||||
#endif
|
||||
for(i = 0; i < arch->registers_cnt; i++)
|
||||
if(arch->plugin->registers[i].size != size)
|
||||
continue;
|
||||
else if(strcmp(arch->plugin->registers[i].name, name) == 0)
|
||||
return &arch->plugin->registers[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* useful */
|
||||
/* arch_filter */
|
||||
int arch_filter(Arch * arch, ArchInstruction * instruction, unsigned char * buf,
|
||||
size_t size)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, instruction->name);
|
||||
#endif
|
||||
if(arch->plugin->filter == NULL)
|
||||
return -error_set_code(1, "%s: %s", arch->plugin->name,
|
||||
"Instruction filter required but not defined");
|
||||
return arch->plugin->filter(arch->plugin, instruction, buf, size);
|
||||
}
|
||||
|
@ -49,5 +49,11 @@ ArchInstruction * arch_get_instruction_by_operands(Arch * arch,
|
||||
ArchRegister * arch_get_register(Arch * arch, size_t index);
|
||||
ArchRegister * arch_get_register_by_id(Arch * arch, unsigned int id);
|
||||
ArchRegister * arch_get_register_by_name(Arch * arch, char const * name);
|
||||
ArchRegister * arch_get_register_by_name_size(Arch * arch, char const * name,
|
||||
uint32_t size);
|
||||
|
||||
/* useful */
|
||||
int arch_filter(Arch * arch, ArchInstruction * ai, unsigned char * buf,
|
||||
size_t size);
|
||||
|
||||
#endif /* !ASM_ARCH_H */
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
#include "Asm/arch.h"
|
||||
|
||||
|
||||
@ -57,6 +60,15 @@ static ArchInstruction _i386_instructions[] =
|
||||
#include "null.ins"
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
static int _i386_filter(ArchPlugin * plugin, ArchInstruction * instruction,
|
||||
unsigned char * buf, size_t size);
|
||||
|
||||
|
||||
/* public */
|
||||
/* variables */
|
||||
/* plug-in */
|
||||
ArchPlugin arch_plugin =
|
||||
{
|
||||
"i386",
|
||||
@ -64,5 +76,19 @@ ArchPlugin arch_plugin =
|
||||
NULL,
|
||||
_i386_registers,
|
||||
_i386_instructions,
|
||||
NULL
|
||||
_i386_filter
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* functions */
|
||||
static int _i386_filter(ArchPlugin * plugin, ArchInstruction * instruction,
|
||||
unsigned char * buf, size_t size)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() 0x%x\n", __func__, buf[0]);
|
||||
#endif
|
||||
/* the filter function is only set for mod r/m bytes at the moment */
|
||||
buf[0] |= 0xc0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,8 +14,10 @@
|
||||
/* helpers */
|
||||
#define OP1F (8 << AOD_SIZE)
|
||||
#define OP2F (16 << AOD_SIZE)
|
||||
#define OP_RM8 AO_DREGISTER(AOF_OFFSETSIZE, 8, 8)
|
||||
#define OP_RMW AO_DREGISTER(AOF_OFFSETSIZE, 8, W)
|
||||
#define OP_RM8_D AO_DREGISTER(AOF_SOFFSET, 8, 8)
|
||||
#define OP_RM8_R AO_REGISTER(AOF_SOFFSET | AOF_FILTER, 8, 8, 0)
|
||||
#define OP_RMW_D AO_DREGISTER(AOF_SOFFSET, 8, W)
|
||||
#define OP_RMW_R AO_REGISTER(AOF_SOFFSET | AOF_FILTER, 8, W, 0)
|
||||
#define OP_U8 AO_IMMEDIATE(0, 0, 8)
|
||||
#define OP_UW AO_IMMEDIATE(0, 0, W)
|
||||
|
||||
@ -25,8 +27,10 @@
|
||||
{ "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 },
|
||||
{ "adc", 0x14, OP1F, OP_al, OP_U8, AOT_NONE },
|
||||
{ "adc", 0x15, OP1F, OP_AX, OP_UW, AOT_NONE },
|
||||
{ "adc", 0x80, OP1F, OP_RM8_D, OP_U8, AOT_NONE },
|
||||
{ "adc", 0x80, OP1F, OP_RM8_R, OP_U8, AOT_NONE },
|
||||
{ "adc", 0x81, OP1F, OP_RMW_D, OP_UW, AOT_NONE },
|
||||
{ "adc", 0x81, OP1F, OP_RMW_R, OP_UW, AOT_NONE },
|
||||
{ "nop", 0x90, OP1F, AOT_NONE, AOT_NONE, AOT_NONE },
|
||||
|
@ -22,7 +22,7 @@
|
||||
/* sparc */
|
||||
/* private */
|
||||
/* variables */
|
||||
static ArchDescription _sparc_description = { ARCH_ENDIAN_BIG, 4, 4 };
|
||||
static ArchDescription _sparc_description = { ARCH_ENDIAN_BIG, 32, 32 };
|
||||
|
||||
#define REG(name, size, id) { "" # name, size, id },
|
||||
static ArchRegister _sparc_registers[] =
|
||||
|
96
src/code.c
96
src/code.c
@ -42,6 +42,11 @@ struct _Code
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
static int _code_filter(Code * code, ArchInstruction * ai, unsigned char * buf,
|
||||
size_t size);
|
||||
|
||||
|
||||
/* functions */
|
||||
/* code_new */
|
||||
Code * code_new(char const * arch, char const * format)
|
||||
@ -185,15 +190,15 @@ 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, int swap);
|
||||
static int _instruction_variable_dregister(Code * code, ArchInstruction * ai,
|
||||
ArchOperand operand, char const * name);
|
||||
static int _instruction_variable_immediate(Code * code, ArchInstruction * ai,
|
||||
ArchOperand operand, void * value, int swap);
|
||||
static int _instruction_variable_opcode(Code * code, ArchInstruction * ai);
|
||||
static int _instruction_variable_operand(Code * code, ArchOperand operand,
|
||||
AsOperand * aso);
|
||||
static int _instruction_variable_register(Code * code, ArchOperand operand,
|
||||
char const * name);
|
||||
static int _instruction_variable_operand(Code * code, ArchInstruction * ai,
|
||||
ArchOperand operand, AsOperand * aso);
|
||||
static int _instruction_variable_register(Code * code, ArchInstruction * ai,
|
||||
ArchOperand operand, char const * name);
|
||||
|
||||
int code_instruction(Code * code, char const * name, AsOperand ** operands,
|
||||
size_t operands_cnt)
|
||||
@ -208,7 +213,7 @@ int code_instruction(Code * code, char const * name, AsOperand ** operands,
|
||||
", 3 0x%x\n", name, ai->value, ai->op1, ai->op2,
|
||||
ai->op3);
|
||||
#endif
|
||||
if(code->description != NULL && code->description->instruction_size)
|
||||
if(code->description != NULL && code->description->instruction_size > 0)
|
||||
return _instruction_fixed(code, ai, operands, operands_cnt);
|
||||
return _instruction_variable(code, ai, operands, operands_cnt);
|
||||
}
|
||||
@ -311,39 +316,42 @@ static int _instruction_variable(Code * code, ArchInstruction * ai,
|
||||
operand = ai->op3;
|
||||
else
|
||||
return -1; /* XXX report error */
|
||||
if(_instruction_variable_operand(code, operand, operands[i])
|
||||
if(_instruction_variable_operand(code, ai, operand, operands[i])
|
||||
!= 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _instruction_variable_dregister(Code * code, ArchOperand operand,
|
||||
char const * name)
|
||||
static int _instruction_variable_dregister(Code * code, ArchInstruction * ai,
|
||||
ArchOperand operand, char const * name)
|
||||
{
|
||||
ArchRegister * ar;
|
||||
uint32_t value;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, name);
|
||||
fprintf(stderr, "DEBUG: %s(0x%08x, \"%s\")\n", __func__, operand, name);
|
||||
#endif
|
||||
if((ar = arch_get_register_by_name(code->arch, name)) == NULL)
|
||||
if(AO_GET_FLAGS(operand) & AOF_IMPLICIT)
|
||||
return 0;
|
||||
if((ar = arch_get_register_by_name_size(code->arch, name, AO_GET_SIZE(
|
||||
operand))) == NULL)
|
||||
return -1;
|
||||
value = ar->id;
|
||||
if(AO_GET_FLAGS(operand) & AOF_OFFSETSIZE)
|
||||
if(AO_GET_FLAGS(operand) & AOF_SOFFSET)
|
||||
{
|
||||
offset = AO_GET_OFFSET(operand);
|
||||
size = AO_GET_OFFSET(operand);
|
||||
operand &= ~(AOM_OFFSET | AOM_SIZE);
|
||||
operand |= (offset << AOD_SIZE);
|
||||
operand |= (size << AOD_SIZE);
|
||||
}
|
||||
else
|
||||
value <<= AO_GET_OFFSET(operand);
|
||||
return _instruction_variable_immediate(code, operand, &value, 0);
|
||||
return _instruction_variable_immediate(code, ai, operand, &value, 0);
|
||||
}
|
||||
|
||||
static int _instruction_variable_immediate(Code * code, ArchOperand operand,
|
||||
void * value, int swap)
|
||||
static int _instruction_variable_immediate(Code * code, ArchInstruction * ai,
|
||||
ArchOperand operand, void * value, int swap)
|
||||
{
|
||||
size_t size;
|
||||
void * buf;
|
||||
@ -390,6 +398,8 @@ static int _instruction_variable_immediate(Code * code, ArchOperand operand,
|
||||
}
|
||||
else
|
||||
return -error_set_code(1, "%u: Size not implemented", size);
|
||||
if(AO_GET_FLAGS(operand) & AOF_FILTER)
|
||||
_code_filter(code, ai, buf, size);
|
||||
if(fwrite(buf, size, 1, code->fp) != 1)
|
||||
return -error_set_code(1, "%s: %s", code->filename, strerror(
|
||||
errno));
|
||||
@ -401,22 +411,27 @@ static int _instruction_variable_opcode(Code * code, ArchInstruction * ai)
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s() 0x%x\n", __func__, ai->value);
|
||||
#endif
|
||||
return _instruction_variable_immediate(code, ai->opcode, &ai->value, 1);
|
||||
return _instruction_variable_immediate(code, ai, ai->opcode, &ai->value,
|
||||
1);
|
||||
}
|
||||
|
||||
static int _instruction_variable_operand(Code * code, ArchOperand operand,
|
||||
AsOperand * aso)
|
||||
static int _instruction_variable_operand(Code * code, ArchInstruction * ai,
|
||||
ArchOperand operand, AsOperand * aso)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\", 0x%08x) opcode=0x%x\n", __func__,
|
||||
ai->name, operand, ai->value);
|
||||
#endif
|
||||
switch(AO_GET_TYPE(operand))
|
||||
{
|
||||
case AOT_IMMEDIATE:
|
||||
return _instruction_variable_immediate(code, operand,
|
||||
aso->value, 1);
|
||||
return _instruction_variable_immediate(code, ai,
|
||||
operand, aso->value, 0);
|
||||
case AOT_DREGISTER:
|
||||
return _instruction_variable_dregister(code, operand,
|
||||
aso->value);
|
||||
return _instruction_variable_dregister(code, ai,
|
||||
operand, aso->value);
|
||||
case AOT_REGISTER:
|
||||
return _instruction_variable_register(code, operand,
|
||||
return _instruction_variable_register(code, ai, operand,
|
||||
aso->value);
|
||||
default:
|
||||
/* FIXME implement */
|
||||
@ -425,9 +440,15 @@ static int _instruction_variable_operand(Code * code, ArchOperand operand,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _instruction_variable_register(Code * code, ArchOperand operand,
|
||||
char const * name)
|
||||
static int _instruction_variable_register(Code * code, ArchInstruction * ai,
|
||||
ArchOperand operand, char const * name)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, name);
|
||||
#endif
|
||||
return _instruction_variable_dregister(code, ai, operand, name);
|
||||
}
|
||||
#if 0
|
||||
ArchRegister * ar;
|
||||
uint32_t value;
|
||||
uint32_t offset;
|
||||
@ -447,8 +468,9 @@ static int _instruction_variable_register(Code * code, ArchOperand operand,
|
||||
}
|
||||
else
|
||||
value <<= AO_GET_OFFSET(operand);
|
||||
return _instruction_variable_immediate(code, operand, &value, 0);
|
||||
return _instruction_variable_immediate(code, ai, operand, &value, 0);
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
switch(AO_GET_SIZE(ai->opcode))
|
||||
{
|
||||
@ -635,3 +657,13 @@ int code_section(Code * code, char const * section)
|
||||
#endif
|
||||
return format_section(code->format, section);
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* plug-in */
|
||||
static int _code_filter(Code * code, ArchInstruction * ai, unsigned char * buf,
|
||||
size_t size)
|
||||
{
|
||||
return arch_filter(code->arch, ai, buf, size);
|
||||
}
|
||||
|
10
test/i386.S
10
test/i386.S
@ -5,10 +5,10 @@
|
||||
aam
|
||||
aam $0x42
|
||||
aas
|
||||
adc $0x42, %al
|
||||
adc $0x42, %eax
|
||||
adc %al, $0x42
|
||||
adc %eax, $0x42
|
||||
adc [%eax], $0x42
|
||||
adc [%ecx], $0x42
|
||||
adc [%eax], $0x42434445
|
||||
adc [%ecx], $0x42434445
|
||||
adc %ecx, $0x42
|
||||
adc [%edx], $0x42434445
|
||||
adc %ebx, $0x42434445
|
||||
nop
|
||||
|
Loading…
Reference in New Issue
Block a user