You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

281 lines
7.9 KiB

#include "../common.h"
static void
print_mov(u8 wide, u8 swap, struct rm dest, struct rm src)
{
const char **regs = wide ? REGS_W1 : REGS_W0;
if (swap) {
struct rm buf = dest;
dest = src;
src = buf;
}
printf("mov ");
/* Dest can not be an immediate, so dest.imm indicates if there's a displacement */
if (dest.reg1 == NO_REGISTER && dest.reg2 == NO_REGISTER && dest.disp != 0) {
printf("[%d]", dest.disp);
} else if (dest.reg2 == NO_REGISTER && dest.imm == 0) {
printf("%s", regs[dest.reg1]);
} else if (dest.reg2 != NO_REGISTER && dest.imm == 0) {
printf("[%s + %s]", REGS_W1[dest.reg1], REGS_W1[dest.reg2]);
} else if (dest.reg2 == NO_REGISTER && dest.imm != 0) {
printf("[%s + %d]", REGS_W1[dest.reg1], dest.disp);
} else if (dest.reg2 != NO_REGISTER && dest.imm != 0) {
printf("[%s + %s + %d]", REGS_W1[dest.reg1], REGS_W1[dest.reg2], dest.disp);
}
printf(", ");
if (src.reg1 == NO_REGISTER) {
if (src.disp == 0) {
printf("%s %d", wide ? "word" : "byte", src.imm); /* only the src can be an immediate */
} else {
printf("[%d]", src.disp);
}
} else {
if (src.reg2 == NO_REGISTER && src.imm == 0) {
printf("%s", regs[src.reg1]);
} else if (src.reg2 != NO_REGISTER && src.imm == 0) {
printf("[%s + %s]", REGS_W1[src.reg1], REGS_W1[src.reg2]);
} else if (src.reg2 == NO_REGISTER && src.imm != 0) {
printf("[%s + %d]", REGS_W1[src.reg1], src.disp);
} else if (src.reg2 != NO_REGISTER && src.imm != 0) {
printf("[%s + %s + %d]", REGS_W1[src.reg1], REGS_W1[src.reg2], src.disp);
}
}
printf("\n");
}
static int
decode_rm(u8 *data, int offset, struct rm *location)
{
int advance = 0;
u8 b2 = data[offset + 1];
u8 mod = (b2 & 0xC0) >> 6;
u8 rm_field = b2 & 0x7;
if (mod == MOD_REGISTER) {
location->reg1 = rm_field;
location->reg2 = -1;
location->disp = 0;
location->imm = 0;
advance = 2;
} else if (mod == MOD_MEMORY) {
s16 b3 = data[offset + 2];
s16 b4 = data[offset + 3];
if (rm_field == 0x6) {
location->reg1 = NO_REGISTER;
location->reg2 = NO_REGISTER;
location->disp = (b4 << 8) | b3;
location->imm = 0;
advance = 4;
} else {
location->reg1 = MOD_PAIRS_FIRST[rm_field];
location->reg2 = MOD_PAIRS_SECOND[rm_field];
location->disp = 0;
location->imm = 1;
advance = 2;
}
} else if (mod == MOD_MEMORY_8) {
s8 b3 = data[offset + 2];
location->reg1 = MOD_PAIRS_FIRST[rm_field];
location->reg2 = MOD_PAIRS_SECOND[rm_field];
location->disp = b3;
location->imm = 1;
advance = 3;
} else if (mod == MOD_MEMORY_16) {
s16 b3 = data[offset + 2];
s16 b4 = data[offset + 3];
location->reg1 = MOD_PAIRS_FIRST[rm_field];
location->reg2 = MOD_PAIRS_SECOND[rm_field];
location->disp = (b4 << 8) | b3;
location->imm = 1;
advance = 4;
}
return(advance);
}
static void
decode_and_print_more_movs(u8 *data, u64 size)
{
printf("bits 16\n\n");
/* We still do not handle corrupt binaries */
u64 offset = 0;
while (offset < size) {
u8 b1 = data[offset + 0];
if ((b1 & MASK_REG_RM) == OPCODE_REG_RM) {
u8 b2 = data[offset + 1];
u8 W_flag = b1 & 0x1;
u8 D_flag = (b1 & 0x2) >> 1;
u8 reg_field = (b2 & 0x38) >> 3;
struct rm dest = { 0 };
struct rm src = { 0 };
dest.reg1 = reg_field;
dest.reg2 = -1;
dest.disp = 0;
dest.imm = 0;
offset += decode_rm(data, offset, &src);
print_mov(W_flag, !D_flag, dest, src);
} else if ((b1 & MASK_IMM_RM) == OPCODE_IMM_RM) {
u8 W_flag = b1 & 0x1;
u8 D_flag = 1; /* Immediate to register-memory always has mod/rm as destination */
struct rm dest = { 0 };
struct rm src = { 0 };
offset += decode_rm(data, offset, &dest);
s16 immediate = 0;
if (W_flag) {
s16 b5 = data[offset];
s16 b6 = data[offset + 1];
immediate = (b6 << 8) | b5;
offset += 2;
} else {
s16 b5 = data[offset];
immediate = b5;
offset += 1;
}
src.reg1 = NO_REGISTER;
src.imm = immediate;
print_mov(W_flag, !D_flag, dest, src);
} else if ((b1 & MASK_IMM_REG) == OPCODE_IMM_REG) {
u8 W_flag = (b1 & 0x8) >> 3;
u16 b2 = data[offset + 1];
u8 reg = b1 & 0x7;
struct rm dest = { 0 };
struct rm src = { 0 };
dest.reg1 = reg;
dest.reg2 = NO_REGISTER;
dest.disp = 0;
dest.imm = 0;
s16 immediate = 0;
if (W_flag) {
/* A 16-bit immediate follows */
u16 b3 = data[offset + 2];
immediate = (b3 << 8) | b2;
offset += 3;
} else {
/* An 8-bit immediate follows */
immediate = b2;
offset += 2;
}
src.reg1 = NO_REGISTER;
src.reg2 = NO_REGISTER;
src.disp = 0;
src.imm = immediate;
print_mov(W_flag, 0, dest, src);
} else if ((b1 & MASK_MEM_ACC) == OPCODE_MEM_ACC) {
u8 W_flag = b1 & 0x1;
u8 b2 = data[offset + 1];
struct rm dest = { 0 };
struct rm src = { 0 };
dest.reg1 = AX;
dest.reg2 = NO_REGISTER;
dest.disp = 0;
dest.imm = 0;
u16 address = 0;
if (W_flag) {
u16 b3 = data[offset + 2];
address = (b3 << 8) | b2;
offset += 3;
} else {
address = b2;
offset += 2;
}
src.reg1 = NO_REGISTER;
src.reg2 = NO_REGISTER;
src.disp = address;
src.imm = 0;
print_mov(W_flag, 0, dest, src);
} else if ((b1 & MASK_ACC_MEM) == OPCODE_ACC_MEM) {
u8 W_flag = b1 & 0x1;
u8 b2 = data[offset + 1];
struct rm dest = { 0 };
struct rm src = { 0 };
dest.reg1 = AX;
dest.reg2 = NO_REGISTER;
dest.disp = 0;
dest.imm = 0;
u16 address = 0;
if (W_flag) {
u16 b3 = data[offset + 2];
address = (b3 << 8) | b2;
offset += 3;
} else {
address = b2;
offset += 2;
}
src.reg1 = NO_REGISTER;
src.reg2 = NO_REGISTER;
src.disp = address;
src.imm = 0;
print_mov(W_flag, 1, dest, src);
}
}
}
int
main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s binary_file\n", argv[0]);
return(1);
}
char *filename = argv[1];
int fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("open");
return(1);
}
u64 size = file_size(fd);
u8 *data = read_file(fd, size);
decode_and_print_more_movs(data, size);
return(0);
}