summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2008-09-08 22:53:49 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2008-09-08 22:53:49 (GMT)
commitb77dcf34b9b2308978e1c6333b34cde9f0e27a8c (patch)
tree9263e556e0e42c915b82fe48a4c3bdc5d2654b24
parentb52f03ab912cd5e51dc2abea20edee6ad38c26fe (diff)
Handled four kinds of the 'test' opcode.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@27 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
-rw-r--r--ChangeLog23
-rw-r--r--src/arch/x86/Makefile.am1
-rw-r--r--src/arch/x86/instruction.h6
-rw-r--r--src/arch/x86/op_mov.c22
-rw-r--r--src/arch/x86/opcodes.h12
-rw-r--r--src/arch/x86/operand.c343
-rw-r--r--src/arch/x86/operand.h16
-rw-r--r--src/arch/x86/processor.c11
8 files changed, 418 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 7fd494f..0725005 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,25 @@
-2008-09-06 Cyrille Bagard <nocbos@gmail.com>
+2008-09-09 Cyrille Bagard <nocbos@gmail.com>
+
+ * src/arch/x86/instruction.h:
+ Handle four kinds of the 'test' opcode.
+
+ * src/arch/x86/Makefile.am:
+ Add op_test.c to libarchx86_a_SOURCES.
+
+ * src/arch/x86/opcodes.h:
+ Register the new decoding functions.
+
+ * src/arch/x86/operand.c:
+ * src/arch/x86/operand.h:
+ Handle the r/m information in a clever way.
+
+ * src/arch/x86/op_mov.c:
+ Reorganize the code ; this must be improved.
+
+ * src/arch/x86/processor.c:
+ Register the new decoding functions.
+
+2008-09-07 Cyrille Bagard <nocbos@gmail.com>
* src/arch/x86/op_lea.c:
* src/arch/x86/op_mov.c:
diff --git a/src/arch/x86/Makefile.am b/src/arch/x86/Makefile.am
index 238cf61..b074f69 100644
--- a/src/arch/x86/Makefile.am
+++ b/src/arch/x86/Makefile.am
@@ -21,6 +21,7 @@ libarchx86_a_SOURCES = \
op_ret.c \
op_sbb.c \
op_sub.c \
+ op_test.c \
op_xor.c \
opcodes.h \
operand.h operand.c \
diff --git a/src/arch/x86/instruction.h b/src/arch/x86/instruction.h
index 1a9b6d4..38315d9 100644
--- a/src/arch/x86/instruction.h
+++ b/src/arch/x86/instruction.h
@@ -88,12 +88,18 @@ typedef enum _X86Opcodes
X86_OP_SUB8_REG1632, /* sub ([0x66] 0x83) */
X86_OP_XOR8_REG1632, /* xor ([0x66] 0x83) */
+ X86_OP_TEST_RM8, /* test ([0x66] 0x84) */
+ X86_OP_TEST_RM1632, /* test ([0x66] 0x85) */
+
X86_OP_MOV_FROM_CONTENT1632, /* mov ([0x66] 0x8b) */
X86_OP_LEA, /* lea ([0x66] 0x8d) */ /* 66 ? */
X86_OP_NOP, /* nop (0x90) */
+ X86_OP_TEST_AL, /* test ([0x66] 0xa8) */
+ X86_OP_TEST_E_AX, /* test ([0x66] 0xa9) */
+
X86_OP_MOV_E_AX, /* mov ([0x66] 0xb8) */
X86_OP_MOV_E_CX, /* mov ([0x66] 0xb9) */
X86_OP_MOV_E_DX, /* mov ([0x66] 0xba) */
diff --git a/src/arch/x86/op_mov.c b/src/arch/x86/op_mov.c
index db731bb..d0a1bfc 100644
--- a/src/arch/x86/op_mov.c
+++ b/src/arch/x86/op_mov.c
@@ -65,27 +65,27 @@ asm_x86_instr *read_instr_mov_with_reg1632(const uint8_t *data, off_t *pos, off_
ASM_INSTRUCTION(result)->opcode = data[(*pos)++];
- /* TODO ! */
- if ((data[*pos] & 0xc0) != 0xc0)
- return NULL;
-
- reg1 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, true);
- if (reg1 == NULL)
+ reg2 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, false);
+ if (reg2 == NULL)
{
free(result);
return NULL;
}
- reg2 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, false);
- if (reg2 == NULL)
+ if ((data[*pos] & 0xc0) == 0xc0)
+ {
+ reg1 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, true);
+ (*pos)++;
+ }
+ else reg1 = x86_create_content1632_operand(data, pos, len, oprsize == AOS_32_BITS, true);
+
+ if (reg1 == NULL)
{
free(result);
- free(reg1);
+ free(reg2);
return NULL;
}
- (*pos)++;
-
ASM_INSTRUCTION(result)->operands = (asm_operand **)calloc(2, sizeof(asm_operand *));
ASM_INSTRUCTION(result)->operands_count = 2;
diff --git a/src/arch/x86/opcodes.h b/src/arch/x86/opcodes.h
index 1d3611f..64614dc 100644
--- a/src/arch/x86/opcodes.h
+++ b/src/arch/x86/opcodes.h
@@ -103,6 +103,18 @@ asm_x86_instr *read_instr_sbb8_with_reg1632(const uint8_t *, off_t *, off_t, uin
/* Décode une instruction de type 'sub'. */
asm_x86_instr *read_instr_sub8_with_reg1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
+/* Décode une instruction de type 'test al, ...' (8 bits). */
+asm_x86_instr *read_instr_test_al(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
+
+/* Décode une instruction de type 'test [e]ax, ...' (16/32b). */
+asm_x86_instr *read_instr_test_e_ax(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
+
+/* Décode une instruction de type 'test' (8 bits). */
+asm_x86_instr *read_instr_test_rm8(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
+
+/* Décode une instruction de type 'test' (16 ou 32 bits). */
+asm_x86_instr *read_instr_test_rm1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
+
/* Décode une instruction de type 'xor' (16 ou 32 bits). */
asm_x86_instr *read_instr_xor_with_reg1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
diff --git a/src/arch/x86/operand.c b/src/arch/x86/operand.c
index ada66f0..a232211 100644
--- a/src/arch/x86/operand.c
+++ b/src/arch/x86/operand.c
@@ -178,7 +178,15 @@ bool get_x86_register(x86_register *reg, AsmOperandSize size, uint8_t value)
switch (size)
{
case AOS_8_BITS:
- return false;
+ switch (value)
+ {
+ case 0 ... 7:
+ reg->reg8 = (X868bRegister)value;
+ break;
+ default:
+ return false;
+ break;
+ }
break;
case AOS_16_BITS:
@@ -418,6 +426,339 @@ asm_x86_operand *x86_create_content1632_operand(const uint8_t *data, off_t *pos,
}
+
+
+
+/******************************************************************************
+* *
+* Paramètres : data = donnée à analyser. *
+* first = indique la partie du ModR/M à traiter. *
+* *
+* Description : Crée une opérande renvoyant vers un registre 8 bits. *
+* *
+* Retour : Opérande mise en place ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+asm_x86_operand *x86_create_r8_operand(uint8_t data, bool first)
+{
+ asm_x86_operand *result; /* Registre à retourner */
+ uint8_t reg; /* Transcription du registre */
+
+ if (first) reg = data & 0x07;
+ else reg = (data & 0x38) >> 3;
+
+ result = create_new_x86_operand();
+
+ ASM_OPERAND(result)->type = AOT_REG;
+ ASM_OPERAND(result)->size = AOS_8_BITS;
+
+ if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, reg))
+ {
+ free(result);
+ return NULL;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = flux de données à analyser. *
+* pos = position courante dans ce flux. [OUT] *
+* len = taille totale des données à analyser. *
+* first = indique la partie du ModR/M à traiter. *
+* *
+* Description : Crée une opérande à partir d'un registre/une mémoire 8 bits. *
+* *
+* Retour : Opérande mise en place ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+asm_x86_operand *x86_create_rm8_operand(const uint8_t *data, off_t *pos, off_t len, bool first)
+{
+ asm_x86_operand *result; /* Registre à retourner */
+ uint8_t mod; /* Modificateur présent */
+
+ /* Registre simple... */
+
+ result = x86_create_r8_operand(data[*pos], first);
+ if (result == NULL) return NULL;
+
+ mod = (data[*pos] & 0xc0);
+
+ (*pos)++;
+
+ if (mod == 0xc0) return result;
+
+ result->content = true;
+
+ /* Vieille astuce de l'emplacement mémoire fixe ? */
+ if (result->rindex.reg8 == X86_REG8_CH && mod == 0x00)
+ {
+ free(result);
+
+ result = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(result), AOS_8_BITS, data, pos, len))
+ {
+ free(result);
+ return NULL;
+ }
+
+ return result;
+
+ }
+
+ /* A la recherche d'un SIB */
+ if (result->rindex.reg8 == X86_REG8_AH)
+ {
+ if (!get_x86_register(&result->rbase, ASM_OPERAND(result)->size, data[*pos] & 0x07))
+ {
+ free(result);
+ return NULL;
+ }
+
+ if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, (data[*pos] & 0x38) >> 3))
+ {
+ free(result);
+ return NULL;
+ }
+
+ result->scale = ((data[*pos] & 0xc0) >> 6);
+
+ if (result->rindex.reg8 == X86_REG8_AH)
+ {
+ result->rindex.reg8 = result->rbase.reg8;
+ result->rbase.reg8 = X86_REG8_NONE;
+ }
+
+ (*pos)++;
+
+ }
+
+ /* Décallage supplémentaire ? */
+ switch (mod)
+ {
+ case 0x00:
+ if (result->rbase.reg8 == X86_REG8_CH)
+ {
+ result->rbase.reg8 = X86_REG8_NONE;
+
+ result->displacement = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(result->displacement), ASM_OPERAND(result)->size, data, pos, len))
+ {
+ free(result->displacement);
+ free(result);
+ return NULL;
+ }
+
+ }
+ break;
+
+ case 0x40:
+ result->displacement = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_8_BITS, data, pos, len))
+ {
+ free(result->displacement);
+ free(result);
+ return NULL;
+ }
+ break;
+
+ case 0x80:
+ result->displacement = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_8_BITS, data, pos, len))
+ {
+ free(result->displacement);
+ free(result);
+ return NULL;
+ }
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = donnée à analyser. *
+* is_reg32 = indique si le registre est un registre 32 bits. *
+* first = indique la partie du ModR/M à traiter. *
+* *
+* Description : Crée une opérande renvoyant vers un registre 16 ou 32 bits. *
+* *
+* Retour : Opérande mise en place ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+asm_x86_operand *x86_create_r1632_operand(uint8_t data, bool is_reg32, bool first)
+{
+ asm_x86_operand *result; /* Registre à retourner */
+ uint8_t reg; /* Transcription du registre */
+
+ if (first) reg = data & 0x07;
+ else reg = (data & 0x38) >> 3;
+
+ result = create_new_x86_operand();
+
+ ASM_OPERAND(result)->type = AOT_REG;
+ ASM_OPERAND(result)->size = (is_reg32 ? AOS_32_BITS : AOS_16_BITS);
+
+ if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, reg))
+ {
+ free(result);
+ return NULL;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = flux de données à analyser. *
+* pos = position courante dans ce flux. [OUT] *
+* len = taille totale des données à analyser. *
+* is_reg32 = indique si le registre est un registre 32 bits. *
+* first = indique la partie du ModR/M à traiter. *
+* *
+* Description : Crée une opérande à partir d'un registre/une mémoire 16/32b. *
+* *
+* Retour : Opérande mise en place ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+asm_x86_operand *x86_create_rm1632_operand(const uint8_t *data, off_t *pos, off_t len, bool is_reg32, bool first)
+{
+ asm_x86_operand *result; /* Registre à retourner */
+ uint8_t mod; /* Modificateur présent */
+
+ /* Registre simple... */
+
+ result = x86_create_r1632_operand(data[*pos], is_reg32, first);
+ if (result == NULL) return NULL;
+
+ mod = (data[*pos] & 0xc0);
+
+ (*pos)++;
+
+ if (mod == 0xc0) return result;
+
+ result->content = true;
+
+ /* Vieille astuce de l'emplacement mémoire fixe ? */
+ if (result->rindex.reg32 == X86_REG32_EBP && mod == 0x00)
+ {
+ free(result);
+
+ result = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(result), AOS_32_BITS/* FIXME ? */, data, pos, len))
+ {
+ free(result);
+ return NULL;
+ }
+
+ return result;
+
+ }
+
+ /* A la recherche d'un SIB */
+ if (result->rindex.reg32 == X86_REG32_ESP)
+ {
+ if (!get_x86_register(&result->rbase, ASM_OPERAND(result)->size, data[*pos] & 0x07))
+ {
+ free(result);
+ return NULL;
+ }
+
+ if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, (data[*pos] & 0x38) >> 3))
+ {
+ free(result);
+ return NULL;
+ }
+
+ result->scale = ((data[*pos] & 0xc0) >> 6);
+
+ if (result->rindex.reg32 == X86_REG32_ESP)
+ {
+ result->rindex.reg32 = result->rbase.reg32;
+ result->rbase.reg32 = X86_REG32_NONE;
+ }
+
+ (*pos)++;
+
+ }
+
+ /* Décallage supplémentaire ? */
+ switch (mod)
+ {
+ case 0x00:
+ if (result->rbase.reg32 == X86_REG32_EBP)
+ {
+ result->rbase.reg32 = X86_REG32_NONE;
+
+ result->displacement = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(result->displacement), ASM_OPERAND(result)->size, data, pos, len))
+ {
+ free(result->displacement);
+ free(result);
+ return NULL;
+ }
+
+ }
+ break;
+
+ case 0x40:
+ result->displacement = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_8_BITS, data, pos, len))
+ {
+ free(result->displacement);
+ free(result);
+ return NULL;
+ }
+ break;
+
+ case 0x80:
+ result->displacement = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_32_BITS, data, pos, len))
+ {
+ free(result->displacement);
+ free(result);
+ return NULL;
+ }
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
/******************************************************************************
* *
* Paramètres : reg = registre à imprimer. *
diff --git a/src/arch/x86/operand.h b/src/arch/x86/operand.h
index fbaba57..c330b8e 100644
--- a/src/arch/x86/operand.h
+++ b/src/arch/x86/operand.h
@@ -51,6 +51,22 @@ asm_x86_operand *x86_create_reg1632_operand_from_modrm(uint8_t, bool, bool);
/* Crée une opérande renvoyant vers un contenu 16 ou 32 bits. */
asm_x86_operand *x86_create_content1632_operand(const uint8_t *, off_t *, off_t, bool, bool);
+
+
+/* Crée une opérande renvoyant vers un registre 8 bits. */
+asm_x86_operand *x86_create_r8_operand(uint8_t, bool);
+
+/* Crée une opérande à partir d'un registre/une mémoire 8 bits. */
+asm_x86_operand *x86_create_rm8_operand(const uint8_t *, off_t *, off_t, bool);
+
+/* Crée une opérande renvoyant vers un registre 16 ou 32 bits. */
+asm_x86_operand *x86_create_r1632_operand(uint8_t, bool, bool);
+
+/* Crée une opérande à partir d'un registre/une mémoire 16/32b. */
+asm_x86_operand *x86_create_rm1632_operand(const uint8_t *, off_t *, off_t, bool, bool);
+
+
+
/* Traduit une opérande de registre en texte. */
void x86_print_reg_operand(const asm_x86_operand *, char *, size_t, AsmSyntax);
diff --git a/src/arch/x86/processor.c b/src/arch/x86/processor.c
index 118dbd6..3ca14b9 100644
--- a/src/arch/x86/processor.c
+++ b/src/arch/x86/processor.c
@@ -234,9 +234,6 @@ void x86_register_instructions(asm_x86_processor *proc)
register_opcode(proc->opcodes[X86_OP_PUSH_IMM1632], 0x66, 0x68, "push", read_instr_push_imm1632);
-
- register_opcode(proc->opcodes[X86_OP_MOV_REG1632], 0x66, 0x89, "mov", read_instr_mov_with_reg1632);
-
register_opcode_with_ext(proc->opcodes[X86_OP_ADD8_REG1632], 0x66, 0x83, 0, "add", read_instr_add8_with_reg1632);
register_opcode_with_ext(proc->opcodes[X86_OP_OR8_REG1632], 0x66, 0x83, 1, "or", read_instr_or8_with_reg1632);
register_opcode_with_ext(proc->opcodes[X86_OP_ADC8_REG1632], 0x66, 0x83, 2, "adc", read_instr_adc8_with_reg1632);
@@ -245,12 +242,20 @@ void x86_register_instructions(asm_x86_processor *proc)
register_opcode_with_ext(proc->opcodes[X86_OP_SUB8_REG1632], 0x66, 0x83, 5, "sub", read_instr_sub8_with_reg1632);
register_opcode_with_ext(proc->opcodes[X86_OP_XOR8_REG1632], 0x66, 0x83, 6, "xor", read_instr_xor8_with_reg1632);
+ register_opcode(proc->opcodes[X86_OP_TEST_RM8], 0x00, 0x84, "test", read_instr_test_rm8);
+ register_opcode(proc->opcodes[X86_OP_TEST_RM1632], 0x66, 0x85, "test", read_instr_test_rm1632);
+
+ register_opcode(proc->opcodes[X86_OP_MOV_REG1632], 0x66, 0x89, "mov", read_instr_mov_with_reg1632);
+
register_opcode(proc->opcodes[X86_OP_MOV_FROM_CONTENT1632], 0x66, 0x8b, "mov", read_instr_mov_from_content_1632);
register_opcode(proc->opcodes[X86_OP_LEA], 0x66, 0x8d, "lea", read_instr_lea);
register_opcode(proc->opcodes[X86_OP_NOP], 0x00, 0x90, "nop", read_instr_nop);
+ register_opcode(proc->opcodes[X86_OP_TEST_AL], 0x00, 0xa8, "test", read_instr_test_al);
+ register_opcode(proc->opcodes[X86_OP_TEST_E_AX], 0x66, 0xa9, "test", read_instr_test_e_ax);
+
register_opcode(proc->opcodes[X86_OP_MOV_E_AX], 0x66, 0xb8, "mov", read_instr_mov_to_1632);
register_opcode(proc->opcodes[X86_OP_MOV_E_CX], 0x66, 0xb9, "mov", read_instr_mov_to_1632);
register_opcode(proc->opcodes[X86_OP_MOV_E_DX], 0x66, 0xba, "mov", read_instr_mov_to_1632);