From bdaba318eb677bb1eda33a6df053132f58a02db6 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sun, 9 Apr 2023 20:03:16 +0300 Subject: [PATCH] add a way to test dissassembling of .asm files automatically --- src/{cpu.c => asm.c} | 45 ++----------- src/main.c | 149 ++++++++++++++++++++++++++++++++++++++----- test-dump-asm.o | 1 + test-dump.asm | 3 + test-input.o | 1 + 5 files changed, 143 insertions(+), 56 deletions(-) rename src/{cpu.c => asm.c} (51%) create mode 100644 test-dump-asm.o create mode 100644 test-dump.asm create mode 100644 test-input.o diff --git a/src/cpu.c b/src/asm.c similarity index 51% rename from src/cpu.c rename to src/asm.c index adba19e..d8fdcc6 100644 --- a/src/cpu.c +++ b/src/asm.c @@ -6,51 +6,15 @@ #define u16 uint16_t #define u8 uint8_t -struct cpu_state { - u16 ax, bx, cx, dx, sp, bp, si, di; -}; +const char *wide_reg_names[8] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; +const char *non_wide_reg_names[8] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; const char *lookup_reg_name(u8 idx, bool wide) { if (wide) { - if (idx == 0b000) { - return "ax"; - } else if (idx == 0b001) { - return "cx"; - } else if (idx == 0b010) { - return "dx"; - } else if (idx == 0b011) { - return "bx"; - } else if (idx == 0b100) { - return "sp"; - } else if (idx == 0b101) { - return "bp"; - } else if (idx == 0b110) { - return "si"; - } else if (idx == 0b111) { - return "di"; - } + return wide_reg_names[idx]; } else { - if (idx == 0b000) { - return "al"; - } else if (idx == 0b001) { - return "cl"; - } else if (idx == 0b010) { - return "dl"; - } else if (idx == 0b011) { - return "bl"; - } else if (idx == 0b100) { - return "ah"; - } else if (idx == 0b101) { - return "ch"; - } else if (idx == 0b110) { - return "dh"; - } else if (idx == 0b111) { - return "bh"; - } + return non_wide_reg_names[idx]; } - - printf("ERROR: Unknown register %d, wide %d", idx, wide); - abort(); } void dissassemble(FILE *src, FILE *dst) { @@ -59,6 +23,7 @@ void dissassemble(FILE *src, FILE *dst) { u8 byte1 = fgetc(src); u8 byte2 = fgetc(src); + // Register memory to/from register if ((byte1 & 0b11111100) == 0b10001000) { bool wide = byte1 & 0b1; bool direction = (byte1 & 0b10) >> 1; diff --git a/src/main.c b/src/main.c index 0560385..322785a 100644 --- a/src/main.c +++ b/src/main.c @@ -1,9 +1,12 @@ #include #include #include +#include #include "os.h" -#include "cpu.c" #include +#include "asm.c" + +#define strequal(a, b) strcmp(a, b) == 0 const char *get_tmp_dir() { #ifdef IS_WINDOWS @@ -17,6 +20,24 @@ const char *get_tmp_dir() { #endif } +int strendswith(const char *str, const char *suffix) +{ + if (!str || !suffix) + return 0; + size_t lenstr = strlen(str); + size_t lensuffix = strlen(suffix); + if (lensuffix > lenstr) + return 0; + return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; +} + +char *strdup(const char *src) { + char *dst = malloc(strlen (src) + 1); + if (dst == NULL) return NULL; + strcpy(dst, src); + return dst; +} + void get_tmp_file(char *filename, const char *prefix) { const char *dir = get_tmp_dir(); sprintf(filename, "%s\\%sXXXXXX", dir, prefix); @@ -24,28 +45,124 @@ void get_tmp_file(char *filename, const char *prefix) { close(fd); } -int main() { - char tmp_filename[MAX_PATH_SIZE]; - get_tmp_file(tmp_filename, "nasm_output"); - - char *example_filename = "examples/many_register_mov.asm"; +void print_usage(const char *program) { + fprintf(stderr, "Usage: %s \n", program); +} +int compile_asm(const char *src, const char *dst) { char command[512] = { 0 }; - snprintf(command, sizeof(command), "nasm \"%s\" -o \"%s\"", example_filename, tmp_filename); - if (system(command)) { - printf("ERROR: Failed to compile '%s'", example_filename); + snprintf(command, sizeof(command), "nasm \"%s\" -o \"%s\"", src, dst); + return system(command); +} + +int compare_files(const char *expected, const char *gotten) { + int rc = -1; + FILE *f1 = fopen(expected, "r"); + FILE *f2 = fopen(gotten, "r"); + + int i = 0; + while (!feof(f1) && !feof(f2)) { + int byte1 = fgetc(f1); + int byte2 = fgetc(f2); + if (byte1 != byte2) { + printf("Mismatch byte at %d, expected %d got %d\n", i, byte1, byte2); + goto err; + } + i++; + } + + if (!feof(f1) || !feof(f2)) { + + goto err; + } + + rc = 0; +err: + fclose(f1); + fclose(f2); + return rc; +} + +int main(int argc, char **argv) { + if (argc != 3) { + print_usage(argv[0]); return -1; } - FILE *assembly = fopen(tmp_filename, "r"); - if (assembly == NULL) { - printf("ERROR: Opening file '%s': %d\n", tmp_filename, errno); + if (strequal(argv[1], "test")) { + char *asm_file = argv[2]; + if (!strendswith(asm_file, ".asm")) { + printf("ERROR: Expected *.asm file, gotten '%s'", asm_file); + return -1; + } + + char *bin_filename = "test-input.o"; + if (compile_asm(asm_file, bin_filename)) { + printf("ERROR: Failed to compile '%s'", asm_file); + return -1; + } + + FILE *bin_test = fopen(bin_filename, "rb"); + if (bin_test == NULL) { + printf("ERROR: Opening file '%s': %d\n", bin_filename, errno); + return -1; + } + + char *dissassembly_filename = "test-dump.asm"; + FILE *dissassembly = fopen(dissassembly_filename, "wb+"); + if (dissassembly == NULL) { + printf("ERROR: Opening file '%s': %d\n", dissassembly_filename, errno); + return -1; + } + dissassemble(bin_test, dissassembly); + fclose(dissassembly); + + char *dissassembly_dump_filename = "test-dump-asm.o"; + if (compile_asm(dissassembly_filename, dissassembly_dump_filename)) { + printf("ERROR: Failed to compile '%s'", dissassembly_filename); + return -1; + } + + if (!compare_files(bin_filename, dissassembly_dump_filename)) { + printf("Test success\n"); + } else { + printf("Test failed\n"); + } + + } else if (strequal(argv[1], "dump")) { + char *input_file = argv[2]; + + if (strendswith(input_file, ".asm")) { + char bin_filename[MAX_PATH_SIZE]; + get_tmp_file(bin_filename, "nasm_output"); + + if (compile_asm(input_file, bin_filename)) { + printf("ERROR: Failed to compile '%s'", input_file); + return -1; + } + + FILE *assembly = fopen(bin_filename, "r"); + if (assembly == NULL) { + printf("ERROR: Opening file '%s': %d\n", bin_filename, errno); + return -1; + } + dissassemble(assembly, stdout); + + remove(bin_filename); + } else { + FILE *assembly = fopen(input_file, "r"); + if (assembly == NULL) { + printf("ERROR: Opening file '%s': %d\n", input_file, errno); + return -1; + } + dissassemble(assembly, stdout); + fclose(assembly); + } + + } else { + print_usage(argv[0]); return -1; } - dissassemble(assembly, stdout); - fclose(assembly); - - remove(tmp_filename); return 0; } diff --git a/test-dump-asm.o b/test-dump-asm.o new file mode 100644 index 0000000..93b300d --- /dev/null +++ b/test-dump-asm.o @@ -0,0 +1 @@ +‰Ù \ No newline at end of file diff --git a/test-dump.asm b/test-dump.asm new file mode 100644 index 0000000..f18de52 --- /dev/null +++ b/test-dump.asm @@ -0,0 +1,3 @@ +bits 16 + +mov cx, bx diff --git a/test-input.o b/test-input.o new file mode 100644 index 0000000..93b300d --- /dev/null +++ b/test-input.o @@ -0,0 +1 @@ +‰Ù \ No newline at end of file