#include #include #include #include #include // Bit patterns for the 8086 OPCODES enum class OPCODES { MOV = 0x88, }; enum class OPMASKS { MOV = 0xfc, }; enum class FLAGS { WORD = 0x01, REG_DEST = 0x02, }; enum class MODE { MEM = 0x00, MEM8 = 0x40, MEM16 = 0x80, REG = 0xc0, }; uint16_t decode_mode(uint16_t instruction); void decode_register(uint16_t instruction, bool word, char *dest); int main(int argc, char *argv[]) { if (argc < 2) { printf("Please provide a file to disassemble\n"); return 1; } const char *filename = argv[1]; FILE *fp = fopen(filename, "rb"); if (fp) { uint16_t inst = 0; const char *op = ""; char out_filename[4096] = {0}; sprintf(out_filename, "%s_out.asm", filename); FILE *out = fopen(out_filename, "w"); if (out) { fprintf(out, "; Disassembled by DASM\n\nbits 16\n\n"); while (fread(&inst, sizeof(inst), 1, fp)) { if ((inst & (uint16_t)OPMASKS::MOV) == (uint16_t)OPCODES::MOV) { op = "mov"; bool reg_dest = (inst & (uint16_t)FLAGS::REG_DEST) == (uint16_t)FLAGS::REG_DEST; bool word = (inst & (uint16_t)FLAGS::WORD) == (uint16_t)FLAGS::WORD; // NOTE: Using right shift will only work on little-endian CPUs uint16_t operands_info = inst >> 8; if (decode_mode(operands_info) == (uint16_t)MODE::REG) { char rm[3] = {0}; char reg[3] = {0}; decode_register(operands_info, word, rm); decode_register(operands_info >> 3, word, reg); fprintf(out, "%s %s, %s\n", op, reg_dest ? reg : rm, reg_dest ? rm : reg); } } else { printf("It's not a mov operation\n"); } } fclose(out); } else { printf("Failed to open output file\n"); } fclose(fp); } else { printf("Failed to open the selected file\n"); } return 0; } uint16_t decode_mode(uint16_t instruction) { uint16_t mode_mask = 0xc0; return instruction & mode_mask; } void decode_register(uint16_t instruction, bool word, char *dest) { static uint16_t reg_mask = 0x07; // clang-format off static const char *table[16] = { "al", "ax", "cl", "cx", "dl", "dx", "bl", "bx", "ah", "sp", "ch", "bp", "dh", "si", "bh", "di" }; // clang-format on static const uint16_t ROW_WIDTH = 2; uint16_t offset = instruction & reg_mask; // Multiply offset by 2 since each row has 2 columns strcpy(dest, table[offset * ROW_WIDTH + (uint16_t)word]); }