From 784e728727cb86840b89a638bca87ea98739451b Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Sun, 30 Oct 2016 15:17:24 +0100 Subject: [PATCH] Clean ldso from using deprecated APIs Issue #1987 --- .../base-linux/src/lib/lx_hybrid/lx_hybrid.cc | 7 + repos/base/include/base/env.h | 11 +- repos/base/include/base/shared_object.h | 41 +- repos/base/lib/mk/cxx.mk | 1 + repos/base/lib/mk/ldso.inc | 2 +- .../base/src/include/base/internal/globals.h | 3 + repos/base/src/lib/base/component.cc | 10 + repos/base/src/lib/cxx/exception.cc | 40 +- repos/base/src/lib/cxx/malloc_free.cc | 35 +- repos/base/src/lib/ldso/debug.cc | 10 +- repos/base/src/lib/ldso/dependency.cc | 70 ++- repos/base/src/lib/ldso/exception.cc | 17 +- repos/base/src/lib/ldso/file.cc | 331 ---------- repos/base/src/lib/ldso/include/debug.h | 17 +- repos/base/src/lib/ldso/include/dynamic.h | 389 ++++++++---- repos/base/src/lib/ldso/include/file.h | 233 ++++++- repos/base/src/lib/ldso/include/init.h | 29 +- repos/base/src/lib/ldso/include/linker.h | 202 +++--- repos/base/src/lib/ldso/include/region_map.h | 118 ++++ .../src/lib/ldso/include/relocation_generic.h | 56 +- repos/base/src/lib/ldso/include/types.h | 43 ++ repos/base/src/lib/ldso/include/util.h | 4 +- repos/base/src/lib/ldso/main.cc | 580 +++++++++--------- repos/base/src/lib/ldso/shared_object.cc | 63 +- repos/base/src/lib/ldso/spec/arm/relocation.h | 16 +- .../base/src/lib/ldso/spec/riscv/relocation.h | 22 +- .../src/lib/ldso/spec/x86_32/relocation.h | 16 +- .../src/lib/ldso/spec/x86_64/relocation.h | 18 +- .../base/src/lib/startup/init_main_thread.cc | 22 - repos/dde_rump/include/rump/bootstrap.h | 21 + repos/dde_rump/include/rump_fs/fs.h | 2 +- repos/dde_rump/src/lib/rump/bootstrap.cc | 66 +- .../src/server/rump_fs/file_system.cc | 56 +- .../dde_rump/src/server/rump_fs/file_system.h | 7 +- repos/dde_rump/src/server/rump_fs/main.cc | 11 +- repos/libports/src/lib/libc/dynamic_linker.cc | 37 +- repos/libports/src/lib/libc/libc_init.h | 28 + repos/libports/src/lib/libc/task.cc | 4 + repos/libports/src/test/ldso/main.cc | 16 +- repos/os/src/lib/vfs/file_system_factory.cc | 17 +- 40 files changed, 1535 insertions(+), 1136 deletions(-) delete mode 100644 repos/base/src/lib/ldso/file.cc create mode 100644 repos/base/src/lib/ldso/include/region_map.h create mode 100644 repos/base/src/lib/ldso/include/types.h create mode 100644 repos/dde_rump/include/rump/bootstrap.h create mode 100644 repos/libports/src/lib/libc/libc_init.h diff --git a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc index a97645269b..485581f647 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -87,6 +87,13 @@ namespace Genode { */ extern void (*call_component_construct)(Genode::Env &) __attribute__((weak)); + + /* + * This function is normally provided by the cxx library, which is not + * used for lx_hybrid programs. For lx_hybrid programs, the exception + * handling is initialized by the host system's regular startup code. + */ + void init_exception_handling(Env &) { } } static void lx_hybrid_component_construct(Genode::Env &env) diff --git a/repos/base/include/base/env.h b/repos/base/include/base/env.h index 8ce8820ed4..4211304896 100644 --- a/repos/base/include/base/env.h +++ b/repos/base/include/base/env.h @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include /* maintain compatibility to deprecated API */ #include @@ -64,6 +64,15 @@ struct Genode::Env virtual Ram_session_capability ram_session_cap() = 0; virtual Cpu_session_capability cpu_session_cap() = 0; + + /* + * XXX temporary + * + * The PD session capability is solely used for upgrading the PD session, + * e.g., when the dynamic linker attaches dataspaces to the linker area. + * Once we add 'Env::upgrade', we can remove this accessor. + */ + virtual Pd_session_capability pd_session_cap() = 0; }; #endif /* _INCLUDE__BASE__ENV_H_ */ diff --git a/repos/base/include/base/shared_object.h b/repos/base/include/base/shared_object.h index 3fdd085190..b04a1171ef 100644 --- a/repos/base/include/base/shared_object.h +++ b/repos/base/include/base/shared_object.h @@ -29,29 +29,36 @@ class Genode::Shared_object private: void *_handle = nullptr; - void *_lookup(const char *symbol) const; + Allocator &_md_alloc; + public: - class Invalid_file : public Genode::Exception { }; - class Invalid_symbol : public Genode::Exception { }; + class Invalid_rom_module : public Genode::Exception { }; + class Invalid_symbol : public Genode::Exception { }; - enum open_flags { - NOW = 0x1, - LAZY = 0x2, - KEEP = 0x4, /* do not unload on destruction */ - }; + enum Keep { DONT_KEEP, KEEP }; + enum Bind { BIND_LAZY, BIND_NOW }; /** * Load shared object and dependencies * - * \param file Shared object to load - * \param flags LAZY for lazy function binding, NOW for immediate binding + * \param env Genode environment, needed to obtain the ROM module + * for the shared object and to populate the linker + * area of the component's address space + * \param md_alloc backing store for the linker's dynamically allocated + * meta data + * \param name ROM module name of shared object to load + * \param bind bind functions immediately (BIND_NOW) or on + * demand (BIND_LAZY) + * \param keep unload ELF object if no longer needed (DONT_KEEP), + * or keep ELF object loaded at all times (KEEP) * - * \throw Invalid_file + * \throw Invalid_rom_module */ - Shared_object(char const *file = nullptr, unsigned flags = LAZY); + Shared_object(Env &, Allocator &md_alloc, char const *name, + Bind bind, Keep keep); /** * Close and unload shared object @@ -78,16 +85,16 @@ class Genode::Shared_object struct Link_map { Genode::addr_t addr; /* load address */ - char const *path; /* object path */ - void const *dynamic; /* pointer to DYNAMIC section */ - Link_map *next; - Link_map *prev; + char const *path; /* object path */ + void const *dynamic; /* pointer to DYNAMIC section */ + Link_map const *next; + Link_map const *prev; }; /** * Return link map of shared object */ - Link_map const * link_map() const; + Link_map const &link_map() const; }; diff --git a/repos/base/lib/mk/cxx.mk b/repos/base/lib/mk/cxx.mk index 7870d2f91f..bcc546dff0 100644 --- a/repos/base/lib/mk/cxx.mk +++ b/repos/base/lib/mk/cxx.mk @@ -1,4 +1,5 @@ CXX_SRC_CC += misc.cc new_delete.cc malloc_free.cc exception.cc guard.cc +INC_DIR += $(REP_DIR)/src/include # We need the libsupc++ include directory STDINC = yes diff --git a/repos/base/lib/mk/ldso.inc b/repos/base/lib/mk/ldso.inc index 24a6a4477c..8c19be304a 100644 --- a/repos/base/lib/mk/ldso.inc +++ b/repos/base/lib/mk/ldso.inc @@ -4,7 +4,7 @@ DIR = $(REP_DIR)/src/lib/ldso include $(BASE_DIR)/mk/base-libs.mk LIBS = $(BASE_LIBS) -SRC_CC = main.cc test.cc exception.cc file.cc dependency.cc debug.cc \ +SRC_CC = main.cc test.cc exception.cc dependency.cc debug.cc \ shared_object.cc SRC_S = jmp_slot.s INC_DIR += $(DIR)/include diff --git a/repos/base/src/include/base/internal/globals.h b/repos/base/src/include/base/internal/globals.h index 9b279256f5..e3975b7cc6 100644 --- a/repos/base/src/include/base/internal/globals.h +++ b/repos/base/src/include/base/internal/globals.h @@ -26,6 +26,9 @@ namespace Genode { extern Region_map *env_stack_area_region_map; extern Ram_session *env_stack_area_ram_session; + void init_exception_handling(Env &); + void init_cxx_heap(Env &); + void init_ldso_phdr(Env &); void init_signal_thread(Env &); void init_log(); } diff --git a/repos/base/src/lib/base/component.cc b/repos/base/src/lib/base/component.cc index 9a10cb03e1..d666d66d38 100644 --- a/repos/base/src/lib/base/component.cc +++ b/repos/base/src/lib/base/component.cc @@ -16,6 +16,9 @@ #include #include +/* base-internal includes */ +#include + namespace { @@ -41,6 +44,11 @@ namespace { { return Genode::env()->cpu_session_cap(); } + + Genode::Pd_session_capability pd_session_cap() override + { + return Genode::env()->pd_session_cap(); + } }; } @@ -61,6 +69,8 @@ struct Genode::Startup { ::Env env { ep }; + bool const exception_handling = (init_exception_handling(env), true); + /* * The construction of the main entrypoint does never return. */ diff --git a/repos/base/src/lib/cxx/exception.cc b/repos/base/src/lib/cxx/exception.cc index 0408c99cbb..5c849333b1 100644 --- a/repos/base/src/lib/cxx/exception.cc +++ b/repos/base/src/lib/cxx/exception.cc @@ -19,6 +19,9 @@ #include #include +/* base-internal includes */ +#include + extern "C" char __eh_frame_start__[]; /* from linker script */ extern "C" void __register_frame (const void *begin); /* from libgcc_eh */ extern "C" char *__cxa_demangle(const char *mangled_name, @@ -69,13 +72,46 @@ void terminate_handler() } +/** + * Init program headers of the dynamic linker + * + * The weak function is used for statically linked binaries. The + * dynamic linker provides an implementation that loads the program + * headers of the linker. This must be done before the first exception + * is thrown. + */ +void Genode::init_ldso_phdr(Env &) __attribute__((weak)); +void Genode::init_ldso_phdr(Env &) { } + + /* * Initialization */ - -void init_exception_handling() +void Genode::init_exception_handling(Env &env) { + init_ldso_phdr(env); + init_cxx_heap(env); + __register_frame(__eh_frame_start__); std::set_terminate(terminate_handler); + + /* + * Trigger first exception. This step has two purposes. + * First, it enables us to detect problems related to exception handling as + * early as possible. If there are problems with the C++ support library, + * it is much easier to debug them at this early stage. Otherwise problems + * with half-working exception handling cause subtle failures that are hard + * to interpret. + * + * Second, the C++ support library allocates data structures lazily on the + * first occurrence of an exception. In some corner cases, this allocation + * consumes several KB of stack. This is usually not a problem when the + * first exception is triggered from the main thread but it becomes an + * issue when the first exception is thrown from the stack of a thread with + * a specially tailored (and otherwise sufficient) stack size. By throwing + * an exception here, we mitigate this issue by eagerly performing those + * allocations. + */ + try { throw 1; } catch (...) { } } diff --git a/repos/base/src/lib/cxx/malloc_free.cc b/repos/base/src/lib/cxx/malloc_free.cc index 6dcfaa8b73..81eda0c318 100644 --- a/repos/base/src/lib/cxx/malloc_free.cc +++ b/repos/base/src/lib/cxx/malloc_free.cc @@ -14,37 +14,44 @@ * under the terms of the GNU General Public License version 2. */ +/* Genode includes */ #include #include #include +#include + +/* base-internal includes */ +#include using namespace Genode; +static Lazy_volatile_object &cxx_heap() +{ + static Lazy_volatile_object heap; + return heap; +} + + /** * Return heap partition for the private use within the cxx library. * - * If we used the 'env()->heap()' with the C++ runtime, we would run into a - * deadlock when a 'Ram_session::Alloc_failed' exception is thrown from within - * 'Heap::alloc'. For creating the exception object, the C++ runtime calls - * '__cxa_allocate_exception', which, in turn, calls 'malloc'. If our 'malloc' - * implementation called 'env()->heap()->alloc()', we would end up in a - * recursive attempt to obtain the 'env()->heap()' lock. - * - * By using a dedicated heap instance for the cxx library, we avoid this - * circular condition. + * For creating the exception object, the C++ runtime calls + * '__cxa_allocate_exception', which, in turn, calls 'malloc'. The cxx library + * uses a local implementation of 'malloc' using a dedicated heap instance. */ -static Heap *cxx_heap() +void Genode::init_cxx_heap(Env &env) { + if (cxx_heap().constructed()) return; + /* * Exception frames are small. Hence, a small static backing store suffices - * for the cxx heap partition in the normal case. The 'env()->ram_session' + * for the cxx heap partition in the normal case. The 'env.ram()' session * is used only if the demand exceeds the capacity of the 'initial_block'. */ static char initial_block[1024*sizeof(long)]; - static Heap heap(env()->ram_session(), env()->rm_session(), - Heap::UNLIMITED, initial_block, sizeof(initial_block)); - return &heap; + cxx_heap().construct(&env.ram(), &env.rm(), + Heap::UNLIMITED, initial_block, sizeof(initial_block)); } diff --git a/repos/base/src/lib/ldso/debug.cc b/repos/base/src/lib/ldso/debug.cc index 021c5e2882..da33959f5a 100644 --- a/repos/base/src/lib/ldso/debug.cc +++ b/repos/base/src/lib/ldso/debug.cc @@ -26,15 +26,15 @@ void binary_ready_hook_for_gdb() { } extern "C" void brk(Linker::Debug *, Linker::Link_map *) { } -void Linker::dump_link_map(Object *o) +void Linker::dump_link_map(Object const &obj) { - for (; o; o = o->next_obj()) { + for (Object const *o = &obj; o; o = o->next_obj()) { if (o->is_binary()) continue; - Genode::log(" ", Genode::Hex(o->link_map()->addr), - " .. ", Genode::Hex(o->link_map()->addr + o->size() - 1), - ": ", o->name()); + log(" ", Hex(o->link_map().addr), + " .. ", Hex(o->link_map().addr + o->size() - 1), + ": ", o->name()); } } diff --git a/repos/base/src/lib/ldso/dependency.cc b/repos/base/src/lib/ldso/dependency.cc index 191e7885c6..83d70b64e2 100644 --- a/repos/base/src/lib/ldso/dependency.cc +++ b/repos/base/src/lib/ldso/dependency.cc @@ -19,63 +19,77 @@ /** * Dependency node */ -Linker::Dependency::Dependency(char const *path, Root_object *root, - Genode::Fifo * const dep, - unsigned flags) - : obj(load(path, this, flags)), root(root) +Linker::Dependency::Dependency(Env &env, Allocator &md_alloc, + char const *path, Root_object *root, + Fifo &deps, + Keep keep) +: + _obj(load(env, md_alloc, path, *this, keep)), + _root(root), + _md_alloc(&md_alloc) { - dep->enqueue(this); - load_needed(dep, flags); + deps.enqueue(this); + load_needed(env, *_md_alloc, deps, keep); } Linker::Dependency::~Dependency() { - if (obj->unload()) { + if (!_obj.unload()) + return; - if (verbose_loading) - Genode::log("Destroy: ", obj->name()); + if (verbose_loading) + log("Destroy: ", _obj.name()); - destroy(Genode::env()->heap(), obj); - } + destroy(_md_alloc, &_obj); } -bool Linker::Dependency::in_dep(char const *file, - Genode::Fifo * const dep) +bool Linker::Dependency::in_dep(char const *file, Fifo const &dep) { - for (Dependency *d = dep->head(); d; d = d->next()) - if (!Genode::strcmp(file, d->obj->name())) + for (Dependency const *d = dep.head(); d; d = d->next()) + if (!strcmp(file, d->obj().name())) return true; return false; } -void Linker::Dependency::load_needed(Genode::Fifo * const dep, - unsigned flags) +void Linker::Dependency::load_needed(Env &env, Allocator &md_alloc, + Fifo &deps, Keep keep) { - for (Dynamic::Needed *n = obj->dynamic()->needed.head(); n; n = n->next()) { - char const *path = n->path(obj->dynamic()->strtab); + _obj.dynamic().for_each_dependency([&] (char const *path) { - Object *o; - if (!in_dep(Linker::file(path), dep)) - new (Genode::env()->heap()) Dependency(path, root, dep, flags); + if (!in_dep(Linker::file(path), deps)) + new (md_alloc) Dependency(env, md_alloc, path, _root, deps, keep); /* re-order initializer list, if needed object has been already added */ - else if ((o = Init::list()->contains(Linker::file(path)))) + else if (Object *o = Init::list()->contains(Linker::file(path))) Init::list()->reorder(o); - } + }); } -Linker::Root_object::Root_object(char const *path, unsigned flags) +Linker::Dependency const &Linker::Dependency::first() const { - new (Genode::env()->heap()) Dependency(path, this, &dep, flags); + return _root ? *_root->first_dep() : *this; +} + + +Linker::Root_object::Root_object(Env &env, Allocator &md_alloc, + char const *path, Bind bind, Keep keep) +: + _md_alloc(md_alloc) +{ + /* + * The life time of 'Dependency' objects is managed via reference + * counting. Hence, we don't need to remember them here. + */ + new (md_alloc) Dependency(env, md_alloc, path, this, _deps, keep); /* provide Genode base library access */ - new (Genode::env()->heap()) Dependency(linker_name(), this, &dep); + new (md_alloc) Dependency(env, md_alloc, linker_name(), this, _deps, DONT_KEEP); /* relocate and call constructors */ - Init::list()->initialize(); + Init::list()->initialize(bind); } diff --git a/repos/base/src/lib/ldso/exception.cc b/repos/base/src/lib/ldso/exception.cc index ea055b23d4..bdfb6685c2 100644 --- a/repos/base/src/lib/ldso/exception.cc +++ b/repos/base/src/lib/ldso/exception.cc @@ -11,6 +11,7 @@ * under the terms of the GNU General Public License version 2. */ +#include #include @@ -32,12 +33,12 @@ struct Phdr_info }; -extern "C" int dl_iterate_phdr(int (*callback) (Phdr_info *info, Genode::size_t size, void *data), void *data) +extern "C" int dl_iterate_phdr(int (*callback) (Phdr_info *info, size_t size, void *data), void *data) { int err = 0; Phdr_info info; - Genode::Lock::Guard guard(Object::lock()); + Lock::Guard guard(lock()); for (Object *e = obj_list_head();e; e = e->next_obj()) { @@ -47,7 +48,7 @@ extern "C" int dl_iterate_phdr(int (*callback) (Phdr_info *info, Genode::size_t info.phnum = e->file()->phdr.count; if (verbose_exception) - Genode::log(e->name(), " reloc ", Genode::Hex(e->reloc_base())); + log(e->name(), " reloc ", Hex(e->reloc_base())); if ((err = callback(&info, sizeof(Phdr_info), data))) break; @@ -87,16 +88,10 @@ extern "C" unsigned long dl_unwind_find_exidx(unsigned long pc, int *pcount) 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()) { - 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; + 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)) diff --git a/repos/base/src/lib/ldso/file.cc b/repos/base/src/lib/ldso/file.cc deleted file mode 100644 index 8f9ebce24c..0000000000 --- a/repos/base/src/lib/ldso/file.cc +++ /dev/null @@ -1,331 +0,0 @@ -/** - * \brief ELF loading/unloading support - * \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. - */ - -/* local includes */ -#include -#include - -/* Genode includes */ -#include -#include -#include -#include -#include -#include - -char const *Linker::ELFMAG = "\177ELF"; - -using namespace Linker; -using namespace Genode; - -namespace Linker -{ - class Rm_area; - struct Elf_file; -} - -/** - * Managed dataspace for ELF files (singelton) - */ -class Linker::Rm_area -{ - public: - - typedef Region_map_client::Local_addr Local_addr; - typedef Region_map_client::Region_conflict Region_conflict; - - private: - - Region_map_client _rm; - - addr_t _base; /* base address of dataspace */ - Allocator_avl _range; /* VM range allocator */ - - protected: - - Rm_area(addr_t base) - : _rm(env()->pd_session()->linker_area()), _range(env()->heap()) - { - _base = (addr_t) env()->rm_session()->attach_at(_rm.dataspace(), base); - _range.add_range(base, Pd_session::LINKER_AREA_SIZE); - } - - public: - - static Rm_area *r(addr_t base = 0) - { - /* - * The capabilities in this class become invalid when doing a - * fork in the noux environment. Hence avoid destruction of - * the singleton object as the destructor would try to access - * the capabilities also in the forked process. - */ - static bool constructed = 0; - static char placeholder[sizeof(Rm_area)]; - if (!constructed) { - construct_at(placeholder, base); - constructed = 1; - } - return reinterpret_cast(placeholder); - } - - /** - * Reserve VM region of 'size' at 'vaddr'. Allocate any free region if - * 'vaddr' is zero - */ - addr_t alloc_region(size_t size, addr_t vaddr = 0) - { - addr_t addr = vaddr; - - if (addr && (_range.alloc_addr(size, addr).error())) - throw Region_conflict(); - else if (!addr && - _range.alloc_aligned(size, (void **)&addr, - get_page_size_log2()).error()) - { - throw Region_conflict(); - } - - return addr; - } - - void free_region(addr_t vaddr) { _range.free((void *)vaddr); } - - /** - * Overwritten from 'Region_map_client' - */ - Local_addr attach_at(Dataspace_capability ds, addr_t local_addr, - size_t size = 0, off_t offset = 0) - { - return retry( - [&] () { - return _rm.attach_at(ds, local_addr - _base, size, offset); - }, - [&] () { env()->parent()->upgrade(env()->pd_session_cap(), "ram_quota=8K"); }); - } - - /** - * Overwritten from 'Region_map_client' - */ - Local_addr attach_executable(Dataspace_capability ds, addr_t local_addr, - size_t size = 0, off_t offset = 0) - { - return retry( - [&] () { - return _rm.attach_executable(ds, local_addr - _base, size, offset); - }, - [&] () { env()->parent()->upgrade(env()->pd_session_cap(), "ram_quota=8K"); }); - } - - void detach(Local_addr local_addr) { _rm.detach((addr_t)local_addr - _base); } -}; - - -/** - * Map ELF files - */ -struct Linker::Elf_file : File -{ - Rom_connection rom; - Ram_dataspace_capability ram_cap[Phdr::MAX_PHDR]; - bool loaded; - Elf_file(char const *name, bool load = true) - : - rom(name), loaded(load) - { - load_phdr(); - - if (load) - load_segments(); - } - - virtual ~Elf_file() - { - if (loaded) - unload_segments(); - } - - /** - * Check if ELF is sane - */ - bool check_compat(Elf::Ehdr const *ehdr) - { - if (memcmp(ehdr, ELFMAG, SELFMAG) != 0) { - Genode::error("LD: binary is not an ELF"); - return false; - } - - if (ehdr->e_ident[EI_CLASS] != ELFCLASS) { - Genode::error("LD: support for 32/64-bit objects only"); - return false; - } - - return true; - } - - /** - * Copy program headers and read entry point - */ - void load_phdr() - { - Elf::Ehdr *ehdr = (Elf::Ehdr *)env()->rm_session()->attach(rom.dataspace(), 0x1000); - - if (!check_compat(ehdr)) - throw Incompatible(); - - /* set entry point and program header information */ - phdr.count = ehdr->e_phnum; - entry = (Entry)ehdr->e_entry; - - /* copy program headers */ - addr_t header = (addr_t)ehdr + ehdr->e_phoff; - for (unsigned i = 0; i < phdr.count; i++, header += ehdr->e_phentsize) - memcpy(&phdr.phdr[i], (void *)header, ehdr->e_phentsize); - - env()->rm_session()->detach(ehdr); - - Phdr p; - loadable_segments(p); - /* start vaddr */ - start = trunc_page(p.phdr[0].p_vaddr); - Elf::Phdr *ph = &p.phdr[p.count - 1]; - /* size of lodable segments */ - size = round_page(ph->p_vaddr + ph->p_memsz) - start; - } - - /** - * Find PT_LOAD segemnts - */ - void loadable_segments(Phdr &result) - { - for (unsigned i = 0; i < phdr.count; i++) { - Elf::Phdr *ph = &phdr.phdr[i]; - - if (ph->p_type != PT_LOAD) - continue; - - if (ph->p_align & (0x1000 - 1)) { - Genode::error("LD: Unsupported alignment ", (void *)ph->p_align); - throw Incompatible(); - } - - result.phdr[result.count++] = *ph; - } - } - - bool is_rx(Elf::Phdr const &ph) { - return ((ph.p_flags & PF_MASK) == (PF_R | PF_X)); } - - bool is_rw(Elf::Phdr const &ph) { - return ((ph.p_flags & PF_MASK) == (PF_R | PF_W)); } - - /** - * Load PT_LOAD segments - */ - void load_segments() - { - Phdr p; - - /* search for PT_LOAD */ - loadable_segments(p); - - /* allocate region */ - reloc_base = Rm_area::r(start)->alloc_region(size, start); - reloc_base = (start == reloc_base) ? 0 : reloc_base; - - if (verbose_loading) - Genode::log("LD: reloc_base: ", Genode::Hex(reloc_base), - " start: ", Genode::Hex(start), - " end: ", Genode::Hex(reloc_base + start + size)); - - for (unsigned i = 0; i < p.count; i++) { - Elf::Phdr *ph = &p.phdr[i]; - - if (is_rx(*ph)) - load_segment_rx(*ph); - - else if (is_rw(*ph)) - load_segment_rw(*ph, i); - - else { - Genode::error("LD: Non-RW/RX segment"); - throw Invalid_file(); - } - } - } - - /** - * Map read-only segment - */ - void load_segment_rx(Elf::Phdr const &p) - { - Rm_area::r()->attach_executable(rom.dataspace(), - trunc_page(p.p_vaddr) + reloc_base, - round_page(p.p_memsz), - trunc_page(p.p_offset)); - } - - /** - * Copy read-write segment - */ - void load_segment_rw(Elf::Phdr const &p, int nr) - { - void *src = env()->rm_session()->attach(rom.dataspace(), 0, p.p_offset); - addr_t dst = p.p_vaddr + reloc_base; - - ram_cap[nr] = env()->ram_session()->alloc(p.p_memsz); - Rm_area::r()->attach_at(ram_cap[nr], dst); - - memcpy((void*)dst, src, p.p_filesz); - - /* clear if file size < memory size */ - if (p.p_filesz < p.p_memsz) - memset((void *)(dst + p.p_filesz), 0, p.p_memsz - p.p_filesz); - - env()->rm_session()->detach(src); - } - - /** - * Unmap segements, RM regions, and free allocated dataspaces - */ - void unload_segments() - { - Phdr p; - loadable_segments(p); - - /* detach from RM area */ - for (unsigned i = 0; i < p.count; i++) - Rm_area::r()->detach(trunc_page(p.phdr[i].p_vaddr) + reloc_base); - - /* free region from RM area */ - Rm_area::r()->free_region(trunc_page(p.phdr[0].p_vaddr) + reloc_base); - - /* free ram of RW segments */ - for (unsigned i = 0; i < Phdr::MAX_PHDR; i++) - if (ram_cap[i].valid()) { - env()->ram_session()->free(ram_cap[i]); - } - } -}; - - -File const *Linker::load(char const *path, bool load) -{ - if (verbose_loading) - Genode::log("LD loading: ", path, " " - "(PHDRS only: ", load ? "no" : "yes", ")"); - - Elf_file *file = new (env()->heap()) Elf_file(Linker::file(path), load); - return file; -} - diff --git a/repos/base/src/lib/ldso/include/debug.h b/repos/base/src/lib/ldso/include/debug.h index 9e11b98797..62d6e80014 100644 --- a/repos/base/src/lib/ldso/include/debug.h +++ b/repos/base/src/lib/ldso/include/debug.h @@ -18,14 +18,21 @@ #include #include -constexpr bool verbose_link_map = false; +/* local includes */ +#include + +constexpr bool verbose_link_map = false; +constexpr bool verbose_lookup = false; +constexpr bool verbose_exception = false; +constexpr bool verbose_shared = false; +constexpr bool verbose_loading = false; namespace Linker { struct Debug; struct Link_map; struct Object; - void dump_link_map(Object *o); + void dump_link_map(Object const &); } /* @@ -128,9 +135,9 @@ struct Linker::Link_map return; for (Link_map *m = first; m; m = m->next) - Genode::log("MAP: addr: ", Genode::Hex(m->addr), - " dynamic: ", m->dynamic, " ", Genode::Cstring(m->path), - " m: ", m, " p: ", m->prev, " n: ", m->next); + log("MAP: addr: ", Hex(m->addr), + " dynamic: ", m->dynamic, " ", Cstring(m->path), + " m: ", m, " p: ", m->prev, " n: ", m->next); } }; diff --git a/repos/base/src/lib/ldso/include/dynamic.h b/repos/base/src/lib/ldso/include/dynamic.h index 1077211db4..bc96fb51c3 100644 --- a/repos/base/src/lib/ldso/include/dynamic.h +++ b/repos/base/src/lib/ldso/include/dynamic.h @@ -14,6 +14,8 @@ #ifndef _INCLUDE__DYNAMIC_H_ #define _INCLUDE__DYNAMIC_H_ +/* local includes */ +#include #include namespace Linker { @@ -54,162 +56,297 @@ struct Linker::Hash_table /** * .dynamic section entries */ -struct Linker::Dynamic +class Linker::Dynamic { - struct Needed : Genode::Fifo::Element - { - Genode::off_t offset; + public: - Needed(Genode::off_t offset) : offset(offset) { } + class Dynamic_section_missing { }; - char const *path(char const *strtab) + private: + + struct Needed : Fifo::Element { - return ((char const *)(strtab + offset)); + off_t offset; + + Needed(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; + + Allocator *_md_alloc = nullptr; + + 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; + + Fifo _needed; + + /** + * \throw Dynamic_section_missing + */ + 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()); + + throw Dynamic_section_missing(); } - char const *name(char const *strtab) + void _section_dt_needed(Elf::Dyn const *d) { - return file(path(strtab)); + if (!_md_alloc) { + error("unexpected call of section_dt_needed"); + return; + } + Needed *n = new (*_md_alloc) Needed(d->un.ptr); + _needed.enqueue(n); } - }; - Dependency const *dep; - Object const *obj; - Elf::Dyn const *dynamic; + template + void _section(T *member, Elf::Dyn const *d) + { + *member = (T)(_obj.reloc_base() + d->un.ptr); + } - Hash_table *hash_table = nullptr; + void _section_dt_debug(Elf::Dyn const *d) + { + Elf::Dyn *_d = const_cast(d); + _d->un.ptr = (Elf::Addr)Debug::d(); + } - 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 *)dynamic_address()) - { - 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; + 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(); + public: - if (pltrel_size) { - switch (pltrel_type) { + enum Pass { FIRST_PASS, SECOND_PASS }; + Dynamic(Dependency const &dep) + : + _dep(&dep), _obj(dep.obj()), _dynamic(*(Elf::Dyn *)dynamic_address()) + { + _init(); + } + + Dynamic(Allocator &md_alloc, Dependency const &dep, Object const &obj, + Linker::Phdr const *phdr) + : + _dep(&dep), _obj(obj), _dynamic(_find_dynamic(phdr)), _md_alloc(&md_alloc) + { + _init(); + } + + ~Dynamic() + { + if (!_md_alloc) + return; + + while (Needed *n = _needed.dequeue()) + destroy(*_md_alloc, n); + } + + void call_init_function() const + { + if (!_init_function) + return; + + if (verbose_relocation) + log(_obj.name(), " init func ", _init_function); + + _init_function(); + } + + Elf::Sym const *symbol(unsigned sym_index) const + { + if (sym_index > _hash_table->nchains()) + return nullptr; + + return _symtab + sym_index; + } + + char const *symbol_name(Elf::Sym const &sym) const + { + return _strtab + sym.st_name; + } + + void const *dynamic_ptr() const { return &_dynamic; } + + void dep(Dependency const &dep) { _dep = &dep; } + + Dependency const &dep() const { return *_dep; } + + /* + * Use DT_HASH table address for linker, assuming that it will always be at + * the beginning of the file + */ + Elf::Addr link_map_addr() const { return trunc_page((Elf::Addr)_hash_table); } + + /** + * Lookup symbol name in this ELF + */ + Elf::Sym const *lookup_symbol(char const *name, unsigned long hash) const + { + Hash_table *h = _hash_table; + + if (!h->buckets()) + return nullptr; + + unsigned long sym_index = h->buckets()[hash % h->nbuckets()]; + + /* traverse hash chain */ + for (; sym_index != STN_UNDEF; sym_index = h->chains()[sym_index]) + { + /* bad object */ + if (sym_index > h->nchains()) + return nullptr; + + Elf::Sym const *sym = symbol(sym_index); + char const *sym_name = symbol_name(*sym); + + /* this omitts everything but 'NOTYPE', 'OBJECT', and 'FUNC' */ + if (sym->type() > STT_FUNC) + continue; + + if (sym->st_value == 0) + continue; + + /* check for symbol name */ + if (name[0] != sym_name[0] || strcmp(name, sym_name)) + continue; + + return sym; + } + + return nullptr; + } + + /** + * \throw Address_info::Invalid_address + */ + Elf::Sym const &symbol_by_addr(addr_t addr) const + { + addr_t const reloc_base = _obj.reloc_base(); + + for (unsigned long i = 0; i < _hash_table->nchains(); i++) + { + Elf::Sym const *sym = symbol(i); + if (!sym) + continue; + + /* skip */ + if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON) + continue; + + addr_t const sym_addr = reloc_base + sym->st_value; + if (addr < sym_addr || addr >= sym_addr + sym->st_size) + continue; + + return *sym; + } + throw Address_info::Invalid_address(); + } + + /** + * Call functor for each dependency, passing the path as argument + */ + template + void for_each_dependency(FUNC const &fn) const + { + for (Needed *n = _needed.head(); n; n = n->next()) + fn(n->path(_strtab)); + } + + void relocate(Bind bind) + { + plt_setup(); + + if (_pltrel_size) { + switch (_pltrel_type) { case DT_RELA: case DT_REL: - Reloc_plt(obj, pltrel_type, pltrel, pltrel_size); + Reloc_plt(_obj, _pltrel_type, _pltrel, _pltrel_size); break; default: - Genode::error("LD: Invalid PLT relocation ", (int)pltrel_type); + error("LD: Invalid PLT relocation ", (int)_pltrel_type); throw Incompatible(); + } } + + relocate_non_plt(bind, FIRST_PASS); } - relocate_non_plt(); - } + void plt_setup() + { + if (_pltgot) + Plt_got r(*_dep, _pltgot); + } - void plt_setup() - { - if (pltgot) - Plt_got r(dep, pltgot); - } + void relocate_non_plt(Bind bind, Pass pass) + { + if (_reloca) + Reloc_non_plt r(*_dep, _reloca, _reloca_size); - 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, pass == SECOND_PASS); - if (rel) - Reloc_non_plt r(dep, rel, rel_size, second_pass); + if (bind == BIND_NOW) + Reloc_bind_now r(*_dep, _pltrel, _pltrel_size); + } - if (bind_now) - Reloc_bind_now r(dep, pltrel, pltrel_size); - } + Elf::Rel const *pltrel() const { return _pltrel; } + D_tag pltrel_type() const { return _pltrel_type; } }; #endif /* _INCLUDE__DYNAMIC_H_ */ diff --git a/repos/base/src/lib/ldso/include/file.h b/repos/base/src/lib/ldso/include/file.h index 4994ecb47f..2400e24c55 100644 --- a/repos/base/src/lib/ldso/include/file.h +++ b/repos/base/src/lib/ldso/include/file.h @@ -1,4 +1,4 @@ -/** +/* * \brief ELF file setup * \author Sebastian Sumpf * \date 2015-03-12 @@ -14,23 +14,20 @@ #ifndef _INCLUDE__FILE_H_ #define _INCLUDE__FILE_H_ +/* Genode includes */ +#include + +/* local includes */ +#include +#include +#include + + 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); + struct Elf_file; } @@ -47,7 +44,7 @@ struct Linker::Phdr /** - * Loaded ELF file + * ELF file info */ struct Linker::File { @@ -72,4 +69,208 @@ struct Linker::File unsigned elf_phdr_count() const { return phdr.count; } }; + +/** + * Mapped ELF file + */ +struct Linker::Elf_file : File +{ + Env &env; + Rom_connection rom; + Ram_dataspace_capability ram_cap[Phdr::MAX_PHDR]; + bool const loaded; + + Elf_file(Env &env, Allocator &md_alloc, char const *name, bool load) + : + env(env), rom(env, name), loaded(load) + { + load_phdr(); + + /* + * Initialize the linker area at the link address of the binary, + * which happens to be the first loaded 'Elf_file'. + * + * XXX Move this initialization to the linker's 'construct' function + * once we use relocatable binaries. + */ + if (load && !Region_map::r().constructed()) + Region_map::r().construct(env, md_alloc, start); + + if (load) + load_segments(); + } + + virtual ~Elf_file() + { + if (loaded) + unload_segments(); + } + + /** + * Check if ELF is sane + */ + bool check_compat(Elf::Ehdr const &ehdr) + { + char const * const ELFMAG = "\177ELF"; + if (memcmp(&ehdr, ELFMAG, SELFMAG) != 0) { + error("LD: binary is not an ELF"); + return false; + } + + if (ehdr.e_ident[EI_CLASS] != ELFCLASS) { + error("LD: support for 32/64-bit objects only"); + return false; + } + + return true; + } + + /** + * Copy program headers and read entry point + */ + void load_phdr() + { + { + /* temporary map the binary to read the program header */ + Attached_dataspace ds(env.rm(), rom.dataspace()); + + Elf::Ehdr const &ehdr = *ds.local_addr(); + + if (!check_compat(ehdr)) + throw Incompatible(); + + /* set entry point and program header information */ + phdr.count = ehdr.e_phnum; + entry = (Entry)ehdr.e_entry; + + /* copy program headers */ + addr_t header = (addr_t)&ehdr + ehdr.e_phoff; + for (unsigned i = 0; i < phdr.count; i++, header += ehdr.e_phentsize) + memcpy(&phdr.phdr[i], (void *)header, ehdr.e_phentsize); + } + + Phdr p; + loadable_segments(p); + /* start vaddr */ + start = trunc_page(p.phdr[0].p_vaddr); + Elf::Phdr *ph = &p.phdr[p.count - 1]; + /* size of lodable segments */ + size = round_page(ph->p_vaddr + ph->p_memsz) - start; + } + + /** + * Find PT_LOAD segemnts + */ + void loadable_segments(Phdr &result) + { + for (unsigned i = 0; i < phdr.count; i++) { + Elf::Phdr *ph = &phdr.phdr[i]; + + if (ph->p_type != PT_LOAD) + continue; + + if (ph->p_align & (0x1000 - 1)) { + error("LD: Unsupported alignment ", (void *)ph->p_align); + throw Incompatible(); + } + + result.phdr[result.count++] = *ph; + } + } + + bool is_rx(Elf::Phdr const &ph) { + return ((ph.p_flags & PF_MASK) == (PF_R | PF_X)); } + + bool is_rw(Elf::Phdr const &ph) { + return ((ph.p_flags & PF_MASK) == (PF_R | PF_W)); } + + /** + * Load PT_LOAD segments + */ + void load_segments() + { + Phdr p; + + /* search for PT_LOAD */ + loadable_segments(p); + + /* allocate region */ + reloc_base = Region_map::r()->alloc_region(size, start); + reloc_base = (start == reloc_base) ? 0 : reloc_base; + + if (verbose_loading) + log("LD: reloc_base: ", Hex(reloc_base), + " start: ", Hex(start), + " end: ", Hex(reloc_base + start + size)); + + for (unsigned i = 0; i < p.count; i++) { + Elf::Phdr *ph = &p.phdr[i]; + + if (is_rx(*ph)) + load_segment_rx(*ph); + + else if (is_rw(*ph)) + load_segment_rw(*ph, i); + + else { + error("LD: Non-RW/RX segment"); + throw Invalid_file(); + } + } + } + + /** + * Map read-only segment + */ + void load_segment_rx(Elf::Phdr const &p) + { + Region_map::r()->attach_executable(rom.dataspace(), + trunc_page(p.p_vaddr) + reloc_base, + round_page(p.p_memsz), + trunc_page(p.p_offset)); + } + + /** + * Copy read-write segment + */ + void load_segment_rw(Elf::Phdr const &p, int nr) + { + void *src = env.rm().attach(rom.dataspace(), 0, p.p_offset); + addr_t dst = p.p_vaddr + reloc_base; + + ram_cap[nr] = env.ram().alloc(p.p_memsz); + Region_map::r()->attach_at(ram_cap[nr], dst); + + memcpy((void*)dst, src, p.p_filesz); + + /* clear if file size < memory size */ + if (p.p_filesz < p.p_memsz) + memset((void *)(dst + p.p_filesz), 0, p.p_memsz - p.p_filesz); + + env.rm().detach(src); + } + + /** + * Unmap segements, RM regions, and free allocated dataspaces + */ + void unload_segments() + { + Phdr p; + loadable_segments(p); + + /* detach from RM area */ + for (unsigned i = 0; i < p.count; i++) + Region_map::r()->detach(trunc_page(p.phdr[i].p_vaddr) + reloc_base); + + /* free region from RM area */ + Region_map::r()->free_region(trunc_page(p.phdr[0].p_vaddr) + reloc_base); + + /* free ram of RW segments */ + for (unsigned i = 0; i < Phdr::MAX_PHDR; i++) + if (ram_cap[i].valid()) { + env.ram().free(ram_cap[i]); + } + } +}; + #endif /* _INCLUDE__FILE_H_ */ diff --git a/repos/base/src/lib/ldso/include/init.h b/repos/base/src/lib/ldso/include/init.h index 2c180911a8..54c49d7d5b 100644 --- a/repos/base/src/lib/ldso/include/init.h +++ b/repos/base/src/lib/ldso/include/init.h @@ -25,7 +25,7 @@ namespace Linker { /** * Handle static construction and relocation of ELF files */ -struct Linker::Init : Genode::List +struct Linker::Init : List { bool in_progress = false; bool restart = false; @@ -39,7 +39,7 @@ struct Linker::Init : Genode::List Object *contains(char const *file) { for (Object *elf = first(); elf; elf = elf->next_init()) - if (!Genode::strcmp(file, elf->name())) + if (!strcmp(file, elf->name())) return elf; return nullptr; @@ -52,24 +52,25 @@ struct Linker::Init : Genode::List 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; + elf->dynamic().for_each_dependency([&] (char const *path) { - if ((e = contains(Linker::file(path)))) +// for (Dynamic::Needed *n = elf->dynamic().needed.head(); n; n = n->next()) { +// char const *path = n->path(elf->dynamic().strtab); + + if (Object *e = contains(Linker::file(path))) reorder(e); - } + }); } - void initialize() + void initialize(Bind bind) { Object *obj = first(); /* relocate */ for (; obj; obj = obj->next_init()) { if (verbose_relocation) - Genode::log("Relocate ", obj->name()); - obj->relocate(); + log("Relocate ", obj->name()); + obj->relocate(bind); } /* @@ -91,13 +92,7 @@ struct Linker::Init : Genode::List Object *next = obj->next_init(); remove(obj); - if (obj->dynamic()->init_function) { - - if (verbose_relocation) - Genode::log(obj->name(), " init func ", obj->dynamic()->init_function); - - obj->dynamic()->init_function(); - } + obj->dynamic().call_init_function(); obj = restart ? first() : next; restart = false; diff --git a/repos/base/src/lib/ldso/include/linker.h b/repos/base/src/lib/ldso/include/linker.h index edd48ee622..a43ebd3f90 100644 --- a/repos/base/src/lib/ldso/include/linker.h +++ b/repos/base/src/lib/ldso/include/linker.h @@ -1,4 +1,4 @@ -/** +/* * \brief Generic linker definitions * \author Sebastian Sumpf * \date 2014-10-24 @@ -14,28 +14,12 @@ #ifndef _INCLUDE__LINKER_H_ #define _INCLUDE__LINKER_H_ -#include -#include -#include -#include -#include -#include - +#include #include #include #include #include -/** - * Debugging - */ -constexpr bool verbose_lookup = false; -constexpr bool verbose_exception = false; -constexpr bool verbose_shared = false; -constexpr bool verbose_loading = false; - -extern Elf::Addr etext; - /** * Forward declartions and helpers */ @@ -48,11 +32,6 @@ namespace Linker { typedef void (*Func)(void); - /** - * Eager binding enable - */ - extern bool bind_now; - /** * Print diagnostic information * @@ -75,7 +54,7 @@ namespace Linker { * * \return Symbol information */ - Elf::Sym const *lookup_symbol(unsigned sym_index, Dependency const *, Elf::Addr *base, + Elf::Sym const *lookup_symbol(unsigned sym_index, Dependency const &, Elf::Addr *base, bool undef = false, bool other = false); /** @@ -93,20 +72,22 @@ namespace Linker { * * \return Symbol information */ - Elf::Sym const *lookup_symbol(char const *name, Dependency const *dep, Elf::Addr *base, + Elf::Sym const *lookup_symbol(char const *name, Dependency const &dep, Elf::Addr *base, bool undef = false, bool other = false); /** * Load an ELF (setup segments and map program header) * - * \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 + * \param md_alloc allocator used for dyamically allocater meta data + * \param path rom module to load + * \param dep dependency entry for new object + * \param flags 'Shared_object::KEEP' will not unload the ELF, + * if the reference count reaches zero * * \return Linker::Object */ - Object *load(char const *path, Dependency *dep, unsigned flags = 0); + Object &load(Env &, Allocator &md_alloc, char const *path, Dependency &dep, + Keep keep); /** * Returns the head of the global object list @@ -119,16 +100,9 @@ namespace Linker { Dependency *binary_root_dep(); /** - * Force to map the program header of the dynamic linker + * Global ELF access lock */ - void load_linker_phdr(); - - /** - * Exceptions - */ - class Incompatible : Genode::Exception { }; - class Invalid_file : Genode::Exception { }; - class Not_found : Genode::Exception { }; + Lock &lock(); /** * Invariants @@ -141,42 +115,45 @@ namespace Linker { /** * Shared object or binary */ -class Linker::Object : public Genode::Fifo::Element, - public Genode::List::Element +class Linker::Object : public Fifo::Element, + public List::Element { + public: + + typedef String<128> Name; + protected: - enum { MAX_PATH = 128 }; - - char _name[MAX_PATH]; + Name _name; File const *_file = nullptr; Elf::Addr _reloc_base = 0; public: - Object(Elf::Addr reloc_base) : _reloc_base(reloc_base) { } - Object(char const *path, File const *file) - : _file(file), _reloc_base(file->reloc_base) + void init(Name const &name, Elf::Addr reloc_base) { - Genode::strncpy(_name, Linker::file(path), MAX_PATH); + _name = name; + _reloc_base = reloc_base; } - virtual ~Object() + void init(Name const &name, File const &file) { - if (_file) - destroy(Genode::env()->heap(), const_cast(_file)); + _name = name; + _file = &file; + _reloc_base = file.reloc_base; } - Elf::Addr reloc_base() const { return _reloc_base; } - char const *name() const { return _name; } + virtual ~Object() { } - File const *file() { return _file; } - Elf::Size const size() const { return _file ? _file->size : 0; } + Elf::Addr reloc_base() const { return _reloc_base; } + char const *name() const { return _name.string(); } + File const *file() const { return _file; } + Elf::Size const size() const { return _file ? _file->size : 0; } virtual bool is_linker() const = 0; virtual bool is_binary() const = 0; - virtual void relocate() = 0; + virtual void relocate(Bind) = 0; virtual void load() = 0; virtual bool unload() { return false;} @@ -184,7 +161,7 @@ class Linker::Object : public Genode::Fifo::Element, /** * Next object in global object list */ - virtual Object *next_obj() const = 0; + virtual Object *next_obj() const = 0; /** * Next object in initialization list @@ -194,79 +171,104 @@ class Linker::Object : public Genode::Fifo::Element, /** * Return dynamic section of ELF */ - virtual Dynamic *dynamic() = 0; + virtual Dynamic const &dynamic() const = 0; /** * Return link map for ELF */ - virtual Link_map *link_map() = 0; + virtual Link_map const &link_map() const = 0; + + /** + * Return type of 'symbol_at_address' + */ + struct Symbol_info { addr_t addr; char const *name; }; /** * 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; - } + virtual Symbol_info symbol_at_address(addr_t addr) const = 0; }; /** * Dependency of object */ -struct Linker::Dependency : Genode::Fifo::Element +class Linker::Dependency : public Fifo::Element, Noncopyable { - Object *obj = nullptr; - Root_object *root = nullptr; + private: - Dependency(Object *obj, Root_object *root) : obj(obj), root(root) { } + Object &_obj; + Root_object *_root = nullptr; + Allocator *_md_alloc = nullptr; - Dependency(char const *path, Root_object *root, Genode::Fifo * const dep, - unsigned flags = 0); - ~Dependency(); + /** + * Check if file is in this dependency tree + */ + bool in_dep(char const *file, Fifo const &); - /** - * Load dependent ELF object - */ - void load_needed(Genode::Fifo * const dep, unsigned flags = 0); + public: - /** - * Check if file is in this dependency tree - */ - bool in_dep(char const *file, Genode::Fifo *const dep); + /* + * Called by 'Ld' constructor + */ + Dependency(Object &obj, Root_object *root) : _obj(obj), _root(root) { } + + Dependency(Env &, Allocator &, char const *path, Root_object *, + Fifo &, Keep); + + ~Dependency(); + + /** + * Load dependent ELF object + */ + void load_needed(Env &, Allocator &, Fifo &, Keep); + + bool root() const { return _root != nullptr; } + + Object const &obj() const { return _obj; } + + /** + * Return first element of dependency list + */ + Dependency const &first() const; }; /** * Root of dependencies */ -struct Linker::Root_object +class Linker::Root_object { - Genode::Fifo dep; + private: - /* main root */ - Root_object() { }; + Fifo _deps; - /* runtime loaded root components */ - Root_object(char const *path, unsigned flags = 0); + Allocator &_md_alloc; - ~Root_object() - { - Dependency *d; - while ((d = dep.dequeue())) - destroy(Genode::env()->heap(), d); - } + public: - Link_map const *link_map() const - { - return dep.head()->obj->link_map(); - } + /* main root */ + Root_object(Allocator &md_alloc) : _md_alloc(md_alloc) { }; + + /* runtime loaded root components */ + Root_object(Env &, Allocator &, char const *path, Bind, Keep); + + ~Root_object() + { + while (Dependency *d = _deps.dequeue()) + destroy(_md_alloc, d); + } + + Link_map const &link_map() const + { + return _deps.head()->obj().link_map(); + } + + Dependency const *first_dep() const { return _deps.head(); } + + void enqueue(Dependency &dep) { _deps.enqueue(&dep); } + + Fifo &deps() { return _deps; } }; #endif /* _INCLUDE__LINKER_H_ */ diff --git a/repos/base/src/lib/ldso/include/region_map.h b/repos/base/src/lib/ldso/include/region_map.h new file mode 100644 index 0000000000..e45ae25829 --- /dev/null +++ b/repos/base/src/lib/ldso/include/region_map.h @@ -0,0 +1,118 @@ +/* + * \brief Linker area + * \author Sebastian Sumpf + * \author Norman Feske + * \date 2015-03-12 + */ + +/* + * Copyright (C) 2015-2016 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__REGION_MAP_H_ +#define _INCLUDE__REGION_MAP_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* base-internal includes */ +#include + +/* local includes */ +#include + +namespace Linker { class Region_map; } + + +/** + * Managed dataspace for ELF objects (singelton) + */ +class Linker::Region_map +{ + public: + + typedef Region_map_client::Local_addr Local_addr; + typedef Region_map_client::Region_conflict Region_conflict; + + private: + + Env &_env; + Region_map_client _rm { _env.pd().linker_area() }; + Allocator_avl _range; /* VM range allocator */ + addr_t const _base; /* base address of dataspace */ + + protected: + + Region_map(Env &env, Allocator &md_alloc, addr_t base) + : + _env(env), _range(&md_alloc), + _base((addr_t)_env.rm().attach_at(_rm.dataspace(), base)) + { + _range.add_range(base, Pd_session::LINKER_AREA_SIZE); + } + + public: + + typedef Lazy_volatile_object Constructible_region_map; + + static Constructible_region_map &r(); + + /** + * Reserve VM region of 'size' at 'vaddr'. Allocate any free region if + * 'vaddr' is zero + */ + addr_t alloc_region(size_t size, addr_t vaddr = 0) + { + addr_t addr = vaddr; + + if (addr && (_range.alloc_addr(size, addr).error())) + throw Region_conflict(); + else if (!addr && + _range.alloc_aligned(size, (void **)&addr, + get_page_size_log2()).error()) + { + throw Region_conflict(); + } + + return addr; + } + + void free_region(addr_t vaddr) { _range.free((void *)vaddr); } + + /** + * Overwritten from 'Region_map_client' + */ + Local_addr attach_at(Dataspace_capability ds, addr_t local_addr, + size_t size = 0, off_t offset = 0) + { + return retry( + [&] () { + return _rm.attach_at(ds, local_addr - _base, size, offset); + }, + [&] () { _env.parent().upgrade(_env.pd_session_cap(), "ram_quota=8K"); }); + } + + /** + * Overwritten from 'Region_map_client' + */ + Local_addr attach_executable(Dataspace_capability ds, addr_t local_addr, + size_t size = 0, off_t offset = 0) + { + return retry( + [&] () { + return _rm.attach_executable(ds, local_addr - _base, size, offset); + }, + [&] () { _env.parent().upgrade(_env.pd_session_cap(), "ram_quota=8K"); }); + } + + void detach(Local_addr local_addr) { _rm.detach((addr_t)local_addr - _base); } +}; + +#endif /* _INCLUDE__REGION_MAP_H_ */ diff --git a/repos/base/src/lib/ldso/include/relocation_generic.h b/repos/base/src/lib/ldso/include/relocation_generic.h index bf10d0fe8d..f5335f9ca3 100644 --- a/repos/base/src/lib/ldso/include/relocation_generic.h +++ b/repos/base/src/lib/ldso/include/relocation_generic.h @@ -18,9 +18,9 @@ constexpr bool verbose_relocation = false; -static inline bool verbose_reloc(Linker::Dependency const *d) +static inline bool verbose_reloc(Linker::Dependency const &d) { - return d->root && verbose_relocation; + return d.root() && verbose_relocation; } /** @@ -45,12 +45,12 @@ namespace Linker */ struct Linker::Plt_got { - Plt_got(Dependency const *dep, Elf::Addr *pltgot) + Plt_got(Dependency const &dep, Elf::Addr *pltgot) { if (verbose_relocation) - Genode::log("OBJ: ", dep->obj->name(), " (", dep, ")"); + log("OBJ: ", dep.obj().name(), " (", &dep, ")"); - pltgot[1] = (Elf::Addr) dep; /* ELF object */ + pltgot[1] = (Elf::Addr) &dep; /* ELF object */ pltgot[2] = (Elf::Addr) &_jmp_slot; /* Linker entry */ } }; @@ -62,11 +62,11 @@ struct Linker::Plt_got template struct Linker::Reloc_plt_generic { - Reloc_plt_generic(Object const *obj, D_tag const type, + Reloc_plt_generic(Object const &obj, D_tag const type, Elf::Rel const *start, unsigned long size) { if (type != TYPE) { - Genode::error("LD: Unsupported PLT relocation type: ", (int)type); + error("LD: Unsupported PLT relocation type: ", (int)type); throw Incompatible(); } @@ -75,13 +75,13 @@ struct Linker::Reloc_plt_generic for (; rel < end; rel++) { if (rel->type() != JMPSLOT) { - Genode::error("LD: Unsupported PLT relocation ", (int)rel->type()); + error("LD: Unsupported PLT relocation ", (int)rel->type()); throw Incompatible(); } /* find relocation address and add relocation base */ - Elf::Addr *addr = (Elf::Addr *)(obj->reloc_base() + rel->offset); - *addr += obj->reloc_base(); + Elf::Addr *addr = (Elf::Addr *)(obj.reloc_base() + rel->offset); + *addr += obj.reloc_base(); } } }; @@ -91,7 +91,7 @@ class Linker::Reloc_non_plt_generic { protected: - Dependency const *_dep; + Dependency const &_dep; /** * Copy relocations, these are just for the main program, we can do them @@ -101,9 +101,9 @@ class Linker::Reloc_non_plt_generic template void _copy(REL const *rel, Elf::Addr *addr) { - if (!_dep->obj->is_binary()) { - Genode::error("LD: copy relocation in DSO " - "(", _dep->obj->name(), " at ", addr, ")"); + if (!_dep.obj().is_binary()) { + error("LD: copy relocation in DSO " + "(", _dep.obj().name(), " at ", addr, ")"); throw Incompatible(); } @@ -112,22 +112,22 @@ class Linker::Reloc_non_plt_generic /* search symbol in other objects, do not return undefined symbols */ if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base, false, true))) { - Genode::warning("LD: symbol not found"); + warning("LD: symbol not found"); return; } Elf::Addr src = reloc_base + sym->st_value; - Genode::memcpy(addr, (void *)src, sym->st_size); + memcpy(addr, (void *)src, sym->st_size); if (verbose_relocation) - Genode::log("Copy relocation: ", Genode::Hex(src), - " -> ", addr, " (", Genode::Hex(sym->st_size), " bytes)" - " val: ", Genode::Hex(sym->st_value)); + log("Copy relocation: ", Hex(src), + " -> ", addr, " (", Hex(sym->st_size), " bytes)" + " val: ", Hex(sym->st_value)); } public: - Reloc_non_plt_generic(Dependency const *dep) : _dep(dep) { } + Reloc_non_plt_generic(Dependency const &dep) : _dep(dep) { } }; @@ -141,11 +141,11 @@ class Linker::Reloc_jmpslot_generic public: - Reloc_jmpslot_generic(Dependency const *dep, 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) { - Genode::error("LD: unsupported JMP relocation type: ", (int)type); + error("LD: unsupported JMP relocation type: ", (int)type); throw Incompatible(); } @@ -154,19 +154,19 @@ class Linker::Reloc_jmpslot_generic Elf::Addr reloc_base; if (!(sym = lookup_symbol(rel->sym(), dep, &reloc_base))) { - Genode::warning("LD: symbol not found"); + warning("LD: symbol not found"); return; } /* write address of symbol to jump slot */ - _addr = (Elf::Addr *)(dep->obj->reloc_base() + rel->offset); + _addr = (Elf::Addr *)(dep.obj().reloc_base() + rel->offset); *_addr = reloc_base + sym->st_value; if (verbose_relocation) { - Genode::log("jmp: rbase ", Genode::Hex(reloc_base), - " s: ", sym, " sval: ", Genode::Hex(sym->st_value)); - Genode::log("jmp_slot at ", _addr, " -> ", *_addr); + log("jmp: rbase ", Hex(reloc_base), + " s: ", sym, " sval: ", Hex(sym->st_value)); + log("jmp_slot at ", _addr, " -> ", *_addr); } } @@ -180,7 +180,7 @@ class Linker::Reloc_jmpslot_generic template struct Linker::Reloc_bind_now_generic { - Reloc_bind_now_generic(Dependency const *dep, 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); diff --git a/repos/base/src/lib/ldso/include/types.h b/repos/base/src/lib/ldso/include/types.h new file mode 100644 index 0000000000..3e5d18a8df --- /dev/null +++ b/repos/base/src/lib/ldso/include/types.h @@ -0,0 +1,43 @@ +/* + * \brief Common types used within the linker + * \author Norman Feske + * \date 2016-10-27 + */ + +/* + * Copyright (C) 2016 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__TYPES_H_ +#define _INCLUDE__TYPES_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace Linker { + + using namespace Genode; + + /** + * Exceptions + */ + class Incompatible : Exception { }; + class Invalid_file : Exception { }; + class Not_found : Exception { }; + + enum Keep { DONT_KEEP = Shared_object::DONT_KEEP, + KEEP = Shared_object::KEEP }; + + enum Bind { BIND_LAZY = Shared_object::BIND_LAZY, + BIND_NOW = Shared_object::BIND_NOW }; +} + +#endif /* _INCLUDE__TYPES_H_ */ diff --git a/repos/base/src/lib/ldso/include/util.h b/repos/base/src/lib/ldso/include/util.h index 52ebaccebf..263d07e3a6 100644 --- a/repos/base/src/lib/ldso/include/util.h +++ b/repos/base/src/lib/ldso/include/util.h @@ -21,11 +21,11 @@ namespace Linker { */ template static inline T trunc_page(T addr) { - return addr & Genode::_align_mask((T)12); } + return addr & _align_mask((T)12); } template static inline T round_page(T addr) { - return Genode::align_addr(addr, (T)12); } + return align_addr(addr, (T)12); } /** * Extract file name from path diff --git a/repos/base/src/lib/ldso/main.cc b/repos/base/src/lib/ldso/main.cc index 193a913d10..296f22331f 100644 --- a/repos/base/src/lib/ldso/main.cc +++ b/repos/base/src/lib/ldso/main.cc @@ -18,10 +18,16 @@ #include #include #include +#include + +/* base-internal includes */ +#include +#include /* local includes */ #include #include +#include using namespace Linker; @@ -32,11 +38,10 @@ namespace Linker { struct Binary; struct Link_map; struct Debug; - + struct Config; }; -static Binary *binary = 0; -bool Linker::bind_now = false; +static Binary *binary_ptr = nullptr; bool Linker::verbose = false; Link_map *Link_map::first; @@ -46,6 +51,25 @@ Link_map *Link_map::first; int genode_atexit(Linker::Func); +Linker::Region_map::Constructible_region_map &Linker::Region_map::r() +{ + /* + * The capabilities in this class become invalid when doing a + * fork in the noux environment. Hence avoid destruction of + * the singleton object as the destructor would try to access + * the capabilities also in the forked process. + */ + return *unmanaged_singleton(); +} + + +Genode::Lock &Linker::lock() +{ + static Lock _lock; + return _lock; +} + + /************************************************************** ** ELF object types (shared object, dynamic binaries, ldso ** **************************************************************/ @@ -53,191 +77,165 @@ int genode_atexit(Linker::Func); /** * The actual ELF object, one per file */ -struct Linker::Elf_object : Object, Genode::Fifo::Element +class Linker::Elf_object : public Object, public Fifo::Element { - Dynamic dyn; - Link_map map; - unsigned ref_count = 1; - unsigned flags = 0; - bool relocated = false; + private: - Elf_object(Dependency const *dep, Elf::Addr reloc_base) - : Object(reloc_base), dyn(dep) - { } + Link_map _map; + unsigned _ref_count = 1; + unsigned const _keep = KEEP; + bool _relocated = false; - Elf_object(char const *path, Dependency const *dep, unsigned flags = 0) - : - Object(path, Linker::load(Linker::file(path))), dyn(dep, this, &_file->phdr), - flags(flags) - { - /* register for static construction and relocation */ - Init::list()->insert(this); - obj_list()->enqueue(this); + /* + * Optional ELF file, skipped for initial 'Ld' initialization + */ + Lazy_volatile_object _elf_file; - /* add to link map */ - Debug::state_change(Debug::ADD, nullptr); - setup_link_map(); - Debug::state_change(Debug::CONSISTENT, &map); - } - - virtual ~Elf_object() - { - if (!_file) - return; - - if (verbose_loading) - Genode::log("LD: destroy ELF object: ", name()); - - /* remove from link map */ - Debug::state_change(Debug::DELETE, &map); - Link_map::remove(&map); - Debug::state_change(Debug::CONSISTENT, nullptr); - - /* remove from loaded objects list */ - obj_list()->remove(this); - } - - /** - * Return symbol of given number from ELF - */ - Elf::Sym const *symbol(unsigned sym_index) const - { - if (sym_index > dyn.hash_table->nchains()) - return 0; - - return dyn.symtab + sym_index; - } - - /** - * Return name of given symbol - */ - 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 - { - Hash_table *h = dyn.hash_table; - - if (!h->buckets()) - return nullptr; - - unsigned long sym_index = h->buckets()[hash % h->nbuckets()]; - - /* traverse hash chain */ - for (; sym_index != STN_UNDEF; sym_index = h->chains()[sym_index]) + bool _init_elf_file(Env &env, Allocator &md_alloc, char const *path) { - /* bad object */ - if (sym_index > h->nchains()) - return nullptr; - - Elf::Sym const *sym = symbol(sym_index); - char const *sym_name = symbol_name(sym); - - /* this omitts everything but 'NOTYPE', 'OBJECT', and 'FUNC' */ - if (sym->type() > STT_FUNC) - continue; - - if (sym->st_value == 0) - continue; - - /* check for symbol name */ - if (name[0] != sym_name[0] || Genode::strcmp(name, sym_name)) - continue; - - return sym; + _elf_file.construct(env, md_alloc, Linker::file(path), true); + Object::init(Linker::file(path), *_elf_file); + return true; } - return nullptr; - } + bool const _elf_file_initialized; - /** - * Fill-out link map infos for this ELF - */ - void setup_link_map() - { - map.addr = _file ? _file->start + reloc_base() : reloc_base(); - map.path = name(); - map.dynamic = (void *)dyn.dynamic; + Dynamic _dyn; - Link_map::add(&map); - }; + public: - - 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 = dyn.hash_table; - - for (unsigned long sym_index = 0; sym_index < h->nchains(); sym_index++) + Elf_object(Dependency const &dep, Object::Name const &name, + Elf::Addr reloc_base) + : + _elf_file_initialized(false), _dyn(dep) { - Elf::Sym const *sym = symbol(sym_index); - - /* skip */ - if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON) - continue; - - Genode::addr_t sym_addr = reloc_base() + sym->st_value; - if (sym_addr > addr || sym_addr < info.addr) - continue; - - info.addr = sym_addr; - info.name = symbol_name(sym); - - if (info.addr == addr) - break; + Object::init(name, reloc_base); } - if (!info.addr) - throw Genode::Address_info::Invalid_address(); - } + Elf_object(Env &env, Allocator &md_alloc, char const *path, + Dependency const &dep, Keep keep) + : + _keep(keep), + _elf_file_initialized(_init_elf_file(env, md_alloc, path)), + _dyn(md_alloc, dep, *this, &_elf_file->phdr) + { + /* register for static construction and relocation */ + Init::list()->insert(this); + obj_list()->enqueue(this); - /** - * Next in initializion list - */ - Object *next_init() const override { - return Genode::List::Element::next(); - } + /* add to link map */ + Debug::state_change(Debug::ADD, nullptr); + setup_link_map(); + Debug::state_change(Debug::CONSISTENT, &_map); + } - /** - * Next in object list - */ - Object *next_obj() const override { - return Genode::Fifo::Element::next(); - } + virtual ~Elf_object() + { + if (!_file) + return; - /** - * Object list - */ - static Genode::Fifo *obj_list() - { - static Genode::Fifo _list; - return &_list; - } + if (verbose_loading) + log("LD: destroy ELF object: ", name()); + /* remove from link map */ + Debug::state_change(Debug::DELETE, &_map); + Link_map::remove(&_map); + Debug::state_change(Debug::CONSISTENT, nullptr); - void load() override { ref_count++; } - bool unload() override { return !(--ref_count) && !(flags & Genode::Shared_object::KEEP); } + /* remove from loaded objects list */ + obj_list()->remove(this); + } - bool is_linker() const override { return false; } - bool is_binary() const override { return false; } + /** + * Return symbol of given number from ELF + */ + Elf::Sym const *symbol(unsigned sym_index) const + { + return _dyn.symbol(sym_index); + } + + // XXX remove this accessor? + void link_map_addr(addr_t addr) { _map.addr = addr; } + + /** + * Return name of given symbol + */ + char const *symbol_name(Elf::Sym const &sym) const + { + return _dyn.symbol_name(sym); + } + + Elf::Sym const *lookup_symbol(char const *name, unsigned long hash) const + { + return _dyn.lookup_symbol(name, hash); + } + + /** + * Fill-out link map infos for this ELF + */ + void setup_link_map() + { + _map.addr = _file ? _file->start + reloc_base() : reloc_base(); + _map.path = name(); + _map.dynamic = _dyn.dynamic_ptr(); + + Link_map::add(&_map); + }; + + Link_map const &link_map() const override { return _map; } + Dynamic const &dynamic() const override { return _dyn; } + + void relocate_global() { _dyn.relocate_non_plt(BIND_NOW, Dynamic::SECOND_PASS); } + + void plt_setup() { _dyn.plt_setup(); } + + void update_dependency(Dependency const &dep) { _dyn.dep(dep); } + + void relocate(Bind bind) override + { + if (!_relocated) + _dyn.relocate(bind); + + _relocated = true; + } + + addr_t base_addr() const { return _map.addr; } + + Symbol_info symbol_at_address(addr_t addr) const override + { + Elf::Sym const sym = _dyn.symbol_by_addr(addr); + + return { _reloc_base + sym.st_value, _dyn.symbol_name(sym) }; + } + + /** + * Next in initializion list + */ + Object *next_init() const override { + return List::Element::next(); + } + + /** + * Next in object list + */ + Object *next_obj() const override { + return Fifo::Element::next(); + } + + /** + * Object list + */ + static Fifo *obj_list() + { + static Fifo _list; + return &_list; + } + + void load() override { _ref_count++; } + bool unload() override { return (_keep == DONT_KEEP) && !(--_ref_count); } + + bool is_linker() const override { return false; } + bool is_binary() const override { return false; } }; @@ -246,32 +244,24 @@ struct Linker::Elf_object : Object, Genode::Fifo::Element */ struct Linker::Ld : Dependency, Elf_object { - Ld() - : Dependency(this, nullptr), Elf_object(this, relocation_address()) - { - Genode::strncpy(_name, linker_name(), Object::MAX_PATH); - } + Ld() : + Dependency(*this, nullptr), + Elf_object(*this, linker_name(), relocation_address()) + { } void setup_link_map() { Elf_object::setup_link_map(); - /** - * 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); + link_map_addr(dynamic().link_map_addr()); } - void load_phdr() + void load_phdr(Env &env, Allocator &md_alloc) { - _file = Linker::load(name(), false); + _file = new (md_alloc) Elf_file(env, md_alloc, name(), false); } - void relocate_global() { dynamic()->relocate_non_plt(true); } - void update_dependency(Dependency const *dep) { dynamic()->dep = dep; } - - static Ld *linker(); + static Ld &linker(); bool is_linker() const override { return true; } @@ -279,45 +269,45 @@ struct Linker::Ld : Dependency, Elf_object * Entry point for jump relocations, it is called from assembly code and is implemented * right below) */ - static Elf::Addr jmp_slot(Dependency const *dep, Elf::Size index) 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) +Elf::Addr Ld::jmp_slot(Dependency const &dep, Elf::Size index) { - Genode::Lock::Guard guard(Elf_object::lock()); + Lock::Guard guard(lock()); if (verbose_relocation) - Genode::log("LD: SLOT ", dep->obj, " ", Genode::Hex(index)); + log("LD: SLOT ", &dep.obj(), " ", Hex(index)); try { - Reloc_jmpslot slot(dep, dep->obj->dynamic()->pltrel_type, - dep->obj->dynamic()->pltrel, index); + Reloc_jmpslot slot(dep, dep.obj().dynamic().pltrel_type(), + dep.obj().dynamic().pltrel(), index); return slot.target_addr(); - } catch (...) { Genode::error("LD: jump slot relocation failed. FATAL!"); } + } catch (...) { error("LD: jump slot relocation failed. FATAL!"); } return 0; } -/** - * Ld object with different vtable typeinfo - */ -struct Linker::Ld_vtable : Ld -{ - Ld_vtable() - { - Elf_object::obj_list()->enqueue(this); - } -}; - /** * Linker object used during bootstrapping on stack (see: 'init_rtld') */ -Linker::Ld *Linker::Ld::linker() +Linker::Ld &Linker::Ld::linker() { + /** + * Ld object with different vtable typeinfo + */ + struct Ld_vtable : Ld + { + Ld_vtable() + { + Elf_object::obj_list()->enqueue(this); + plt_setup(); + } + }; static Ld_vtable _linker; - return &_linker; + return _linker; } @@ -326,26 +316,28 @@ Linker::Ld *Linker::Ld::linker() */ struct Linker::Binary : Root_object, Elf_object { - Binary() - : Elf_object(binary_name(), new (Genode::env()->heap()) Dependency(this, this)) + Binary(Env &env, Allocator &md_alloc, Bind bind) + : + Root_object(md_alloc), + Elf_object(env, md_alloc, binary_name(), + *new (md_alloc) Dependency(*this, this), KEEP) { /* 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); + Dependency *binary = const_cast(&dynamic().dep()); + Root_object::enqueue(*binary); + Dependency *linker = new (md_alloc) Dependency(Ld::linker(), this); + Root_object::enqueue(*linker); - /* update linker dep */ - Ld::linker()->update_dependency(linker); + Ld::linker().update_dependency(*linker); - /* place linker on second place in link map as well */ - Ld::linker()->setup_link_map(); + /* place linker on second place in link map */ + Ld::linker().setup_link_map(); /* load dependencies */ - binary->load_needed(&dep); + binary->load_needed(env, md_alloc, deps(), DONT_KEEP); /* relocate and call constructors */ - Init::list()->initialize(); + Init::list()->initialize(bind); } Elf::Addr lookup_symbol(char const *name) @@ -358,7 +350,7 @@ struct Linker::Binary : Root_object, Elf_object return 0; } - void call_entry_point(Genode::Env &env) + void call_entry_point(Env &env) { /* call static construtors and register destructors */ Func * const ctors_start = (Func *)lookup_symbol("_ctors_start"); @@ -372,16 +364,16 @@ struct Linker::Binary : Root_object, Elf_object /* call component entry point */ /* XXX the function type for call_component_construct() is a candidate * for a base-internal header */ - typedef void (*Entry)(Genode::Env &); + typedef void (*Entry)(Env &); Entry const entry = reinterpret_cast(_file->entry); entry(env); } - void relocate() override + void relocate(Bind bind) override { /* relocate ourselves */ - Elf_object::relocate(); + Elf_object::relocate(bind); /* * After having loaded the main program, we relocate the linker's @@ -389,7 +381,7 @@ struct Linker::Binary : Root_object, Elf_object * also present within the main program, become relocated to the correct * positions */ - Ld::linker()->relocate_global(); + Ld::linker().relocate_global(); } bool is_binary() const override { return true; } @@ -400,22 +392,21 @@ struct Linker::Binary : Root_object, Elf_object ** Global Linker namespace functions ** ***************************************/ -Object *Linker::load(char const *path, Dependency *dep, unsigned flags) +Object &Linker::load(Env &env, Allocator &md_alloc, char const *path, + Dependency &dep, Keep keep) { for (Object *e = Elf_object::obj_list()->head(); e; e = e->next_obj()) { if (verbose_loading) - Genode::log("LOAD: ", Linker::file(path), " == ", e->name()); + log("LOAD: ", Linker::file(path), " == ", e->name()); - if (!Genode::strcmp(Linker::file(path), e->name())) { + if (!strcmp(Linker::file(path), e->name())) { e->load(); - return e; + return *e; } } - Elf_object *e = new (Genode::env()->heap()) Elf_object(path, dep, flags); - dep->obj = e; - return e; + return *new (md_alloc) Elf_object(env, md_alloc, path, dep, keep); } @@ -425,30 +416,30 @@ Object *Linker::obj_list_head() } -Elf::Sym const *Linker::lookup_symbol(unsigned sym_index, Dependency const *dep, +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); + Elf_object const &elf = static_cast(dep.obj()); + Elf::Sym const *symbol = elf.symbol(sym_index); if (!symbol) { - Genode::warning("LD: unknown symbol index ", Genode::Hex(sym_index)); + warning("LD: unknown symbol index ", Hex(sym_index)); return 0; } if (symbol->bind() == STB_LOCAL) { - *base = dep->obj->reloc_base(); + *base = dep.obj().reloc_base(); return symbol; } - return lookup_symbol(e->symbol_name(symbol), dep, base, undef, other); + return lookup_symbol(elf.symbol_name(*symbol), dep, base, undef, other); } -Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const *dep, +Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const &dep, Elf::Addr *base, bool undef, bool other) { - Dependency const *curr = dep->root ? dep->root->dep.head() : dep; + Dependency const *curr = &dep.first(); unsigned long hash = Hash_table::hash(name); Elf::Sym const *weak_symbol = 0; Elf::Addr weak_base = 0; @@ -457,45 +448,45 @@ Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const *dep, //TODO: handle vertab and search in object list for (;curr; curr = curr->next()) { - if (other && curr == dep) + if (other && curr == &dep) continue; - Elf_object const *elf = static_cast(curr->obj); + Elf_object const &elf = static_cast(curr->obj()); - if ((symbol = elf->lookup_symbol(name, hash)) && (symbol->st_value || undef)) { + if ((symbol = elf.lookup_symbol(name, hash)) && (symbol->st_value || undef)) { - if (dep->root && verbose_lookup) - Genode::log("LD: lookup ", name, " obj_src ", elf->name(), - " st ", symbol, " info ", Genode::Hex(symbol->st_info), - " weak: ", symbol->weak()); + if (dep.root() && verbose_lookup) + log("LD: lookup ", name, " obj_src ", elf.name(), + " st ", symbol, " info ", Hex(symbol->st_info), + " weak: ", symbol->weak()); if (!undef && symbol->st_shndx == SHN_UNDEF) continue; if (!symbol->weak() && symbol->st_shndx != SHN_UNDEF) { - *base = elf->reloc_base(); + *base = elf.reloc_base(); return symbol; } if (!weak_symbol) { weak_symbol = symbol; - weak_base = elf->reloc_base(); + weak_base = elf.reloc_base(); } } } /* try searching binary's dependencies */ - if (!weak_symbol && dep->root) { - if (binary && dep != binary->dep.head()) { - return lookup_symbol(name, binary->dep.head(), base, undef, other); + if (!weak_symbol && dep.root()) { + if (binary_ptr && &dep != binary_ptr->first_dep()) { + return lookup_symbol(name, *binary_ptr->first_dep(), base, undef, other); } else { - Genode::error("LD: could not lookup symbol \"", name, "\""); + error("LD: could not lookup symbol \"", name, "\""); throw Not_found(); } } - if (dep->root && verbose_lookup) - Genode::log("LD: return ", weak_symbol); + if (dep.root() && verbose_lookup) + log("LD: return ", weak_symbol); if (!weak_symbol) throw Not_found(); @@ -505,13 +496,6 @@ Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const *dep, } -void Linker::load_linker_phdr() -{ - if (!Ld::linker()->file()) - Ld::linker()->load_phdr(); -} - - /******************** ** Initialization ** ********************/ @@ -524,49 +508,77 @@ extern "C" void init_rtld() { /* * 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 - * not call any virtual funtions of this object + * type relocation might produce a wrong vtable pointer (at least on ARM), do + * not call any virtual funtions of this object. */ - Ld linker_stack; - linker_stack.relocate(); - - /* make sure this does not get destroyed the usual way */ - linker_stack.ref_count++; + Ld linker_on_stack; + linker_on_stack.relocate(BIND_LAZY); /* * Create actual linker object with different vtable type and set PLT to new * DAG. */ - Ld::linker()->dynamic()->plt_setup(); + Ld::linker(); } Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); } -struct Failed_to_load_program { }; +class Linker::Config +{ + private: + + Bind _bind = BIND_LAZY; + bool _verbose = false; + + public: + + Config(Env &env) + { + try { + Attached_rom_dataspace config(env, "config"); + + if (config.xml().attribute_value("ld_bind_now", false)) + _bind = BIND_NOW; + + _verbose = config.xml().attribute_value("ld_verbose", false); + } catch (Rom_connection::Rom_connection_failed) { } + } + + Bind bind() const { return _bind; } + bool verbose() const { return _verbose; } +}; + + +static Genode::Lazy_volatile_object &heap() +{ + return *unmanaged_singleton>(); +} + + +void Genode::init_ldso_phdr(Env &env) +{ + heap().construct(env.ram(), env.rm()); + + /* load program headers of linker now */ + if (!Ld::linker().file()) + Ld::linker().load_phdr(env, *heap()); +} void Component::construct(Genode::Env &env) { - /* load program headers of linker now */ - if (!Ld::linker()->file()) - Ld::linker()->load_phdr(); - - /* read configuration, release ROM afterwards */ - try { - Genode::Attached_rom_dataspace config(env, "config"); - - bind_now = config.xml().attribute_value("ld_bind_now", false); - verbose = config.xml().attribute_value("ld_verbose", false); - } catch (Genode::Rom_connection::Rom_connection_failed) { } + /* read configuration */ + static Config config(env); + verbose = config.verbose(); /* load binary and all dependencies */ try { - binary = new(Genode::env()->heap()) Binary(); + binary_ptr = unmanaged_singleton(env, *heap(), config.bind()); } catch (...) { - Genode::error("LD: failed to load program"); - throw Failed_to_load_program(); + error("LD: failed to load program"); + throw; } /* print loaded object information */ @@ -577,7 +589,7 @@ void Component::construct(Genode::Env &env) " .. ", Hex(Thread::stack_area_virtual_base() + Thread::stack_area_virtual_size() - 1), ": stack area"); - dump_link_map(Elf_object::obj_list()->head()); + dump_link_map(*Elf_object::obj_list()->head()); } } catch (...) { } @@ -586,5 +598,5 @@ void Component::construct(Genode::Env &env) binary_ready_hook_for_gdb(); /* start binary */ - binary->call_entry_point(env); + binary_ptr->call_entry_point(env); } diff --git a/repos/base/src/lib/ldso/shared_object.cc b/repos/base/src/lib/ldso/shared_object.cc index 5dfaae7a16..29855374bc 100644 --- a/repos/base/src/lib/ldso/shared_object.cc +++ b/repos/base/src/lib/ldso/shared_object.cc @@ -19,9 +19,9 @@ ** Helpers ** *************/ -static Linker::Root_object *to_root(void *h) +static Linker::Root_object const &to_root(void *h) { - return static_cast(h); + return *static_cast(h); } @@ -39,7 +39,7 @@ static Genode::Lock & shared_object_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()) + if (addr >= e->link_map().addr && addr < e->link_map().addr + e->size()) return e; throw Genode::Address_info::Invalid_address(); @@ -50,25 +50,28 @@ static Linker::Object *find_obj(Genode::addr_t addr) ** API ** *********/ -Genode::Shared_object::Shared_object(char const *file, unsigned flags) +Genode::Shared_object::Shared_object(Env &env, Allocator &md_alloc, + char const *file, Bind bind, Keep keep) +: + _md_alloc(md_alloc) { using namespace Linker; if (verbose_shared) - Genode::log("LD: open '", file ? file : "binary", "'"); + log("LD: open '", file ? file : "binary", "'"); try { - Genode::Lock::Guard guard(shared_object_lock()); + 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); + _handle = new (md_alloc) + Root_object(env, md_alloc, file ? file : binary_name(), + bind == BIND_NOW ? Linker::BIND_NOW : Linker::BIND_LAZY, + keep == KEEP ? Linker::KEEP : Linker::DONT_KEEP); /* print loaded object information */ try { if (Linker::verbose) - Linker::dump_link_map(to_root(_handle)->dep.head()->obj); + Linker::dump_link_map(to_root(_handle).first_dep()->obj()); } catch (...) { } } catch (...) { throw Invalid_file(); } @@ -80,23 +83,24 @@ void *Genode::Shared_object::_lookup(const char *name) const using namespace Linker; if (verbose_shared) - Genode::log("LD: shared object lookup '", name, "'"); + log("LD: shared object lookup '", name, "'"); try { - Genode::Lock::Guard guard(Object::lock()); + Lock::Guard guard(Linker::lock()); - Elf::Addr base; - Root_object *root = to_root(_handle); - Elf::Sym const *symbol = lookup_symbol(name, root->dep.head(), &base, true); + Root_object const &root = to_root(_handle); + + Elf::Addr base; + Elf::Sym const *symbol = lookup_symbol(name, *root.first_dep(), &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 +Genode::Shared_object::Link_map const &Genode::Shared_object::link_map() const { - return (Link_map const *)to_root(_handle)->link_map(); + return (Link_map const &)to_root(_handle).link_map(); } @@ -105,26 +109,33 @@ Genode::Shared_object::~Shared_object() using namespace Linker; if (verbose_shared) - Genode::log("LD: close shared object"); + log("LD: close shared object"); - Genode::Lock::Guard guard(shared_object_lock()); - destroy(Genode::env()->heap(), to_root(_handle)); + Lock::Guard guard(shared_object_lock()); + destroy(_md_alloc, &const_cast(to_root(_handle))); } -Genode::Address_info::Address_info(Genode::addr_t address) +Genode::Address_info::Address_info(addr_t address) { using namespace Genode; if (verbose_shared) - Genode::log("LD: address-info request: ", Genode::Hex(address)); + log("LD: address-info request: ", Hex(address)); Linker::Object *e = find_obj(address); - e->info(address, *this); + + path = e->name(); + base = e->reloc_base(); + + Linker::Object::Symbol_info const symbol = e->symbol_at_address(address); + + addr = symbol.addr; + name = symbol.name; if (verbose_shared) - Genode::log("LD: found address info: obj: ", path, " sym: ", name, - " addr: ", Genode::Hex(addr)); + log("LD: found address info: obj: ", path, " sym: ", name, + " addr: ", Hex(addr)); } diff --git a/repos/base/src/lib/ldso/spec/arm/relocation.h b/repos/base/src/lib/ldso/spec/arm/relocation.h index 8fac05c59f..841b4f26ed 100644 --- a/repos/base/src/lib/ldso/spec/arm/relocation.h +++ b/repos/base/src/lib/ldso/spec/arm/relocation.h @@ -72,26 +72,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 (_dep->obj->reloc_base()) - *addr += _dep->obj->reloc_base(); + if (_dep.obj().reloc_base()) + *addr += _dep.obj().reloc_base(); } public: - Reloc_non_plt(Dependency const *dep, Elf::Rela const *, unsigned long) + Reloc_non_plt(Dependency const &dep, Elf::Rela const *, unsigned long) : Reloc_non_plt_generic(dep) { - Genode::error("LD: DT_RELA not supported"); + error("LD: DT_RELA not supported"); throw Incompatible(); } - Reloc_non_plt(Dependency const *dep, Elf::Rel const *rel, unsigned long size, + 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 *)(_dep->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 +104,8 @@ 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: - if (_dep->root) { - Genode::warning("LD: Unkown relocation ", (int)rel->type()); + if (_dep.root()) { + warning("LD: Unkown relocation ", (int)rel->type()); throw Incompatible(); } break; diff --git a/repos/base/src/lib/ldso/spec/riscv/relocation.h b/repos/base/src/lib/ldso/spec/riscv/relocation.h index 1c40c48333..67e928fd41 100644 --- a/repos/base/src/lib/ldso/spec/riscv/relocation.h +++ b/repos/base/src/lib/ldso/spec/riscv/relocation.h @@ -51,7 +51,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic */ void _relative(Elf::Rela const *rel, Elf::Addr *addr) { - *addr = _dep->obj->reloc_base() + rel->addend; + *addr = _dep.obj().reloc_base() + rel->addend; } /** @@ -68,23 +68,23 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic *addr = reloc_base + sym->st_value + (addend ? rel->addend : 0); if (verbose_reloc(_dep)) - Genode::log("LD: GLOB DAT ", addr, " -> ", Genode::Hex(*addr), - " r ", Genode::Hex(reloc_base), - " v ", Genode::Hex(sym->st_value)); + log("LD: GLOB DAT ", addr, " -> ", Hex(*addr), + " r ", Hex(reloc_base), + " v ", Hex(sym->st_value)); } public: - Reloc_non_plt(Dependency const *dep, Elf::Rela const *rel, unsigned long size) + 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 *)(_dep->obj->reloc_base() + rel->offset); + Elf::Addr *addr = (Elf::Addr *)(_dep.obj().reloc_base() + rel->offset); if (verbose_reloc(_dep)) - Genode::log("LD: reloc: ", rel, " type: ", (int)rel->type()); + log("LD: reloc: ", rel, " type: ", (int)rel->type()); switch(rel->type()) { case R_JMPSLOT: _glob_dat_64(rel, addr, false); break; @@ -92,8 +92,8 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic case R_RELATIVE: _relative(rel, addr); break; default: - if (!_dep->obj->is_linker()) { - Genode::warning("LD: unkown relocation ", (int)rel->type()); + if (!_dep.obj().is_linker()) { + warning("LD: unkown relocation ", (int)rel->type()); throw Incompatible(); } break; @@ -101,10 +101,10 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic } } - Reloc_non_plt(Dependency const *dep, Elf::Rel const *, unsigned long, bool) + Reloc_non_plt(Dependency const &dep, Elf::Rel const *, unsigned long, bool) : Reloc_non_plt_generic(dep) { - Genode::error("LD: DT_REL not supported"); + error("LD: DT_REL not supported"); throw Incompatible(); } }; diff --git a/repos/base/src/lib/ldso/spec/x86_32/relocation.h b/repos/base/src/lib/ldso/spec/x86_32/relocation.h index 4dd51a3542..dcbc30b568 100644 --- a/repos/base/src/lib/ldso/spec/x86_32/relocation.h +++ b/repos/base/src/lib/ldso/spec/x86_32/relocation.h @@ -52,27 +52,27 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic void _relative(Elf::Rel const *rel, Elf::Addr *addr) { - if (_dep->obj->reloc_base()) - *addr += _dep->obj->reloc_base(); + if (_dep.obj().reloc_base()) + *addr += _dep.obj().reloc_base(); } public: - Reloc_non_plt(Dependency const *dep, Elf::Rela const *, unsigned long) + Reloc_non_plt(Dependency const &dep, Elf::Rela const *, unsigned long) : Reloc_non_plt_generic(dep) { - Genode::error("LD: DT_RELA not supported"); + error("LD: DT_RELA not supported"); throw Incompatible(); } - Reloc_non_plt(Dependency const *dep, Elf::Rel const *rel, unsigned long size, + 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 *)(_dep->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 +84,8 @@ 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: - if (_dep->root) { - Genode::warning("LD: Unkown relocation ", (int)rel->type()); + if (_dep.root()) { + warning("LD: Unkown relocation ", (int)rel->type()); throw Incompatible(); } break; diff --git a/repos/base/src/lib/ldso/spec/x86_64/relocation.h b/repos/base/src/lib/ldso/spec/x86_64/relocation.h index f72b4d1429..a9fce645f9 100644 --- a/repos/base/src/lib/ldso/spec/x86_64/relocation.h +++ b/repos/base/src/lib/ldso/spec/x86_64/relocation.h @@ -45,7 +45,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic */ void _relative(Elf::Rela const *rel, Elf::Addr *addr) { - *addr = _dep->obj->reloc_base() + rel->addend; + *addr = _dep.obj().reloc_base() + rel->addend; } /** @@ -62,19 +62,19 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic *addr = reloc_base + sym->st_value + (addend ? rel->addend : 0); if (verbose_reloc(_dep)) - Genode::log("GLOB DAT ", addr, " -> ", *addr, - " r ", reloc_base, " v ", sym->st_value); + log("GLOB DAT ", addr, " -> ", *addr, + " r ", reloc_base, " v ", sym->st_value); } public: - Reloc_non_plt(Dependency const *dep, Elf::Rela const *rel, unsigned long size) + 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 *)(_dep->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 +83,8 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic case R_RELATIVE: _relative(rel, addr); break; default: - if (!_dep->obj->is_linker()) { - Genode::warning("LD: Unkown relocation ", (int)rel->type()); + if (!_dep.obj().is_linker()) { + warning("LD: Unkown relocation ", (int)rel->type()); throw Incompatible(); } break; @@ -92,10 +92,10 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic } } - Reloc_non_plt(Dependency const *dep, Elf::Rel const *, unsigned long, bool) + Reloc_non_plt(Dependency const &dep, Elf::Rel const *, unsigned long, bool) : Reloc_non_plt_generic(dep) { - Genode::error("LD: DT_REL not supported"); + error("LD: DT_REL not supported"); throw Incompatible(); } }; diff --git a/repos/base/src/lib/startup/init_main_thread.cc b/repos/base/src/lib/startup/init_main_thread.cc index 502e1492e3..350d3971c0 100644 --- a/repos/base/src/lib/startup/init_main_thread.cc +++ b/repos/base/src/lib/startup/init_main_thread.cc @@ -94,28 +94,6 @@ extern "C" void init_main_thread() (void*)env(); init_log(); - /* initialize exception handling */ - init_exception_handling(); - - /* - * Trigger first exception. This step has two purposes. - * First, it enables us to detect problems related to exception handling as - * early as possible. If there are problems with the C++ support library, - * it is much easier to debug them at this early stage. Otherwise problems - * with half-working exception handling cause subtle failures that are hard - * to interpret. - * - * Second, the C++ support library allocates data structures lazily on the - * first occurrence of an exception. This allocation traverses into - * Genode's heap and, in some corner cases, consumes several KB of stack. - * This is usually not a problem when the first exception is triggered from - * the main thread but it becomes an issue when the first exception is - * thrown from the stack of a thread with a specially tailored (and - * otherwise sufficient) stack size. By throwing an exception here, we - * mitigate this issue by eagerly performing those allocations. - */ - try { throw 1; } catch (...) { } - /* create a thread object for the main thread */ main_thread(); diff --git a/repos/dde_rump/include/rump/bootstrap.h b/repos/dde_rump/include/rump/bootstrap.h new file mode 100644 index 0000000000..2279eff890 --- /dev/null +++ b/repos/dde_rump/include/rump/bootstrap.h @@ -0,0 +1,21 @@ +/* + * \brief Rump initialization + * \author Norman Feske + * \date 2016-11-02 + */ + +/* + * Copyright (C) 2016 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__RUMP__BOOTSTRAP_H_ +#define _INCLUDE__RUMP__BOOTSTRAP_H_ + +#include +#include + +void rump_bootstrap_init(Genode::Env &env, Genode::Allocator &heap); + +#endif /* _INCLUDE__RUMP__BOOTSTRAP_H_ */ diff --git a/repos/dde_rump/include/rump_fs/fs.h b/repos/dde_rump/include/rump_fs/fs.h index eb5dac47a5..8af07a44a5 100644 --- a/repos/dde_rump/include/rump_fs/fs.h +++ b/repos/dde_rump/include/rump_fs/fs.h @@ -1,4 +1,4 @@ -/** +/* * \brief Definitions for FS front-end * \author Sebastian Sumpf * \date 2014-01-22 diff --git a/repos/dde_rump/src/lib/rump/bootstrap.cc b/repos/dde_rump/src/lib/rump/bootstrap.cc index e3e9d76e21..38b074fa6c 100644 --- a/repos/dde_rump/src/lib/rump/bootstrap.cc +++ b/repos/dde_rump/src/lib/rump/bootstrap.cc @@ -17,7 +17,7 @@ extern "C" { #include } -#include +#include #include #include #include @@ -35,7 +35,46 @@ typedef Elf32_Sym Elf_Sym; static bool const verbose = false; -static Genode::Shared_object *obj_main; +static Genode::Shared_object *obj_main; +static Genode::Env *env_ptr; +static Genode::Allocator *heap_ptr; + + +void rump_bootstrap_init(Genode::Env &env, Genode::Allocator &alloc) +{ + /* ignore subsequent calls */ + if (env_ptr) + return; + + env_ptr = &env; + heap_ptr = &alloc; +} + + +/** + * Exception type + */ +class Missing_call_of_rump_bootstrap_init { }; + + +static Genode::Env &env() +{ + if (!env_ptr) + throw Missing_call_of_rump_bootstrap_init(); + + return *env_ptr; +} + + +static Genode::Allocator &heap() +{ + if (!heap_ptr) + throw Missing_call_of_rump_bootstrap_init(); + + return *heap_ptr; +} + + struct Sym_tab { @@ -183,13 +222,17 @@ struct Sym_tab * Call init functions of libraries */ static void _dl_init(Genode::Shared_object::Link_map const *map, - rump_modinit_fn mod_init, - rump_compload_fn comp_init) + rump_modinit_fn mod_init, + rump_compload_fn comp_init) { using namespace Genode; - Shared_object *obj; - try { obj = new (Genode::env()->heap()) Shared_object(map->path); } - catch (...) { error("Could not dlopen ", map->path); return; } + Shared_object *obj = nullptr; + try { + obj = new (heap()) Shared_object(::env(), heap(), map->path, + Shared_object::BIND_LAZY, + Shared_object::DONT_KEEP); + } + catch (...) { error("could not dlopen ", map->path); return; } struct modinfo **mi_start, **mi_end; struct rump_component **rc_start, **rc_end; @@ -218,9 +261,14 @@ void rumpuser_dl_bootstrap(rump_modinit_fn domodinit, rump_symload_fn symload, /* open main program and request link map */ using namespace Genode; - obj_main = new (env()->heap()) Shared_object(nullptr, Shared_object::NOW); + try { + obj_main = new (heap()) Shared_object(::env(), heap(), nullptr, + Shared_object::BIND_NOW, + Shared_object::KEEP); + } + catch (...) { error("could not dlopen the main executable"); return; } - Shared_object::Link_map const *map = obj_main->link_map(); + Shared_object::Link_map const *map = &obj_main->link_map(); for (; map->next; map = map->next) ; Shared_object::Link_map const *curr_map; diff --git a/repos/dde_rump/src/server/rump_fs/file_system.cc b/repos/dde_rump/src/server/rump_fs/file_system.cc index 13afd9517f..0dff819958 100644 --- a/repos/dde_rump/src/server/rump_fs/file_system.cc +++ b/repos/dde_rump/src/server/rump_fs/file_system.cc @@ -13,11 +13,12 @@ #include "file_system.h" -#include +#include #include #include #include #include +#include /** * We define our own fs arg structure to fit all sizes, we assume that 'fspec' @@ -31,28 +32,24 @@ struct fs_args fs_args() { Genode::memset(pad, 0, sizeof(pad)); } }; -namespace File_system { - class Sync; -}; + +namespace File_system { class Sync; }; + static char const *fs_types[] = { RUMP_MOUNT_CD9660, RUMP_MOUNT_EXT2FS, RUMP_MOUNT_FFS, RUMP_MOUNT_MSDOS, RUMP_MOUNT_NTFS, RUMP_MOUNT_UDF, 0 }; typedef Genode::String<16> Fs_type; -static Fs_type & fs_type() -{ - static Fs_type inst = Genode::config()->xml_node().attribute_value("fs", Fs_type()); - return inst; -} static bool _supports_symlinks; -static bool _check_type(char const *type) + +static bool _check_type(Fs_type const &type) { for (int i = 0; fs_types[i]; i++) - if (!Genode::strcmp(type, fs_types[i])) + if (!Genode::strcmp(type.string(), fs_types[i])) return true; return false; } @@ -66,35 +63,32 @@ static void _print_types() } -static bool check_symlinks() +static bool check_symlinks(Fs_type const &fs_type) { - if (!Genode::strcmp(fs_type().string(), RUMP_MOUNT_EXT2FS)) - return true; - - if (!Genode::strcmp(fs_type().string(), RUMP_MOUNT_FFS)) - return true; - - return false; + return (fs_type == RUMP_MOUNT_EXT2FS) + || (fs_type == RUMP_MOUNT_FFS); } -static bool check_read_only() +static bool check_read_only(Fs_type const &fs_type) { - if (!Genode::strcmp(fs_type().string(), RUMP_MOUNT_CD9660)) - return true; - - return false; + return fs_type == RUMP_MOUNT_CD9660; } -void File_system::init() +void File_system::init(Genode::Env &env, Genode::Allocator &alloc, Genode::Xml_node config) { - if (!_check_type(fs_type().string())) { + Fs_type const fs_type = config.attribute_value("fs", Fs_type()); + + if (!_check_type(fs_type)) { Genode::error("Invalid or no file system given (use \'\"/>)"); _print_types(); throw Genode::Exception(); } - Genode::log("Using ", fs_type().string(), " as file system"); + Genode::log("Using ", fs_type, " as file system"); + + /* make Genode env and heap known to the rump kernel */ + rump_bootstrap_init(env, alloc); /* start rump kernel */ rump_init(); @@ -104,16 +98,16 @@ void File_system::init() /* mount into extra-terrestrial-file system */ struct fs_args args; - int opts = check_read_only() ? RUMP_MNT_RDONLY : 0; + int opts = check_read_only(fs_type) ? RUMP_MNT_RDONLY : 0; args.fspec = (char *)GENODE_DEVICE; - if (rump_sys_mount(fs_type().string(), "/", opts, &args, sizeof(args)) == -1) { - Genode::error("Mounting '", fs_type().string(), "' file system failed (errno ", errno, " )"); + if (rump_sys_mount(fs_type.string(), "/", opts, &args, sizeof(args)) == -1) { + Genode::error("Mounting '", fs_type, "' file system failed (errno ", errno, " )"); throw Genode::Exception(); } /* check support for symlinks */ - _supports_symlinks = check_symlinks(); + _supports_symlinks = check_symlinks(fs_type); } diff --git a/repos/dde_rump/src/server/rump_fs/file_system.h b/repos/dde_rump/src/server/rump_fs/file_system.h index c4f45cbc35..645c75edcd 100644 --- a/repos/dde_rump/src/server/rump_fs/file_system.h +++ b/repos/dde_rump/src/server/rump_fs/file_system.h @@ -13,6 +13,11 @@ #ifndef _FILE_SYSTEM_H_ #define _FILE_SYSTEM_H_ +/* Genode includes */ +#include +#include +#include + extern "C" { #include #include @@ -26,7 +31,7 @@ extern "C" { } namespace File_system { - void init(); + void init(Genode::Env &, Genode::Allocator &heap, Genode::Xml_node config); bool supports_symlinks(); } diff --git a/repos/dde_rump/src/server/rump_fs/main.cc b/repos/dde_rump/src/server/rump_fs/main.cc index 4a8fe3e847..fef4519acc 100644 --- a/repos/dde_rump/src/server/rump_fs/main.cc +++ b/repos/dde_rump/src/server/rump_fs/main.cc @@ -15,6 +15,7 @@ /* Genode includes */ #include #include +#include #include #include #include @@ -481,16 +482,20 @@ struct File_system::Main Genode::Signal_handler
sync_handler { env.ep(), *this, &Main::sync }; + Heap heap { env.ram(), env.rm() }; + /* * Initialize root interface */ - Sliced_heap sliced_heap = { env.ram(), env.rm() }; + Sliced_heap sliced_heap { env.ram(), env.rm() }; - Root fs_root = { env, sliced_heap }; + Root fs_root { env, sliced_heap }; + + Attached_rom_dataspace config { env, "config" }; Main(Genode::Env &env) : env(env) { - File_system::init(); + File_system::init(env, heap, config.xml()); /* set all bits but the stickies */ rump_sys_umask(S_ISUID|S_ISGID|S_ISVTX); diff --git a/repos/libports/src/lib/libc/dynamic_linker.cc b/repos/libports/src/lib/libc/dynamic_linker.cc index 798d008c3a..4f97bbbcb1 100644 --- a/repos/libports/src/lib/libc/dynamic_linker.cc +++ b/repos/libports/src/lib/libc/dynamic_linker.cc @@ -11,6 +11,9 @@ #include #include +/* libc-internal includes */ +#include + extern "C" { #include } @@ -26,6 +29,19 @@ char *dlerror(void) } +static Genode::Env *genode_env = nullptr; + + +namespace Libc { + + void init_dl(Genode::Env &env) + { + if (!genode_env) + genode_env = &env; + } +} + + static Shared_object *to_object(void *handle) { return static_cast(handle); @@ -39,21 +55,28 @@ void *dlopen(const char *name, int mode) /* error on unsupported mode values */ if (mode & ~supported) { snprintf(err_str, MAX_ERR, "Unsupported mode 0x%x\n", mode & ~supported); - error("dlopen: ", Cstring(err_str)); + error(__func__, ": ", Cstring(err_str)); return nullptr; } - Shared_object *obj = 0; - unsigned flags = mode & RTLD_NOW ? Shared_object::NOW : Shared_object::LAZY; - flags |= mode & RTLD_NODELETE ? Shared_object::KEEP : 0; + Shared_object::Bind const bind = + (mode & RTLD_NOW) ? Shared_object::BIND_NOW : Shared_object::BIND_LAZY; + + Shared_object::Keep const keep = + (mode & RTLD_NODELETE) ? Shared_object::KEEP : Shared_object::DONT_KEEP; + + if (!genode_env) { + error(__func__, ": support for dynamic linking not initialized"); + return nullptr; + } try { - obj = new (env()->heap()) Shared_object(name, flags); + return new (env()->heap()) + Shared_object(*genode_env, *env()->heap(), name, bind, keep); } catch (...) { snprintf(err_str, MAX_ERR, "Unable to open file %s\n", name); } - - return (void *)obj; + return nullptr; } diff --git a/repos/libports/src/lib/libc/libc_init.h b/repos/libports/src/lib/libc/libc_init.h new file mode 100644 index 0000000000..7fe5d0c2b4 --- /dev/null +++ b/repos/libports/src/lib/libc/libc_init.h @@ -0,0 +1,28 @@ +/* + * \brief Interfaces for initializing libc subsystems + * \author Norman Feske + * \date 2016-10-27 + */ + +/* + * Copyright (C) 2016 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 _LIBC_INIT_H_ +#define _LIBC_INIT_H_ + +/* Genode includes */ +#include + +namespace Libc { + + /** + * Support for shared libraries + */ + void init_dl(Genode::Env &env); +} + +#endif /* _LIBC_INIT_H_ */ diff --git a/repos/libports/src/lib/libc/task.cc b/repos/libports/src/lib/libc/task.cc index 62e5860c6b..4ca4caa9e4 100644 --- a/repos/libports/src/lib/libc/task.cc +++ b/repos/libports/src/lib/libc/task.cc @@ -23,6 +23,7 @@ #include #include #include "vfs_plugin.h" +#include "libc_init.h" /* escape sequences for highlighting debug message prefixes */ @@ -203,6 +204,9 @@ namespace Genode { extern void (*call_component_construct)(Genode::Env &); } void Libc::call_component_construct(Genode::Env &env) { + /* pass Genode::Env to libc subsystems that depend on it */ + init_dl(env); + task = unmanaged_singleton(env); task->run(); } diff --git a/repos/libports/src/test/ldso/main.cc b/repos/libports/src/test/ldso/main.cc index 8fe68c41e2..93d28fe3cb 100644 --- a/repos/libports/src/test/ldso/main.cc +++ b/repos/libports/src/test/ldso/main.cc @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include using namespace Genode; @@ -166,7 +168,7 @@ static void test_dynamic_cast() ** Shared-object API ** ***********************/ -static void test_shared_object_api() +static void test_shared_object_api(Env &env, Allocator &alloc) { /* * When loading the shared object, we expect the global constructor @@ -175,15 +177,18 @@ static void test_shared_object_api() * 'lib_dl_so' is a local variable such that its destructor is called * when leaving the scope of the function. */ - Shared_object lib_dl_so("test-ldso_lib_dl.lib.so"); + Shared_object lib_dl_so(env, alloc, "test-ldso_lib_dl.lib.so", + Shared_object::BIND_LAZY, Shared_object::DONT_KEEP); } /** * Main function of LDSO test */ -int main(int argc, char **argv) +void Component::construct(Genode::Env &env) { + static Heap heap(env.ram(), env.rm()); + printf("\n"); printf("Dynamic-linker test\n"); printf("===================\n"); @@ -250,12 +255,11 @@ int main(int argc, char **argv) printf("Shared-object API\n"); printf("-----------------\n"); - test_shared_object_api(); + test_shared_object_api(env, heap); printf("\n"); printf("Destruction\n"); printf("-----------\n"); - /* test if return value is propagated correctly by dynamic linker */ - return 123; + Libc::exit(123); } diff --git a/repos/os/src/lib/vfs/file_system_factory.cc b/repos/os/src/lib/vfs/file_system_factory.cc index 0d09376c6d..951c0c9cea 100644 --- a/repos/os/src/lib/vfs/file_system_factory.cc +++ b/repos/os/src/lib/vfs/file_system_factory.cc @@ -132,14 +132,17 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory /** * \throw Factory_not_available */ - Vfs::File_system_factory &_load_factory(Genode::Allocator &alloc, + Vfs::File_system_factory &_load_factory(Genode::Env &env, + Genode::Allocator &alloc, Library_name const &lib_name) { Genode::Shared_object *shared_object = nullptr; try { shared_object = new (alloc) - Genode::Shared_object(lib_name.string()); + Genode::Shared_object(env, alloc, lib_name.string(), + Genode::Shared_object::BIND_LAZY, + Genode::Shared_object::DONT_KEEP); typedef Vfs::File_system_factory *(*Query_fn)(); @@ -147,7 +150,7 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory return *query_fn(); - } catch (Genode::Shared_object::Invalid_file) { + } catch (Genode::Shared_object::Invalid_rom_module) { PWRN("could not open '%s'", lib_name.string()); throw Factory_not_available(); @@ -160,13 +163,15 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory } } - bool _probe_external_factory(Genode::Allocator &alloc, Genode::Xml_node node) + bool _probe_external_factory(Genode::Env &env, Genode::Allocator &alloc, + Genode::Xml_node node) { Library_name const lib_name = _library_name(_node_name(node)); try { _list.insert(new (alloc) - External_entry(_node_name(node).string(), _load_factory(alloc, lib_name))); + External_entry(_node_name(node).string(), + _load_factory(env, alloc, lib_name))); return true; } catch (Factory_not_available) { return false; } @@ -187,7 +192,7 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory try { /* probe for file system implementation available as shared lib */ - if (_probe_external_factory(alloc, node)) { + if (_probe_external_factory(env, alloc, node)) { /* try again with the new file system type loaded */ if (Vfs::File_system *fs = _try_create(env, alloc, node)) return fs;