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.
282 lines
7.9 KiB
282 lines
7.9 KiB
2 years ago
|
#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);
|
||
|
}
|