/* OpenIDA - Outil d'analyse de fichiers binaires
* operand.c - gestion des operandes de l'architecture x86
*
* Copyright (C) 2008 Cyrille Bagard
*
* This file is part of OpenIDA.
*
* OpenIDA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* OpenIDA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see .
*/
#include "operand.h"
#include
#include
#include
#include
#include "registers.h"
#include "../operand.h"
#include "../operand-int.h"
#include "../../common/extstr.h"
/* ---------------------- COQUILLE VIDE POUR LES OPERANDES X86 ---------------------- */
/* Définition d'un opérande de x86 (instance) */
struct _GX86Operand
{
GArchOperand parent; /* Instance parente */
};
/* Définition d'un opérande de x86 (classe) */
struct _GX86OperandClass
{
GArchOperandClass parent; /* Classe parente */
};
/* Initialise la classe des opérandes x86 de base. */
static void g_x86_operand_class_init(GX86OperandClass *);
/* Initialise une instance d'opérande de base pour x86. */
static void g_x86_operand_init(GX86Operand *);
/* ------------------------ OPERANDES VISANT UN REGISTRE X86 ------------------------ */
/* Définition d'un opérande visant un registre x86 (instance) */
struct _GX86RegisterOperand
{
GX86Operand parent; /* Instance parente */
x86_register *reg; /* Registre représenté */
};
/* Définition d'un opérande visant un registre x86 (classe) */
struct _GX86RegisterOperandClass
{
GX86OperandClass parent; /* Classe parente */
};
/* Initialise la classe des opérandes de registre x86. */
static void g_x86_register_operand_class_init(GX86RegisterOperandClass *);
/* Initialise une instance d'opérande de registre x86. */
static void g_x86_register_operand_init(GX86RegisterOperand *);
/* Traduit un opérande en version humainement lisible. */
static char *g_x86_register_operand_get_text(const GX86RegisterOperand *, const exe_format *, AsmSyntax);
/* ----------------------- OPERANDES COMPLEXES DE TYPE MOD/RM ----------------------- */
/* Définition d'un opérande x86 de type ModRM (instance) */
struct _GX86ModRMOperand
{
GX86Operand parent; /* Instance parente */
uint8_t scale; /* Puissance de deux */
x86_register *index; /* Registre servant d'indice */
x86_register *base; /* Registre de base */
GImmOperand *displacement; /* Décallage supplémentaire */
};
/* Définition d'un opérande x86 de type ModRM (classe) */
struct _GX86ModRMOperandClass
{
GX86OperandClass parent; /* Classe parente */
};
/* Initialise la classe des opérandes x86 de type ModRM. */
static void g_x86_mod_rm_operand_class_init(GX86ModRMOperandClass *);
/* Initialise une instance d'opérande x86 de type ModRM. */
static void g_x86_mod_rm_operand_init(GX86ModRMOperand *);
/* Traduit un opérande en version humainement lisible. */
static char *g_x86_mod_rm_operand_get_text(const GX86ModRMOperand *, const exe_format *, AsmSyntax);
/* ------------------------- OPERANDES D'ADRESSES RELATIVES ------------------------- */
/* Définition d'un opérande x86 d'adresse relative (instance) */
struct _GX86RelativeOperand
{
GX86Operand parent; /* Instance parente */
GImmOperand *immediate; /* Adresse visée reconstituée */
};
/* Définition d'un opérande x86 d'adresse relative (classe) */
struct _GX86RelativeOperandClass
{
GX86OperandClass parent; /* Classe parente */
};
/* Initialise la classe des opérandes x86 d'adresse relative. */
static void g_x86_relative_operand_class_init(GX86RelativeOperandClass *);
/* Initialise une instance d'opérande x86 d'adresse relative. */
static void g_x86_relative_operand_init(GX86RelativeOperand *);
/* Traduit un opérande en version humainement lisible. */
static char *g_x86_relative_operand_get_text(const GX86RelativeOperand *, const exe_format *, AsmSyntax);
/* ------------------------ OPERANDES D'EMPLACEMENTS MEMOIRE ------------------------ */
/* Définition d'un opérande visant un emplacement mémoire x86 (instance) */
struct _GX86MOffsOperand
{
GX86Operand parent; /* Instance parente */
GImmOperand *offset; /* Adresse mémoire visée */
};
/* Définition d'un opérande visant un emplacement mémoire x86 (classe) */
struct _GX86MOffsOperandClass
{
GX86OperandClass parent; /* Classe parente */
};
/* Initialise la classe des opérandes d'emplacement mémoire x86. */
static void g_x86_moffs_operand_class_init(GX86MOffsOperandClass *);
/* Initialise une instance d'opérande d'emplacement mémoire x86. */
static void g_x86_moffs_operand_init(GX86MOffsOperand *);
/* Traduit un opérande en version humainement lisible. */
static char *g_x86_moffs_operand_get_text(const GX86MOffsOperand *, const exe_format *, AsmSyntax);
/* ---------------------------------------------------------------------------------- */
/* COQUILLE VIDE POUR LES OPERANDES X86 */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini par la GLib pour un opérande de x86. */
G_DEFINE_TYPE(GX86Operand, g_x86_operand, G_TYPE_ARCH_OPERAND);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des opérandes x86 de base. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_operand_class_init(GX86OperandClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : operand = instance à initialiser. *
* *
* Description : Initialise une instance d'opérande de base pour x86. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_operand_init(GX86Operand *operand)
{
}
/* ---------------------------------------------------------------------------------- */
/* OPERANDES VISANT UN REGISTRE X86 */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini par la GLib pour un opérande de registre x86. */
G_DEFINE_TYPE(GX86RegisterOperand, g_x86_register_operand, G_TYPE_X86_OPERAND);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des opérandes de registre x86. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_register_operand_class_init(GX86RegisterOperandClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : operand = instance à initialiser. *
* *
* Description : Initialise une instance d'opérande de registre x86. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_register_operand_init(GX86RegisterOperand *operand)
{
GArchOperand *parent; /* Instance parente */
parent = G_ARCH_OPERAND(operand);
parent->get_text = (get_operand_text_fc)g_x86_register_operand_get_text;
}
/******************************************************************************
* *
* Paramètres : data = flux de données à analyser. *
* pos = position courante dans ce flux. [OUT] *
* len = taille totale des données à analyser. *
* size = taille de l'opérande, et donc du registre. *
* base = indice du premier registre. *
* *
* Description : Crée un opérande visant un registre x86. *
* *
* Retour : Opérande mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_x86_register_operand_new_from_opcode(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size, bin_t base)
{
GX86RegisterOperand *result; /* Structure à retourner */
x86_register *reg; /* Registre lu */
reg = get_x86_register(size, data[*pos] - base);
if (reg != NULL)
{
(*pos)++;
result = g_object_new(G_TYPE_X86_REGISTER_OPERAND, NULL);
result->reg = reg;
}
else result = NULL;
return G_ARCH_OPERAND(result);
}
/******************************************************************************
* *
* Paramètres : data = flux de données à analyser. *
* pos = position courante dans ce flux. [OUT] *
* len = taille totale des données à analyser. *
* size = taille de l'opérande, et donc du registre. *
* first = indique la partie du ModR/M à traiter. *
* *
* Description : Crée un opérande visant un registre x86. *
* *
* Retour : Opérande mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_x86_register_operand_new_from_mod_rm(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size, bool first)
{
GX86RegisterOperand *result; /* Structure à retourner */
bin_t index; /* Registre lu */
x86_register *reg; /* Registre créé */
if (first) index = data[*pos] & 0x07;
else index = (data[*pos] & 0x38) >> 3;
reg = get_x86_register(size, index);
if (reg != NULL)
{
(*pos)++;
result = g_object_new(G_TYPE_X86_REGISTER_OPERAND, NULL);
result->reg = reg;
}
else result = NULL;
return G_ARCH_OPERAND(result);
}
/******************************************************************************
* *
* Paramètres : index = indice du registre visé. *
* size = taille de l'opérande, et donc du registre. *
* *
* Description : Crée un opérande visant un registre x86 donné. *
* *
* Retour : Opérande mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_x86_register_operand_new_from_index(bin_t index, AsmOperandSize size)
{
GX86RegisterOperand *result; /* Structure à retourner */
x86_register *reg; /* Registre lu */
reg = get_x86_register(size, index);
if (reg != NULL)
{
result = g_object_new(G_TYPE_X86_REGISTER_OPERAND, NULL);
result->reg = reg;
}
else result = NULL;
return G_ARCH_OPERAND(result);
}
/******************************************************************************
* *
* Paramètres : operand = opérande à traiter. *
* format = format du binaire manipulé. *
* syntax = type de représentation demandée. *
* *
* Description : Traduit un opérande en version humainement lisible. *
* *
* Retour : Chaîne de caractères à libérer de la mémoire. *
* *
* Remarques : - *
* *
******************************************************************************/
static char *g_x86_register_operand_get_text(const GX86RegisterOperand *operand, const exe_format *format, AsmSyntax syntax)
{
char *result; /* Chaîne à retourner */
result = x86_register_as_text(operand->reg, syntax);
return result;
}
/* ---------------------------------------------------------------------------------- */
/* OPERANDES COMPLEXES DE TYPE MOD/RM */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini par la GLib pour un opérande x86 de type ModRM. */
G_DEFINE_TYPE(GX86ModRMOperand, g_x86_mod_rm_operand, G_TYPE_ARCH_OPERAND);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des opérandes x86 de type ModRM. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_mod_rm_operand_class_init(GX86ModRMOperandClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : operand = instance à initialiser. *
* *
* Description : Initialise une instance d'opérande x86 de type ModRM. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_mod_rm_operand_init(GX86ModRMOperand *operand)
{
GArchOperand *parent; /* Instance parente */
parent = G_ARCH_OPERAND(operand);
parent->get_text = (get_operand_text_fc)g_x86_mod_rm_operand_get_text;
}
/******************************************************************************
* *
* Paramètres : data = flux de données à analyser. *
* pos = position courante dans ce flux. [OUT] *
* len = taille totale des données à analyser. *
* size = taille de l'opérande, et donc du registre. *
* *
* Description : Crée un opérande x86 de type ModRM. *
* *
* Retour : Opérande mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_x86_mod_rm_operand_new(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size)
{
GX86ModRMOperand *result; /* Structure à retourner */
uint8_t mod; /* Modificateur présent */
x86_register *reg; /* Registre lu */
mod = (data[*pos] & 0xc0);
if (mod == 0xc0)
return g_x86_register_operand_new_from_mod_rm(data, pos, len, size, true);
reg = get_x86_register(size, data[*pos] & 0x07);
if (reg == NULL) return NULL;
(*pos)++;
/* Vieille astuce de l'emplacement mémoire fixe ? */
if (is_x86_register_base_pointer(reg) && mod == 0x00)
{
free_x86_register(reg);
return g_imm_operand_new_from_data(MDS_32_BITS/* FIXME */, data, pos, len, SRE_LITTLE);
}
result = g_object_new(G_TYPE_X86_MOD_RM_OPERAND, NULL);
/* A la recherche d'un SIB */
if (is_x86_register_stack_pointer(reg))
{
free_x86_register(reg);
result->base = get_x86_register(size, data[*pos] & 0x07);
if (result->base == NULL) goto gxmron_error;
result->index = get_x86_register(size, (data[*pos] & 0x38) >> 3);
if (result->index == NULL) goto gxmron_error;
result->scale = ((data[*pos] & 0xc0) >> 6);
if (is_x86_register_stack_pointer(result->index))
{
free_x86_register(result->index);
result->index = result->base;
result->base = NULL;
}
(*pos)++;
}
else result->index = reg;
/* Décallage supplémentaire ? */
switch (mod)
{
case 0x00:
if (result->base != NULL && is_x86_register_base_pointer(result->base))
{
free_x86_register(result->base);
result->base = NULL;
result->displacement = g_imm_operand_new_from_data(size/* FIXME : !convert mds/aos */, data, pos, len, SRE_LITTLE);
if (result->displacement == NULL) goto gxmron_error;
}
break;
case 0x40:
result->displacement = g_imm_operand_new_from_data(MDS_8_BITS_SIGNED, data, pos, len, SRE_LITTLE);
if (result->displacement == NULL) goto gxmron_error;
break;
case 0x80:
result->displacement = g_imm_operand_new_from_data(MDS_32_BITS_SIGNED/* FIXME ! 16/32 */, data, pos, len, SRE_LITTLE);
if (result->displacement == NULL) goto gxmron_error;
break;
}
return G_ARCH_OPERAND(result);
gxmron_error:
/* FIXME free(result);*/
return NULL;
}
/******************************************************************************
* *
* Paramètres : operand = opérande à traiter. *
* format = format du binaire manipulé. *
* syntax = type de représentation demandée. *
* *
* Description : Traduit un opérande en version humainement lisible. *
* *
* Retour : Chaîne de caractères à libérer de la mémoire. *
* *
* Remarques : - *
* *
******************************************************************************/
static char *g_x86_mod_rm_operand_get_text(const GX86ModRMOperand *operand, const exe_format *format, AsmSyntax syntax)
{
char *result; /* Chaîne à retourner */
char *tmp; /* Chaîne de registre */
switch (syntax)
{
case ASX_INTEL:
result = (char *)calloc(1 + 10 + 2, sizeof(char));
strcpy(result, "[");
if (operand->scale > 0)
snprintf(&result[1], 12, "%d*", (int)pow(2, operand->scale));
tmp = x86_register_as_text(operand->index, syntax);
result = stradd(result, tmp);
free(tmp);
if (operand->base != NULL)
{
result = stradd(result, "+");
tmp = x86_register_as_text(operand->base, syntax);
result = stradd(result, tmp);
free(tmp);
}
if (operand->displacement != NULL)
{
if (g_imm_operand_is_negative(operand->displacement)) result = stradd(result, "-");
else result = stradd(result, "+");
tmp = g_arch_operand_get_text(G_ARCH_OPERAND(operand->displacement), format, syntax);
result = stradd(result, tmp);
free(tmp);
}
result = stradd(result, "]");
break;
case ASX_ATT:
result = strdup("[modRM]");
break;
}
return result;
}
/* ---------------------------------------------------------------------------------- */
/* OPERANDES D'ADRESSES RELATIVES */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini par la GLib pour un opérande x86 d'adresse relative. */
G_DEFINE_TYPE(GX86RelativeOperand, g_x86_relative_operand, G_TYPE_X86_OPERAND);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des opérandes x86 d'adresse relative. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_relative_operand_class_init(GX86RelativeOperandClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : operand = instance à initialiser. *
* *
* Description : Initialise une instance d'opérande x86 d'adresse relative. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_relative_operand_init(GX86RelativeOperand *operand)
{
GArchOperand *parent; /* Instance parente */
parent = G_ARCH_OPERAND(operand);
parent->get_text = (get_operand_text_fc)g_x86_relative_operand_get_text;
}
/******************************************************************************
* *
* Paramètres : data = flux de données à analyser. *
* pos = position courante dans ce flux. [OUT] *
* len = taille totale des données à analyser. *
* size = taille de l'opérande, et donc du registre. *
* base = indice du premier registre. *
* *
* Description : Crée un opérande X86 d'adresse relative. *
* *
* Retour : Opérande mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_x86_relative_operand_new(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size, vmpa_t base)
{
GX86RelativeOperand *result; /* Structure à retourner */
off_t init_pos; /* Position avant lecture */
uint8_t val8; /* Valeur sur 8 bits */
uint16_t val16; /* Valeur sur 16 bits */
uint32_t val32; /* Valeur sur 32 bits */
uint32_t address32; /* Adresse finale visée */
init_pos = *pos;
switch (size)
{
case AOS_8_BITS_UNSIGNED:
read_u8(&val8, data, pos, len, SRE_LITTLE);
address32 = val8;
break;
case AOS_16_BITS_UNSIGNED:
read_u16(&val16, data, pos, len, SRE_LITTLE);
address32 = val16;
break;
case AOS_32_BITS_UNSIGNED:
read_u32(&val32, data, pos, len, SRE_LITTLE);
address32 = val32;
break;
default:
return NULL;
break;
}
address32 += base + (*pos - init_pos);
result = g_object_new(G_TYPE_X86_RELATIVE_OPERAND, NULL);
result->immediate = g_imm_operand_new_from_value(AOS_32_BITS/*FIXME*/, address32);
return G_ARCH_OPERAND(result);
}
/******************************************************************************
* *
* Paramètres : operand = opérande à traiter. *
* format = format du binaire manipulé. *
* syntax = type de représentation demandée. *
* *
* Description : Traduit un opérande en version humainement lisible. *
* *
* Retour : Chaîne de caractères à libérer de la mémoire. *
* *
* Remarques : - *
* *
******************************************************************************/
static char *g_x86_relative_operand_get_text(const GX86RelativeOperand *operand, const exe_format *format, AsmSyntax syntax)
{
char *result; /* Chaîne à retourner */
result = g_arch_operand_get_text(operand->immediate, format, syntax);
return result;
}
/******************************************************************************
* *
* Paramètres : operand = opérande à traiter. *
* *
* Description : Fournit l'adresse relative représentée par une opérande X86. *
* *
* Retour : Valeur portée par l'opérande. *
* *
* Remarques : - *
* *
******************************************************************************/
const GImmOperand *g_x86_relative_operand_get_value(const GX86RelativeOperand *operand)
{
return operand->immediate;
}
/* ---------------------------------------------------------------------------------- */
/* OPERANDES D'EMPLACEMENTS MEMOIRE */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini par la GLib pour un opérande d'emplacement mémoire x86. */
G_DEFINE_TYPE(GX86MOffsOperand, g_x86_moffs_operand, G_TYPE_X86_OPERAND);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des opérandes d'emplacement mémoire x86.*
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_moffs_operand_class_init(GX86MOffsOperandClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : operand = instance à initialiser. *
* *
* Description : Initialise une instance d'opérande d'emplacement mémoire x86.*
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_x86_moffs_operand_init(GX86MOffsOperand *operand)
{
GArchOperand *parent; /* Instance parente */
parent = G_ARCH_OPERAND(operand);
parent->get_text = (get_operand_text_fc)g_x86_moffs_operand_get_text;
}
/******************************************************************************
* *
* Paramètres : data = flux de données à analyser. *
* pos = position courante dans ce flux. [OUT] *
* len = taille totale des données à analyser. *
* size = taille de l'opérande, et donc du registre. *
* *
* Description : Crée un opérande d'emplacement mémoire x86. *
* *
* Retour : Opérande mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_x86_moffs_operand_new(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size)
{
GX86MOffsOperand *result; /* Structure à retourner */
GImmOperand *offset; /* Emplacement lu */
result = NULL;
offset = g_imm_operand_new_from_data(size/* FIXME : !convert mds/aos */, data, pos, len, SRE_LITTLE);
if (offset != NULL)
{
result = g_object_new(G_TYPE_X86_MOFFS_OPERAND, NULL);
result->offset = offset;
}
return G_ARCH_OPERAND(result);
}
/******************************************************************************
* *
* Paramètres : operand = opérande à traiter. *
* format = format du binaire manipulé. *
* syntax = type de représentation demandée. *
* *
* Description : Traduit un opérande en version humainement lisible. *
* *
* Retour : Chaîne de caractères à libérer de la mémoire. *
* *
* Remarques : - *
* *
******************************************************************************/
static char *g_x86_moffs_operand_get_text(const GX86MOffsOperand *operand, const exe_format *format, AsmSyntax syntax)
{
char *result; /* Chaîne à retourner */
result = g_arch_operand_get_text(operand->offset, format, syntax);
result = strprep(result, "ds:");
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(GArchInstruction *instr, const bin_t *data, off_t *pos, off_t len, X86OperandType type, ...)
{
va_list ap; /* Liste des compléments */
AsmOperandSize oprsize; /* Taille des opérandes */
vmpa_t offset; /* Adresse courante */
bin_t base; /* Indice du premier registre */
GArchOperand *op; /* Opérande unique décodé */
va_start(ap, type);
/* Lecture du premier opérande */
switch (type)
{
case X86_OTP_IMM8:
op = g_imm_operand_new_from_data(MDS_8_BITS, data, pos, len, SRE_LITTLE);
break;
case X86_OTP_IMM1632:
if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
op = g_imm_operand_new_from_data(oprsize == AOS_32_BITS ? MDS_32_BITS : MDS_16_BITS, data, pos, len, SRE_LITTLE);
break;
case X86_OTP_REL8:
offset = va_arg(ap, vmpa_t);
op = g_x86_relative_operand_new(data, pos, len, AOS_8_BITS, offset + 1);
break;
case X86_OTP_REL1632:
oprsize = va_arg(ap, AsmOperandSize);
offset = va_arg(ap, vmpa_t);
op = g_x86_relative_operand_new(data, pos, len, oprsize, offset + 1);
break;
case X86_OTP_R8:
op = g_x86_register_operand_new_from_mod_rm(data, pos, len, AOS_8_BITS, true);
break;
case X86_OTP_R1632:
oprsize = va_arg(ap, AsmOperandSize);
op = g_x86_register_operand_new_from_mod_rm(data, pos, len, oprsize, true);
break;
case X86_OTP_OP_R8:
base = (bin_t)va_arg(ap, int);
op = g_x86_register_operand_new_from_opcode(data, pos, len, AOS_8_BITS, base);
break;
case X86_OTP_OP_R1632:
oprsize = va_arg(ap, AsmOperandSize);
base = (bin_t)va_arg(ap, int);
op = g_x86_register_operand_new_from_opcode(data, pos, len, oprsize, base);
break;
case X86_OTP_RM8:
op = g_x86_mod_rm_operand_new(data, pos, len, AOS_8_BITS);
break;
case X86_OTP_RM1632:
oprsize = va_arg(ap, AsmOperandSize);
op = g_x86_mod_rm_operand_new(data, pos, len, oprsize);
break;
case X86_OTP_CL:
op = g_x86_register_operand_new_from_index(0x01, AOS_8_BITS);
break;
case X86_OTP_AL:
op = g_x86_register_operand_new_from_index(0x00, AOS_8_BITS);
break;
case X86_OTP_E_AX:
oprsize = va_arg(ap, AsmOperandSize);
op = g_x86_register_operand_new_from_index(0x00, oprsize);
break;
}
va_end(ap);
if (op == NULL) return false;
g_arch_instruction_attach_one_operand(instr, 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(GArchInstruction *instr, const bin_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 */
bin_t base; /* Indice du premier registre */
GArchOperand *op1; /* Premier opérande décodé */
off_t op2_pos; /* Position après lecture #2 */
GArchOperand *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_IMM8:
op1 = g_imm_operand_new_from_data(MDS_8_BITS, data, &op1_pos, len, SRE_LITTLE);
break;
case X86_OTP_IMM1632:
if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
op1 = g_imm_operand_new_from_data(oprsize == AOS_32_BITS ? MDS_32_BITS : MDS_16_BITS, data, &op1_pos, len, SRE_LITTLE);
break;
case X86_OTP_MOFFS8:
op1 = g_x86_moffs_operand_new(data, &op1_pos, len, AOS_8_BITS);
break;
case X86_OTP_MOFFS1632:
oprsize = va_arg(ap, AsmOperandSize);
op1 = g_x86_moffs_operand_new(data, &op1_pos, len, oprsize);
break;
case X86_OTP_R8:
op1 = g_x86_register_operand_new_from_mod_rm(data, &op1_pos, len, AOS_8_BITS, op1_first);
break;
case X86_OTP_R1632:
oprsize = va_arg(ap, AsmOperandSize);
op1 = g_x86_register_operand_new_from_mod_rm(data, &op1_pos, len, oprsize, op1_first);
break;
case X86_OTP_OP_R8:
base = (bin_t)va_arg(ap, int);
op1 = g_x86_register_operand_new_from_opcode(data, &op1_pos, len, AOS_8_BITS, base);
break;
case X86_OTP_OP_R1632:
oprsize = va_arg(ap, AsmOperandSize);
base = (bin_t)va_arg(ap, int);
op1 = g_x86_register_operand_new_from_opcode(data, &op1_pos, len, oprsize, base);
break;
case X86_OTP_RM8:
op1 = g_x86_mod_rm_operand_new(data, &op1_pos, len, AOS_8_BITS);
break;
case X86_OTP_RM1632:
oprsize = va_arg(ap, AsmOperandSize);
op1 = g_x86_mod_rm_operand_new(data, &op1_pos, len, oprsize);
break;
case X86_OTP_CL:
op1 = g_x86_register_operand_new_from_index(0x01, AOS_8_BITS);
break;
case X86_OTP_AL:
op1 = g_x86_register_operand_new_from_index(0x00, AOS_8_BITS);
break;
case X86_OTP_E_AX:
oprsize = va_arg(ap, AsmOperandSize);
op1 = g_x86_register_operand_new_from_index(0x00, oprsize);
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 = g_imm_operand_new_from_data(MDS_8_BITS, data, &op2_pos, len, SRE_LITTLE);
break;
case X86_OTP_IMM1632:
if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
op2 = g_imm_operand_new_from_data(oprsize == AOS_32_BITS ? MDS_32_BITS : MDS_16_BITS, data, &op2_pos, len, SRE_LITTLE);
break;
case X86_OTP_MOFFS8:
op2 = g_x86_moffs_operand_new(data, &op2_pos, len, AOS_8_BITS);
break;
case X86_OTP_MOFFS1632:
if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
op2 = g_x86_moffs_operand_new(data, &op2_pos, len, oprsize);
break;
case X86_OTP_R8:
op2 = g_x86_register_operand_new_from_mod_rm(data, &op2_pos, len, AOS_8_BITS, op2_first);
break;
case X86_OTP_R1632:
if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
op2 = g_x86_register_operand_new_from_mod_rm(data, &op2_pos, len, oprsize, op2_first);
break;
case X86_OTP_RM8:
op2 = g_x86_mod_rm_operand_new(data, &op2_pos, len, AOS_8_BITS);
break;
case X86_OTP_RM1632:
if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
op2 = g_x86_mod_rm_operand_new(data, &op2_pos, len, oprsize);
break;
case X86_OTP_CL:
op2 = g_x86_register_operand_new_from_index(0x01, AOS_8_BITS);
break;
case X86_OTP_AL:
op2 = g_x86_register_operand_new_from_index(0x00, AOS_8_BITS);
break;
case X86_OTP_E_AX:
if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize);
op2 = g_x86_register_operand_new_from_index(0x00, oprsize);
break;
}
if (op2 == NULL)
{
free(op1);
va_end(ap);
return false;
}
va_end(ap);
/* Assemblage final */
*pos = MAX(op1_pos, op2_pos);
g_arch_instruction_attach_two_operands(instr, op1, op2);
return true;
}