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.
 
 
 

349 lines
9.7 KiB

#include "../common.h"
static void
print_inst(int instruction_offset, struct instruction *inst, int *labels, int label_count)
{
if (inst->opcode > 0xF) {
for (int i = 0; i < label_count; ++i) {
if (instruction_offset + inst->size + inst->jump_offset == labels[i]) {
printf("%s label_%d\n", OP_NAMES[inst->opcode], i);
return;
}
}
CRASH_SHOULDNOT();
}
const char **regs = inst->wide ? REGS_W1 : REGS_W0;
struct rm dest = inst->dst;
struct rm src = inst->src;
if (inst->swap) {
struct rm buf = dest;
dest = src;
src = buf;
}
printf("%s ", OP_NAMES[inst->opcode]);
/* 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", inst->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 int
decode_and_print_add_sub_cmp_jmp(u8 *data, u64 size, struct instruction *stream)
{
printf("bits 16\n\n");
/* We still do not handle corrupt binaries */
u64 offset = 0;
int stream_at = 0;
while (offset < size) {
int saved_offset = offset;
u8 b1 = data[offset + 0];
u8 b2 = data[offset + 1];
u8 antiop = b1 & ANTIOP_MASK;
u8 op = 0;
if (antiop == 0x00 || antiop == 0x4) {
op = (b1 & 0x38) >> 3;
} else {
op = (b2 & 0x38) >> 3;
}
if (antiop == 0x00) {
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);
struct instruction inst = {
.size = offset - saved_offset,
.opcode = op,
.dst = dest,
.src = src,
.wide = W_flag,
.swap = !D_flag
};
stream[stream_at++] = inst;
continue;
} else if (antiop == 0x80) {
u8 W_flag = b1 & 0x1;
u8 S_flag = (b1 & 0x2) >> 1;
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 (S_flag && !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;
struct instruction inst = {
.size = offset - saved_offset,
.opcode = op,
.dst = dest,
.src = src,
.wide = W_flag,
.swap = !D_flag
};
stream[stream_at++] = inst;
continue;
} else if (antiop == 0x4) {
u8 W_flag = b1 & 0x1;
s16 immediate = 0;
struct rm dest = { 0 };
struct rm src = { 0 };
dest.reg1 = AX;
dest.reg2 = NO_REGISTER;
dest.disp = 0;
dest.imm = 0;
if (W_flag) {
s16 b3 = data[offset + 2];
immediate= (b3 << 8) | b2;
offset += 3;
} else {
immediate = b2;
offset += 2;
}
src.reg1 = NO_REGISTER;
src.reg2 = NO_REGISTER;
src.disp = 0;
src.imm = immediate;
struct instruction inst = {
.size = offset - saved_offset,
.opcode = op,
.dst = dest,
.src = src,
.wide = W_flag,
.swap = 0,
};
stream[stream_at++] = inst;
continue;
}
offset += 2;
struct instruction inst = {
.size = offset - saved_offset,
.opcode = b1,
.jump_offset = (s8) b2
};
stream[stream_at++] = inst;
}
return(stream_at);
}
static int
insert_labels(struct instruction *in_stream, int instruction_count, int *labels)
{
int instruction_offset = 0;
int label_count = 0;
for (int i = 0; i < instruction_count; ++i) {
struct instruction *inst = in_stream + i;
if (inst->opcode > 0xF) {
/* jmp-like */
int target = instruction_offset + inst->size + inst->jump_offset;
int label_exists = 0;
for (int j = 0; j < label_count; ++j) {
if (labels[j] == target) {
label_exists = 1;
break;
}
}
if (!label_exists) {
labels[label_count++] = target;
}
}
instruction_offset += inst->size;
}
return(label_count);
}
static void
print_instruction_stream(struct instruction *stream, int instruction_count,
int *labels, int label_count)
{
int instruction_offset = 0;
for (int i = 0; i < instruction_count; ++i) {
struct instruction *inst = stream + i;
for (int j = 0; j < label_count; ++j) {
if (labels[j] == instruction_offset) {
printf("label_%d:\n", j);
break;
}
}
print_inst(instruction_offset, stream + i, labels, label_count);
instruction_offset += inst->size;
}
}
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);
struct instruction stream[MAX_INSTRUCTIONS] = { 0 };
int labels[MAX_LABELS] = { 0 };
int instruction_count = decode_and_print_add_sub_cmp_jmp(data, size, stream);
int label_count = insert_labels(stream, instruction_count, labels);
print_instruction_stream(stream, instruction_count, labels, label_count);
return(0);
}