From 81abea70fdbcd5a73a2144a0413df401a17c0aff Mon Sep 17 00:00:00 2001 From: d0p1 Date: Sun, 17 Aug 2025 13:25:31 +0200 Subject: [PATCH] feat(tools): fas2dump: generate elf file with symbol table from .fas --- .gitignore | 3 + bin/fas2sym/buffer.c | 39 +++++ bin/fas2sym/elf.c | 216 ++++++++++++++++++++++++++ bin/fas2sym/fas.c | 192 +++++++++++++++++++++++ bin/fas2sym/fas2sym.h | 37 +++++ bin/fas2sym/main.c | 152 ++++++++++++++++++ bin/fasdump/main.c | 338 +++++++++++++++++++++++++++++++++++++++++ boot/loader/loader.asm | 6 +- boot/loader/video.inc | 17 ++- include/elf.h | 192 +++++++++++++++++++++-- include/fas.h | 140 +++++++++++++++++ tools/Makefile | 13 +- 12 files changed, 1320 insertions(+), 25 deletions(-) create mode 100644 bin/fas2sym/buffer.c create mode 100644 bin/fas2sym/elf.c create mode 100644 bin/fas2sym/fas.c create mode 100644 bin/fas2sym/fas2sym.h create mode 100644 bin/fas2sym/main.c create mode 100644 bin/fasdump/main.c create mode 100644 include/fas.h diff --git a/.gitignore b/.gitignore index f718bb3..6bf9e4d 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,9 @@ bochsrc.bxrc *.EFI *.fd *.mod +*.fas +*.sym +*.dbg webring.json webring.txt kernel/const.inc diff --git a/bin/fas2sym/buffer.c b/bin/fas2sym/buffer.c new file mode 100644 index 0000000..f70c973 --- /dev/null +++ b/bin/fas2sym/buffer.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include "fas2sym.h" + +int +buffer_put(struct buffer *buff, const uint8_t *data, size_t size, + size_t *index) +{ + if (index != NULL) + { + *index = buff->cnt; + } + + while (buff->cap < buff->cnt + size) + { + buff->cap = (buff->cap == 0 ? 32 : buff->cap * 2); + buff->data = (uint8_t *)realloc(buff->data, buff->cap); + if (buff->data == NULL) + { + msg_err(NULL); + return (-1); + } + } + + memcpy(buff->data + buff->cnt, data, size); + buff->cnt += size; + + return (0); +} + +void +buffer_cleanup(struct buffer *buff) +{ + buff->cnt = 0; + buff->cap = 0; + free(buff->data); + buff->data = 0; +} diff --git a/bin/fas2sym/elf.c b/bin/fas2sym/elf.c new file mode 100644 index 0000000..0dbd462 --- /dev/null +++ b/bin/fas2sym/elf.c @@ -0,0 +1,216 @@ +#include +#include +#include +#include "fas2sym.h" + +enum sections { + SEC_NULL = 0, + SEC_SHSTRTAB, + SEC_STRTAB, + SEC_SYMTAB, + SEC_END +}; + +static Elf32_Ehdr elf_ehdr = { + { + ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, + ELFCLASS32, ELFDATA2LSB, EV_CURRENT, + 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + ET_REL, EM_386, EV_CURRENT, 0, 0, 0, 0, + sizeof(Elf32_Ehdr), sizeof(Elf32_Phdr), 0, + sizeof(Elf32_Shdr), SEC_END, SEC_SHSTRTAB +}; + +static Elf32_Shdr elf_shdrs[SEC_END] = { + { 0, SHT_NULL, 0, 0, 0, 0, SHN_UNDEF, 0, 0, 0 }, + /* .shstrtab */ + { 1, SHT_STRTAB, 0, 0, 0, 0, SHN_UNDEF, 0, 1, 0 }, + /* .strtab */ + { 11, SHT_STRTAB, 0, 0, 0, 0, SHN_UNDEF, 0, 1, 0 }, + /* .symtab */ + { + 19, SHT_SYMTAB, 0, 0, 0, 0, + SEC_STRTAB, 0, 4, sizeof(Elf32_Sym) + } +}; + +static struct buffer elf_shstrtab = { 0, 0, NULL }; +static struct buffer elf_strtab = { 0, 0, NULL }; +static struct buffer elf_symtab = { 0, 0, NULL }; + +static int +elf_shstrtab_init(void) +{ + const uint8_t initial[] = "\0.shstrtab\0.strtab\0.symtab\0"; + + return (buffer_put(&elf_shstrtab, initial, sizeof(initial), NULL)); +} + +static int +elf_strtab_init(void) +{ + const uint8_t initial[] = "\0"; + + return (buffer_put(&elf_strtab, initial, sizeof(initial), NULL)); +} + +static int +elf_symtab_init(void) +{ + const Elf32_Sym initial = { 0, 0, 0, 0, 0, SHN_UNDEF }; + + return (buffer_put(&elf_symtab, (uint8_t *)&initial, + sizeof(Elf32_Sym), NULL)); +} + +int +elf_init(void) +{ + if (elf_shstrtab_init() != 0) + { + return (-1); + } + + if (elf_strtab_init() != 0) + { + return (-1); + } + + if (elf_symtab_init() != 0) + { + return (-1); + } + + return (0); +} + +int +elf_add_symbol(uint32_t name_off, uint32_t value, uint32_t size, + uint8_t info, uint16_t sect) +{ + Elf32_Sym sym = { 0 }; + + sym.st_name = name_off; + sym.st_value = value; + sym.st_size = size; + sym.st_info = info; + sym.st_shndx = sect; + + msg_verbose(2, "add symbol: %s", + (char *)(elf_strtab.data + name_off)); + + return (buffer_put(&elf_symtab, (uint8_t *)&sym, + sizeof(Elf32_Sym), NULL)); +} + +int +elf_add_str(const char *str, size_t len, size_t *idx) +{ + return (buffer_put(&elf_strtab, (uint8_t *)str, len, idx)); +} + +static int +elf_write_tab(struct buffer *buff, FILE *fp) +{ + if (buff->cnt == 0 || buff->data == NULL) + { + return (0); + } + + if (fwrite(buff->data, buff->cnt, 1, fp) != 1) + { + return (-1); + } + + return (0); +} + +static void +elf_compute_section_offsets(void) +{ + size_t offset; + + offset = sizeof(Elf32_Ehdr); + elf_shdrs[SEC_SHSTRTAB].sh_offset = offset; + elf_shdrs[SEC_SHSTRTAB].sh_size = elf_shstrtab.cnt; + + offset += elf_shstrtab.cnt; + + elf_shdrs[SEC_STRTAB].sh_offset = offset; + elf_shdrs[SEC_STRTAB].sh_size = elf_strtab.cnt; + + offset += elf_strtab.cnt; + + elf_shdrs[SEC_SYMTAB].sh_offset = offset; + elf_shdrs[SEC_SYMTAB].sh_size = elf_symtab.cnt; +} + +int +elf_write(const char *file) +{ + FILE *fp; + int status; + size_t offset; + + fp = fopen(file, "wb"); + if (fp == NULL) + { + msg_err(file); + return (-1); + } + + status = -1; + + /* compute section headers offset */ + elf_ehdr.e_shoff = sizeof(Elf32_Ehdr); + elf_ehdr.e_shoff += elf_shstrtab.cnt + elf_strtab.cnt; + elf_ehdr.e_shoff += elf_symtab.cnt; + + if (fwrite(&elf_ehdr, sizeof(Elf32_Ehdr), 1, fp) != 1) + { + msg_errx("%s: An error occurred while writting elf header", file); + goto end; + } + + if (elf_write_tab(&elf_shstrtab, fp) != 0) + { + msg_errx("%s: An error occured while writting .shstrtab data", file); + goto end; + } + if (elf_write_tab(&elf_strtab, fp) != 0) + { + msg_errx("%s: An error occured while writting .strtab data", file); + goto end; + } + + if (elf_write_tab(&elf_symtab, fp) != 0) + { + msg_errx("%s: An error occured while writting .symtab data", file); + goto end; + } + + /* section headers */ + elf_compute_section_offsets(); + /* XXX: fix me */ + elf_shdrs[SEC_SYMTAB].sh_info = 0; /* (elf_symtab.cnt / sizeof(Elf32_Sym)) + 1;*/ + + if (fwrite(elf_shdrs, sizeof(Elf32_Shdr), SEC_END, fp) != SEC_END) + { + msg_errx("%s: An error occured while writting sections headers", file); + goto end; + } + + status = 0; +end: + fclose(fp); + return (status); +} + +void +elf_cleanup(void) +{ + buffer_cleanup(&elf_shstrtab); + buffer_cleanup(&elf_strtab); + buffer_cleanup(&elf_symtab); +} diff --git a/bin/fas2sym/fas.c b/bin/fas2sym/fas.c new file mode 100644 index 0000000..49c5332 --- /dev/null +++ b/bin/fas2sym/fas.c @@ -0,0 +1,192 @@ +#include +#include +#include +#include +#include +#include +#include "fas2sym.h" + +static FAS_Hdr fas_hdr; +static char *fas_strtab = NULL; +static FAS_Sym *fas_symtab = NULL; +static uint8_t *fas_psrc = NULL; +static size_t fas_sym_cnt = 0; + +static void +pstr2cstr(char *dst, const uint8_t *src) +{ + size_t psz; + + psz = *src++; + while (psz > 0) + { + *dst++ = *src++; + psz--; + } + + *dst = '\0'; +} + +static int +fas_load_table(uint8_t **dest, size_t offset, size_t size, FILE *fp) +{ + if (size == 0) + { + return (0); /* XXX */ + } + + *dest = (uint8_t *)malloc(size); + if (*dest == NULL) + { + msg_err(NULL); + return (-1); + } + + if (fseek(fp, offset, SEEK_SET) != 0) + { + msg_err(NULL); + return (-1); + } + + if (fread(*dest, size, 1, fp) != 1) + { + msg_errx("An unexpected error/eof occured while reading"); + return (-1); + } + + return (0); +} + +int +fas_load_file(const char *file) +{ + FILE *fp; + + fp = fopen(file, "rb"); + if (fp == NULL) + { + msg_err(file); + return (-1); + } + + if (fread(&fas_hdr, sizeof(FAS_Hdr), 1, fp) != 1) + { + msg_errx("%s: unexpected error/eof while reading FAS header", + file); + goto err; + } + + if (fas_hdr.magic != FAS_MAGIC) + { + msg_errx("%s: invalid magic, got '%08" PRIX32 + "' instead of '%08" PRIX32 "'", + file, (uint32_t)FAS_MAGIC); + goto err; + } + + if (fas_load_table((uint8_t **)&fas_strtab, fas_hdr.strtab_off, + fas_hdr.strtab_len, fp) != 0) + { + msg_errx("%s: can't load string table", file); + goto err_cleanup; + } + + if (fas_load_table((uint8_t **)&fas_symtab, fas_hdr.symtab_off, + fas_hdr.symtab_len, fp) != 0) + { + msg_errx("%s: can't load symbol table", file); + goto err_cleanup; + } + + if (fas_load_table(&fas_psrc, fas_hdr.psrc_off, fas_hdr.psrc_len, + fp) != 0) + { + msg_errx("%s: can't load preprocessed sources", file); + goto err_cleanup; + } + + fas_sym_cnt = fas_hdr.symtab_len / sizeof(FAS_Sym); + + msg_verbose(1, "%zu symbol(s) loaded from %s", fas_sym_cnt, file); + + fclose(fp); + return (0); + +err_cleanup: + fas_cleanup(); +err: + fclose(fp); + return (-1); +} + +static uint32_t +fas_export_symbol_name(uint32_t name_off) +{ + size_t idx = 0; + char *ptr; + char name[256] = { 0 }; + + if (name_off == 0) + { + return (0); /* anonymous symbol */ + } + + if (name_off & (1<<31)) /* if in fas strtab */ + { + ptr = fas_strtab + (name_off & ~(1<<31)); /* XXX */ + } + else /* otherwhise it's in psrc */ + { + pstr2cstr(name, fas_psrc + name_off); + ptr = name; + } + + if (elf_add_str(ptr, strlen(ptr) + 1, &idx) != 0) + { + /* error occured */ + return (0); + } + + return (idx); +} + +void +fas_export_symbols(void) +{ + size_t idx; + char *name_ptr; + size_t name_idx; + + /* export file name symbol */ + name_ptr = fas_strtab + fas_hdr.ifnm_off; + elf_add_str(name_ptr, strlen(name_ptr) + 1, &name_idx); + elf_add_symbol(name_idx, 0, 0, ELF32_ST_INFO(STB_LOCAL, STT_FILE), + SHN_ABS); + + /* export other symbol */ + for (idx = 0; idx < fas_sym_cnt; idx++) + { + if ((fas_symtab[idx].flags & FAS_SYM_DEF) == 0 || + fas_symtab[idx].flags & FAS_SYM_ASM_TIME) + { + continue; + } + + name_idx = fas_export_symbol_name(fas_symtab[idx].name_off); + + elf_add_symbol(name_idx, fas_symtab[idx].value, 0, + ELF32_ST_INFO(STB_LOCAL, STT_OBJECT), SHN_ABS); + } + +} + +void +fas_cleanup(void) +{ + free(fas_psrc); + fas_psrc = NULL; + free(fas_symtab); + fas_symtab = NULL; + free(fas_strtab); + fas_strtab = NULL; +} diff --git a/bin/fas2sym/fas2sym.h b/bin/fas2sym/fas2sym.h new file mode 100644 index 0000000..ab993db --- /dev/null +++ b/bin/fas2sym/fas2sym.h @@ -0,0 +1,37 @@ +#ifndef FAS2SYM_H +# define FAS2SYM_H 1 + +# include +# include +# include + +struct buffer { + size_t cap; + size_t cnt; + uint8_t *data; +}; + +/* buffer.c */ +int buffer_put(struct buffer *buff, const uint8_t *data, + size_t size, size_t *index); +void buffer_cleanup(struct buffer *buff); + +/* fas.c */ +int fas_load_file(const char *file); +void fas_export_symbols(void); +void fas_cleanup(void); + +/* elf.c */ +int elf_init(void); +int elf_add_str(const char *str, size_t len, size_t *idx); +int elf_add_symbol(uint32_t name_off, uint32_t value, uint32_t size, + uint8_t info, uint16_t sect); +int elf_write(const char *file); +void elf_cleanup(void); + +/* main.c */ +void msg_err(const char *fmt, ...); +void msg_errx(const char *fmt, ...); +void msg_verbose(int level, const char *fmt, ...); + +#endif /* !FAS2SYM_H */ diff --git a/bin/fas2sym/main.c b/bin/fas2sym/main.c new file mode 100644 index 0000000..2df5688 --- /dev/null +++ b/bin/fas2sym/main.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include "fas2sym.h" + +static const char *prg_name; +static const char *outfile = "out.sym"; +static int verbose = 0; + +static void +msg_err_common(const char *fmt, va_list ap) +{ + fprintf(stderr, "%s: ", prg_name); + if (fmt) + { + vfprintf(stderr, fmt, ap); + } +} + +void +msg_errx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + msg_err_common(fmt, ap); + fprintf(stderr, "\n"); + + va_end(ap); +} + +void +msg_err(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + msg_err_common(fmt, ap); + if (fmt) + { + fprintf(stderr, ": "); + } + + fprintf(stderr, "%s\n", strerror(errno)); + + va_end(ap); +} + +void +msg_verbose(int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (level <= verbose) + { + vprintf(fmt, ap); + printf("\n"); + } + va_end(ap); +} + +static void +usage(int retval) +{ + if (retval == EXIT_FAILURE) + { + fprintf(stderr, "Try '%s -h' for more information.\n", + prg_name); + } + else + { + printf("Usage: %s [-o OUTPUT] file\n", prg_name); + } + + exit(retval); +} + +static void +version(void) +{ + printf("%s (%s) %s\n", prg_name, MK_PACKAGE, MK_COMMIT); + + exit(EXIT_SUCCESS); +} + +int +main(int argc, char **argv) +{ + int c; + int status; + + prg_name = basename(argv[0]); + + while ((c = getopt(argc, argv, "hvVo:")) != -1) + { + switch (c) + { + case 'h': + usage(EXIT_SUCCESS); + break; + case 'V': + version(); + break; + case 'v': + verbose++; + break; + case 'o': + outfile = optarg; + break; + default: + usage(EXIT_FAILURE); + break; + } + } + + if (optind >= argc) + { + usage(EXIT_FAILURE); + } + + if (fas_load_file(argv[optind]) != 0) + { + return (EXIT_FAILURE); + } + + status = EXIT_FAILURE; + + if (elf_init() != 0) + { + goto cleanup; + } + + fas_export_symbols(); + + if (elf_write(outfile) != 0) + { + goto cleanup; + } + + status = EXIT_SUCCESS; +cleanup: + elf_cleanup(); + fas_cleanup(); + + return (status); +} diff --git a/bin/fasdump/main.c b/bin/fasdump/main.c new file mode 100644 index 0000000..9803dc7 --- /dev/null +++ b/bin/fasdump/main.c @@ -0,0 +1,338 @@ +#include +#include +#include +#include +#include + +struct buff { + size_t size; + uint8_t *data; +}; + +static char *prg_name = "fasdump"; +static struct fas_header hdr; +static struct buff strtab = { 0, NULL }; +static struct buff symtab = { 0, NULL }; +static struct buff psrc = { 0, NULL }; +static struct buff asmdmp = { 0, NULL }; +static struct buff sectab = { 0, NULL }; +static struct buff symref = { 0, NULL }; + +static void +version(void) +{ + printf("%s (%s) %s\n", prg_name, MK_PACKAGE, MK_COMMIT); + exit(EXIT_SUCCESS); +} + +static void +usage(int retval) +{ + if (retval == EXIT_FAILURE) + { + fprintf(stderr, "Try '%s -h' for more informations.", prg_name); + } + + exit(retval); +} + +static int +readall(uint8_t *dest, size_t size, FILE *fp) +{ + size_t total; + size_t byte_read; + + total = 0; + do + { + byte_read = fread(dest + total, 1, size - total, fp); + if (byte_read == 0) + { + return (-1); + } + + total += byte_read; + } + while (total < size); + + return (0); +} + +static int +load_table(struct buff *dst, size_t off, size_t len, FILE *fp) +{ + dst->size = len; + if (len == 0) + { + return (0); + } + + dst->data = (uint8_t *)malloc(len); + if (dst->data == NULL) + { + return (-1); + } + + if (fseek(fp, off, SEEK_SET) != 0) + { + goto clean_up; + } + + if (readall(dst->data, len, fp) != 0) + { + goto clean_up; + } + + return (0); + +clean_up: + free(dst->data); + dst->size = 0; + return (-1); +} + +static int +read_header(FILE *fp) +{ + if (readall((uint8_t *)&hdr, sizeof(struct fas_header), fp) != 0) + { + return (-1); + } + + if (hdr.magic != FAS_MAGIC) + { + return (-1); + } + + return (0); +} + +static inline char * +strtab_get(size_t off) +{ + if (off > strtab.size) + { + return (NULL); + } + + return (strtab.data + off); +} + +static void +print_header(void) +{ + printf("FAS Header:\n"); + printf(" Magic: %X\n", hdr.magic); + printf(" Fasm version: %d.%d\n", hdr.ver_major, + hdr.ver_minor); + printf(" Length: %hu\n", hdr.length); + printf(" Input file: %s\n", strtab_get(hdr.ifnm_off)); + printf(" Output file: %s\n", strtab_get(hdr.ofnm_off)); + printf(" String table offset: 0x%08X\n", hdr.strtab_off); + printf(" String table length: %u\n", hdr.strtab_len); + printf(" Symbol table offset: 0x%08X\n", hdr.symtab_off); + printf(" Symbol table length: %u\n", hdr.symtab_len); + printf(" ASM dump offset: 0x%08X\n", hdr.asmdmp_off); + printf(" ASM dump length: %d\n", hdr.asmdmp_len); + printf(" Section table offset: 0x%08X\n", hdr.sectab_off); + printf(" Section table length: %d\n", hdr.sectab_len); + printf(" Symref table offset: 0x%08X\n", hdr.symref_off); + printf(" Symref table length: %d\n", hdr.symref_len); + + printf("\n"); +} + +static void +print_sections(void) +{ + size_t seccnt; + size_t idx; + uint32_t *sec; + + seccnt = sectab.size / sizeof(uint32_t); + sec = (uint32_t *)sectab.data; + printf("Section names:\n"); + for (idx = 0; idx < seccnt; idx++) + { + printf(" %s\n", strtab_get(sec[idx])); + } + printf("\n"); +} + +static void +pstr2cstr(char *dst, const char *src) +{ + size_t plen; + + plen = *src++; + + while (plen > 0) + { + *dst++ = *src++; + plen--; + } + *dst = '\0'; +} + +static void +print_sym_name(uint32_t off) +{ + char name_str[255] = {0}; + + if (off == 0) + { + return; + } + if (off & (1<<31)) + { + strncpy(name_str, strtab_get(off & ~(1<<31)), 255); + name_str[254] = '\0'; + } + else + { + pstr2cstr(name_str, psrc.data + off); + } + + printf("%s", name_str); +} + +static void +print_sym_section(uint8_t type, uint32_t rel) +{ + if (type == FAS_ABS) + { + printf("ABS "); + return; + } + + if (rel & (1<<31)) + { + printf("UND "); + } + else + { + printf("%-3" PRIu32 " %-2" PRIu8 " ", rel, type); + } +} +/* +static const char * +get_symbol_type(uint8_t type) +{ + switch (type) + { + case FAS_ABS: + return ("ABS"); + case FAS_REL_32: + return ("REL_32"); + default: + break; + } + + return ("???"); +} +*/ +static void +print_symbols(void) +{ + size_t symcnt; + size_t idx; + struct fas_symbol *sym; + + printf("Symbol table:\n"); + symcnt = symtab.size / sizeof(struct fas_symbol); + sym = (struct fas_symbol *)symtab.data; + + printf(" Num: Value Size Ndx Name\n"); + + for (idx = 0; idx < symcnt; idx++) + { + printf("%6d: ", idx); + printf("0x%016" PRIx64 " ", sym[idx].value); + printf("%-4" PRIu8 " ", sym[idx].size); + //printf("%s ", get_symbol_type(sym[idx].type)); + print_sym_section(sym[idx].type, sym[idx].reloc); + print_sym_name(sym[idx].name_off); + printf("\n"); +/* + printf("\t %04" PRIx16 " : ", sym[idx].flags); + if (sym[idx].flags & FAS_SYM_DEF) printf("DEF "); + if (sym[idx].flags & FAS_SYM_ASM_TIME) printf("ASM_TIME "); + if (sym[idx].flags & FAS_SYM_NOT_FWD_REF) printf("NOT_FWD "); + if (sym[idx].flags & FAS_SYM_USED) printf("USED "); + if (sym[idx].flags & FAS_SYM_PRD_USED) printf("PRD_USED "); + if (sym[idx].flags & FAS_SYM_LPRD_USED) printf("LPRD_USED "); + if (sym[idx].flags & FAS_SYM_PRD_DEF) printf("PRD_DEF "); + if (sym[idx].flags & FAS_SYM_LPRD_DEF) printf("LPRD_DEF "); + if (sym[idx].flags & FAS_SYM_OPT_ADJ) printf("OPT_ADJ "); + if (sym[idx].flags & FAS_SYM_TWO_CMPLMNT) printf("TWO_CMPLMNT "); + if (sym[idx].flags & FAS_SYM_MARKER) printf("MARKER "); + printf("\n"); +*/ + /*printf("%X\n", sym[idx].value);*/ + } + printf("\n"); +} + +static void +print_asm_dump(void) +{ + struct fas_asmdmp *dmp; + + dmp = (struct fas_asmdmp *)asmdmp.data; + printf(" 0x%" PRIx32 " 0x%" PRIx64 "\n", dmp->of_off, dmp->addr); +} + +static int +process_file(char *fname) +{ + FILE *fp; + + fp = fopen(fname, "rb"); + if (fp == NULL) + { + return (EXIT_FAILURE); + } + + read_header(fp); + load_table(&strtab, hdr.strtab_off, hdr.strtab_len, fp); + load_table(&symtab, hdr.symtab_off, hdr.symtab_len, fp); + load_table(&psrc, hdr.psrc_off, hdr.psrc_len, fp); + load_table(&asmdmp, hdr.asmdmp_off, hdr.asmdmp_len, fp); + load_table(§ab, hdr.sectab_off, hdr.sectab_len, fp); + + print_header(); + print_sections(); + print_symbols(); + print_asm_dump(); + + fclose(fp); + + return (EXIT_SUCCESS); +} + +int +main(int argc, char *argv[]) +{ + while ((argc > 1) && (argv[1][0] == '-')) + { + switch (argv[1][1]) + { + case 'h': + usage(EXIT_SUCCESS); + break; + case 'V': + version(); + break; + default: + usage(EXIT_FAILURE); + break; + } + + argv++; + argc--; + } + + if (argc <= 1) usage(EXIT_FAILURE); + + return (process_file(argv[1])); +} diff --git a/boot/loader/loader.asm b/boot/loader/loader.asm index 6c09612..0463717 100644 --- a/boot/loader/loader.asm +++ b/boot/loader/loader.asm @@ -98,7 +98,7 @@ _start: jmp .skip_fat - ; fallback to fat12 + ; fallback to fat12 ; for now fat12 is asumed .fat_fallback: mov si, szMsgFatFallback @@ -129,7 +129,7 @@ _start: xor bx, bx call disk_read_sectors - + ; load stage 2 mov ax, KERNEL_PRELOAD/0x10 mov es, ax @@ -146,7 +146,7 @@ _start: call boot_info_print_mmap ; video information - ;call video_setup + call video_setup ; load GDT and enter Protected-Mode lgdt [gdt_ptr] diff --git a/boot/loader/video.inc b/boot/loader/video.inc index e492471..80a7f39 100644 --- a/boot/loader/video.inc +++ b/boot/loader/video.inc @@ -6,7 +6,7 @@ struc VesaInfo .Version dw ? .OEMNamePtr dd ? .Capabilities dd ? - .VideoModesPtr dw ? + .VideoModesPtr dd ? .CountOf64KBlocks dw ? .OEMSoftwareRevision dw ? .OEMVendorNamePtr dd ? @@ -28,7 +28,7 @@ struc VesaModeInfo .WindowPositioning dd ? .BytesPerScanLine dw ? - ; -- + ; -- .Width dw ? .Height dw ? .WidthChar db ? @@ -72,11 +72,11 @@ video_setup: jne .err cmp [vesa_block_buffer.Signature], 'VESA' jne .err - - push [vesa_block_buffer.OEMProductNamePtr] - push [vesa_block_buffer.OEMVendorNamePtr] - push [vesa_block_buffer.CountOf64KBlocks] - push [vesa_block_buffer.OEMNamePtr] + ; XXX: fix me + push word [vesa_block_buffer.OEMProductNamePtr] + push word [vesa_block_buffer.OEMVendorNamePtr] + push word [vesa_block_buffer.CountOf64KBlocks] + push word [vesa_block_buffer.OEMNamePtr] xor ecx, ecx mov cx, [vesa_block_buffer.Version] push ecx @@ -84,7 +84,7 @@ video_setup: call bios_log mov di, vesa_info_block_buffer - mov bx, [vesa_block_buffer.VideoModesPtr] + mov ebx, [vesa_block_buffer.VideoModesPtr] mov cx, [bx] cmp cx, 0xFFFF je .err @@ -110,6 +110,7 @@ vesa_block_buffer VesaInfo vesa_info_block_buffer VesaModeInfo szMsgVesaInfo db "Version: %x", CR, LF, "OEM Name: %s", CR, LF, "Total Memory: %d", CR, LF, "Vendor name: %s", CR, LF, "Product name: %s", 0 +szMsgVesaModeInfo db "%dx%dx%d", CR, LF, 0 szMsgDetectVideo db "Fetch video information.", 0 szMsgFramebuffer db "Fb: %x", 0 szMsgErrorVesa db "Failed to detect VBE mode", 0 diff --git a/include/elf.h b/include/elf.h index bce1a7e..68fe4bf 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1,23 +1,189 @@ #ifndef ELF_H # define ELF_H 1 +/* spec: https://refspecs.linuxfoundation.org/elf/elf.pdf + * elf(5) + */ # include -# define ELF_MAG0 0x7F -# define ELF_MAG1 0x45 -# define ELF_MAG2 0x4C -# define ELF_MAG3 0x46 +# define ELFMAG0 0x7F +# define ELFMAG1 0x45 +# define ELFMAG2 0x4C +# define ELFMAG3 0x46 -# define EI_NIDENT 16 +# define EI_MAG0 0 +# define EI_MAG1 1 +# define EI_MAG2 2 +# define EI_MAG3 3 +# define EI_CLASS 4 +# define EI_DATA 5 +# define EI_VERSION 6 +# define EI_PAD 7 +# define EI_NIDENT 16 -struct elf_header -{ - uint8_t e_ident[EI_NIDENT]; - uint16_t e_type; - uint16_t e_machine; - uint32_t e_version; -}; +# define ET_NONE 0 +# define ET_REL 1 +# define ET_EXEC 2 +# define ET_DYN 3 +# define ET_CORE 4 +# define ET_LOPROC 0xFF00 +# define ET_HIPROC 0xFFFF -/* TODO */ +# define EM_NONE 0 +# define EM_M32 1 +# define EM_SPARC 2 +# define EM_386 3 +# define EM_68K 4 +# define EM_88K 5 +# define EM_860 7 +# define EM_MIPS 8 +# define EM_MIPS_RS4_BE 10 + +# define EV_NONE 0 +# define EV_CURRENT 1 + +# define ELFCLASSNONE 0 +# define ELFCLASS32 1 +# define ELFCLASS64 2 + +# define ELFDATANONE 0 +# define ELFDATA2LSB 1 +# define ELFDATA2MSB 2 + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +typedef struct { + uint8_t e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +# define SHN_UNDEF 0 +# define SHN_LORESERVE 0xFF00 +# define SHN_LOPROC 0xFF00 +# define SHN_HIPROC 0xFF1F +# define SHN_ABS 0xFFF1 +# define SHN_COMMON 0xFFF2 +# define SHN_HIRESERVE 0xFFFF + +# define SHT_NULL 0 +# define SHT_PROGBITS 1 +# define SHT_SYMTAB 2 +# define SHT_STRTAB 3 +# define SHT_RELA 4 +# define SHT_HASH 5 +# define SHT_DYNAMIC 6 +# define SHT_NOTE 7 +# define SHT_NOBITS 8 +# define SHT_REL 9 +# define SHT_SHLIB 10 +# define SHT_DYNSYM 11 +# define SHT_LOPROC 0x70000000 +# define SHT_HIPROC 0x7FFFFFFF +# define SHT_LOUSER 0x80000000 +# define SHT_HIUSER 0xFFFFFFFF + +# define SHF_WRITE 0x1 +# define SHF_ALLOC 0x2 +# define SHF_EXECINSTR 0x4 +# define SHF_MASKPROC 0xF0000000 + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +# define STN_UNDER 0 + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + uint8_t st_info; + uint8_t st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +# define ELF32_ST_BIND(x) ((x)>>4) +# define ELF32_ST_TYPE(x) ((x)&0xf) +# define ELF32_ST_INFO(b, t) (((b)<<4)+((t)&0xf)) + +# define STB_LOCAL 0 +# define STB_GLOBAL 1 +# define STB_WEAK 2 +# define STB_LOPROC 13 +# define STB_HIPROC 15 + +# define STT_NOTYPE 0 +# define STT_OBJECT 1 +# define STT_FUNC 2 +# define STT_SECTION 3 +# define STT_FILE 4 +# define STT_LOPROC 13 +# define STT_HIPROC 15 + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +# define ELF32_R_SYM(x) ((x)>>8) +# define ELF32_R_TYPE(x) ((uint8_t)(i)); +# define ELF32_R_INFO(s,t) (((s)<<8)+(uint8_t)(t)) + +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +# define PT_NULL 0 +# define PT_LOAD 1 +# define PT_DYNAMIC 2 +# define PT_INTERP 3 +# define PT_NOTE 4 +# define PT_SHLIB 5 +# define PT_PHDR 6 +# define PT_LOPROC 0x70000000 +# define PT_HIPROC 0x7FFFFFFF + +# define PF_X 0x1 +# define PF_W 0x2 +# define PF_R 0x4 +# define PF_MASKPROC 0xF0000000 #endif /* !ELF_H */ diff --git a/include/fas.h b/include/fas.h new file mode 100644 index 0000000..6081ddb --- /dev/null +++ b/include/fas.h @@ -0,0 +1,140 @@ +#ifndef FAS_H +# define FAS_H 1 + +# include + +# define FAS_MAGIC 0x1A736166 + +typedef struct fas_header +{ + uint32_t magic; + uint8_t ver_major; + uint8_t ver_minor; + uint16_t length; + uint32_t ifnm_off; + uint32_t ofnm_off; + uint32_t strtab_off; + uint32_t strtab_len; + uint32_t symtab_off; + uint32_t symtab_len; + uint32_t psrc_off; + uint32_t psrc_len; + uint32_t asmdmp_off; + uint32_t asmdmp_len; + uint32_t sectab_off; + uint32_t sectab_len; + uint32_t symref_off; + uint32_t symref_len; +} FAS_Hdr; + +# define FAS_SYM_DEF 0x001 +# define FAS_SYM_ASM_TIME 0x002 +# define FAS_SYM_NOT_FWD_REF 0x004 +# define FAS_SYM_USED 0x008 +# define FAS_SYM_PRD_USED 0x010 +# define FAS_SYM_LPRD_USED 0x020 +# define FAS_SYM_PRD_DEF 0x040 +# define FAS_SYM_LPRD_DEF 0x080 +# define FAS_SYM_OPT_ADJ 0x100 +# define FAS_SYM_TWO_CMPLMNT 0x200 +# define FAS_SYM_MARKER 0x400 + +enum fas_symbol_type +{ + FAS_ABS, + FAS_REL_SEG, + FAS_REL_32, + FAS_REL_R_32, + FAS_REL_64, + FAS_GOT_32, + FAS_PLT_32, + FAS_PLT_R_32 +}; + + +typedef struct fas_symbol +{ + uint64_t value; + uint16_t flags; + uint8_t size; + uint8_t type; + uint32_t ext_SIB; + uint16_t pass_ldef; + uint16_t pass_lused; + uint32_t reloc; + uint32_t name_off; + uint32_t psrc_line_off; +} FAS_Sym; + +struct fas_psrc_line +{ + uint32_t from; + uint32_t lineno; + uint32_t src_off; + uint32_t macro_off; + uint8_t tokens[]; +}; + +enum fas_code +{ + FAS_CODE_16 = 16, + FAS_CODE_32 = 32, + FAS_CODE_64 = 64 +}; + +struct fas_asmdmp +{ + uint32_t of_off; + uint32_t psrc_line_off; + uint64_t addr; + uint32_t ext_SIB; + uint32_t reloc; + uint8_t type; + uint8_t code; + uint8_t virt; + uint8_t high; +}; + +enum fas_register +{ + FAS_REG_BX = 0x23, + FAS_REG_BP = 0x25, + FAS_REG_SI = 0x26, + FAS_REG_DI = 0x27, + FAS_REG_EAX = 0x40, + FAS_REG_ECX = 0x41, + FAS_REG_EDX = 0x42, + FAS_REG_EBX = 0x43, + FAS_REG_ESP = 0x44, + FAS_REG_EBP = 0x45, + FAS_REG_ESI = 0x46, + FAS_REG_EDI = 0x47, + FAS_REG_R8D = 0x48, + FAS_REG_R9D = 0x49, + FAS_REG_R10D = 0x4A, + FAS_REG_R11D = 0x4B, + FAS_REG_R12D = 0x4C, + FAS_REG_R13D = 0x4D, + FAS_REG_R14D = 0x4E, + FAS_REG_R15D = 0x4F, + FAS_REG_RAX = 0x80, + FAS_REG_RCX = 0x81, + FAS_REG_RDX = 0x82, + FAS_REG_RBX = 0x83, + FAS_REG_RSP = 0x84, + FAS_REG_RBP = 0x85, + FAS_REG_RSI = 0x86, + FAS_REG_RDI = 0x87, + FAS_REG_R8 = 0x88, + FAS_REG_R9 = 0x89, + FAS_REG_R10 = 0x8A, + FAS_REG_R11 = 0x8B, + FAS_REG_R12 = 0x8C, + FAS_REG_R13 = 0x8D, + FAS_REG_R14 = 0x8E, + FAS_REG_R15 = 0x8F, + FAS_REG_EIP = 0x94, + FAS_REG_RIP = 0x98, +}; + +#endif /* !FAS_H */ diff --git a/tools/Makefile b/tools/Makefile index bd09f1e..80d8a39 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,4 +1,9 @@ -TARGET = ld$(EXEXT) parted$(EXEXT) readcoff$(EXEXT) elf2coff$(EXEXT) ar$(EXEXT) ranlib$(EXEXT) +TARGET = ld$(EXEXT) parted$(EXEXT) readcoff$(EXEXT) \ + elf2coff$(EXEXT) ar$(EXEXT) ranlib$(EXEXT) \ + fasdump$(EXEXT) fas2sym$(EXEXT) + +FAS2SYM_SRCS = main.c fas.c elf.c buffer.c +FAS2SYM_OBJS = $(addprefix ../bin/fas2sym/, $(FAS2SYM_SRCS:.c=.o)) .PHONY: all all: $(TARGET) @@ -21,6 +26,12 @@ ranlib$(EXEXT): ../bin/ranlib/main.c ../bin/ar/archive.c ar$(EXEXT): ../bin/ar/main.c $(TOOL_CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) +fasdump$(EXEXT): ../bin/fasdump/main.c + $(TOOL_CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) + +fas2sym$(EXEXT): $(FAS2SYM_OBJS) + $(TOOL_CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) + .PHONY: install install: $(TARGET)