From 36e01b720e64b15eb698cc766153cff32456325c Mon Sep 17 00:00:00 2001 From: Sebastian Sumpf Date: Tue, 10 Mar 2015 11:16:03 +0100 Subject: [PATCH] ldso: Refactor dynamic linker Issue #1349 --- repos/base/lib/mk/ldso.inc | 3 +- repos/base/src/lib/ldso/arm/relocation.h | 24 +- repos/base/src/lib/ldso/debug.cc | 19 + repos/base/src/lib/ldso/dependency.cc | 81 ++ repos/base/src/lib/ldso/exception.cc | 116 +++ repos/base/src/lib/ldso/include/debug.h | 126 +++ repos/base/src/lib/ldso/include/dynamic.h | 222 ++++ repos/base/src/lib/ldso/include/file.h | 75 ++ repos/base/src/lib/ldso/include/init.h | 110 ++ repos/base/src/lib/ldso/include/linker.h | 220 ++-- .../src/lib/ldso/include/relocation_generic.h | 39 +- repos/base/src/lib/ldso/include/trace.h | 38 - repos/base/src/lib/ldso/include/util.h | 44 + repos/base/src/lib/ldso/main.cc | 985 +++--------------- repos/base/src/lib/ldso/shared_object.cc | 121 +++ repos/base/src/lib/ldso/x86_32/relocation.h | 22 +- repos/base/src/lib/ldso/x86_64/relocation.h | 20 +- 17 files changed, 1266 insertions(+), 999 deletions(-) create mode 100644 repos/base/src/lib/ldso/debug.cc create mode 100644 repos/base/src/lib/ldso/dependency.cc create mode 100644 repos/base/src/lib/ldso/exception.cc create mode 100644 repos/base/src/lib/ldso/include/debug.h create mode 100644 repos/base/src/lib/ldso/include/dynamic.h create mode 100644 repos/base/src/lib/ldso/include/file.h create mode 100644 repos/base/src/lib/ldso/include/init.h delete mode 100644 repos/base/src/lib/ldso/include/trace.h create mode 100644 repos/base/src/lib/ldso/include/util.h create mode 100644 repos/base/src/lib/ldso/shared_object.cc diff --git a/repos/base/lib/mk/ldso.inc b/repos/base/lib/mk/ldso.inc index ab0c2fa9a..0c37b504e 100644 --- a/repos/base/lib/mk/ldso.inc +++ b/repos/base/lib/mk/ldso.inc @@ -4,7 +4,8 @@ DIR = $(REP_DIR)/src/lib/ldso include $(BASE_DIR)/mk/base-libs.mk LIBS = $(BASE_LIBS) -SRC_CC = main.cc test.cc file.cc +SRC_CC = main.cc test.cc exception.cc file.cc dependency.cc debug.cc \ + shared_object.cc SRC_S = jmp_slot.s INC_DIR += $(DIR)/include LD_OPT += -Bsymbolic-functions --version-script=$(DIR)/symbol.map diff --git a/repos/base/src/lib/ldso/arm/relocation.h b/repos/base/src/lib/ldso/arm/relocation.h index fba36fb42..8f7a05c20 100644 --- a/repos/base/src/lib/ldso/arm/relocation.h +++ b/repos/base/src/lib/ldso/arm/relocation.h @@ -43,12 +43,11 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic Elf::Addr reloc_base; Elf::Sym const *sym; - if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base))) + if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base))) return; /* S + A - P */ *addr = reloc_base + sym->st_value - (Elf::Addr)addr + *addr; - trace("REL32", (unsigned long)addr, *addr, 0); } void _glob_dat(Elf::Rel const *rel, Elf::Addr *addr, bool no_addend) @@ -56,14 +55,13 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic Elf::Addr reloc_base; Elf::Sym const *sym; - if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base))) + if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base))) return; Elf::Addr addend = no_addend ? 0 : *addr; /* S + A */ *addr = addend + reloc_base + sym->st_value; - trace("GLOB_DAT", (unsigned long)addr, *addr, 0); } void _relative(Elf::Addr *addr) @@ -73,25 +71,26 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic * relocations within its text-segment (e.g., 'initial_sp' and friends), which * we cannot write to from here). */ - if (_dag->obj->reloc_base()) - *addr += _dag->obj->reloc_base(); + if (_dep->obj->reloc_base()) + *addr += _dep->obj->reloc_base(); } public: - Reloc_non_plt(Dag const *dag, Elf::Rela const *, unsigned long) - : Reloc_non_plt_generic(dag) + Reloc_non_plt(Dependency const *dep, Elf::Rela const *, unsigned long) + : Reloc_non_plt_generic(dep) { PERR("LD: DT_RELA not supported"); throw Incompatible(); } - Reloc_non_plt(Dag const *dag, Elf::Rel const *rel, unsigned long size, bool second_pass) - : Reloc_non_plt_generic(dag) + Reloc_non_plt(Dependency const *dep, Elf::Rel const *rel, unsigned long size, + bool second_pass) + : Reloc_non_plt_generic(dep) { Elf::Rel const *end = rel + (size / sizeof(Elf::Rel)); for (; rel < end; rel++) { - Elf::Addr *addr = (Elf::Addr *)(_dag->obj->reloc_base() + rel->offset); + Elf::Addr *addr = (Elf::Addr *)(_dep->obj->reloc_base() + rel->offset); if (second_pass && rel->type() != R_GLOB_DAT) continue; @@ -104,8 +103,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic case R_GLOB_DAT: _glob_dat(rel, addr, second_pass); break; case R_RELATIVE: _relative(addr); break; default: - trace("UNKREL", rel->type(), 0, 0); - if (_dag->root) { + if (_dep->root) { PWRN("LD: Unkown relocation %u", rel->type()); throw Incompatible(); } diff --git a/repos/base/src/lib/ldso/debug.cc b/repos/base/src/lib/ldso/debug.cc new file mode 100644 index 000000000..4f1e00448 --- /dev/null +++ b/repos/base/src/lib/ldso/debug.cc @@ -0,0 +1,19 @@ +/** + * \brief GDB debugging support + * \author Sebastian Sumpf + * \date 2015-03-12 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include + +/** + * C-break function for GDB + */ +extern "C" void brk(Linker::Debug *, Linker::Link_map *) { } diff --git a/repos/base/src/lib/ldso/dependency.cc b/repos/base/src/lib/ldso/dependency.cc new file mode 100644 index 000000000..40be09afd --- /dev/null +++ b/repos/base/src/lib/ldso/dependency.cc @@ -0,0 +1,81 @@ +/** + * \brief Manage object dependencies + * \author Sebastian Sumpf + * \date 2015-03-12 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include +#include +#include + + +/** + * Dependency node + */ +Linker::Dependency::Dependency(char const *path, Root_object *root, + Genode::Fifo * const dep, + unsigned flags) + : obj(load(path, this, flags)), root(root) +{ + dep->enqueue(this); + load_needed(dep, flags); +} + + +Linker::Dependency::~Dependency() +{ + if (obj->unload()) { + + if (verbose_loading) + PDBG("Destroy: %s\n", obj->name()); + + destroy(Genode::env()->heap(), obj); + } +} + + +bool Linker::Dependency::in_dep(char const *file, + Genode::Fifo * const dep) +{ + for (Dependency *d = dep->head(); d; d = d->next()) + if (!Genode::strcmp(file, d->obj->name())) + return true; + + return false; +} + + +void Linker::Dependency::load_needed(Genode::Fifo * const dep, + unsigned flags) +{ + for (Dynamic::Needed *n = obj->dynamic()->needed.head(); n; n = n->next()) { + char const *path = n->path(obj->dynamic()->strtab); + + Object *o; + if (!in_dep(Linker::file(path), dep)) + new (Genode::env()->heap()) Dependency(path, root, dep, flags); + + /* re-order initializer list, if needed object has been already added */ + else if ((o = Init::list()->contains(Linker::file(path)))) + Init::list()->reorder(o); + } +} + + +Linker::Root_object::Root_object(char const *path, unsigned flags) +{ + new (Genode::env()->heap()) Dependency(path, this, &dep, flags); + + /* provide Genode base library access */ + new (Genode::env()->heap()) Dependency(linker_name(), this, &dep);; + + /* relocate and call constructors */ + Init::list()->initialize(); +} diff --git a/repos/base/src/lib/ldso/exception.cc b/repos/base/src/lib/ldso/exception.cc new file mode 100644 index 000000000..8cb88dc29 --- /dev/null +++ b/repos/base/src/lib/ldso/exception.cc @@ -0,0 +1,116 @@ +/** + * \brief GCC excption handling support + * \author Sebastian Sumpf + * \date 2015-03-12 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include + + +using namespace Linker; + +/********* + ** x86 ** + *********/ + +/** + * "Walk through shared objects" support, see man page of 'dl_iterate_phdr' + */ +struct Phdr_info +{ + Elf::Addr addr; /* module relocation base */ + char const *name; /* module name */ + Elf::Phdr const *phdr; /* pointer to module's phdr */ + Elf::Half phnum; /* number of entries in phdr */ +}; + + +extern "C" int dl_iterate_phdr(int (*callback) (Phdr_info *info, Genode::size_t size, void *data), void *data) +{ + int err = 0; + Phdr_info info; + + Genode::Lock::Guard guard(Object::lock()); + + for (Object *e = obj_list_head();e; e = e->next_obj()) { + + info.addr = e->reloc_base(); + info.name = e->name(); + info.phdr = e->file()->phdr.phdr; + info.phnum = e->file()->phdr.count; + + if (verbose_exception) + PDBG("%s reloc " EFMT, e->name(), e->reloc_base()); + + if ((err = callback(&info, sizeof(Phdr_info), data))) + break; + } + + return err; +} + + +/********* + ** ARM ** + *********/ + +/** + * Return EXIDX program header + */ +static Elf::Phdr const *phdr_exidx(File const *file) +{ + for (unsigned i = 0; i < file->elf_phdr_count(); i++) { + Elf::Phdr const *ph = file->elf_phdr(i); + + if (ph->p_type == PT_ARM_EXIDX) + return ph; + } + + return 0; +} + + +/** + * Find ELF and exceptions table segment that that is located under 'pc', + * address of exception table and number of entries 'pcount' + */ +extern "C" unsigned long dl_unwind_find_exidx(unsigned long pc, int *pcount) +{ + /* size of exception table entries */ + enum { EXIDX_ENTRY_SIZE = 8 }; + *pcount = 0; + + /* + * Since this function may be called before the main function, load linker's + * program header now + */ + load_linker_phdr(); + + for (Object *e = obj_list_head(); e; e = e->next_obj()) + { + /* address of first PT_LOAD header */ + Genode::addr_t base = e->reloc_base() + e->file()->start; + + /* is the 'pc' somewhere within this ELF image */ + if ((pc < base) || (pc >= base + e->file()->size)) + continue; + + /* retrieve PHDR of exception-table segment */ + Elf::Phdr const *exidx = phdr_exidx(e->file()); + if (!exidx) + continue; + + *pcount = exidx->p_memsz / EXIDX_ENTRY_SIZE; + return exidx->p_vaddr + e->reloc_base(); + } + + return 0; +} + diff --git a/repos/base/src/lib/ldso/include/debug.h b/repos/base/src/lib/ldso/include/debug.h new file mode 100644 index 000000000..c6cbe8e57 --- /dev/null +++ b/repos/base/src/lib/ldso/include/debug.h @@ -0,0 +1,126 @@ +/** + * \brief Debugger support + * \author Sebastian Sumpf + * \date 2015-03-10 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__DEBUG_H_ +#define _INCLUDE__DEBUG_H_ + +#include +#include + +constexpr bool verbose_link_map = false; + +namespace Linker { + struct Debug; + struct Link_map; +} + +/** + * LIBC debug support + */ +extern "C" void brk(Linker::Debug *, Linker::Link_map *); + +struct Linker::Debug +{ + /* + * This state value describes the mapping change taking place when + * the brk address is called. + */ + enum State { + CONSISTENT, /* mapping change is complete */ + ADD, /* beginning to add a new object */ + DELETE /* beginning to remove an object mapping */ + }; + + Debug() : Brk(brk) { } + + int version = 1; /* unused */ + struct Link_map *map = nullptr;; /* start of link map */ + + /* + * This is the address of a function internal to the run-time linker, that + * will always be called when the linker begins to map in a library or unmap + * it, and again when the mapping change is complete. The debugger can set a + * breakpoint at this address if it wants to notice shared object mapping + * changes. + */ + void (*Brk)(Debug *, Link_map *); + State state = CONSISTENT; + + static void state_change(State s, Link_map *m) + { + d()->state = s; + d()->Brk(d(), m); + } + + static Debug *d() + { + static Debug _d; + return &_d; + } +}; + + +/** + * Link map + */ +struct Linker::Link_map +{ + Elf::Addr addr; /* base address of library */ + char const *path; /* path */ + void const *dynamic; /* DYNAMIC section */ + + Link_map *next = nullptr; + Link_map *prev = nullptr; + + static Link_map *first; + + static void add(Link_map *map) + { + map->next = nullptr;; + if (!first) { + first = map; + Debug::d()->map = map; + return; + } + + Link_map *m; + for (m = first; m->next; m = m->next) ; + + m->next = map; + map->prev = m; + } + + static void remove(Link_map *map) + { + if (map->prev) + map->prev->next = map->next; + + if (map->next) + map->next->prev = map->prev; + + if (map == first) + first = map->next; + } + + static void dump() + { + if (!verbose_link_map) + return; + + for (Link_map *m = first; m; m = m->next) + PINF("MAP: addr: " EFMT " dynamic: %p %s m: %p p: %p n: %p", + m->addr, m->dynamic, m->path, m, m->prev, m->next); + } +}; + +#endif /* _INCLUDE__DEBUG_H_ */ diff --git a/repos/base/src/lib/ldso/include/dynamic.h b/repos/base/src/lib/ldso/include/dynamic.h new file mode 100644 index 000000000..d11576fdb --- /dev/null +++ b/repos/base/src/lib/ldso/include/dynamic.h @@ -0,0 +1,222 @@ +/** + * \brief ELF-dynamic section (see ELF ABI) + * \author Sebastian Sumpf + * \date 2015-03-12 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__DYNAMIC_H_ +#define _INCLUDE__DYNAMIC_H_ + +#include + +namespace Linker { + struct Hash_table; + struct Dynamic; +} + + /** + * Offset of dynamic section of this ELF. This is filled out during linkage by + * static linker. + */ + extern Genode::addr_t _DYNAMIC; + + +/** + * ELF hash table and hash function + */ +struct Linker::Hash_table +{ + unsigned long nbuckets() const { return *((Elf::Hashelt *)this); } + unsigned long nchains() const { return *(((Elf::Hashelt *)this) + 1); } + + Elf::Hashelt const *buckets() { return ((Elf::Hashelt *)this + 2); } + Elf::Hashelt const *chains() { return buckets() + nbuckets(); } + + /** + * ELF hash function Figure 5.12 of the 'System V ABI' + */ + static unsigned long hash(char const *name) + { + unsigned const char *p = (unsigned char const *)name; + unsigned long h = 0, g; + + while (*p) { + h = (h << 4) + *p++; + if ((g = h & 0xf0000000) != 0) + h ^= g >> 24; + h &= ~g; + } + return h; + } +}; + + +/** + * .dynamic section entries + */ +struct Linker::Dynamic +{ + struct Needed : Genode::Fifo::Element + { + Genode::off_t offset; + + Needed(Genode::off_t offset) : offset(offset) { } + + char const *path(char const *strtab) + { + return ((char const *)(strtab + offset)); + } + + char const *name(char const *strtab) + { + return file(path(strtab)); + } + }; + + Dependency const *dep; + Object const *obj; + Elf::Dyn const *dynamic; + + Hash_table *hash_table = nullptr; + + Elf::Rela *reloca = nullptr; + unsigned long reloca_size = 0; + + Elf::Sym *symtab = nullptr; + char *strtab = nullptr; + unsigned long strtab_size = 0; + + Elf::Addr *pltgot = nullptr; + + Elf::Rel *pltrel = nullptr; + unsigned long pltrel_size = 0; + D_tag pltrel_type = DT_NULL; + + Func init_function = nullptr; + + Elf::Rel *rel = nullptr; + unsigned long rel_size = 0; + + Genode::Fifo needed; + + Dynamic(Dependency const *dep) + : + dep(dep), obj(dep->obj), dynamic((Elf::Dyn *)(obj->reloc_base() + &_DYNAMIC)) + { + init(); + } + + Dynamic(Dependency const *dep, Object const *obj, Linker::Phdr const *phdr) + : + dep(dep), obj(obj), dynamic(find_dynamic(phdr)) + { + init(); + } + + ~Dynamic() + { + Needed *n; + while ((n = needed.dequeue())) + destroy(Genode::env()->heap(), n); + } + + Elf::Dyn const *find_dynamic(Linker::Phdr const *p) + { + for (unsigned i = 0; i < p->count; i++) + if (p->phdr[i].p_type == PT_DYNAMIC) + return reinterpret_cast(p->phdr[i].p_vaddr + obj->reloc_base()); + + return 0; + } + + void section_dt_needed(Elf::Dyn const *d) + { + Needed *n = new(Genode::env()->heap()) Needed(d->un.ptr); + needed.enqueue(n); + } + + template + void section(T *member, Elf::Dyn const *d) + { + *member = (T)(obj->reloc_base() + d->un.ptr); + } + + void section_dt_debug(Elf::Dyn const *d) + { + Elf::Dyn *_d = const_cast(d); + _d->un.ptr = (Elf::Addr)Debug::d(); + } + + void init() + { + for (Elf::Dyn const *d = dynamic; d->tag != DT_NULL; d++) { + switch (d->tag) { + + case DT_NEEDED : section_dt_needed(d); break; + case DT_PLTRELSZ: pltrel_size = d->un.val; break; + case DT_PLTGOT : section(&pltgot, d); break; + case DT_HASH : section(&hash_table, d); break; + case DT_RELA : section(&reloca, d); break; + case DT_RELASZ : reloca_size = d->un.val; break; + case DT_SYMTAB : section(&symtab, d); break; + case DT_STRTAB : section(&strtab, d); break; + case DT_STRSZ : strtab_size = d->un.val; break; + case DT_INIT : section(&init_function, d); break; + case DT_PLTREL : pltrel_type = (D_tag)d->un.val; break; + case DT_JMPREL : section(&pltrel, d); break; + case DT_REL : section(&rel, d); break; + case DT_RELSZ : rel_size = d->un.val; break; + case DT_DEBUG : section_dt_debug(d); break; + default: + break; + } + } + } + + void relocate() + { + plt_setup(); + + if (pltrel_size) { + switch (pltrel_type) { + + case DT_RELA: + case DT_REL: + Reloc_plt(obj, pltrel_type, pltrel, pltrel_size); + break; + default: + PERR("LD: Invalid PLT relocation %u", pltrel_type); + throw Incompatible(); + } + } + + relocate_non_plt(); + } + + void plt_setup() + { + if (pltgot) + Plt_got r(dep, pltgot); + } + + void relocate_non_plt(bool second_pass = false) + { + if (reloca) + Reloc_non_plt r(dep, reloca, reloca_size); + + if (rel) + Reloc_non_plt r(dep, rel, rel_size, second_pass); + + if (bind_now) + Reloc_bind_now r(dep, pltrel, pltrel_size); + } +}; + +#endif /* _INCLUDE__DYNAMIC_H_ */ diff --git a/repos/base/src/lib/ldso/include/file.h b/repos/base/src/lib/ldso/include/file.h new file mode 100644 index 000000000..4994ecb47 --- /dev/null +++ b/repos/base/src/lib/ldso/include/file.h @@ -0,0 +1,75 @@ +/** + * \brief ELF file setup + * \author Sebastian Sumpf + * \date 2015-03-12 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__FILE_H_ +#define _INCLUDE__FILE_H_ + +namespace Linker { + struct Phdr; + struct File; + + /** + * Load object + * + * \param path Path of object + * \param load True, load binary; False, load ELF header only + * + * \throw Invalid_file Segment is neither read-only/executable or read/write + * \throw Region_conflict There is already something at the given address + * \throw Incompatible Not an ELF + * + * \return File descriptor + */ + File const *load(char const *path, bool load = true); +} + + +/** + * Program header + */ +struct Linker::Phdr +{ + enum { MAX_PHDR = 10 }; + + Elf::Phdr phdr[MAX_PHDR]; + unsigned count = 0; +}; + + +/** + * Loaded ELF file + */ +struct Linker::File +{ + typedef void (*Entry)(void); + + Phdr phdr; + Entry entry; + Elf::Addr reloc_base = 0; + Elf::Addr start = 0; + Elf::Size size = 0; + + virtual ~File() { } + + Elf::Phdr const *elf_phdr(unsigned index) const + { + if (index < phdr.count) + return &phdr.phdr[index]; + + return 0; + } + + unsigned elf_phdr_count() const { return phdr.count; } +}; + +#endif /* _INCLUDE__FILE_H_ */ diff --git a/repos/base/src/lib/ldso/include/init.h b/repos/base/src/lib/ldso/include/init.h new file mode 100644 index 000000000..267ae0b64 --- /dev/null +++ b/repos/base/src/lib/ldso/include/init.h @@ -0,0 +1,110 @@ +/** + * \brief Initialization list (calls ctors) + * \author Sebastian Sumpf + * \date 2015-03-12 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__INIT_H_ +#define _INCLUDE__INIT_H_ + +#include + + +namespace Linker { + struct Init; +} + + +/** + * Handle static construction and relocation of ELF files + */ +struct Linker::Init : Genode::List +{ + bool in_progress = false; + bool restart = false; + + static Init *list() + { + static Init _list; + return &_list; + } + + Object *contains(char const *file) + { + for (Object *elf = first(); elf; elf = elf->next_init()) + if (!Genode::strcmp(file, elf->name())) + return elf; + + return nullptr; + } + + void reorder(Object *elf) + { + /* put in front of initializer list */ + remove(elf); + insert(elf); + + /* re-order dependencies */ + for (Dynamic::Needed *n = elf->dynamic()->needed.head(); n; n = n->next()) { + char const *path = n->path(elf->dynamic()->strtab); + Object *e; + + if ((e = contains(Linker::file(path)))) + reorder(e); + } + } + + void initialize() + { + Object *obj = first(); + + /* relocate */ + for (; obj; obj = obj->next_init()) { + if (verbose_relocation) + PDBG("Relocate %s", obj->name()); + obj->relocate(); + } + + /* + * Recursive initialization call is not allowed here. This might happend + * when Shared_objects (e.g. dlopen and friends) are constructed from within + * global constructors (ctors). + */ + if (in_progress) { + restart = true; + return; + } + + in_progress = true; + + /* call static constructors */ + obj = first(); + while (obj) { + + Object *next = obj->next_init(); + remove(obj); + + if (obj->dynamic()->init_function) { + + if (verbose_relocation) + PDBG("%s init func %p", obj->name(), obj->dynamic()->init_function); + + obj->dynamic()->init_function(); + } + + obj = restart ? first() : next; + restart = false; + } + + in_progress = false; + } +}; + +#endif /* _INCLUDE__INIT_H_ */ diff --git a/repos/base/src/lib/ldso/include/linker.h b/repos/base/src/lib/ldso/include/linker.h index bf378e076..ccc6c4b9a 100644 --- a/repos/base/src/lib/ldso/include/linker.h +++ b/repos/base/src/lib/ldso/include/linker.h @@ -16,18 +16,20 @@ #include #include +#include #include #include #include + +#include #include -#include +#include +#include /** * Debugging */ constexpr bool verbose_lookup = false; -constexpr bool verbose_link_map = false; -constexpr bool verbose_relocation = false; constexpr bool verbose_exception = false; constexpr bool verbose_shared = false; constexpr bool verbose_loading = false; @@ -35,20 +37,25 @@ constexpr bool verbose_loading = false; /** * Forward declartions and helpers */ -namespace Linker -{ +namespace Linker { class Object; - struct Phdr; - struct File; struct Root_object; - struct Dag; + struct Dependency; struct Elf_object; + struct Dynamic; + + typedef void (*Func)(void); + + /** + * Eager binding enable + */ + extern bool bind_now; /** * Find symbol via index * * \param sym_index Symbol index within object - * \param dag Directed acyclic graph of object + * \param dep Dependency of object * \param base Returned address of symbol * \param undef True, return undefined symbol; False return defined * symbols only @@ -59,15 +66,14 @@ namespace Linker * * \return Symbol information */ - Elf::Sym const *locate_symbol(unsigned sym_index, Dag const *, Elf::Addr *base, + Elf::Sym const *lookup_symbol(unsigned sym_index, Dependency const *, Elf::Addr *base, bool undef = false, bool other = false); - /** * Find symbol via name * * \param name Symbol name - * \param dag Directed acyclic graph of object + * \param dep Dependency of object * \param base Returned address of symbol * \param undef True, return undefined symbol; False return defined * symbols only @@ -78,22 +84,35 @@ namespace Linker * * \return Symbol information */ - Elf::Sym const *search_symbol(char const *name, Dag const *dag, Elf::Addr *base, + Elf::Sym const *lookup_symbol(char const *name, Dependency const *dep, Elf::Addr *base, bool undef = false, bool other = false); /** - * Load object + * Load an ELF (setup segments and map program header) * - * \param path Path of object - * \param load True, load binary; False, load ELF header only - * - * \throw Invalid_file Segment is neither read-only/executable or read/write - * \throw Region_conflict There is already something at the given address - * \throw Incompatible Not an ELF + * \param path File to load + * \param dep Dependency entry for new object + * \param flags 'Genode::Shared_object::KEEP' will not unload the ELF, if the + * reference count reaches zero * - * \return File descriptor + * \return Linker::Object */ - File const *load(char const *path, bool load = true); + Object *load(char const *path, Dependency *dep, unsigned flags = 0); + + /** + * Returns the head of the global object list + */ + Object *obj_list_head(); + + /** + * Returns the root-dependeny of the dynamic binary + */ + Dependency *binary_root_dep(); + + /** + * Force to map the program header of the dynamic linker + */ + void load_linker_phdr(); /** * Exceptions @@ -102,30 +121,6 @@ namespace Linker class Invalid_file : Genode::Exception { }; class Not_found : Genode::Exception { }; - /** - * Page handling - */ - template - static inline T trunc_page(T addr) { - return addr & Genode::_align_mask((T)12); } - - template - static inline T round_page(T addr) { - return Genode::align_addr(addr, (T)12); } - - /** - * Extract file name from path - */ - inline char const *file(char const *path) - { - /* strip directories */ - char const *f, *r = path; - for (f = r; *f; f++) - if (*f == '/') - r = f + 1; - return r; - } - /** * Invariants */ @@ -134,41 +129,11 @@ namespace Linker } -struct Linker::Phdr -{ - enum { MAX_PHDR = 10 }; - - Elf::Phdr phdr[MAX_PHDR]; - unsigned count = 0; -}; - - -struct Linker::File -{ - typedef void (*Entry)(void); - - Phdr phdr; - Entry entry; - Elf::Addr reloc_base = 0; - Elf::Addr start = 0; - Elf::Size size = 0; - - virtual ~File() { } - - Elf::Phdr const *elf_phdr(unsigned index) const - { - if (index < phdr.count) - return &phdr.phdr[index]; - - return 0; - } - - unsigned elf_phdr_count() const { return phdr.count; } - -}; - - -class Linker::Object : public Genode::Fifo::Element +/** + * Shared object or binary + */ +class Linker::Object : public Genode::Fifo::Element, + public Genode::List::Element { protected: @@ -195,36 +160,103 @@ class Linker::Object : public Genode::Fifo::Element Elf::Addr reloc_base() const { return _file ? _file->reloc_base : 0; } char const *name() const { return _name; } - File const *file() { return _file; } + File const *file() { return _file; } + Elf::Size const size() const { return _file ? _file->size : 0; } virtual bool is_linker() const = 0; virtual bool is_binary() const = 0; - Elf::Size const size() const { return _file ? _file->size : 0; } + virtual void relocate() = 0; + + virtual void load() = 0; + virtual bool unload() { return false;} + + /** + * Next object in global object list + */ + virtual Object *next_obj() const = 0; + + /** + * Next object in initialization list + */ + virtual Object *next_init() const = 0; + + /** + * Return dynamic section of ELF + */ + virtual Dynamic *dynamic() = 0; + + /** + * Return link map for ELF + */ + virtual Link_map *link_map() = 0; + + /** + * Return address info for symboal at addr + */ + virtual void info(Genode::addr_t addr, Genode::Address_info &info) = 0; + + /** + * Global ELF access lock + */ + static Genode::Lock & lock() + { + static Genode::Lock _lock; + return _lock; + } }; -struct Linker::Dag : Genode::Fifo::Element +/** + * Dependency of object + */ +struct Linker::Dependency : Genode::Fifo::Element { - Object *obj = nullptr; + Object *obj = nullptr; Root_object *root = nullptr; - Dag(Object *obj, Root_object *root) : obj(obj), root(root) { } + Dependency(Object *obj, Root_object *root) : obj(obj), root(root) { } - Dag(char const *path, Root_object *root, Genode::Fifo * const dag, + Dependency(char const *path, Root_object *root, Genode::Fifo * const dep, unsigned flags = 0); - ~Dag(); + ~Dependency(); - void load_needed(Genode::Fifo * const dag, unsigned flags = 0); - bool in_dag(char const *file, Genode::Fifo *const dag); + /** + * Load dependent ELF object + */ + void load_needed(Genode::Fifo * const dep, unsigned flags = 0); + + /** + * Check if file is in this dependency tree + */ + bool in_dep(char const *file, Genode::Fifo *const dep); }; -static inline bool verbose_reloc(Linker::Dag const *d) +/** + * Root of dependencies + */ +struct Linker::Root_object { - return d->root && verbose_relocation; -} + Genode::Fifo dep; -extern "C" void _jmp_slot(void); + /* main root */ + Root_object() { }; + + /* runtime loaded root components */ + Root_object(char const *path, unsigned flags = 0); + + ~Root_object() + { + Dependency *d; + while ((d = dep.dequeue())) + destroy(Genode::env()->heap(), d); + } + + Link_map const *link_map() const + { + return dep.head()->obj->link_map(); + } +}; #endif /* _INCLUDE__LINKER_H_ */ diff --git a/repos/base/src/lib/ldso/include/relocation_generic.h b/repos/base/src/lib/ldso/include/relocation_generic.h index b5853ebbe..a4fa6d403 100644 --- a/repos/base/src/lib/ldso/include/relocation_generic.h +++ b/repos/base/src/lib/ldso/include/relocation_generic.h @@ -16,6 +16,19 @@ #include +constexpr bool verbose_relocation = false; + +static inline bool verbose_reloc(Linker::Dependency const *d) +{ + return d->root && verbose_relocation; +} + +/** + * Low level linker entry for jump slot relocations + */ +extern "C" void _jmp_slot(void); + + namespace Linker { struct Plt_got; @@ -32,12 +45,12 @@ namespace Linker */ struct Linker::Plt_got { - Plt_got(Dag const *dag, Elf::Addr *pltgot) + Plt_got(Dependency const *dep, Elf::Addr *pltgot) { if (verbose_relocation) - PDBG("OBJ: %s (%p)", dag->obj->name(), dag); + PDBG("OBJ: %s (%p)", dep->obj->name(), dep); - pltgot[1] = (Elf::Addr) dag; /* ELF object */ + pltgot[1] = (Elf::Addr) dep; /* ELF object */ pltgot[2] = (Elf::Addr) &_jmp_slot; /* Linker entry */ } }; @@ -78,7 +91,7 @@ class Linker::Reloc_non_plt_generic { protected: - Dag const *_dag; + Dependency const *_dep; /** * Copy relocations, these are just for the main program, we can do them @@ -88,8 +101,8 @@ class Linker::Reloc_non_plt_generic template void _copy(REL const *rel, Elf::Addr *addr) { - if (!_dag->obj->is_binary()) { - PERR("LD: Copy relocation in DSO (%s at %p)", _dag->obj->name(), addr); + if (!_dep->obj->is_binary()) { + PERR("LD: Copy relocation in DSO (%s at %p)", _dep->obj->name(), addr); throw Incompatible(); } @@ -97,7 +110,7 @@ class Linker::Reloc_non_plt_generic Elf::Addr reloc_base; /* search symbol in other objects, do not return undefined symbols */ - if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base, false, true))) { + if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base, false, true))) { PWRN("LD: Symbol not found"); return; } @@ -112,7 +125,7 @@ class Linker::Reloc_non_plt_generic public: - Reloc_non_plt_generic(Dag const *dag) : _dag(dag) { } + Reloc_non_plt_generic(Dependency const *dep) : _dep(dep) { } }; @@ -126,7 +139,7 @@ class Linker::Reloc_jmpslot_generic public: - Reloc_jmpslot_generic(Dag const *dag, unsigned const type, Elf::Rel const* pltrel, + Reloc_jmpslot_generic(Dependency const *dep, unsigned const type, Elf::Rel const* pltrel, Elf::Size const index) { if (type != TYPE) { @@ -138,13 +151,13 @@ class Linker::Reloc_jmpslot_generic Elf::Sym const *sym; Elf::Addr reloc_base; - if (!(sym = locate_symbol(rel->sym(), dag, &reloc_base))) { + if (!(sym = lookup_symbol(rel->sym(), dep, &reloc_base))) { PWRN("LD: Symbol not found"); return; } /* write address of symbol to jump slot */ - _addr = (Elf::Addr *)(dag->obj->reloc_base() + rel->offset); + _addr = (Elf::Addr *)(dep->obj->reloc_base() + rel->offset); *_addr = reloc_base + sym->st_value; @@ -164,12 +177,12 @@ class Linker::Reloc_jmpslot_generic template struct Linker::Reloc_bind_now_generic { - Reloc_bind_now_generic(Dag const *dag, Elf::Rel const *pltrel, unsigned long const size) + Reloc_bind_now_generic(Dependency const *dep, Elf::Rel const *pltrel, unsigned long const size) { Elf::Size last_index = size / sizeof(REL); for (Elf::Size index = 0; index < last_index; index++) - Reloc_jmpslot_generic reloc(dag, TYPE, pltrel, index); + Reloc_jmpslot_generic reloc(dep, TYPE, pltrel, index); } }; diff --git a/repos/base/src/lib/ldso/include/trace.h b/repos/base/src/lib/ldso/include/trace.h deleted file mode 100644 index c350b9bb0..000000000 --- a/repos/base/src/lib/ldso/include/trace.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * \brief Trace support for linker intialization - * \author Sebastian Sumpf - * \date 2014-10-26 - */ - -/* - * Copyright (C) 2014 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__TRACE_H_ -#define _INCLUDE__TRACE_H_ - -#if 0 -typedef Genode::addr_t l4_umword_t; -typedef Genode::addr_t l4_addr_t; - -namespace Fiasco { - #include -} -#else -namespace Fiasco { - inline void fiasco_tbuf_log_3val(char const *,unsigned, unsigned, unsigned) { } -} -extern "C" void wait_for_continue(); -#endif - -namespace Linker { - inline void trace(char const *str, unsigned v1, unsigned v2, unsigned v3) - { - Fiasco::fiasco_tbuf_log_3val(str, v1, v2, v3); - } -} - -#endif /* _INCLUDE__TRACE_H_ */ diff --git a/repos/base/src/lib/ldso/include/util.h b/repos/base/src/lib/ldso/include/util.h new file mode 100644 index 000000000..52ebacceb --- /dev/null +++ b/repos/base/src/lib/ldso/include/util.h @@ -0,0 +1,44 @@ +/** + * \brief Helper functions + * \author Sebastian Sumpf + * \date 2015-03-12 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__UTIL_H_ +#define _INCLUDE__UTIL_H_ + +namespace Linker { + + /** + * Page handling + */ + template + static inline T trunc_page(T addr) { + return addr & Genode::_align_mask((T)12); } + + template + static inline T round_page(T addr) { + return Genode::align_addr(addr, (T)12); } + + /** + * Extract file name from path + */ + inline char const *file(char const *path) + { + /* strip directories */ + char const *f, *r = path; + for (f = r; *f; f++) + if (*f == '/') + r = f + 1; + return r; + } +} + +#endif /* _INCLUDE__UTIL_H_ */ diff --git a/repos/base/src/lib/ldso/main.cc b/repos/base/src/lib/ldso/main.cc index 3780423a9..0787bbad3 100644 --- a/repos/base/src/lib/ldso/main.cc +++ b/repos/base/src/lib/ldso/main.cc @@ -13,20 +13,24 @@ #include #include -#include #include #include #include -#include +#include +#include using namespace Linker; +namespace Linker { + struct Dynamic; + struct Ld; + struct Ld_vtable; + struct Binary; + struct Link_map; + struct Debug; -/** - * Offset of dynamic section of this ELF is filled out during linkage - */ -extern Genode::addr_t _DYNAMIC; +}; /** * Genode args to the 'main' function @@ -35,346 +39,41 @@ extern char **genode_argv; extern int genode_argc; extern char **genode_envp; - -namespace Linker { - struct Dynamic; - struct Hash_table; - struct Ld; - struct Ld_vtable; - struct Binary; - struct Link_map; - struct Debug; - - typedef void (*Func)(void); -}; - -static bool bind_now = false; -static Binary *binary = 0; +static Binary *binary = 0; +bool Linker::bind_now = false; +Link_map *Link_map::first; /** * Registers dtors */ int genode_atexit(Linker::Func); -/** - * LIBC debug support - */ -extern "C" void brk(Debug *, Link_map *) { } -struct Linker::Debug -{ - /* - * This state value describes the mapping change taking place when - * the brk address is called. - */ - enum State { - CONSISTENT, /* mapping change is complete */ - ADD, /* beginning to add a new object */ - DELETE /* beginning to remove an object mapping */ - }; - - Debug() : Brk(brk) { } - - int version = 1; /* unused */ - struct Link_map *map = nullptr;; /* start of link map */ - - /* - * This is the address of a function internal to the run-time linker, that - * will always be called when the linker begins to map in a library or unmap - * it, and again when the mapping change is complete. The debugger can set a - * breakpoint at this address if it wants to notice shared object mapping - * changes. - */ - void (*Brk)(Debug *, Link_map *); - State state = CONSISTENT; - - static void state_change(State s, Link_map *m) - { - d()->state = s; - d()->Brk(d(), m); - } - - static Debug *d() - { - static Debug _d; - return &_d; - } -}; - - -/** - * Link map - */ -struct Linker::Link_map -{ - Elf::Addr addr; /* base address of library */ - char const *path; /* path */ - void const *dynamic; /* DYNAMIC section */ - - Link_map *next = nullptr; - Link_map *prev = nullptr; - - static Link_map *first; - - static void add(Link_map *map) - { - map->next = nullptr;; - if (!first) { - first = map; - Debug::d()->map = map; - return; - } - - Link_map *m; - for (m = first; m->next; m = m->next) ; - - m->next = map; - map->prev = m; - } - - static void remove(Link_map *map) - { - if (map->prev) - map->prev->next = map->next; - - if (map->next) - map->next->prev = map->prev; - - if (map == first) - first = map->next; - } - - static void dump() - { - if (!verbose_link_map) - return; - - for (Link_map *m = first; m; m = m->next) - PINF("MAP: addr: " EFMT " dynamic: %p %s m: %p p: %p n: %p", - m->addr, m->dynamic, m->path, m, m->prev, m->next); - } -}; - -Link_map *Link_map::first; - - -/** - * ELF hash table and hash function - */ -struct Linker::Hash_table -{ - unsigned long nbuckets() const { return *((Elf::Hashelt *)this); } - unsigned long nchains() const { return *(((Elf::Hashelt *)this) + 1); } - - Elf::Hashelt const *buckets() { return ((Elf::Hashelt *)this + 2); } - Elf::Hashelt const *chains() { return buckets() + nbuckets(); } - - /** - * ELF hash function Figure 5.12 of the 'System V ABI' - */ - static unsigned long hash(char const *name) - { - unsigned const char *p = (unsigned char const *)name; - unsigned long h = 0, g; - - while (*p) { - h = (h << 4) + *p++; - if ((g = h & 0xf0000000) != 0) - h ^= g >> 24; - h &= ~g; - } - return h; - } -}; - - -/** - * .dynamic section entries - */ -struct Linker::Dynamic -{ - struct Needed : Genode::Fifo::Element - { - Genode::off_t offset; - - Needed(Genode::off_t offset) : offset(offset) { } - - char const *path(char const *strtab) - { - return ((char const *)(strtab + offset)); - } - - char const *name(char const *strtab) - { - return file(path(strtab)); - } - }; - - Dag const *dag; - Object const *obj; - Elf::Dyn const *dynamic; - - Hash_table *hash_table = nullptr; - - Elf::Rela *reloca = nullptr; - unsigned long reloca_size = 0; - - Elf::Sym *symtab = nullptr; - char *strtab = nullptr; - unsigned long strtab_size = 0; - - Elf::Addr *pltgot = nullptr; - - Elf::Rel *pltrel = nullptr; - unsigned long pltrel_size = 0; - D_tag pltrel_type = DT_NULL; - - Func init_function = nullptr; - - Elf::Rel *rel = nullptr; - unsigned long rel_size = 0; - - Genode::Fifo needed; - - Dynamic(Dag const *dag) - : - dag(dag), obj(dag->obj), dynamic((Elf::Dyn *)(obj->reloc_base() + &_DYNAMIC)) - { - init(); - } - - Dynamic(Dag const *dag, Object const *obj, Linker::Phdr const *phdr) - : - dag(dag), obj(obj), dynamic(find_dynamic(phdr)) - { - init(); - } - - ~Dynamic() - { - Needed *n; - while ((n = needed.dequeue())) - destroy(Genode::env()->heap(), n); - } - - Elf::Dyn const *find_dynamic(Linker::Phdr const *p) - { - for (unsigned i = 0; i < p->count; i++) - if (p->phdr[i].p_type == PT_DYNAMIC) - return reinterpret_cast(p->phdr[i].p_vaddr + obj->reloc_base()); - - return 0; - } - - void section_dt_needed(Elf::Dyn const *d) - { - Needed *n = new(Genode::env()->heap()) Needed(d->un.ptr); - needed.enqueue(n); - } - - template - void section(T *member, Elf::Dyn const *d) - { - *member = (T)(obj->reloc_base() + d->un.ptr); - } - - void section_dt_debug(Elf::Dyn const *d) - { - Elf::Dyn *_d = const_cast(d); - _d->un.ptr = (Elf::Addr)Debug::d(); - } - - void init() - { - for (Elf::Dyn const *d = dynamic; d->tag != DT_NULL; d++) { - switch (d->tag) { - - case DT_NEEDED : section_dt_needed(d); break; - case DT_PLTRELSZ: pltrel_size = d->un.val; break; - case DT_PLTGOT : section(&pltgot, d); break; - case DT_HASH : section(&hash_table, d); break; - case DT_RELA : section(&reloca, d); break; - case DT_RELASZ : reloca_size = d->un.val; break; - case DT_SYMTAB : section(&symtab, d); break; - case DT_STRTAB : section(&strtab, d); break; - case DT_STRSZ : strtab_size = d->un.val; break; - case DT_INIT : section(&init_function, d); break; - case DT_PLTREL : pltrel_type = (D_tag)d->un.val; break; - case DT_JMPREL : section(&pltrel, d); break; - case DT_REL : section(&rel, d); break; - case DT_RELSZ : rel_size = d->un.val; break; - case DT_DEBUG : section_dt_debug(d); break; - default: - trace("DT", d->tag, 0, 0); - break; - } - } - } - - void relocate() - { - plt_setup(); - - if (pltrel_size) { - switch (pltrel_type) { - - case DT_RELA: - case DT_REL: - Reloc_plt(obj, pltrel_type, pltrel, pltrel_size); - break; - default: - PERR("LD: Invalid PLT relocation %u", pltrel_type); - throw Incompatible(); - } - } - - relocate_non_plt(); - } - - void plt_setup() - { - if (pltgot) - Plt_got r(dag, pltgot); - } - - void relocate_non_plt(bool second_pass = false) - { - if (reloca) - Reloc_non_plt r(dag, reloca, reloca_size); - - if (rel) - Reloc_non_plt r(dag, rel, rel_size, second_pass); - - if (bind_now) - Reloc_bind_now r(dag, pltrel, pltrel_size); - } -}; - - -static void register_initializer(Elf_object *elf); +/************************************************************** + ** ELF object types (shared object, dynamic binaries, ldso ** + **************************************************************/ /** * The actual ELF object, one per file */ -struct Linker::Elf_object : Object, Genode::List::Element, - Genode::Fifo::Element +struct Linker::Elf_object : Object, Genode::Fifo::Element { - Dynamic dynamic; + Dynamic dyn; Link_map map; unsigned ref_count = 1; unsigned flags = 0; bool relocated = false; - Elf_object(Dag const *dag) : dynamic(dag) + Elf_object(Dependency const *dep) : dyn(dep) { } - Elf_object(char const *path, Dag const *dag, unsigned flags = 0) + Elf_object(char const *path, Dependency const *dep, unsigned flags = 0) : - Object(path, Linker::load(Linker::file(path))), dynamic(dag, this, &_file->phdr), + Object(path, Linker::load(Linker::file(path))), dyn(dep, this, &_file->phdr), flags(flags) { /* register for static construction and relocation */ - register_initializer(this); + Init::list()->insert(this); obj_list()->enqueue(this); /* add to link map */ @@ -400,51 +99,33 @@ struct Linker::Elf_object : Object, Genode::List::Element, obj_list()->remove(this); } - void setup_link_map() - { - map.addr = _file ? _file->start + reloc_base() : reloc_base(); - map.path = name(); - map.dynamic = (void *)dynamic.dynamic; - - Link_map::add(&map); - }; - - virtual void relocate() - { - if (!relocated) - dynamic.relocate(); - - relocated = true; - } - /** * Return symbol of given number from ELF */ - Elf::Sym const * symbol(unsigned sym_index) const + Elf::Sym const *symbol(unsigned sym_index) const { - if (sym_index > dynamic.hash_table->nchains()) + if (sym_index > dyn.hash_table->nchains()) return 0; - return dynamic.symtab + sym_index; + return dyn.symtab + sym_index; } /** * Return name of given symbol */ - char const *symbol_name(Elf::Sym const *sym) const - { - return dynamic.strtab + sym->st_name; + char const *symbol_name(Elf::Sym const *sym) const { + return dyn.strtab + sym->st_name; } /** * Lookup symbol name in this ELF */ - Elf::Sym const * lookup_symbol(char const *name, unsigned long hash) const + Elf::Sym const *lookup_symbol(char const *name, unsigned long hash) const { - Hash_table *h = dynamic.hash_table; + Hash_table *h = dyn.hash_table; if (!h->buckets()) - return 0; + return nullptr; unsigned long sym_index = h->buckets()[hash % h->nbuckets()]; @@ -453,7 +134,7 @@ struct Linker::Elf_object : Object, Genode::List::Element, { /* bad object */ if (sym_index > h->nchains()) - return 0; + return nullptr; Elf::Sym const *sym = symbol(sym_index); char const *sym_name = symbol_name(sym); @@ -472,19 +153,40 @@ struct Linker::Elf_object : Object, Genode::List::Element, return sym; } - return 0; + return nullptr; } /** - * Search for symbol at addr + * Fill-out link map infos for this ELF */ - void info(Genode::addr_t addr, Genode::Address_info &info) const + void setup_link_map() + { + map.addr = _file ? _file->start + reloc_base() : reloc_base(); + map.path = name(); + map.dynamic = (void *)dyn.dynamic; + + Link_map::add(&map); + }; + + + Link_map *link_map() override { return ↦ } + Dynamic *dynamic() override { return &dyn; } + + void relocate() override + { + if (!relocated) + dyn.relocate(); + + relocated = true; + } + + void info(Genode::addr_t addr, Genode::Address_info &info) override { info.path = name(); info.base = map.addr; info.addr = 0; - Hash_table *h = dynamic.hash_table; + Hash_table *h = dyn.hash_table; for (unsigned long sym_index = 0; sym_index < h->nchains(); sym_index++) { @@ -509,70 +211,32 @@ struct Linker::Elf_object : Object, Genode::List::Element, throw Genode::Address_info::Invalid_address(); } - Elf_object *init_next() const - { - return Genode::List::Element::next(); + /** + * Next in initializion list + */ + Object *next_init() const override { + return Genode::List::Element::next(); } - - Elf_object *obj_next() const - { + /** + * Next in object list + */ + Object *next_obj() const override { return Genode::Fifo::Element::next(); } + /** + * Object list + */ static Genode::Fifo *obj_list() { static Genode::Fifo _list; return &_list; } - static Elf_object *find_obj(Genode::addr_t addr) - { - for (Elf_object *e = obj_list()->head(); e; e = e->obj_next()) - if (addr >= e->map.addr && addr < e->map.addr + e->size()) - return e; - throw Genode::Address_info::Invalid_address(); - } - - static Elf_object *load(char const *path, Dag *dag, unsigned flags = 0) - { - for (Elf_object *e = obj_list()->head(); e; e = e->obj_next()) { - - if (verbose_loading) - PDBG("LOAD: %s == %s", Linker::file(path), e->name()); - - if (!Genode::strcmp(Linker::file(path), e->name())) { - e->ref_count++; - return e; - } - } - - Elf_object *e = new (Genode::env()->heap()) Elf_object(path, dag, flags); - dag->obj = e; - return e; - } - - bool unload() { return !(--ref_count) && !(flags & Genode::Shared_object::KEEP); } - - static Genode::Lock & lock() - { - static Genode::Lock _lock; - return _lock; - } - - - Elf::Phdr const *phdr_exidx() const - { - for (unsigned i = 0; i < _file->elf_phdr_count(); i++) { - Elf::Phdr const *ph = _file->elf_phdr(i); - - if (ph->p_type == PT_ARM_EXIDX) - return ph; - } - - return 0; - } + void load() override { ref_count++; } + bool unload() override { return !(--ref_count) && !(flags & Genode::Shared_object::KEEP); } bool is_linker() const override { return false; } bool is_binary() const override { return false; } @@ -580,158 +244,13 @@ struct Linker::Elf_object : Object, Genode::List::Element, /** - * Handle static construction and relocation of ELF files + * The dynamic linker object (ld.lib.so) */ -struct Init : Genode::List +struct Linker::Ld : Dependency, Elf_object { - bool in_progress = false; - bool restart = false; - - static Init *list() - { - static Init _list; - return &_list; - } - - Elf_object *contains(char const *file) - { - for (Elf_object *e = first(); e; e = e->init_next()) - if (!Genode::strcmp(file, e->name())) - return e; - - return nullptr; - } - - void reorder(Elf_object const *elf) - { - /* put in front of initializer list */ - remove(elf); - insert(elf); - - /* re-order dependencies */ - for (Dynamic::Needed *n = elf->dynamic.needed.head(); n; n = n->next()) { - char const *path = n->path(elf->dynamic.strtab); - Elf_object *e; - - if ((e = contains(Linker::file(path)))) - reorder(e); - } - } - - void initialize() - { - Elf_object *obj = first(); - - /* relocate */ - for (; obj; obj = obj->init_next()) { - if (verbose_relocation) - PDBG("Relocate %s", obj->name()); - obj->relocate(); - } - - /* - * Recursive initialization call is not allowed here. This might happend - * when Shared_objects (e.g. dlopen and friends) are constructed from within - * global constructors (ctors). - */ - if (in_progress) { - restart = true; - return; - } - - in_progress = true; - - /* call static constructors */ - obj = first(); - while (obj) { - - Elf_object *next = obj->init_next(); - remove(obj); - - if (obj->dynamic.init_function) { - - if (verbose_relocation) - PDBG("%s init func %p", obj->name(), obj->dynamic.init_function); - - obj->dynamic.init_function(); - } - - obj = restart ? first() : next; - restart = false; - } - - in_progress = false; - } -}; - - -void register_initializer(Elf_object *elf) -{ - Init::list()->insert(elf); -} - - -/** - * Dag node - */ -Linker::Dag::Dag(char const *path, Root_object *root, Genode::Fifo * const dag, unsigned flags) - : obj(Elf_object::load(path, this, flags)), root(root) -{ - dag->enqueue(this); - load_needed(dag, flags); -} - - -Linker::Dag::~Dag() -{ - if ((static_cast(obj))->unload()) { - - if (verbose_loading) - PDBG("Destroy: %s\n", obj->name()); - - destroy(Genode::env()->heap(), obj); - } -} - - -bool Linker::Dag::in_dag(char const *file, Genode::Fifo * const dag) -{ - for (Dag *d = dag->head(); d; d = d->next()) - if (!Genode::strcmp(file, d->obj->name())) - return true; - - return false; -} - - -void Linker::Dag::load_needed(Genode::Fifo * const dag, unsigned flags) -{ - Elf_object *elf = static_cast(obj); - - for (Dynamic::Needed *n = elf->dynamic.needed.head(); n; n = n->next()) { - char const *path = n->path(elf->dynamic.strtab); - Elf_object *e; - - if (!in_dag(Linker::file(path), dag)) - new (Genode::env()->heap()) Dag(path, root, dag, flags); - - /* re-order initializer list, if needed object has been already added */ - else if ((e = Init::list()->contains(Linker::file(path)))) - Init::list()->reorder(e); - } -} - - -/** - * The dynamic linker has its own ELF ojbect type - */ -struct Linker::Ld : Dag, Elf_object -{ - Ld() : Dag(this, nullptr), Elf_object(this) + Ld() : Dependency(this, nullptr), Elf_object(this) { Genode::strncpy(_name, linker_name(), Object::MAX_PATH); - - trace("LD", 0, 0, 0); } void setup_link_map() @@ -742,7 +261,7 @@ struct Linker::Ld : Dag, Elf_object * Use DT_HASH table address for linker, assuming that it will always be at * the beginning of the file */ - map.addr = trunc_page((Elf::Addr)dynamic.hash_table); + map.addr = trunc_page((Elf::Addr)dynamic()->hash_table); } void load_phdr() @@ -750,20 +269,38 @@ struct Linker::Ld : Dag, Elf_object _file = Linker::load(name(), false); } - void relocate_global() { dynamic.relocate_non_plt(true); } - void update_dag(Dag const *dag) { dynamic.dag = dag; } + void relocate_global() { dynamic()->relocate_non_plt(true); } + void update_dependency(Dependency const *dep) { dynamic()->dep = dep; } static Ld *linker(); bool is_linker() const override { return true; } /** - * Entry point for jump relocations, it is called from assembly + * Entry point for jump relocations, it is called from assembly code and is implemented + * right below) */ - static Elf::Addr jmp_slot(Dag const *dag, Elf::Size offset) asm("jmp_slot"); + static Elf::Addr jmp_slot(Dependency const *dep, Elf::Size index) asm("jmp_slot"); }; +Elf::Addr Ld::jmp_slot(Dependency const *dep, Elf::Size index) +{ + Genode::Lock::Guard guard(Elf_object::lock()); + + if (verbose_relocation) + PDBG("SLOT %p " EFMT, dep->obj, index); + + try { + Reloc_jmpslot slot(dep, dep->obj->dynamic()->pltrel_type, + dep->obj->dynamic()->pltrel, index); + return slot.target_addr(); + } catch (...) { PERR("LD: Jump slot relocation failed. FATAL!"); } + + return 0; +} + + /** * Ld object with different vtable typeinfo */ @@ -775,7 +312,9 @@ struct Linker::Ld_vtable : Ld } }; - +/** + * Linker object used during bootstrapping on stack (see: 'init_rtld') + */ Linker::Ld *Linker::Ld::linker() { static Ld_vtable _linker; @@ -783,80 +322,28 @@ Linker::Ld *Linker::Ld::linker() } -Elf::Addr Ld::jmp_slot(Dag const *dag, Elf::Size index) -{ - Elf_object const *obj = static_cast(dag->obj); - - Genode::Lock::Guard guard(Elf_object::lock()); - - if (verbose_relocation) - PDBG("SLOT %p " EFMT, obj, index); - - try { - Reloc_jmpslot slot(dag, obj->dynamic.pltrel_type, obj->dynamic.pltrel, index); - return slot.target_addr(); - } catch (...) { PERR("LD: Jump slot relocation failed. FATAL!"); } - - return 0; -} - - -struct Linker::Root_object -{ - Genode::Fifo dag; - - /* main root */ - Root_object() { }; - - /* runtime loaded root components */ - Root_object(char const *path, unsigned flags = 0) - { - new (Genode::env()->heap()) Dag(path, this, &dag, flags); - - /* provide Genode base library access */ - new (Genode::env()->heap()) Dag(linker_name(), this, &dag);; - - /* relocate and call constructors */ - Init::list()->initialize(); - } - - ~Root_object() - { - Dag *d; - while ((d = dag.dequeue())) - destroy(Genode::env()->heap(), d); - } - - Link_map const *link_map() const - { - Elf_object const *obj = static_cast(dag.head()->obj); - return obj ? &obj->map : 0; - } -}; - - /** - * The program to load has its own ELF object type + * The dynamic binary to load */ struct Linker::Binary : Root_object, Elf_object { Binary() - : Elf_object(binary_name(), new (Genode::env()->heap()) Dag(this, this)) + : Elf_object(binary_name(), new (Genode::env()->heap()) Dependency(this, this)) { - /* create dag for binary and linker */ - Dag *binary = const_cast(dynamic.dag); - dag.enqueue(binary); - Dag *linker = new (Genode::env()->heap()) Dag(Ld::linker(), this); - dag.enqueue(linker); + /* create dep for binary and linker */ + Dependency *binary = const_cast(dynamic()->dep); + dep.enqueue(binary); + Dependency *linker = new (Genode::env()->heap()) Dependency(Ld::linker(), this); + dep.enqueue(linker); - /* update linker dag */ - Ld::linker()->update_dag(linker); + /* update linker dep */ + Ld::linker()->update_dependency(linker); /* place linker on second place in link map as well */ Ld::linker()->setup_link_map(); /* load dependencies */ - binary->load_needed(&dag); + binary->load_needed(&dep); /* relocate and call constructors */ Init::list()->initialize(); @@ -908,13 +395,39 @@ struct Linker::Binary : Root_object, Elf_object }; -/** - * This is called mostly from the relocation code - * XXX: 'undef' needs to be true for dlsym - */ -Elf::Sym const *Linker::locate_symbol(unsigned sym_index, Dag const *dag, Elf::Addr *base, bool undef, bool other) +/*************************************** + ** Global Linker namespace functions ** + ***************************************/ + +Object *Linker::load(char const *path, Dependency *dep, unsigned flags) { - Elf_object const *e = static_cast(dag->obj); + for (Object *e = Elf_object::obj_list()->head(); e; e = e->next_obj()) { + + if (verbose_loading) + PDBG("LOAD: %s == %s", Linker::file(path), e->name()); + + if (!Genode::strcmp(Linker::file(path), e->name())) { + e->load(); + return e; + } + } + + Elf_object *e = new (Genode::env()->heap()) Elf_object(path, dep, flags); + dep->obj = e; + return e; +} + + +Object *Linker::obj_list_head() +{ + return Elf_object::obj_list()->head(); +} + + +Elf::Sym const *Linker::lookup_symbol(unsigned sym_index, Dependency const *dep, + Elf::Addr *base, bool undef, bool other) +{ + Elf_object const *e = static_cast(dep->obj); Elf::Sym const *symbol = e->symbol(sym_index); if (!symbol) { @@ -923,18 +436,18 @@ Elf::Sym const *Linker::locate_symbol(unsigned sym_index, Dag const *dag, Elf::A } if (symbol->bind() == STB_LOCAL) { - trace("NONLOCAL", symbol->bind(), 0, 0); - *base = dag->obj->reloc_base(); + *base = dep->obj->reloc_base(); return symbol; } - return search_symbol(e->symbol_name(symbol), dag, base, undef, other); + return lookup_symbol(e->symbol_name(symbol), dep, base, undef, other); } -Elf::Sym const *Linker::search_symbol(char const *name, Dag const *dag, Elf::Addr *base, bool undef, bool other) +Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const *dep, + Elf::Addr *base, bool undef, bool other) { - Dag const *curr = dag->root ? dag->root->dag.head() : dag; + Dependency const *curr = dep->root ? dep->root->dep.head() : dep; unsigned long hash = Hash_table::hash(name); Elf::Sym const *weak_symbol = 0; Elf::Addr weak_base = 0; @@ -943,14 +456,14 @@ Elf::Sym const *Linker::search_symbol(char const *name, Dag const *dag, Elf::Add //TODO: handle vertab and search in object list for (;curr; curr = curr->next()) { - if (other && curr == dag) + if (other && curr == dep) continue; Elf_object const *elf = static_cast(curr->obj); if ((symbol = elf->lookup_symbol(name, hash)) && (symbol->st_value || undef)) { - if (dag->root && verbose_lookup) + if (dep->root && verbose_lookup) PINF("Lookup %s obj_src %s st %p info %x weak: %u", name, elf->name(), symbol, symbol->st_info, symbol->weak()); if (!undef && symbol->st_shndx == SHN_UNDEF) @@ -968,11 +481,11 @@ Elf::Sym const *Linker::search_symbol(char const *name, Dag const *dag, Elf::Add } } - /* try searching binary's DAG */ - if (!weak_symbol && dag->root && dag != binary->dag.head()) - return search_symbol(name, binary->dag.head(), base, undef, other); + /* try searching binary's dependencies */ + if (!weak_symbol && dep->root && dep != binary->dep.head()) + return lookup_symbol(name, binary->dep.head(), base, undef, other); - if (dag->root && verbose_lookup) + if (dep->root && verbose_lookup) PDBG("Return %p", weak_symbol); if (!weak_symbol) @@ -983,14 +496,23 @@ Elf::Sym const *Linker::search_symbol(char const *name, Dag const *dag, Elf::Add } +void Linker::load_linker_phdr() +{ + if (!Ld::linker()->file()) + Ld::linker()->load_phdr(); +} + + +/******************** + ** Initialization ** + ********************/ + /** * Called before anything else, even '_main', we cannot access any global data * here, we have to relocate our own ELF first */ extern "C" void init_rtld() { - trace("init_rtld", 0, 0, 0); - /* * Allocate on stack, since the linker has not been relocated yet, the vtable * type relocation might prdouce a wrong vtable pointer (at least on ARM), do @@ -1002,196 +524,25 @@ extern "C" void init_rtld() /* make sure this does not get destroyed the usual way */ linker_stack.ref_count++; - trace("init_rtld finished", 0, 0, 0); - /* * Create actual linker object with different vtable type and set PLT to new * DAG. */ - Ld::linker()->dynamic.plt_setup(); -} - - -/** - * "Walk through shared objects" support, see man page of 'dl_iterate_phdr' - */ -struct Phdr_info -{ - Elf::Addr addr; /* module relocation base */ - char const *name; /* module name */ - Elf::Phdr const *phdr; /* pointer to module's phdr */ - Elf::Half phnum; /* number of entries in phdr */ -}; - - -extern "C" int dl_iterate_phdr(int (*callback) (Phdr_info *info, Genode::size_t size, void *data), void *data) -{ - int err = 0; - Phdr_info info; - - Genode::Lock::Guard guard(Elf_object::lock()); - - Elf_object *e = Elf_object::obj_list()->head(); - for (;e; e = e->obj_next()) { - - info.addr = e->reloc_base(); - info.name = e->name(); - info.phdr = e->file()->phdr.phdr; - info.phnum = e->file()->phdr.count; - - if (verbose_exception) - PDBG("%s reloc " EFMT, e->name(), e->reloc_base()); - - if ((err = callback(&info, sizeof(Phdr_info), data))) - break; - } - - return err; -} - - -/** - * Find ELF and exceptions table segment that that is located under 'pc', - * address of excption table and number of entries 'pcount' - */ -extern "C" unsigned long dl_unwind_find_exidx(unsigned long pc, int *pcount) -{ - /* size of exception table entries */ - enum { EXIDX_ENTRY_SIZE = 8 }; - *pcount = 0; - - /* - * Since this function may be called before the main function, load linker's - * program header now - */ - if (!Ld::linker()->file()) - Ld::linker()->load_phdr(); - - Elf_object *e = Elf_object::obj_list()->head(); - for (; e; e = e->obj_next()) - { - /* address of first PT_LOAD header */ - Genode::addr_t base = e->reloc_base() + e->file()->start; - - /* is the 'pc' somewhere within this ELF image */ - if ((pc < base) || (pc >= base + e->file()->size)) - continue; - - /* retrieve PHDR of exception-table segment */ - Elf::Phdr const *exidx = e->phdr_exidx(); - if (!exidx) - continue; - - *pcount = exidx->p_memsz / EXIDX_ENTRY_SIZE; - return exidx->p_vaddr + e->reloc_base(); - } - - return 0; -} - - -/***************************** - ** Shared object interface ** - *****************************/ - -static Root_object *to_root(void *h) -{ - return static_cast(h); -} - - -/** - * Needed during shared object creation and destruction, since global lists are - * manipulated - */ -static Genode::Lock & shared_object_lock() -{ - static Genode::Lock _lock; - return _lock; -} - - -Genode::Shared_object::Shared_object(char const *file, unsigned flags) -{ - using namespace Linker; - - if (verbose_shared) - PDBG("open '%s'", file ? file : "binary"); - - try { - Genode::Lock::Guard guard(shared_object_lock()); - - /* update bind now variable */ - bind_now = (flags & Shared_object::NOW) ? true : false; - - _handle = (Root_object *)new (Genode::env()->heap()) Root_object(file ? file : binary_name(), flags); - } catch (...) { throw Invalid_file(); } -} - - -void *Genode::Shared_object::_lookup(const char *name) const -{ - using namespace Linker; - - if (verbose_shared) - PDBG("lookup '%s'", name); - - try { - Genode::Lock::Guard guard(Elf_object::lock()); - - Elf::Addr base; - Root_object *root = to_root(_handle); - Elf::Sym const *symbol = search_symbol(name, root->dag.head(), &base, true); - - return (void *)(base + symbol->st_value); - } catch (...) { throw Shared_object::Invalid_symbol(); } -} - - -Genode::Shared_object::Link_map const * Genode::Shared_object::link_map() const -{ - return (Link_map const *)to_root(_handle)->link_map(); -} - - -Genode::Shared_object::~Shared_object() -{ - using namespace Linker; - - if (verbose_shared) - PDBG("close"); - - Genode::Lock::Guard guard(shared_object_lock()); - destroy(Genode::env()->heap(), to_root(_handle)); -} - - -Genode::Address_info::Address_info(Genode::addr_t address) -{ - using namespace Genode; - - if (verbose_shared) - PDBG("request: %lx", address); - - Elf_object *e = Elf_object::find_obj(address); - e->info(address, *this); - - if (verbose_shared) - PDBG("Found: obj: %s sym: %s addr: %lx", path, name, addr); + Ld::linker()->dynamic()->plt_setup(); } static void dump_loaded() { - Elf_object *o = Elf_object::obj_list()->head(); - for(; o; o = o->obj_next()) { + Object *o = Elf_object::obj_list()->head(); + for(; o; o = o->next_obj()) { if (o->is_binary()) continue; - Elf_object *e = static_cast(o); Genode::printf(" " EFMT " .. " EFMT ": %s\n", - e->map.addr, e->map.addr + e->size() - 1, e->name()); + o->link_map()->addr, o->link_map()->addr + o->size() - 1, + o->name()); } } diff --git a/repos/base/src/lib/ldso/shared_object.cc b/repos/base/src/lib/ldso/shared_object.cc new file mode 100644 index 000000000..0f8133486 --- /dev/null +++ b/repos/base/src/lib/ldso/shared_object.cc @@ -0,0 +1,121 @@ +/** + * \brief Implentation of Genode's shared-object interface + * \author Sebastian Sumpf + * \date 2015-03-11 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include + + +/************* + ** Helpers ** + *************/ + +static Linker::Root_object *to_root(void *h) +{ + return static_cast(h); +} + + +/** + * Needed during shared object creation and destruction, since global lists are + * manipulated + */ +static Genode::Lock & shared_object_lock() +{ + static Genode::Lock _lock; + return _lock; +} + + +static Linker::Object *find_obj(Genode::addr_t addr) +{ + for (Linker::Object *e = Linker::obj_list_head(); e; e = e->next_obj()) + if (addr >= e->link_map()->addr && addr < e->link_map()->addr + e->size()) + return e; + + throw Genode::Address_info::Invalid_address(); +} + + +/********* + ** API ** + *********/ + +Genode::Shared_object::Shared_object(char const *file, unsigned flags) +{ + using namespace Linker; + + if (verbose_shared) + PDBG("open '%s'", file ? file : "binary"); + + try { + Genode::Lock::Guard guard(shared_object_lock()); + + /* update bind now variable */ + bind_now = (flags & Shared_object::NOW) ? true : false; + + _handle = (Root_object *)new (Genode::env()->heap()) Root_object(file ? file : binary_name(), flags); + } catch (...) { throw Invalid_file(); } +} + + +void *Genode::Shared_object::_lookup(const char *name) const +{ + using namespace Linker; + + if (verbose_shared) + PDBG("lookup '%s'", name); + + try { + Genode::Lock::Guard guard(Object::lock()); + + Elf::Addr base; + Root_object *root = to_root(_handle); + Elf::Sym const *symbol = lookup_symbol(name, root->dep.head(), &base, true); + + return (void *)(base + symbol->st_value); + } catch (...) { throw Shared_object::Invalid_symbol(); } +} + + +Genode::Shared_object::Link_map const * Genode::Shared_object::link_map() const +{ + return (Link_map const *)to_root(_handle)->link_map(); +} + + +Genode::Shared_object::~Shared_object() +{ + using namespace Linker; + + if (verbose_shared) + PDBG("close"); + + Genode::Lock::Guard guard(shared_object_lock()); + destroy(Genode::env()->heap(), to_root(_handle)); +} + + +Genode::Address_info::Address_info(Genode::addr_t address) +{ + using namespace Genode; + + if (verbose_shared) + PDBG("request: %lx", address); + + Linker::Object *e = find_obj(address); + e->info(address, *this); + + if (verbose_shared) + PDBG("Found: obj: %s sym: %s addr: %lx", path, name, addr); +} + + diff --git a/repos/base/src/lib/ldso/x86_32/relocation.h b/repos/base/src/lib/ldso/x86_32/relocation.h index 251addcd9..b1d54c225 100644 --- a/repos/base/src/lib/ldso/x86_32/relocation.h +++ b/repos/base/src/lib/ldso/x86_32/relocation.h @@ -43,36 +43,35 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic Elf::Addr reloc_base; Elf::Sym const *sym; - if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base))) + if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base))) return; *addr = (addend ? *addr : 0) + reloc_base + sym->st_value; - trace("REL32", (unsigned long)addr, *addr, 0); } void _relative(Elf::Rel const *rel, Elf::Addr *addr) { - if (_dag->obj->reloc_base()) - *addr += _dag->obj->reloc_base(); + if (_dep->obj->reloc_base()) + *addr += _dep->obj->reloc_base(); } public: - Reloc_non_plt(Dag const *dag, Elf::Rela const *, unsigned long) - : Reloc_non_plt_generic(dag) + Reloc_non_plt(Dependency const *dep, Elf::Rela const *, unsigned long) + : Reloc_non_plt_generic(dep) { PERR("LD: DT_RELA not supported"); - trace("Non_plt", 0, 0, 0); throw Incompatible(); } - Reloc_non_plt(Dag const *dag, Elf::Rel const *rel, unsigned long size, bool second_pass) - : Reloc_non_plt_generic(dag) + Reloc_non_plt(Dependency const *dep, Elf::Rel const *rel, unsigned long size, + bool second_pass) + : Reloc_non_plt_generic(dep) { Elf::Rel const *end = rel + (size / sizeof(Elf::Rel)); for (; rel < end; rel++) { - Elf::Addr *addr = (Elf::Addr *)(_dag->obj->reloc_base() + rel->offset); + Elf::Addr *addr = (Elf::Addr *)(_dep->obj->reloc_base() + rel->offset); if (second_pass && rel->type() != R_GLOB_DAT) continue; @@ -84,8 +83,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic case R_COPY : _copy(rel, addr); break; case R_RELATIVE: _relative(rel, addr); break; default: - trace("UNKREL", rel->type(), 0, 0); - if (_dag->root) { + if (_dep->root) { PWRN("LD: Unkown relocation %u", rel->type()); throw Incompatible(); } diff --git a/repos/base/src/lib/ldso/x86_64/relocation.h b/repos/base/src/lib/ldso/x86_64/relocation.h index 1b611888f..a1d7872da 100644 --- a/repos/base/src/lib/ldso/x86_64/relocation.h +++ b/repos/base/src/lib/ldso/x86_64/relocation.h @@ -44,8 +44,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic */ void _relative(Elf::Rela const *rel, Elf::Addr *addr) { - trace("64", _dag->obj->reloc_base(), rel->addend, 0); - *addr = _dag->obj->reloc_base() + rel->addend; + *addr = _dep->obj->reloc_base() + rel->addend; } /** @@ -57,24 +56,24 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic Elf::Addr reloc_base; Elf::Sym const *sym; - if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base))) + if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base))) return; *addr = reloc_base + sym->st_value + (addend ? rel->addend : 0); - if (verbose_reloc(_dag)) + if (verbose_reloc(_dep)) PDBG("GLOB DAT %p -> %llx r %llx v %llx", addr, *addr, reloc_base, sym->st_value); } public: - Reloc_non_plt(Dag const *dag, Elf::Rela const *rel, unsigned long size) - : Reloc_non_plt_generic(dag) + Reloc_non_plt(Dependency const *dep, Elf::Rela const *rel, unsigned long size) + : Reloc_non_plt_generic(dep) { Elf::Rela const *end = rel + (size / sizeof(Elf::Rela)); for (; rel < end; rel++) { - Elf::Addr *addr = (Elf::Addr *)(_dag->obj->reloc_base() + rel->offset); + Elf::Addr *addr = (Elf::Addr *)(_dep->obj->reloc_base() + rel->offset); switch(rel->type()) { case R_64: _glob_dat_64(rel, addr, true); break; @@ -83,8 +82,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic case R_RELATIVE: _relative(rel, addr); break; default: - trace("UNKRELA", rel->type(), 0, 0); - if (!_dag->obj->is_linker()) { + if (!_dep->obj->is_linker()) { PWRN("LD: Unkown relocation %u", rel->type()); throw Incompatible(); } @@ -93,8 +91,8 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic } } - Reloc_non_plt(Dag const *dag, Elf::Rel const *, unsigned long, bool) - : Reloc_non_plt_generic(dag) + Reloc_non_plt(Dependency const *dep, Elf::Rel const *, unsigned long, bool) + : Reloc_non_plt_generic(dep) { PERR("LD: DT_REL not supported"); throw Incompatible();