From 0f93a28a4bcab38b683fb1b3418b4503434e8cfe Mon Sep 17 00:00:00 2001 From: sfja Date: Fri, 4 Apr 2025 02:20:40 +0200 Subject: [PATCH] add link --- Makefile | 18 +++++- asm/build_header.c | 40 ++++++------ kern/main.asm | 8 +++ link/common.c | 151 +++++++++++++++++++++++++++++++++++++++++++++ link/kern.c | 55 +++++++++++++++++ link/link.h | 57 +++++++++++++++++ link/main.c | 76 +++++++++++++++++++++++ 7 files changed, 384 insertions(+), 21 deletions(-) create mode 100644 link/common.c create mode 100644 link/kern.c create mode 100644 link/link.h create mode 100644 link/main.c diff --git a/Makefile b/Makefile index c59b442..bf693d7 100644 --- a/Makefile +++ b/Makefile @@ -36,13 +36,16 @@ HEADERS = $(shell find . -name *.h) ASM_SOURCES = $(shell find asm/ -name *.c -not -name main.c) ASM_OBJECTS = $(patsubst %.c,build/%.o,$(ASM_SOURCES)) +LINK_SOURCES = $(shell find link/ -name *.c) +LINK_OBJECTS = $(patsubst %.c,build/%.o,$(LINK_SOURCES)) + VM_SOURCES = $(shell find vm/ -name *.c) VM_OBJECTS = $(patsubst %.c,build/%.o,$(VM_SOURCES)) KERN_SOURCES = $(shell find kern/ -name *.c) KERN_OBJECTS = $(patsubst %.c,build/%.o,$(KERN_SOURCES)) -all: bin/vm bin/build_disk_image bin/asm +all: bin/vm bin/build_disk_image bin/asm bin/link bin/vm: $(VM_OBJECTS) $(ASM_OBJECTS) build/image @mkdir -p $(dir $@) @@ -56,6 +59,10 @@ bin/build_disk_image: $(KERN_OBJECTS) $(ASM_OBJECTS) @mkdir -p $(dir $@) $(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS) +bin/link: $(LINK_OBJECTS) + @mkdir -p $(dir $@) + $(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS) + bin/asm: $(ASM_OBJECTS) build/asm/main.o @mkdir -p $(dir $@) $(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS) @@ -64,6 +71,15 @@ build/%.o: %.c $(HEADERS) @mkdir -p $(dir $@) $(CC) $< -c -o $@ $(C_FLAGS) $(OPTIMIZATION) $(F_FLAGS) +.PHONY: run_kern clean + +run_kern_main_asm: bin/asm bin/vm + ./bin/asm kern/main.asm + ./bin/vm -i out.o + +link_kern: bin/asm bin/link + ./bin/asm kern/main.asm -o build/kern_main.o + ./bin/link -p kern -o build/kern.out build/kern_main.o clean: rm -rf build/ bin/ diff --git a/asm/build_header.c b/asm/build_header.c index 4037d5d..2f20857 100644 --- a/asm/build_header.c +++ b/asm/build_header.c @@ -11,17 +11,17 @@ typedef struct { char* ident; Loc loc; uint16_t ip; -} GlobalSym; +} HeaderGlobalSym; typedef struct { size_t id; char* ident; -} ExternSym; +} HeaderExternSym; typedef struct { size_t id; uint16_t ip; -} ExternRef; +} HeaderExternRef; #define DEFINE_VEC_FIELDS(T, NAME) \ size_t NAME##_capacity; \ @@ -29,9 +29,9 @@ typedef struct { size_t NAME##_size; struct HeaderBuilder { - DEFINE_VEC_FIELDS(GlobalSym, global_syms) - DEFINE_VEC_FIELDS(ExternSym, extern_syms) - DEFINE_VEC_FIELDS(ExternRef, extern_refs) + DEFINE_VEC_FIELDS(HeaderGlobalSym, global_syms) + DEFINE_VEC_FIELDS(HeaderExternSym, extern_syms) + DEFINE_VEC_FIELDS(HeaderExternRef, extern_refs) size_t program_size; }; @@ -48,9 +48,9 @@ HeaderBuilder* header_builder_new(void) HeaderBuilder* builder = malloc(sizeof(HeaderBuilder)); *builder = (HeaderBuilder) { - VEC_CTOR_INIT(GlobalSym, global_syms, 8), - VEC_CTOR_INIT(ExternSym, extern_syms, 8), - VEC_CTOR_INIT(ExternRef, extern_refs, 8), + VEC_CTOR_INIT(HeaderGlobalSym, global_syms, 8), + VEC_CTOR_INIT(HeaderExternSym, extern_syms, 8), + VEC_CTOR_INIT(HeaderExternRef, extern_refs, 8), .program_size = 0, }; @@ -84,19 +84,19 @@ void header_builder_free(HeaderBuilder* builder) void header_builder_add_global_sym( HeaderBuilder* builder, char* ident, Loc loc, uint16_t ip) { - VEC_PUSH(builder, GlobalSym, global_syms, ident, loc, ip); + VEC_PUSH(builder, HeaderGlobalSym, global_syms, ident, loc, ip); } void header_builder_add_extern_sym( HeaderBuilder* builder, size_t id, char* ident) { - VEC_PUSH(builder, ExternSym, extern_syms, id, ident); + VEC_PUSH(builder, HeaderExternSym, extern_syms, id, ident); } void header_builder_add_extern_ref( HeaderBuilder* builder, size_t id, uint16_t ip) { - VEC_PUSH(builder, ExternRef, extern_refs, id, ip); + VEC_PUSH(builder, HeaderExternRef, extern_refs, id, ip); } int header_builder_resolve_global_syms( @@ -161,9 +161,9 @@ int header_builder_write(const HeaderBuilder* builder, size_t header_size = 5 + 1 + 1 + 1 + 1 + 1; for (size_t i = 0; i < builder->global_syms_size; ++i) - header_size += 1 + 1 + strlen(builder->global_syms[i].ident); + header_size += 1 + 1 + (strlen(builder->global_syms[i].ident) + 1) / 2; for (size_t i = 0; i < builder->extern_syms_size; ++i) - header_size += 1 + 1 + strlen(builder->extern_syms[i].ident); + header_size += 1 + 1 + (strlen(builder->extern_syms[i].ident) + 1) / 2; for (size_t i = 0; i < builder->extern_refs_size; ++i) header_size += 1 + 1; header_size *= 2; @@ -192,7 +192,7 @@ int header_builder_write(const HeaderBuilder* builder, TRY_WRITE_WORD((W)header_size); TRY_WRITE_WORD((W)builder->global_syms_size); for (size_t i = 0; i < builder->global_syms_size; ++i) { - const GlobalSym* sym = &builder->global_syms[i]; + const HeaderGlobalSym* sym = &builder->global_syms[i]; TRY_WRITE_WORD(sym->ip); size_t ident_len = strlen(sym->ident); TRY_WRITE_WORD((W)ident_len); @@ -201,7 +201,7 @@ int header_builder_write(const HeaderBuilder* builder, } TRY_WRITE_WORD((W)builder->extern_syms_size); for (size_t i = 0; i < builder->extern_syms_size; ++i) { - const ExternSym* sym = &builder->extern_syms[i]; + const HeaderExternSym* sym = &builder->extern_syms[i]; TRY_WRITE_WORD((W)sym->id); size_t ident_len = strlen(sym->ident); TRY_WRITE_WORD((W)ident_len); @@ -210,7 +210,7 @@ int header_builder_write(const HeaderBuilder* builder, } TRY_WRITE_WORD((W)builder->extern_refs_size); for (size_t i = 0; i < builder->extern_refs_size; ++i) { - const ExternRef* ref = &builder->extern_refs[i]; + const HeaderExternRef* ref = &builder->extern_refs[i]; TRY_WRITE_WORD((W)ref->id); TRY_WRITE_WORD(ref->ip); } @@ -228,21 +228,21 @@ void header_builder_print(const HeaderBuilder* builder) printf("address symbol\n"); printf("-----------------------\n"); for (size_t i = 0; i < builder->global_syms_size; ++i) { - GlobalSym* sym = &builder->global_syms[i]; + HeaderGlobalSym* sym = &builder->global_syms[i]; printf("%04x, %s\n", sym->ip, sym->ident); } printf("\nexterns:\n"); printf("id symbol\n"); printf("--------------------\n"); for (size_t i = 0; i < builder->extern_syms_size; ++i) { - ExternSym* sym = &builder->extern_syms[i]; + HeaderExternSym* sym = &builder->extern_syms[i]; printf("%-3ld %s\n", sym->id, sym->ident); } printf("\nextern uses:\n"); printf("id address\n"); printf("-----------\n"); for (size_t i = 0; i < builder->extern_refs_size; ++i) { - ExternRef* ref = &builder->extern_refs[i]; + HeaderExternRef* ref = &builder->extern_refs[i]; printf("%3ld %04x\n", ref->id, ref->ip); } } diff --git a/kern/main.asm b/kern/main.asm index d3e8807..65de327 100644 --- a/kern/main.asm +++ b/kern/main.asm @@ -1,6 +1,11 @@ include "arch.asm" +global start +extern stuff +global keyboard_interrupt +extern stuff_2 + start: ; rsp points *at* the top element mov rbp, 2048 @@ -23,6 +28,8 @@ interrupt_table: ; size d16 1 d16 keyboard_interrupt + call stuff + call stuff_2 nop keyboard_interrupt: @@ -34,6 +41,7 @@ keyboard_interrupt: push r2 push r3 + call stuff in r0, Device_Keyboard cmp r0, 44 diff --git a/link/common.c b/link/common.c new file mode 100644 index 0000000..798c082 --- /dev/null +++ b/link/common.c @@ -0,0 +1,151 @@ +#include "link.h" +#include +#include +#include +#include + +const char* file_iter_next(FileIter* iter) +{ + while (iter->files) { + const char* arg = iter->argv[iter->argc]; + iter->argc += 1; + if (strcmp(arg, "-o") == 0) { + iter->argc += 1; + continue; + } else if (strcmp(arg, "-p") == 0) { + iter->argc += 1; + continue; + } + iter->files -= 1; + return arg; + } + return NULL; +} + +void header_destroy(Header* header) +{ + for (size_t i = 0; i < header->global_syms_size; ++i) { + free(header->global_syms[i].ident); + } + free(header->global_syms); + for (size_t i = 0; i < header->extern_syms_size; ++i) { + free(header->extern_syms[i].ident); + } + free(header->extern_syms); + free(header->extern_refs); +} + +int header_read_from(Header* header, FILE* fp, const char* filename) +{ + int res = 0; + + uint16_t ident[6] = { 0 }; + if (fread(ident, sizeof(uint16_t), 5, fp) != 5) { + res = 1; + goto leave_1; + } + if (strcmp((char*)ident, "vc3-object") != 0) { + res = 2; + goto leave_1; + } + uint16_t header_size; + if (fread(&header_size, sizeof(uint16_t), 1, fp) != 1) { + res = 3; + goto leave_1; + } + // We want header size in words, not bytes. + header_size /= 2; + + fseek(fp, 0, SEEK_SET); + + uint16_t* data = malloc(sizeof(uint16_t) * header_size); + if (fread(data, sizeof(uint16_t), header_size, fp) != header_size) { + res = 4; + goto leave_2; + } + + size_t dc = 6; + + uint16_t global_syms_size = data[dc++]; + HeaderGlobalSym* global_syms + = malloc(sizeof(HeaderGlobalSym) * global_syms_size); + for (size_t i = 0; i < global_syms_size; ++i) { + uint16_t offset = data[dc++]; + uint16_t ident_len = data[dc++]; + char* ident = calloc(ident_len + 1, sizeof(char)); + strncpy(ident, (char*)&data[dc], ident_len); + dc += (ident_len + 1) / 2; + global_syms[i] = (HeaderGlobalSym) { offset, ident }; + } + + uint16_t extern_syms_size = data[dc++]; + HeaderExternSym* extern_syms + = malloc(sizeof(HeaderExternSym) * extern_syms_size); + for (size_t i = 0; i < extern_syms_size; ++i) { + uint16_t id = data[dc++]; + uint16_t ident_len = data[dc++]; + char* ident = calloc(ident_len + 1, sizeof(char)); + strncpy(ident, (char*)&data[dc], ident_len); + dc += (ident_len + 1) / 2; + extern_syms[i] = (HeaderExternSym) { id, ident }; + } + + uint16_t extern_refs_size = data[dc++]; + HeaderExternRef* extern_refs + = malloc(sizeof(HeaderExternRef) * extern_refs_size); + for (size_t i = 0; i < extern_refs_size; ++i) { + uint16_t id = data[dc++]; + uint16_t offset = data[dc++]; + extern_refs[i] = (HeaderExternRef) { id, offset }; + } + + uint16_t program_size = data[dc++]; + // We want program size in words too. + program_size /= 2; + + *header = (Header) { + header_size, + global_syms_size, + global_syms, + extern_syms_size, + extern_syms, + extern_refs_size, + extern_refs, + program_size, + }; + + res = 0; +leave_2: + free(data); +leave_1: + if (res != 0) { + fprintf(stderr, "error: malformed object file '%s'\n", filename); + printf("res = %d\n", res); + } + return res; +} + +void header_print(const Header* header) +{ + printf("globals:\n"); + printf("address symbol\n"); + printf("-----------------------\n"); + for (size_t i = 0; i < header->global_syms_size; ++i) { + HeaderGlobalSym* sym = &header->global_syms[i]; + printf("%04x, %s\n", sym->offset, sym->ident); + } + printf("\nexterns:\n"); + printf("id symbol\n"); + printf("--------------------\n"); + for (size_t i = 0; i < header->extern_syms_size; ++i) { + HeaderExternSym* sym = &header->extern_syms[i]; + printf("%-3d %s\n", sym->id, sym->ident); + } + printf("\nextern uses:\n"); + printf("id address\n"); + printf("-----------\n"); + for (size_t i = 0; i < header->extern_refs_size; ++i) { + HeaderExternRef* ref = &header->extern_refs[i]; + printf("%3d %04x\n", ref->id, ref->offset); + } +} diff --git a/link/kern.c b/link/kern.c new file mode 100644 index 0000000..76c1afb --- /dev/null +++ b/link/kern.c @@ -0,0 +1,55 @@ +#include "link.h" +#include +#include +#include + +int link_kern(const Args* args, FileIter input_files) +{ + int res = 0; + + FILE* output_fp = fopen(args->output_file, "wb"); + if (!output_fp) { + fprintf(stderr, + "could not open output file '%s' for writing: %s\n", + args->output_file, + strerror(errno)); + goto leave_0; + } + + FILE* input_fp = NULL; + Header header = (Header) { 0 }; + + const char* input_filename = file_iter_next(&input_files); + while (input_filename != NULL) { + input_fp = fopen(input_filename, "rb"); + if (!input_fp) { + fprintf(stderr, + "could not open input file '%s' for reading: %s\n", + input_filename, + strerror(errno)); + goto leave_1; + } + + int read_res = header_read_from(&header, input_fp, input_filename); + if (read_res != 0) { + res = -1; + goto leave_1; + } + header_print(&header); + + fclose(input_fp); + input_fp = NULL; + + input_filename = file_iter_next(&input_files); + } + + res = 0; +leave_1: + if (input_fp) + fclose(input_fp); + if (header.header_size != 0) + header_destroy(&header); + fclose(output_fp); +leave_0: + return res; +} diff --git a/link/link.h b/link/link.h new file mode 100644 index 0000000..42b44fc --- /dev/null +++ b/link/link.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +typedef enum { + Profile_Linked, + Profile_Shared, + Profile_Kern, +} Profile; + +static const char* profile_strs[] = { "linked", "shared", "kern" }; + +typedef struct { + const char* output_file; + int input_files; + Profile profile; +} Args; + +typedef struct { + int argc; + char** argv; + int files; +} FileIter; + +const char* file_iter_next(FileIter* iter); + +typedef struct { + uint16_t offset; + char* ident; +} HeaderGlobalSym; + +typedef struct { + uint16_t id; + char* ident; +} HeaderExternSym; + +typedef struct { + uint16_t id; + uint16_t offset; +} HeaderExternRef; + +typedef struct { + uint16_t header_size; + uint16_t global_syms_size; + HeaderGlobalSym* global_syms; + uint16_t extern_syms_size; + HeaderExternSym* extern_syms; + uint16_t extern_refs_size; + HeaderExternRef* extern_refs; + uint16_t program_size; +} Header; + +void header_destroy(Header* header); +int header_read_from(Header* header, FILE* fp, const char* filename); +void header_print(const Header* header); + +int link_kern(const Args* args, FileIter input_files); diff --git a/link/main.c b/link/main.c new file mode 100644 index 0000000..061d936 --- /dev/null +++ b/link/main.c @@ -0,0 +1,76 @@ +#include "link.h" +#include +#include +#include +#include + +static inline Args parse_args(int argc, char** argv); + +int main(int argc, char** argv) +{ + Args args = parse_args(argc, argv); + FileIter input_files = { 1, argv, args.input_files }; + + switch (args.profile) { + case Profile_Linked: + case Profile_Shared: + fprintf(stderr, + "profile '%s' not implemented\n", + profile_strs[args.profile]); + break; + case Profile_Kern: + return link_kern(&args, input_files); + } +} + +static inline Args parse_args(int argc, char** argv) +{ + const char* output_file = NULL; + int input_files = 0; + Profile profile = Profile_Linked; + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "-o") == 0) { + i += 1; + if (i >= argc) { + fprintf(stderr, "no filename given to -o\n"); + exit(1); + } + output_file = argv[i]; + } else if (strcmp(argv[i], "-p") == 0) { + i += 1; + if (i >= argc) { + fprintf(stderr, "no profile given to -p\n"); + exit(1); + } + + size_t strs_size = sizeof(profile_strs) / sizeof(profile_strs[0]); + bool found = false; + for (size_t si = 0; si < strs_size; ++si) { + if (strcmp(profile_strs[si], argv[i]) == 0) { + profile = (Profile)si; + found = true; + break; + } + } + if (!found) { + fprintf(stderr, "invalid profile '%s'\n", argv[i]); + fprintf(stderr, "valid profiles: linked, shared, kern\n"); + exit(1); + } + } else { + input_files += 1; + } + } + if (input_files == 0) { + fprintf(stderr, "no input files specified\n"); + exit(1); + } + if (output_file == NULL) { + output_file = "a.out"; + } + return (Args) { + output_file, + input_files, + profile, + }; +}