Actually do a bunch of useful stuff

This commit is contained in:
Kevin Lange 2016-11-29 21:30:15 +09:00
parent 60b4c64604
commit 9602779808
2 changed files with 176 additions and 2 deletions

View File

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

174
linker.c
View File

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