#include "xed-agen.h"
#include "xed-decoded-inst-api.h"
static xed_register_callback_fn_t register_callback = 0;
static xed_segment_base_callback_fn_t segment_callback = 0;
void xed_agen_register_callback(xed_register_callback_fn_t register_fn,
xed_segment_base_callback_fn_t segment_fn) {
register_callback = register_fn;
segment_callback = segment_fn;
}
xed_error_enum_t xed_agen(xed_decoded_inst_t* xedd,
unsigned int memop_index,
void* context,
xed_uint64_t* out_address) {
xed_uint64_t out = 0;
xed_uint64_t base_value = 0;
xed_uint64_t index_value = 0;
xed_uint64_t segment_base = 0;
xed_uint64_t scale = 0;
xed_int64_t displacement = 0;
xed_operand_values_t* xedv = 0;
xed_uint32_t addr_width = 0;
xed_uint32_t opnd_width = 0;
xed_bool_t real_mode = 0;
xed_bool_t error=0;
xed_reg_enum_t base_reg = XED_REG_INVALID;
xed_reg_enum_t seg_reg = XED_REG_INVALID;
xed_attribute_enum_t attr;
if (xedd == 0)
return XED_ERROR_GENERAL_ERROR;
if (memop_index != 0 && memop_index != 1)
return XED_ERROR_BAD_MEMOP_INDEX;
if (register_callback == 0)
return XED_ERROR_NO_AGEN_CALL_BACK_REGISTERED;
if (segment_callback == 0)
return XED_ERROR_NO_AGEN_CALL_BACK_REGISTERED;
xedv = xed_decoded_inst_operands(xedd);
addr_width = xed_operand_values_get_effective_address_width(xedv);
opnd_width = xed_operand_values_get_effective_operand_width(xedv);
real_mode = xed_operand_values_get_real_mode(xedv);
base_reg = xed_decoded_inst_get_base_reg(xedd,memop_index);
if (base_reg != XED_REG_INVALID)
base_value = (*register_callback)(base_reg, context, &error);
if (error)
return XED_ERROR_CALLBACK_PROBLEM;
if (memop_index == 1)
attr = XED_ATTRIBUTE_STACKPUSH1;
else
attr = XED_ATTRIBUTE_STACKPUSH0;
if (xed_decoded_inst_get_attribute(xedd,attr)) {
base_value = base_value - (opnd_width>>3);
}
seg_reg = xed_decoded_inst_get_seg_reg(xedd,memop_index);
if (seg_reg != XED_REG_INVALID) {
if (real_mode) {
segment_base = (*register_callback)(seg_reg, context, &error);
segment_base <<= 4;
}
else {
segment_base = (*segment_callback)(seg_reg, context, &error);
}
if (error)
return XED_ERROR_CALLBACK_PROBLEM;
}
if (memop_index == 0) {
xed_reg_enum_t index_reg;
index_reg = xed_decoded_inst_get_index_reg(xedd,memop_index);
if (index_reg != XED_REG_INVALID) {
index_value = (*register_callback)(index_reg, context, &error);
if (error)
return XED_ERROR_CALLBACK_PROBLEM;
scale = xed_decoded_inst_get_scale(xedd,0);
}
displacement = xed_decoded_inst_get_memory_displacement(xedd,0);
}
if (addr_width == 64) {
xed_uint64_t base64 = base_value;
xed_uint64_t disp64 = XED_STATIC_CAST(xed_uint64_t, displacement);
xed_uint64_t lin64 = 0;
if (base_reg == XED_REG_RIP) {
xed_uint64_t inst_len = xed_decoded_inst_get_length(xedd);
lin64 = base64 + inst_len + displacement;
if (xed3_operand_get_asz(xedd)) {
lin64 = lin64 & ((1ULL<<32)-1);
}
}
else {
xed_uint64_t index64 = index_value;
xed_uint64_t ea64 = base64 + index64 * scale + disp64;
lin64 = segment_base + ea64;
}
out = lin64;
}
else if (addr_width == 32) {
xed_uint32_t base32 = base_value;
xed_uint32_t index32 = index_value;
xed_uint32_t disp32 = XED_STATIC_CAST(xed_uint32_t, displacement);
xed_uint32_t ea32 = base32 + index32 * scale + disp32;
xed_uint32_t lin32 = segment_base + ea32;
out = lin32;
}
else if (addr_width == 16) {
xed_uint16_t base16 = base_value;
xed_uint16_t index16 = index_value;
xed_uint16_t disp16 = XED_STATIC_CAST(xed_uint16_t, displacement);;
xed_uint16_t ea16 = base16 + index16 * scale + disp16;
xed_uint16_t lin32 = segment_base + ea16;
if (real_mode) {
xed_uint32_t masked20 = lin32 & 0x000FFFFF;
out = masked20;
}
else
out = lin32;
}
if (out_address)
*out_address = out;
else
return XED_ERROR_NO_OUTPUT_POINTER;
return XED_ERROR_NONE;
}