diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2008-09-20 15:28:57 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2008-09-20 15:28:57 (GMT) |
commit | 2ccf097c9344465944089bebbc2ffd66ac93e1fd (patch) | |
tree | 74c535a32198bb04139cd85431e7c6ed780c5973 /src/arch/x86/operand.c | |
parent | 286c0872cc37d3dd6c2633cb61e4680123015d52 (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.c | 410 |
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; + +} |