1
0

add a way to test dissassembling of .asm files automatically

This commit is contained in:
Rokas Puzonas 2023-04-09 20:03:16 +03:00
parent 32f7f00952
commit bdaba318eb
5 changed files with 143 additions and 56 deletions

View File

@ -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;

View File

@ -1,9 +1,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include "os.h"
#include "cpu.c"
#include <errno.h>
#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 <test|dump> <file>\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;
}

1
test-dump-asm.o Normal file
View File

@ -0,0 +1 @@

3
test-dump.asm Normal file
View File

@ -0,0 +1,3 @@
bits 16
mov cx, bx

1
test-input.o Normal file
View File

@ -0,0 +1 @@