Skip to content

Instantly share code, notes, and snippets.

@mateiidavid
Last active February 19, 2024 20:33
Show Gist options
  • Save mateiidavid/fe5f3134871de76346ff2d3b6825e913 to your computer and use it in GitHub Desktop.
Save mateiidavid/fe5f3134871de76346ff2d3b6825e913 to your computer and use it in GitHub Desktop.
perfaware-8086-pt-1
#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