Permalink
Browse files

x86: Decoding for opcode 0xe8 ("call")

Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
  • Loading branch information...
1 parent 4242395 commit 656d1cbb260f86a227da479584b86d3ab5d2614f @penberg penberg committed Apr 25, 2010
View
@@ -246,7 +246,7 @@ static const uint32_t decode_table[256] = {
/*[0xE5]*/ 0,
/*[0xE6]*/ 0,
/*[0xE7]*/ 0,
- /*[0xE8]*/ 0,
+ /*[0xE8]*/ INSTR_CALL | ADDMODE_REL | WIDTH_FULL,
/*[0xE9]*/ 0,
/*[0xEA]*/ 0,
/*[0xEB]*/ 0,
@@ -346,6 +346,10 @@ decode_src_operand(struct x86_instr *instr)
switch (instr->flags & SRC_MASK) {
case SRC_NONE:
break;
+ case SRC_REL:
+ operand->type = OP_REL;
+ operand->rel = instr->rel_data;
+ break;
case SRC_IMM:
case SRC_IMM8:
operand->type = OP_IMM;
@@ -371,6 +375,20 @@ decode_src_operand(struct x86_instr *instr)
}
}
+static void
+decode_rel(struct x86_instr *instr, uint8_t* RAM, addr_t *pc)
+{
+ addr_t new_pc = *pc;
+
+ uint8_t imm_lo = RAM[new_pc++];
+ uint8_t imm_hi = RAM[new_pc++];
+
+ instr->imm_data = (int16_t)((imm_hi << 8) | imm_lo);
+ instr->nr_bytes += 2;
+
+ *pc = new_pc;
+}
+
static void
decode_imm_full(struct x86_instr *instr, uint8_t* RAM, addr_t *pc)
{
@@ -414,6 +432,15 @@ decode_imm(struct x86_instr *instr, uint8_t* RAM, addr_t *pc)
}
}
+static void
+decode_imm_rel(struct x86_instr *instr, uint8_t* RAM, addr_t *pc)
+{
+ if (instr->flags & IMM_MASK)
+ decode_imm(instr, RAM, pc);
+ else
+ decode_rel(instr, RAM, pc);
+}
+
static void
decode_disp(struct x86_instr *instr, uint8_t* RAM, addr_t *pc)
{
@@ -531,8 +558,8 @@ arch_8086_decode_instr(struct x86_instr *instr, uint8_t* RAM, addr_t pc)
if (instr->flags & MEM_DISP_MASK)
decode_disp(instr, RAM, &pc);
- if (instr->flags & IMM_MASK)
- decode_imm(instr, RAM, &pc);
+ if (instr->flags & (IMM_MASK|REL_MASK))
+ decode_imm_rel(instr, RAM, &pc);
decode_src_operand(instr);
View
@@ -12,10 +12,11 @@
#include <stdint.h>
enum x86_operand_type {
- OP_REG,
OP_IMM,
OP_MEM,
OP_MEM_DISP,
+ OP_REG,
+ OP_REL,
};
enum x86_seg_override {
@@ -36,7 +37,10 @@ struct x86_operand {
enum x86_operand_type type;
uint8_t reg;
int32_t disp; /* address displacement can be negative */
- uint32_t imm;
+ union {
+ uint32_t imm;
+ int32_t rel;
+ };
};
enum x86_instr_flags {
@@ -55,20 +59,23 @@ enum x86_instr_flags {
SRC_IMM8 = (1U << 14),
IMM_MASK = SRC_IMM|SRC_IMM8,
- SRC_REG = (1U << 15),
- SRC_ACC = (1U << 16),
- SRC_MEM = (1U << 17),
- SRC_MEM_DISP_BYTE = (1U << 18),
- SRC_MEM_DISP_FULL = (1U << 19),
- SRC_MASK = SRC_NONE|SRC_IMM|SRC_IMM8|SRC_REG|SRC_ACC|SRC_MEM|SRC_MEM_DISP_BYTE|SRC_MEM_DISP_FULL,
+ SRC_REL = (1U << 15),
+ REL_MASK = SRC_REL,
+
+ SRC_REG = (1U << 16),
+ SRC_ACC = (1U << 17),
+ SRC_MEM = (1U << 18),
+ SRC_MEM_DISP_BYTE = (1U << 19),
+ SRC_MEM_DISP_FULL = (1U << 20),
+ SRC_MASK = SRC_NONE|IMM_MASK|REL_MASK|SRC_REG|SRC_ACC|SRC_MEM|SRC_MEM_DISP_BYTE|SRC_MEM_DISP_FULL,
/* Destination operand */
- DST_NONE = (1U << 20),
- DST_REG = (1U << 21),
- DST_ACC = (1U << 22), /* AL/AX */
- DST_MEM = (1U << 23),
- DST_MEM_DISP_BYTE = (1U << 24), /* 8 bits */
- DST_MEM_DISP_FULL = (1U << 25), /* 16 bits or 32 bits */
+ DST_NONE = (1U << 21),
+ DST_REG = (1U << 22),
+ DST_ACC = (1U << 23), /* AL/AX */
+ DST_MEM = (1U << 24),
+ DST_MEM_DISP_BYTE = (1U << 25), /* 8 bits */
+ DST_MEM_DISP_FULL = (1U << 26), /* 16 bits or 32 bits */
DST_MASK = DST_NONE|DST_REG|DST_ACC|DST_MEM|DST_MEM_DISP_BYTE|DST_MEM_DISP_FULL,
MEM_DISP_MASK = SRC_MEM_DISP_BYTE|SRC_MEM_DISP_FULL|DST_MEM_DISP_BYTE|DST_MEM_DISP_FULL,
@@ -81,13 +88,14 @@ enum x86_addmode {
ADDMODE_ACC_MEM = SRC_ACC|DST_MEM|DIR_REVERSED, /* AL/AX -> memory */
ADDMODE_ACC_REG = SRC_ACC|DST_REG, /* AL/AX -> reg */
ADDMODE_IMM = SRC_IMM|DST_NONE, /* immediate operand */
+ ADDMODE_IMM8_RM = SRC_IMM8|MOD_RM|DIR_REVERSED, /* immediate -> register/memory */
ADDMODE_IMM_ACC = SRC_IMM|DST_ACC, /* immediate -> AL/AX */
ADDMODE_IMM_REG = SRC_IMM|DST_REG, /* immediate -> register */
- ADDMODE_IMM8_RM = SRC_IMM8|MOD_RM|DIR_REVERSED, /* immediate -> register/memory */
ADDMODE_IMPLIED = SRC_NONE|DST_NONE, /* no operands */
ADDMODE_MEM_ACC = SRC_ACC|DST_MEM, /* memory -> AL/AX */
ADDMODE_REG = SRC_REG|DST_NONE, /* register */
ADDMODE_REG_RM = SRC_REG|MOD_RM|DIR_REVERSED, /* register -> register/memory */
+ ADDMODE_REL = SRC_REL|DST_NONE, /* relative */
ADDMODE_RM_REG = DST_REG|MOD_RM, /* register/memory -> register */
};
@@ -100,7 +108,10 @@ struct x86_instr {
uint8_t rm; /* R/M */
uint8_t reg_opc; /* Reg/Opcode */
uint32_t disp; /* Address displacement */
- uint32_t imm_data; /* Immediate data */
+ union {
+ uint32_t imm_data; /* Immediate data */
+ int32_t rel_data; /* Relative address data */
+ };
unsigned long type; /* See enum x86_instr_types */
unsigned long flags; /* See enum x86_instr_flags */
View
@@ -200,14 +200,17 @@ static const char *to_reg_name(struct x86_instr *instr, int reg_num)
}
static int
-print_operand(char *operands, size_t size, struct x86_instr *instr, struct x86_operand *operand)
+print_operand(addr_t pc, char *operands, size_t size, struct x86_instr *instr, struct x86_operand *operand)
{
int ret = 0;
switch (operand->type) {
case OP_IMM:
ret = snprintf(operands, size, "$0x%x", operand->imm);
break;
+ case OP_REL:
+ ret = snprintf(operands, size, "%x", (unsigned int)((long)pc + instr->nr_bytes + operand->rel));
+ break;
case OP_REG:
ret = snprintf(operands, size, "%s", to_reg_name(instr, operand->reg));
break;
@@ -237,13 +240,13 @@ arch_8086_disasm_instr(cpu_t *cpu, addr_t pc, char *line, unsigned int max_line)
/* AT&T syntax operands */
if (!(instr.flags & SRC_NONE))
- len += print_operand(operands+len, sizeof(operands)-len, &instr, &instr.src);
+ len += print_operand(pc, operands+len, sizeof(operands)-len, &instr, &instr.src);
if (!(instr.flags & SRC_NONE) && !(instr.flags & DST_NONE))
len += snprintf(operands+len, sizeof(operands)-len, ",");
if (!(instr.flags & DST_NONE))
- len += print_operand(operands+len, sizeof(operands)-len, &instr, &instr.dst);
+ len += print_operand(pc, operands+len, sizeof(operands)-len, &instr, &instr.dst);
snprintf(line, max_line, "%s%s\t%s", prefix_names[instr.rep_prefix], to_mnemonic(&instr), operands);
View
@@ -1,5 +1,13 @@
+# This test case is not runnable, it simply attempts to cover as much of the
+# x86 instruction set encoding as possible.
.code16gcc
.text
+
+ .globl function_0
+ .type function_0, @function
+function_0:
+ retw
+
.globl _start
.type _start, @function
_start:
@@ -412,3 +420,15 @@ _start:
# 0xd7
xlat
+
+ # 0xe8
+ callw function_0
+ callw function_1
+
+ nop
+ nop
+
+ .globl function_1
+ .type function_1, @function
+function_1:
+ retw
Binary file not shown.

0 comments on commit 656d1cb

Please sign in to comment.