diff --git a/Makefile b/Makefile index 25b13678..6bef1b89 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ AR=i686-pc-toaru-ar all: ld.so libdemo.so demo ld.so: linker.c link.ld - i686-pc-toaru-gcc -std=c99 -o ld.so -Os -T link.ld linker.c + i686-pc-toaru-gcc -std=c99 -U__STRICT_ANSI__ -o ld.so -Os -T link.ld linker.c demo: demo.c i686-pc-toaru-gcc -o demo demo.c -L. -ldemo @@ -18,7 +18,7 @@ libc.so: # init and fini don't belong in our shared object ${AR} d libc.a lib_a-init.o ${AR} d libc.a lib_a-fini.o - # Kill reentrant make crap + # Remove references to newlib's reentrant malloc ${AR} d libc.a lib_a-calloc.o ${AR} d libc.a lib_a-callocr.o ${AR} d libc.a lib_a-cfreer.o diff --git a/linker.c b/linker.c index 19f7e1e3..12bc6bac 100644 --- a/linker.c +++ b/linker.c @@ -11,6 +11,9 @@ #include "../kernel/include/elf.h" #include "../userspace/lib/trace.h" +#include "../userspace/lib/list.c" +#include "../userspace/lib/hashmap.c" + typedef int (*entry_point_t)(int, char *[], char**); extern char end[]; @@ -20,6 +23,16 @@ struct elf_object { Elf32_Header header; }; + +struct reloc { + uintptr_t addr; + uintptr_t replacement; +}; + +int return_butts() { + return 1234; +} + int main(int argc, char * argv[]) { TRACE("Linker end address is %p", &end); TRACE("Linking main object: %s", argv[1]); @@ -64,6 +77,10 @@ int main(int argc, char * argv[]) { TRACE("program headers are 0x%x bytes", main.header.e_phentsize); TRACE("there are %d program headers", main.header.e_phnum); + char * string_table = NULL; + char * dyn_string_table = NULL; + Elf32_Sym * dyn_symbol_table = NULL; + uintptr_t latest_heap = (uintptr_t)sbrk(0); { @@ -131,6 +148,163 @@ int main(int argc, char * argv[]) { free(phdr); } + { + TRACE("Scanning for string table..."); + Elf32_Shdr * shdr = alloca(main.header.e_shentsize); + size_t i = 0; + for (uintptr_t x = 0 ; x < main.header.e_shentsize * main.header.e_shnum; x += main.header.e_shentsize) { + fseek(main.file, main.header.e_shoff + x, SEEK_SET); + fread(shdr, main.header.e_shentsize, 1, main.file); + if (shdr->sh_type == SHT_STRTAB) { + if (i == main.header.e_shstrndx) { + TRACE("Found section string table, copying somewhere safe."); + string_table = malloc(shdr->sh_size); + fseek(main.file, shdr->sh_offset, SEEK_SET); + fread(string_table, shdr->sh_size, 1, main.file); + } + } + i++; + } + } + + if (!string_table) { + TRACE("no section string table?"); + return 1; + } + + { + TRACE("Scanning for dynamic string table..."); + Elf32_Shdr * shdr = alloca(main.header.e_shentsize); + size_t i = 0; + for (uintptr_t x = 0 ; x < main.header.e_shentsize * main.header.e_shnum; x += main.header.e_shentsize) { + fseek(main.file, main.header.e_shoff + x, SEEK_SET); + fread(shdr, main.header.e_shentsize, 1, main.file); + if (shdr->sh_type == SHT_STRTAB) { + if (!strcmp((char *)((uintptr_t)string_table + shdr->sh_name), ".dynstr")) { + TRACE("Found symbol string table. It is loaded at 0x%x, storing that for later.", shdr->sh_addr); + dyn_string_table = (char *)shdr->sh_addr; + } + } + i++; + } + } + + { + TRACE("Scanning for dynamic symbol table..."); + Elf32_Shdr * shdr = alloca(main.header.e_shentsize); + size_t i = 0; + for (uintptr_t x = 0 ; x < main.header.e_shentsize * main.header.e_shnum; x += main.header.e_shentsize) { + fseek(main.file, main.header.e_shoff + x, SEEK_SET); + fread(shdr, main.header.e_shentsize, 1, main.file); + if (shdr->sh_type == 11) { /* TODO constant */ + if (!strcmp((char *)((uintptr_t)string_table + shdr->sh_name), ".dynsym")) { + TRACE("Found dynamic symbol table. It is loaded at 0x%x, storing that for later.", shdr->sh_addr); + Elf32_Sym * table = (Elf32_Sym *)(shdr->sh_addr); + dyn_symbol_table = table; + while ((uintptr_t)table - ((uintptr_t)shdr->sh_addr) < shdr->sh_size) { + TRACE("%s: 0x%x [0x%x]", (char *)((uintptr_t)dyn_string_table + table->st_name), table->st_value, table->st_size); + table++; + } + } + } + i++; + } + } + + if (!dyn_symbol_table) { + TRACE("WARNING: No dynamic symbol table found?"); + } + + list_t * stuff_to_load = list_create(); + + { + TRACE("Scanning for dynamic section..."); + Elf32_Shdr * shdr = alloca(main.header.e_shentsize); + size_t i = 0; + for (uintptr_t x = 0 ; x < main.header.e_shentsize * main.header.e_shnum; x += main.header.e_shentsize) { + fseek(main.file, main.header.e_shoff + x, SEEK_SET); + fread(shdr, main.header.e_shentsize, 1, main.file); + if (shdr->sh_type == 6) { /* TODO constant */ + TRACE("Found dynamic section. Loaded at 0x%x.", shdr->sh_addr); + Elf32_Dyn * table = (Elf32_Dyn *)(shdr->sh_addr); + while ((uintptr_t)table - ((uintptr_t)shdr->sh_addr) < shdr->sh_size) { + if (!table->d_tag) break; + switch (table->d_tag) { + case 1: + TRACE("NEEDED - %s", dyn_string_table + table->d_un.d_val); + list_insert(stuff_to_load, dyn_string_table + table->d_un.d_val); + break; + case 5: + TRACE("STRTAB - 0x%x", table->d_un.d_ptr); + break; + case 6: + TRACE("STRTAB - 0x%x", table->d_un.d_ptr); + break; + case 12: + TRACE("INIT - 0x%x", table->d_un.d_ptr); + break; + case 13: + TRACE("INIT - 0x%x", table->d_un.d_ptr); + break; + default: + TRACE("%d - 0x%x", table->d_tag, table->d_un); + } + table++; + } + } + i++; + } + } + + { + TRACE("Need to load:"); + foreach(item, stuff_to_load) { + TRACE(" - %s", item->value); + } + } + + { + TRACE("Searching for REL sections to resolve."); + Elf32_Shdr * shdr = alloca(main.header.e_shentsize); + size_t i = 0; + for (uintptr_t x = 0 ; x < main.header.e_shentsize * main.header.e_shnum; x += main.header.e_shentsize) { + fseek(main.file, main.header.e_shoff + x, SEEK_SET); + fread(shdr, main.header.e_shentsize, 1, main.file); + if (shdr->sh_type == 9) { /* TODO constant */ + Elf32_Rel * table = (Elf32_Rel *)(shdr->sh_addr); + while ((uintptr_t)table - ((uintptr_t)shdr->sh_addr) < shdr->sh_size) { + unsigned int symbol = ELF32_R_SYM(table->r_info); + unsigned char type = ELF32_R_TYPE(table->r_info); + Elf32_Sym * sym = &dyn_symbol_table[symbol]; + TRACE("offset[0x%x] = %d %d (%s)", table->r_offset, symbol, type, dyn_string_table + sym->st_name); + if (type == 6) { + /* blob dat, memcpy size of symbol */ + memcpy((void *)table->r_offset, &sym->st_value, sizeof(uintptr_t)); + } else if (type == 7) { + if (!strcmp(dyn_string_table + sym->st_name, "return_42") ) { + /* lol */ + uintptr_t x = (uintptr_t)&return_butts; + memcpy((void *)table->r_offset, &x, sizeof(x)); + } + } + table++; + } + } + i++; + } + } + + { + TRACE("Examining all section headers..."); + Elf32_Shdr * shdr = alloca(main.header.e_shentsize); + for (uintptr_t x = 0 ; x < main.header.e_shentsize * main.header.e_shnum; x += main.header.e_shentsize) { + fseek(main.file, main.header.e_shoff + x, SEEK_SET); + fread(shdr, main.header.e_shentsize, 1, main.file); + + TRACE("[%d] %s at offset 0x%x of size 0x%x", shdr->sh_type, (char *)((uintptr_t)string_table + shdr->sh_name), shdr->sh_offset, shdr->sh_size); + } + } + /* Place the heap at the end */ { TRACE("Returning heap to 0x%x", latest_heap);