diff options
-rw-r--r-- | 04_dynld_nostd/dynld.c | 78 | ||||
-rw-r--r-- | 04_dynld_nostd/libgreet.c | 10 | ||||
-rw-r--r-- | lib/include/elf.h | 64 |
3 files changed, 110 insertions, 42 deletions
diff --git a/04_dynld_nostd/dynld.c b/04_dynld_nostd/dynld.c index 56d48b7..a7b0fe1 100644 --- a/04_dynld_nostd/dynld.c +++ b/04_dynld_nostd/dynld.c @@ -205,6 +205,41 @@ const Elf64Rela* get_reloca(const Dso* dso, const uint64_t idx) { } +/// ----------- +/// Init & Fini +/// ----------- + +typedef void (*initfptr)(); + +static void init(const Dso* dso) { + if (dso->dynamic[DT_INIT]) { + initfptr* fn = (initfptr*)(dso->base + dso->dynamic[DT_INIT]); + (*fn)(); + } + + size_t nfns = dso->dynamic[DT_INIT_ARRAYSZ] / sizeof(initfptr); + initfptr* fns = (initfptr*)(dso->base + dso->dynamic[DT_INIT_ARRAY]); + while (nfns--) { + (*fns++)(); + } +} + +typedef void (*finifptr)(); + +static void fini(const Dso* dso) { + size_t nfns = dso->dynamic[DT_FINI_ARRAYSZ] / sizeof(finifptr); + finifptr* fns = (finifptr*)(dso->base + dso->dynamic[DT_FINI_ARRAY]) + nfns /* reverse destruction order */; + while (nfns--) { + (*--fns)(); + } + + if (dso->dynamic[DT_FINI]) { + finifptr* fn = (finifptr*)(dso->base + dso->dynamic[DT_FINI]); + (*fn)(); + } +} + + /// ------------- /// Symbol lookup /// ------------- @@ -226,12 +261,12 @@ int strcmp(const char* s1, const char* s2) { // // `dso` A handle to the dso which dynamic symbol table should be searched. // `sym_name` Name of the symbol to look up. -// `sym_type` Type of the symbol to look up (STT_OBJECT | STT_FUNC). -void* lookup_sym(const Dso* dso, const char* sym_name, unsigned sym_type) { +void* lookup_sym(const Dso* dso, const char* sym_name) { for (unsigned i = 0; i < get_num_dynsyms(dso); ++i) { const Elf64Sym* sym = get_sym(dso, i); - if (ELF64_ST_TYPE(sym->info) == sym_type && ELF64_ST_BIND(sym->info) == STB_GLOBAL && sym->shndx != SHN_UNDEF) { + if ((ELF64_ST_TYPE(sym->info) == STT_OBJECT || ELF64_ST_TYPE(sym->info) == STT_FUNC) && ELF64_ST_BIND(sym->info) == STB_GLOBAL && + sym->shndx != SHN_UNDEF) { if (strcmp(sym_name, get_str(dso, sym->name)) == 0) { return dso->base + sym->value; } @@ -367,7 +402,7 @@ typedef struct LinkMap LinkMap; // Resolve the relocation `reloc` by looking up the address of the symbol // referenced by the relocation. If the address of the symbol was found the // relocation is patched, if the address was not found the process exits. -static void resolve_reloc(const Dso* dso, const LinkMap* map, const Elf64Rela* reloc, unsigned symtype) { +static void resolve_reloc(const Dso* dso, const LinkMap* map, const Elf64Rela* reloc) { // Get symbol referenced by relocation. const int symidx = ELF64_R_SYM(reloc->info); const Elf64Sym* sym = get_sym(dso, symidx); @@ -376,20 +411,28 @@ static void resolve_reloc(const Dso* dso, const LinkMap* map, const Elf64Rela* r // Get relocation typy. unsigned reloctype = ELF64_R_TYPE(reloc->info); - // Lookup symbol address. + // Find symbol address. void* symaddr = 0; - // TODO: Explain special handling of R_X86_64_COPY. - for (const LinkMap* lmap = (reloctype == R_X86_64_COPY ? map->next : map); lmap && symaddr == 0; lmap = lmap->next) { - symaddr = lookup_sym(lmap->dso, symname, symtype); + // FIXME: Should relocations of type `R_X86_64_64` only be looked up in `dso` directly? + if (reloctype == R_X86_64_RELATIVE) { + // Symbols address is computed by re-basing the relative address based on the DSOs base address. + symaddr = (void*)(dso->base + reloc->addend); + } else { + // TODO: Explain special handling of R_X86_64_COPY. + for (const LinkMap* lmap = (reloctype == R_X86_64_COPY ? map->next : map); lmap && symaddr == 0; lmap = lmap->next) { + symaddr = lookup_sym(lmap->dso, symname); + } } ERROR_ON(symaddr == 0, "Failed lookup symbol %s while resolving relocations!", symname); - pfmt("Resolved reloc %s to %p (base %p)\n", symname, symaddr, dso->base); + pfmt("Resolved reloc %s to %p (base %p)\n", reloctype == R_X86_64_RELATIVE ? "<relative>" : symname, symaddr, dso->base); // Perform relocation according to relocation type. switch (reloctype) { case R_X86_64_GLOB_DAT: /* GOT entry for data objects. */ case R_X86_64_JUMP_SLOT: /* PLT entry. */ + case R_X86_64_64: /* 64bit relocation (non-lazy). */ + case R_X86_64_RELATIVE: /* DSO base relative relocation. */ // Patch storage unit of relocation with absolute address of the symbol. *(uint64_t*)(dso->base + reloc->offset) = (uint64_t)symaddr; break; @@ -412,14 +455,14 @@ static void resolve_relocs(const Dso* dso, const LinkMap* map) { // variables). for (unsigned long relocidx = 0; relocidx < (dso->dynamic[DT_RELASZ] / sizeof(Elf64Rela)); ++relocidx) { const Elf64Rela* reloc = get_reloca(dso, relocidx); - resolve_reloc(dso, map, reloc, STT_OBJECT); + resolve_reloc(dso, map, reloc); } // Resolve all relocation from the PLT jump table found in `dso`. There is // typically one relocation per undefined dynamic function symbol. for (unsigned long relocidx = 0; relocidx < (dso->dynamic[DT_PLTRELSZ] / sizeof(Elf64Rela)); ++relocidx) { const Elf64Rela* reloc = get_pltreloca(dso, relocidx); - resolve_reloc(dso, map, reloc, STT_FUNC); + resolve_reloc(dso, map, reloc); } } @@ -486,11 +529,15 @@ void dl_entry(const uint64_t* prctx) { // Resolve relocations of the library (dependency). resolve_relocs(&dso_lib, &map_prog); - // Resolve relocations of the main program. resolve_relocs(&dso_prog, &map_prog); - // Install dynamic resolve handler. + // Initialize library. + init(&dso_lib); + // Initialize main program. + init(&dso_prog); + + // Install dynamic resolve handler (lazy resolve). // // The dynamic resolve handler is used when binding symbols lazily. Hence // it should not be called in this example as we resolve all relocations @@ -517,5 +564,10 @@ void dl_entry(const uint64_t* prctx) { // Transfer control to user program. dso_prog.entry(); + // Finalize main program. + fini(&dso_prog); + // Finalize library. + fini(&dso_lib); + _exit(0); } diff --git a/04_dynld_nostd/libgreet.c b/04_dynld_nostd/libgreet.c index 439e236..e697690 100644 --- a/04_dynld_nostd/libgreet.c +++ b/04_dynld_nostd/libgreet.c @@ -1,5 +1,7 @@ // Copyright (c) 2020 Johannes Stoelp +#include <io.h> + int gCalled = 0; const char* get_greet() { @@ -11,3 +13,11 @@ const char* get_greet2() { ++gCalled; return "Hello 2 from libgreet.so!"; } + +__attribute__((constructor)) static void libinit() { /* static -> generates R_X86_64_RELATIVE relocation */ + pfmt("libgreet.so: libinit\n"); +} + +__attribute__((destructor)) void libfini() { /* non static -> generates R_X86_64_64 relocation */ + pfmt("libgreet.so: libfini\n"); +} diff --git a/lib/include/elf.h b/lib/include/elf.h index f0a0940..7a2e597 100644 --- a/lib/include/elf.h +++ b/lib/include/elf.h @@ -84,32 +84,36 @@ typedef struct { /// Dynamic Section /// --------------- -#define DT_NULL 0 /* [ignored] Marks end of dynamic section */ -#define DT_NEEDED 1 /* [val] Name of needed library */ -#define DT_PLTRELSZ 2 /* [val] Size in bytes of PLT relocs */ -#define DT_PLTGOT 3 /* [ptr] Processor defined value */ -#define DT_HASH 4 /* [ptr] Address of symbol hash table */ -#define DT_STRTAB 5 /* [ptr] Address of string table */ -#define DT_SYMTAB 6 /* [ptr] Address of symbol table */ -#define DT_RELA 7 /* [ptr] Address of Rela relocs */ -#define DT_RELASZ 8 /* [val] Total size of Rela relocs */ -#define DT_RELAENT 9 /* [val] Size of one Rela reloc */ -#define DT_STRSZ 10 /* [val] Size of string table */ -#define DT_SYMENT 11 /* [val] Size of one symbol table entry */ -#define DT_INIT 12 /* [ptr] Address of init function */ -#define DT_FINI 13 /* [ptr] Address of termination function */ -#define DT_SONAME 14 /* [val] Name of shared object */ -#define DT_RPATH 15 /* [val] Library search path (deprecated) */ -#define DT_SYMBOLIC 16 /* [ignored] Start symbol search here */ -#define DT_REL 17 /* [ptr] Address of Rel relocs */ -#define DT_RELSZ 18 /* [val] Total size of Rel relocs */ -#define DT_RELENT 19 /* [val] Size of one Rel reloc */ -#define DT_PLTREL 20 /* [val] Type of reloc in PLT */ -#define DT_DEBUG 21 /* [ptr] For debugging; unspecified */ -#define DT_TEXTREL 22 /* [ignored] Reloc might modify .text */ -#define DT_JMPREL 23 /* [ptr] Address of PLT relocs */ -#define DT_BIND_NOW 24 /* [ignored] Process relocations of object */ -#define DT_MAX_CNT 25 +#define DT_NULL 0 /* [ignored] Marks end of dynamic section */ +#define DT_NEEDED 1 /* [val] Name of needed library */ +#define DT_PLTRELSZ 2 /* [val] Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* [ptr] Processor defined value */ +#define DT_HASH 4 /* [ptr] Address of symbol hash table */ +#define DT_STRTAB 5 /* [ptr] Address of string table */ +#define DT_SYMTAB 6 /* [ptr] Address of symbol table */ +#define DT_RELA 7 /* [ptr] Address of Rela relocs */ +#define DT_RELASZ 8 /* [val] Total size of Rela relocs */ +#define DT_RELAENT 9 /* [val] Size of one Rela reloc */ +#define DT_STRSZ 10 /* [val] Size of string table */ +#define DT_SYMENT 11 /* [val] Size of one symbol table entry */ +#define DT_INIT 12 /* [ptr] Address of init function */ +#define DT_FINI 13 /* [ptr] Address of termination function */ +#define DT_SONAME 14 /* [val] Name of shared object */ +#define DT_RPATH 15 /* [val] Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* [ignored] Start symbol search here */ +#define DT_REL 17 /* [ptr] Address of Rel relocs */ +#define DT_RELSZ 18 /* [val] Total size of Rel relocs */ +#define DT_RELENT 19 /* [val] Size of one Rel reloc */ +#define DT_PLTREL 20 /* [val] Type of reloc in PLT */ +#define DT_DEBUG 21 /* [ptr] For debugging; unspecified */ +#define DT_TEXTREL 22 /* [ignored] Reloc might modify .text */ +#define DT_JMPREL 23 /* [ptr] Address of PLT relocs */ +#define DT_BIND_NOW 24 /* [ignored] Process relocations of object */ +#define DT_INIT_ARRAY 25 /* [ptr] Address of array of initialization functions */ +#define DT_FINI_ARRAY 26 /* [ptr] Address of array of termination functions */ +#define DT_INIT_ARRAYSZ 27 /* [val] Size in bytes of the initialization array */ +#define DT_FINI_ARRAYSZ 28 /* [val] Size in bytes of the termination array */ +#define DT_MAX_CNT 29 typedef struct { uint64_t tag; @@ -167,6 +171,8 @@ typedef struct { #define ELF64_R_TYPE(i) ((i)&0xffffffffL) // x86_64 relocation types. -#define R_X86_64_COPY 5 /* Copy content from sym addr to relocation address */ -#define R_X86_64_GLOB_DAT 6 /* Address affected by relocation: `offset` (+ base) */ -#define R_X86_64_JUMP_SLOT 7 /* Address affected by relocation: `offset` (+ base) */ +#define R_X86_64_64 1 /* Absolute 64bit address, address affected by relocation: `base + offset` */ +#define R_X86_64_COPY 5 /* Copy content from sym addr to relocation address: `base + offset` */ +#define R_X86_64_GLOB_DAT 6 /* Address affected by relocation: `base + offset` */ +#define R_X86_64_JUMP_SLOT 7 /* Address affected by relocation: `base + offset` */ +#define R_X86_64_RELATIVE 8 /* Relative address *`base + offset` = `base + addend` */ |