Last active
February 19, 2024 20:33
-
-
Save mateiidavid/fe5f3134871de76346ff2d3b6825e913 to your computer and use it in GitHub Desktop.
perfaware-8086-pt-1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#define assert(expr) \ | |
if (!(expr)) { \ | |
printf("%s:%d %s() %s\n", __FILE__, __LINE__, __func__, #expr); \ | |
*(volatile int *)0 = 0; \ | |
} | |
// A macro executes just one statement so we need the do while | |
#define LOG(level, fmt, ...) \ | |
do { \ | |
if (level <= g_log_level) { \ | |
printf(fmt, ##__VA_ARGS__); \ | |
} \ | |
} while (0) | |
#define INFO(fmt, ...) LOG(1, fmt, ##__VA_ARGS__) | |
#define OPCODE_MV 0b001000010 | |
typedef enum { | |
// MOV opcode | |
MOV_REG = 0x22, | |
} Opcode; | |
typedef enum { | |
REG = 0x3, | |
} Mode; | |
int g_log_level = 0; | |
static const char *g_registers[][2] = { | |
{"al", "ax"}, {"cl", "cx"}, {"dl", "dx"}, {"bl", "bx"}, | |
{"ah", "sp"}, {"ch", "bp"}, {"dh", "si"}, {"bh", "di"}, | |
}; | |
typedef struct { | |
u_int8_t d; | |
u_int8_t w; | |
Opcode op; | |
Mode mod; | |
} Instruction; | |
void print_usage(char *pname) | |
{ | |
printf("Usage: %s [OPTIONS] [FILE]\n" | |
"Description: An 8086 disassembler that only supports register-to-register " | |
"instructions\n" | |
"Example: %s test-asm\n\n" | |
"Options:\n" | |
" -h, --help print help message\n" | |
" -v display info messages\n" | |
" -vv display debug messages\n", | |
pname, pname); | |
} | |
char *args(int argc, char *argv[]) | |
{ | |
if (argc < 2) { | |
fprintf(stderr, "Error: at least one argument must be provided, got: %d\n", argc - 1); | |
print_usage(argv[0]); | |
exit(0); | |
} | |
for (int i = 1; i < argc; i++) { | |
char *arg = argv[i]; | |
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { | |
print_usage(argv[0]); | |
exit(0); | |
} | |
else if (strcmp(arg, "-v") == 0) { | |
g_log_level += 1; | |
} | |
else { | |
return arg; | |
} | |
} | |
fprintf(stderr, "Error: no filename provided to decoder\n"); | |
exit(1); | |
} | |
void decode(u_int8_t *buf, size_t buf_len) | |
{ | |
for (int i = 0; i < buf_len - 1; i += 2) { | |
u_int8_t opcode = buf[i]; | |
u_int8_t operands = buf[i + 1]; | |
if (!((opcode >> 2) & (u_int8_t)OPCODE_MV)) { | |
fprintf(stderr, "Unsupported opcode found in instruction stream\n"); | |
} | |
Instruction inst = {.d = opcode & 0x2, .w = opcode & 0x1, .mod = (operands >> 6) & 0x3}; | |
if ((inst.mod & 0x3) != 0x3) { | |
fprintf(stderr, "Unsupported mod: %x\n", inst.mod); | |
exit(1); | |
} | |
const char *reg = g_registers[(operands >> 3) & 0x7][inst.w]; | |
const char *rrm = g_registers[operands & 0x7][inst.w]; | |
if (inst.d) { | |
printf("mov %s, %s\n", reg, rrm); | |
} | |
else { | |
printf("mov %s, %s\n", rrm, reg); | |
} | |
} | |
} | |
int main(int argc, char *argv[]) | |
{ | |
char *fpath = args(argc, argv); | |
INFO("Reading from fpath: %s\n", fpath); | |
FILE *fd = fopen(fpath, "r"); | |
assert(fd); | |
fseek(fd, 0, SEEK_END); | |
size_t file_sz = ftell(fd); | |
rewind(fd); | |
u_int8_t *buf = malloc(file_sz); | |
assert(buf); | |
size_t n = 0; | |
int offset = 0; | |
while ((n = fread(buf + n, file_sz, 1, fd)) > 0) { | |
offset += n; | |
INFO("Read %lu bytes (%d total)\n", n, offset); | |
} | |
printf(";; %s disassembly\n\n", fpath); | |
printf("bits 16\n\n"); | |
decode(buf, file_sz); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment