summaryrefslogtreecommitdiff
path: root/src/arch/x86/operand.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2008-09-20 15:28:57 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2008-09-20 15:28:57 (GMT)
commit2ccf097c9344465944089bebbc2ffd66ac93e1fd (patch)
tree74c535a32198bb04139cd85431e7c6ed780c5973 /src/arch/x86/operand.c
parent286c0872cc37d3dd6c2633cb61e4680123015d52 (diff)
Centralized all the code used to decode instructions.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@32 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/arch/x86/operand.c')
-rw-r--r--src/arch/x86/operand.c410
1 files changed, 402 insertions, 8 deletions
diff --git a/src/arch/x86/operand.c b/src/arch/x86/operand.c
index 10a908e..375b0a5 100644
--- a/src/arch/x86/operand.c
+++ b/src/arch/x86/operand.c
@@ -25,6 +25,7 @@
#include <malloc.h>
#include <math.h>
+#include <stdarg.h>
#include <stdio.h>
@@ -33,6 +34,9 @@
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+
/* Liste des registres 8 bits */
typedef enum _X868bRegister
@@ -127,6 +131,12 @@ void _x86_print_reg_operand(const x86_register *reg, AsmOperandSize, char *, siz
+/* Crée une opérande renvoyant vers un registre 16 ou 32 bits. */
+asm_x86_operand *x86_create_r1632_operand_from_opcode(uint8_t, bool, uint8_t);
+
+
+
+
/******************************************************************************
* *
@@ -471,7 +481,6 @@ asm_x86_operand *x86_create_r8_operand(uint8_t data, bool first)
* 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. *
* *
@@ -481,14 +490,14 @@ asm_x86_operand *x86_create_r8_operand(uint8_t data, bool first)
* *
******************************************************************************/
-asm_x86_operand *x86_create_rm8_operand(const uint8_t *data, off_t *pos, off_t len, bool first)
+asm_x86_operand *x86_create_rm8_operand(const uint8_t *data, off_t *pos, off_t len, ...)
{
asm_x86_operand *result; /* Registre à retourner */
uint8_t mod; /* Modificateur présent */
/* Registre simple... */
- result = x86_create_r8_operand(data[*pos], first);
+ result = x86_create_r8_operand(data[*pos], true);
if (result == NULL) return NULL;
mod = (data[*pos] & 0xc0);
@@ -628,11 +637,44 @@ asm_x86_operand *x86_create_r1632_operand(uint8_t data, bool is_reg32, bool firs
/******************************************************************************
* *
+* Paramètres : data = donnée à analyser. *
+* is_reg32 = indique si le registre est un registre 32 bits. *
+* base = valeur du premier registre. *
+* *
+* 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_from_opcode(uint8_t data, bool is_reg32, uint8_t base)
+{
+ asm_x86_operand *result; /* Registre à retourner */
+
+ 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, data - base))
+ {
+ 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. *
* *
@@ -642,14 +684,14 @@ asm_x86_operand *x86_create_r1632_operand(uint8_t data, bool is_reg32, bool firs
* *
******************************************************************************/
-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 *x86_create_rm1632_operand(const uint8_t *data, off_t *pos, off_t len, bool is_reg32, ...)
{
asm_x86_operand *result; /* Registre à retourner */
uint8_t mod; /* Modificateur présent */
/* Registre simple... */
- result = x86_create_r1632_operand(data[*pos], is_reg32, first);
+ result = x86_create_r1632_operand(data[*pos], is_reg32, true);
if (result == NULL) return NULL;
mod = (data[*pos] & 0xc0);
@@ -1169,8 +1211,6 @@ asm_x86_operand *x86_create_moffs1632_operand(const uint8_t *data, off_t *pos, o
void x86_print_moffs_operand(const asm_x86_operand *operand, char *buffer, size_t len, AsmSyntax syntax)
{
- size_t pos; /* Position de traitement */
-
switch (syntax)
{
case ASX_INTEL:
@@ -1239,3 +1279,357 @@ asm_x86_operand *x86_create_rel8_operand_in_32b(uint64_t base, const uint8_t *da
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. *
+* *
+* Description : Crée une opérande à partir d'une adresse relative (16/32b). *
+* *
+* Retour : Opérande mise en place ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+asm_x86_operand *x86_create_rel1632_operand_in_32b(uint64_t base, const uint8_t *data, off_t *pos, off_t len, bool is_reg32)
+{
+ asm_x86_operand *result; /* Emplacement à retourner */
+ off_t init_pos; /* Position avant lecture */
+ int8_t offset; /* Décallage à appliquer */
+ uint32_t address; /* Adresse finale visée */
+
+ result = create_new_x86_operand();
+
+ init_pos = *pos;
+ address = base;
+
+ if (!read_imm_value(is_reg32 ? AOS_32_BITS : AOS_16_BITS, data, pos, len, &offset))
+ {
+ free(result);
+ return NULL;
+ }
+
+ address = base + (*pos - init_pos) + offset;
+
+ if (!fill_imm_operand_with_value(ASM_OPERAND(result), AOS_32_BITS, &address))
+ {
+ free(result);
+ return NULL;
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* AIDE A LA CREATION D'OPERANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction dont la définition est à compléter. [OUT]*
+* data = flux de données à analyser. *
+* pos = position courante dans ce flux. [OUT] *
+* len = taille totale des données à analyser. *
+* type = type de l'opérande. *
+* ... = éventuelle(s) information(s) complémentaire(s). *
+* *
+* Description : Procède à la lecture d'un opérande donné. *
+* *
+* Retour : Bilan de l'opération : true en cas de succès, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool x86_read_one_operand(asm_x86_instr *instr, const uint8_t *data, off_t *pos, off_t len, X86OperandType type, ...)
+{
+ va_list ap; /* Liste des compléments */
+ AsmOperandSize oprsize; /* Taille des opérandes */
+ uint64_t offset; /* Adresse courante */
+ uint8_t base; /* Indice du premier registre */
+ asm_x86_operand *op; /* Opérande unique décodé */
+
+ va_start(ap, type);
+
+ /* Lecture du premier opérande */
+
+ switch (type)
+ {
+ case X86_OTP_IMM8:
+ op = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(op), AOS_8_BITS, data, pos, len))
+ {
+ free(op);
+ op = NULL;
+ }
+ break;
+
+ case X86_OTP_IMM1632:
+ oprsize = va_arg(ap, AsmOperandSize);
+ op = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(op), oprsize, data, pos, len))
+ {
+ free(op);
+ op = NULL;
+ }
+ break;
+
+ case X86_OTP_REL8:
+ offset = va_arg(ap, uint64_t);
+ /* TODO : 64bits */
+ op = x86_create_rel8_operand_in_32b(offset + 1, data, pos, len);
+ break;
+
+ case X86_OTP_REL1632:
+ oprsize = va_arg(ap, AsmOperandSize);
+ offset = va_arg(ap, uint64_t);
+ /* TODO : 64bits */
+ op = x86_create_rel1632_operand_in_32b(offset + 1, data, pos, len, oprsize == AOS_32_BITS);
+ break;
+
+ case X86_OTP_R8:
+ op = x86_create_r8_operand(data[(*pos)++], true);
+ break;
+
+ case X86_OTP_R1632:
+ oprsize = va_arg(ap, AsmOperandSize);
+ op = x86_create_r1632_operand(data[(*pos)++], oprsize == AOS_32_BITS, true);
+ break;
+
+ case X86_OTP_OP_R1632:
+ oprsize = va_arg(ap, AsmOperandSize);
+ base = (uint8_t)va_arg(ap, int);
+ op = x86_create_r1632_operand_from_opcode(data[(*pos)++], oprsize == AOS_32_BITS, base);
+ break;
+
+ case X86_OTP_RM8:
+ op = x86_create_rm8_operand(data, pos, len);
+ break;
+
+ case X86_OTP_RM1632:
+ oprsize = va_arg(ap, AsmOperandSize);
+ op = x86_create_rm1632_operand(data, pos, len, oprsize == AOS_32_BITS);
+ break;
+
+ case X86_OTP_AL:
+ op = x86_create_r8_operand(0x00, true);
+ break;
+
+ case X86_OTP_E_AX:
+ oprsize = va_arg(ap, AsmOperandSize);
+ op = x86_create_r1632_operand(0x00, oprsize == AOS_32_BITS, true);
+ break;
+
+ }
+
+ va_end(ap);
+
+ if (op == NULL) return false;
+
+ /* Assemblage final */
+
+ ASM_INSTRUCTION(instr)->operands = (asm_operand **)calloc(1, sizeof(asm_operand *));
+ ASM_INSTRUCTION(instr)->operands_count = 1;
+
+ ASM_INSTRUCTION(instr)->operands[0] = ASM_OPERAND(op);
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction dont la définition est à compléter. [OUT]*
+* data = flux de données à analyser. *
+* pos = position courante dans ce flux. [OUT] *
+* len = taille totale des données à analyser. *
+* type1 = type du premier opérande. *
+* type2 = type du second opérande. *
+* ... = éventuelle(s) information(s) complémentaire(s). *
+* *
+* Description : Procède à la lecture de deux opérandes donnés. *
+* *
+* Retour : Bilan de l'opération : true en cas de succès, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool x86_read_two_operands(asm_x86_instr *instr, const uint8_t *data, off_t *pos, off_t len, X86OperandType type1, X86OperandType type2, ...)
+{
+ va_list ap; /* Liste des compléments */
+ AsmOperandSize oprsize; /* Taille des opérandes */
+ bool op1_first; /* Position de l'opérande #1 */
+ bool op2_first; /* Position de l'opérande #2 */
+ off_t op1_pos; /* Position après lecture #1 */
+ asm_x86_operand *op1; /* Premier opérande décodé */
+ off_t op2_pos; /* Position après lecture #2 */
+ asm_x86_operand *op2; /* Second opérande décodé */
+
+ va_start(ap, type2);
+
+ oprsize = AOS_UNDEFINED;
+
+ if (type1 & X86_OTP_RM_TYPE)
+ {
+ op1_first = true;
+ op2_first = false;
+ }
+ else if (type2 & X86_OTP_RM_TYPE)
+ {
+ op1_first = false;
+ op2_first = true;
+ }
+ else
+ {
+ op1_first = true;
+ op2_first = false;
+ }
+
+ /* Lecture du premier opérande */
+
+ op1_pos = *pos;
+
+ switch (type1)
+ {
+ case X86_OTP_MOFFS8:
+ op1 = x86_create_moffs8_operand(data, &op1_pos, len);
+ break;
+
+ case X86_OTP_MOFFS1632:
+ oprsize = va_arg(ap, AsmOperandSize);
+ op1 = x86_create_moffs1632_operand(data, &op1_pos, len, oprsize == AOS_32_BITS);
+ break;
+
+ case X86_OTP_R8:
+ op1 = x86_create_r8_operand(data[op1_pos++], op1_first);
+ break;
+
+ case X86_OTP_R1632:
+ oprsize = va_arg(ap, AsmOperandSize);
+ op1 = x86_create_r1632_operand(data[op1_pos++], oprsize == AOS_32_BITS, op1_first);
+ break;
+
+ case X86_OTP_RM8:
+ op1 = x86_create_rm8_operand(data, &op1_pos, len);
+ break;
+
+ case X86_OTP_RM1632:
+ oprsize = va_arg(ap, AsmOperandSize);
+ op1 = x86_create_rm1632_operand(data, &op1_pos, len, oprsize == AOS_32_BITS);
+ break;
+
+ case X86_OTP_AL:
+ op1 = x86_create_r8_operand(0x00, op1_first);
+ break;
+
+ case X86_OTP_E_AX:
+ oprsize = va_arg(ap, AsmOperandSize);
+ op1 = x86_create_r1632_operand(0x00, oprsize == AOS_32_BITS, op1_first);
+ break;
+
+ }
+
+ if (op1 == NULL)
+ {
+ va_end(ap);
+ return false;
+ }
+
+ /* Lecture du second opérande */
+
+ if ((type1 & X86_OTP_REG_TYPE || type1 & X86_OTP_RM_TYPE) && (type2 & X86_OTP_IMM_TYPE))
+ op2_pos = op1_pos;
+ else op2_pos = *pos;
+
+ switch (type2)
+ {
+ case X86_OTP_IMM8:
+ op2 = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(op2), AOS_8_BITS, data, &op2_pos, len))
+ {
+ free(op2);
+ op2 = NULL;
+ }
+ break;
+
+ case X86_OTP_IMM1632:
+ if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
+ op2 = create_new_x86_operand();
+ if (!fill_imm_operand(ASM_OPERAND(op2), oprsize, data, &op2_pos, len))
+ {
+ free(op2);
+ op2 = NULL;
+ }
+ break;
+
+ case X86_OTP_MOFFS8:
+ op2 = x86_create_moffs8_operand(data, &op2_pos, len);
+ break;
+
+ case X86_OTP_MOFFS1632:
+ if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
+ op2 = x86_create_moffs1632_operand(data, &op2_pos, len, oprsize == AOS_32_BITS);
+ break;
+
+ case X86_OTP_R8:
+ op2 = x86_create_r8_operand(data[op2_pos++], op2_first);
+ break;
+
+ case X86_OTP_R1632:
+ if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
+ op2 = x86_create_r1632_operand(data[op2_pos++], oprsize == AOS_32_BITS, op2_first);
+ break;
+
+ case X86_OTP_RM8:
+ op2 = x86_create_rm8_operand(data, &op2_pos, len);
+ break;
+
+ case X86_OTP_RM1632:
+ if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
+ op2 = x86_create_rm1632_operand(data, &op2_pos, len, oprsize == AOS_32_BITS);
+ break;
+
+ case X86_OTP_AL:
+ op2 = x86_create_r8_operand(0x00, op2_first);
+ break;
+
+ case X86_OTP_E_AX:
+ if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
+ op2 = x86_create_r1632_operand(0x00, oprsize == AOS_32_BITS, op2_first);
+ break;
+
+ }
+
+ if (op2 == NULL)
+ {
+ free(op1);
+ va_end(ap);
+ return false;
+ }
+
+ va_end(ap);
+
+ /* Assemblage final */
+
+ *pos = MAX(op1_pos, op2_pos);
+
+ ASM_INSTRUCTION(instr)->operands = (asm_operand **)calloc(2, sizeof(asm_operand *));
+ ASM_INSTRUCTION(instr)->operands_count = 2;
+
+ ASM_INSTRUCTION(instr)->operands[0] = ASM_OPERAND(op1);
+ ASM_INSTRUCTION(instr)->operands[1] = ASM_OPERAND(op2);
+
+ return true;
+
+}