summaryrefslogtreecommitdiff
path: root/src/arch/x86/operand.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86/operand.c')
-rw-r--r--src/arch/x86/operand.c343
1 files changed, 342 insertions, 1 deletions
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. *