Clean ldso from using deprecated APIs

Issue #1987
This commit is contained in:
Norman Feske 2016-10-30 15:17:24 +01:00 committed by Christian Helmuth
parent 20faa8b84e
commit 784e728727
40 changed files with 1535 additions and 1136 deletions

View File

@ -87,6 +87,13 @@ namespace Genode {
*/ */
extern void (*call_component_construct)(Genode::Env &) __attribute__((weak)); 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) static void lx_hybrid_component_construct(Genode::Env &env)

View File

@ -18,8 +18,8 @@
#include <base/entrypoint.h> #include <base/entrypoint.h>
#include <ram_session/capability.h> #include <ram_session/capability.h>
#include <cpu_session/capability.h> #include <cpu_session/capability.h>
#include <pd_session/capability.h>
#include <rm_session/rm_session.h> #include <rm_session/rm_session.h>
#include <pd_session/pd_session.h>
/* maintain compatibility to deprecated API */ /* maintain compatibility to deprecated API */
#include <deprecated/env.h> #include <deprecated/env.h>
@ -64,6 +64,15 @@ struct Genode::Env
virtual Ram_session_capability ram_session_cap() = 0; virtual Ram_session_capability ram_session_cap() = 0;
virtual Cpu_session_capability cpu_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_ */ #endif /* _INCLUDE__BASE__ENV_H_ */

View File

@ -29,29 +29,36 @@ class Genode::Shared_object
private: private:
void *_handle = nullptr; void *_handle = nullptr;
void *_lookup(const char *symbol) const; void *_lookup(const char *symbol) const;
Allocator &_md_alloc;
public: public:
class Invalid_file : public Genode::Exception { }; class Invalid_rom_module : public Genode::Exception { };
class Invalid_symbol : public Genode::Exception { }; class Invalid_symbol : public Genode::Exception { };
enum open_flags { enum Keep { DONT_KEEP, KEEP };
NOW = 0x1, enum Bind { BIND_LAZY, BIND_NOW };
LAZY = 0x2,
KEEP = 0x4, /* do not unload on destruction */
};
/** /**
* Load shared object and dependencies * Load shared object and dependencies
* *
* \param file Shared object to load * \param env Genode environment, needed to obtain the ROM module
* \param flags LAZY for lazy function binding, NOW for immediate binding * 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 * Close and unload shared object
@ -80,14 +87,14 @@ class Genode::Shared_object
Genode::addr_t addr; /* load address */ Genode::addr_t addr; /* load address */
char const *path; /* object path */ char const *path; /* object path */
void const *dynamic; /* pointer to DYNAMIC section */ void const *dynamic; /* pointer to DYNAMIC section */
Link_map *next; Link_map const *next;
Link_map *prev; Link_map const *prev;
}; };
/** /**
* Return link map of shared object * Return link map of shared object
*/ */
Link_map const * link_map() const; Link_map const &link_map() const;
}; };

View File

@ -1,4 +1,5 @@
CXX_SRC_CC += misc.cc new_delete.cc malloc_free.cc exception.cc guard.cc 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 # We need the libsupc++ include directory
STDINC = yes STDINC = yes

View File

@ -4,7 +4,7 @@ DIR = $(REP_DIR)/src/lib/ldso
include $(BASE_DIR)/mk/base-libs.mk include $(BASE_DIR)/mk/base-libs.mk
LIBS = $(BASE_LIBS) 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 shared_object.cc
SRC_S = jmp_slot.s SRC_S = jmp_slot.s
INC_DIR += $(DIR)/include INC_DIR += $(DIR)/include

View File

@ -26,6 +26,9 @@ namespace Genode {
extern Region_map *env_stack_area_region_map; extern Region_map *env_stack_area_region_map;
extern Ram_session *env_stack_area_ram_session; 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_signal_thread(Env &);
void init_log(); void init_log();
} }

View File

@ -16,6 +16,9 @@
#include <base/component.h> #include <base/component.h>
#include <base/env.h> #include <base/env.h>
/* base-internal includes */
#include <base/internal/globals.h>
namespace { namespace {
@ -41,6 +44,11 @@ namespace {
{ {
return Genode::env()->cpu_session_cap(); 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 }; ::Env env { ep };
bool const exception_handling = (init_exception_handling(env), true);
/* /*
* The construction of the main entrypoint does never return. * The construction of the main entrypoint does never return.
*/ */

View File

@ -19,6 +19,9 @@
#include <base/log.h> #include <base/log.h>
#include <util/string.h> #include <util/string.h>
/* base-internal includes */
#include <base/internal/globals.h>
extern "C" char __eh_frame_start__[]; /* from linker script */ extern "C" char __eh_frame_start__[]; /* from linker script */
extern "C" void __register_frame (const void *begin); /* from libgcc_eh */ extern "C" void __register_frame (const void *begin); /* from libgcc_eh */
extern "C" char *__cxa_demangle(const char *mangled_name, 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 * Initialization
*/ */
void Genode::init_exception_handling(Env &env)
void init_exception_handling()
{ {
init_ldso_phdr(env);
init_cxx_heap(env);
__register_frame(__eh_frame_start__); __register_frame(__eh_frame_start__);
std::set_terminate(terminate_handler); 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 (...) { }
} }

View File

@ -14,37 +14,44 @@
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */
#include <base/env.h> #include <base/env.h>
#include <base/heap.h> #include <base/heap.h>
#include <util/string.h> #include <util/string.h>
#include <util/volatile_object.h>
/* base-internal includes */
#include <base/internal/globals.h>
using namespace Genode; using namespace Genode;
static Lazy_volatile_object<Heap> &cxx_heap()
{
static Lazy_volatile_object<Heap> heap;
return heap;
}
/** /**
* Return heap partition for the private use within the cxx library. * 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 * For creating the exception object, the C++ runtime calls
* deadlock when a 'Ram_session::Alloc_failed' exception is thrown from within * '__cxa_allocate_exception', which, in turn, calls 'malloc'. The cxx library
* 'Heap::alloc'. For creating the exception object, the C++ runtime calls * uses a local implementation of 'malloc' using a dedicated heap instance.
* '__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.
*/ */
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 * 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'. * is used only if the demand exceeds the capacity of the 'initial_block'.
*/ */
static char initial_block[1024*sizeof(long)]; static char initial_block[1024*sizeof(long)];
static Heap heap(env()->ram_session(), env()->rm_session(), cxx_heap().construct(&env.ram(), &env.rm(),
Heap::UNLIMITED, initial_block, sizeof(initial_block)); Heap::UNLIMITED, initial_block, sizeof(initial_block));
return &heap;
} }

View File

@ -26,15 +26,15 @@ void binary_ready_hook_for_gdb() { }
extern "C" void brk(Linker::Debug *, Linker::Link_map *) { } 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()) if (o->is_binary())
continue; continue;
Genode::log(" ", Genode::Hex(o->link_map()->addr), log(" ", Hex(o->link_map().addr),
" .. ", Genode::Hex(o->link_map()->addr + o->size() - 1), " .. ", Hex(o->link_map().addr + o->size() - 1),
": ", o->name()); ": ", o->name());
} }
} }

View File

@ -19,63 +19,77 @@
/** /**
* Dependency node * Dependency node
*/ */
Linker::Dependency::Dependency(char const *path, Root_object *root, Linker::Dependency::Dependency(Env &env, Allocator &md_alloc,
Genode::Fifo<Dependency> * const dep, char const *path, Root_object *root,
unsigned flags) Fifo<Dependency> &deps,
: obj(load(path, this, flags)), root(root) Keep keep)
:
_obj(load(env, md_alloc, path, *this, keep)),
_root(root),
_md_alloc(&md_alloc)
{ {
dep->enqueue(this); deps.enqueue(this);
load_needed(dep, flags); load_needed(env, *_md_alloc, deps, keep);
} }
Linker::Dependency::~Dependency() Linker::Dependency::~Dependency()
{ {
if (obj->unload()) { if (!_obj.unload())
return;
if (verbose_loading) if (verbose_loading)
Genode::log("Destroy: ", obj->name()); log("Destroy: ", _obj.name());
destroy(Genode::env()->heap(), obj); destroy(_md_alloc, &_obj);
}
} }
bool Linker::Dependency::in_dep(char const *file, bool Linker::Dependency::in_dep(char const *file, Fifo<Dependency> const &dep)
Genode::Fifo<Dependency> * const dep)
{ {
for (Dependency *d = dep->head(); d; d = d->next()) for (Dependency const *d = dep.head(); d; d = d->next())
if (!Genode::strcmp(file, d->obj->name())) if (!strcmp(file, d->obj().name()))
return true; return true;
return false; return false;
} }
void Linker::Dependency::load_needed(Genode::Fifo<Dependency> * const dep, void Linker::Dependency::load_needed(Env &env, Allocator &md_alloc,
unsigned flags) Fifo<Dependency> &deps, Keep keep)
{ {
for (Dynamic::Needed *n = obj->dynamic()->needed.head(); n; n = n->next()) { _obj.dynamic().for_each_dependency([&] (char const *path) {
char const *path = n->path(obj->dynamic()->strtab);
Object *o; if (!in_dep(Linker::file(path), deps))
if (!in_dep(Linker::file(path), dep)) new (md_alloc) Dependency(env, md_alloc, path, _root, deps, keep);
new (Genode::env()->heap()) Dependency(path, root, dep, flags);
/* re-order initializer list, if needed object has been already added */ /* 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); 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 */ /* 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 */ /* relocate and call constructors */
Init::list()->initialize(); Init::list()->initialize(bind);
} }

View File

@ -11,6 +11,7 @@
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
#include <base/log.h>
#include <linker.h> #include <linker.h>
@ -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; int err = 0;
Phdr_info info; Phdr_info info;
Genode::Lock::Guard guard(Object::lock()); Lock::Guard guard(lock());
for (Object *e = obj_list_head();e; e = e->next_obj()) { 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; info.phnum = e->file()->phdr.count;
if (verbose_exception) 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))) if ((err = callback(&info, sizeof(Phdr_info), data)))
break; break;
@ -87,16 +88,10 @@ extern "C" unsigned long dl_unwind_find_exidx(unsigned long pc, int *pcount)
enum { EXIDX_ENTRY_SIZE = 8 }; enum { EXIDX_ENTRY_SIZE = 8 };
*pcount = 0; *pcount = 0;
/* for (Object *e = obj_list_head(); e; e = e->next_obj()) {
* Since this function may be called before the main function, load linker's
* program header now
*/
load_linker_phdr();
for (Object *e = obj_list_head(); e; e = e->next_obj())
{
/* address of first PT_LOAD header */ /* 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 */ /* is the 'pc' somewhere within this ELF image */
if ((pc < base) || (pc >= base + e->file()->size)) if ((pc < base) || (pc >= base + e->file()->size))

View File

@ -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 <linker.h>
#include <base/internal/page_size.h>
/* Genode includes */
#include <util/construct_at.h>
#include <base/allocator_avl.h>
#include <base/env.h>
#include <os/attached_rom_dataspace.h>
#include <region_map/client.h>
#include <util/retry.h>
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<Rm_area>(placeholder, base);
constructed = 1;
}
return reinterpret_cast<Rm_area *>(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<Region_map::Out_of_metadata>(
[&] () {
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<Region_map::Out_of_metadata>(
[&] () {
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;
}

View File

@ -18,14 +18,21 @@
#include <base/log.h> #include <base/log.h>
#include <elf.h> #include <elf.h>
/* local includes */
#include <types.h>
constexpr bool verbose_link_map = false; 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 { namespace Linker {
struct Debug; struct Debug;
struct Link_map; struct Link_map;
struct Object; struct Object;
void dump_link_map(Object *o); void dump_link_map(Object const &);
} }
/* /*
@ -128,8 +135,8 @@ struct Linker::Link_map
return; return;
for (Link_map *m = first; m; m = m->next) for (Link_map *m = first; m; m = m->next)
Genode::log("MAP: addr: ", Genode::Hex(m->addr), log("MAP: addr: ", Hex(m->addr),
" dynamic: ", m->dynamic, " ", Genode::Cstring(m->path), " dynamic: ", m->dynamic, " ", Cstring(m->path),
" m: ", m, " p: ", m->prev, " n: ", m->next); " m: ", m, " p: ", m->prev, " n: ", m->next);
} }
}; };

View File

@ -14,6 +14,8 @@
#ifndef _INCLUDE__DYNAMIC_H_ #ifndef _INCLUDE__DYNAMIC_H_
#define _INCLUDE__DYNAMIC_H_ #define _INCLUDE__DYNAMIC_H_
/* local includes */
#include <types.h>
#include <relocation.h> #include <relocation.h>
namespace Linker { namespace Linker {
@ -54,13 +56,19 @@ struct Linker::Hash_table
/** /**
* .dynamic section entries * .dynamic section entries
*/ */
struct Linker::Dynamic class Linker::Dynamic
{ {
struct Needed : Genode::Fifo<Needed>::Element public:
{
Genode::off_t offset;
Needed(Genode::off_t offset) : offset(offset) { } class Dynamic_section_missing { };
private:
struct Needed : Fifo<Needed>::Element
{
off_t offset;
Needed(off_t offset) : offset(offset) { }
char const *path(char const *strtab) char const *path(char const *strtab)
{ {
@ -73,143 +81,272 @@ struct Linker::Dynamic
} }
}; };
Dependency const *dep; Dependency const *_dep;
Object const *obj; Object const &_obj;
Elf::Dyn const *dynamic; Elf::Dyn const &_dynamic;
Hash_table *hash_table = nullptr; Allocator *_md_alloc = nullptr;
Elf::Rela *reloca = nullptr; Hash_table *_hash_table = nullptr;
unsigned long reloca_size = 0;
Elf::Sym *symtab = nullptr; Elf::Rela *_reloca = nullptr;
char *strtab = nullptr; unsigned long _reloca_size = 0;
unsigned long strtab_size = 0;
Elf::Addr *pltgot = nullptr; Elf::Sym *_symtab = nullptr;
char *_strtab = nullptr;
unsigned long _strtab_size = 0;
Elf::Rel *pltrel = nullptr; Elf::Addr *_pltgot = nullptr;
unsigned long pltrel_size = 0;
D_tag pltrel_type = DT_NULL;
Func init_function = nullptr; Elf::Rel *_pltrel = nullptr;
unsigned long _pltrel_size = 0;
D_tag _pltrel_type = DT_NULL;
Elf::Rel *rel = nullptr; Func _init_function = nullptr;
unsigned long rel_size = 0;
Genode::Fifo<Needed> needed; Elf::Rel *_rel = nullptr;
unsigned long _rel_size = 0;
Dynamic(Dependency const *dep) Fifo<Needed> _needed;
:
dep(dep), obj(dep->obj), dynamic((Elf::Dyn *)dynamic_address())
{
init();
}
Dynamic(Dependency const *dep, Object const *obj, Linker::Phdr const *phdr) /**
: * \throw Dynamic_section_missing
dep(dep), obj(obj), dynamic(find_dynamic(phdr)) */
{ Elf::Dyn const &_find_dynamic(Linker::Phdr const *p)
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++) for (unsigned i = 0; i < p->count; i++)
if (p->phdr[i].p_type == PT_DYNAMIC) if (p->phdr[i].p_type == PT_DYNAMIC)
return reinterpret_cast<Elf::Dyn const *>(p->phdr[i].p_vaddr + obj->reloc_base()); return *reinterpret_cast<Elf::Dyn const *>
(p->phdr[i].p_vaddr + _obj.reloc_base());
return 0; throw Dynamic_section_missing();
} }
void section_dt_needed(Elf::Dyn const *d) void _section_dt_needed(Elf::Dyn const *d)
{ {
Needed *n = new(Genode::env()->heap()) Needed(d->un.ptr); if (!_md_alloc) {
needed.enqueue(n); error("unexpected call of section_dt_needed");
return;
}
Needed *n = new (*_md_alloc) Needed(d->un.ptr);
_needed.enqueue(n);
} }
template <typename T> template <typename T>
void section(T *member, Elf::Dyn const *d) void _section(T *member, Elf::Dyn const *d)
{ {
*member = (T)(obj->reloc_base() + d->un.ptr); *member = (T)(_obj.reloc_base() + d->un.ptr);
} }
void section_dt_debug(Elf::Dyn const *d) void _section_dt_debug(Elf::Dyn const *d)
{ {
Elf::Dyn *_d = const_cast<Elf::Dyn *>(d); Elf::Dyn *_d = const_cast<Elf::Dyn *>(d);
_d->un.ptr = (Elf::Addr)Debug::d(); _d->un.ptr = (Elf::Addr)Debug::d();
} }
void init() void _init()
{ {
for (Elf::Dyn const *d = dynamic; d->tag != DT_NULL; d++) { for (Elf::Dyn const *d = &_dynamic; d->tag != DT_NULL; d++) {
switch (d->tag) { switch (d->tag) {
case DT_NEEDED : _section_dt_needed(d); break;
case DT_NEEDED : section_dt_needed(d); break; case DT_PLTRELSZ: _pltrel_size = d->un.val; break;
case DT_PLTRELSZ: pltrel_size = d->un.val; break; case DT_PLTGOT : _section<typeof(_pltgot)>(&_pltgot, d); break;
case DT_PLTGOT : section<typeof(pltgot)>(&pltgot, d); break; case DT_HASH : _section<typeof(_hash_table)>(&_hash_table, d); break;
case DT_HASH : section<typeof(hash_table)>(&hash_table, d); break; case DT_RELA : _section<typeof(_reloca)>(&_reloca, d); break;
case DT_RELA : section<typeof(reloca)>(&reloca, d); break; case DT_RELASZ : _reloca_size = d->un.val; break;
case DT_RELASZ : reloca_size = d->un.val; break; case DT_SYMTAB : _section<typeof(_symtab)>(&_symtab, d); break;
case DT_SYMTAB : section<typeof(symtab)>(&symtab, d); break; case DT_STRTAB : _section<typeof(_strtab)>(&_strtab, d); break;
case DT_STRTAB : section<typeof(strtab)>(&strtab, d); break; case DT_STRSZ : _strtab_size = d->un.val; break;
case DT_STRSZ : strtab_size = d->un.val; break; case DT_INIT : _section<typeof(_init_function)>(&_init_function, d); break;
case DT_INIT : section<typeof(init_function)>(&init_function, d); break; case DT_PLTREL : _pltrel_type = (D_tag)d->un.val; break;
case DT_PLTREL : pltrel_type = (D_tag)d->un.val; break; case DT_JMPREL : _section<typeof(_pltrel)>(&_pltrel, d); break;
case DT_JMPREL : section<typeof(pltrel)>(&pltrel, d); break; case DT_REL : _section<typeof(_rel)>(&_rel, d); break;
case DT_REL : section<typeof(rel)>(&rel, d); break; case DT_RELSZ : _rel_size = d->un.val; break;
case DT_RELSZ : rel_size = d->un.val; break; case DT_DEBUG : _section_dt_debug(d); break;
case DT_DEBUG : section_dt_debug(d); break;
default: default:
break; break;
} }
} }
} }
void relocate() public:
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 <typename FUNC>
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(); plt_setup();
if (pltrel_size) { if (_pltrel_size) {
switch (pltrel_type) { switch (_pltrel_type) {
case DT_RELA: case DT_RELA:
case DT_REL: case DT_REL:
Reloc_plt(obj, pltrel_type, pltrel, pltrel_size); Reloc_plt(_obj, _pltrel_type, _pltrel, _pltrel_size);
break; break;
default: default:
Genode::error("LD: Invalid PLT relocation ", (int)pltrel_type); error("LD: Invalid PLT relocation ", (int)_pltrel_type);
throw Incompatible(); throw Incompatible();
} }
} }
relocate_non_plt(); relocate_non_plt(bind, FIRST_PASS);
} }
void plt_setup() void plt_setup()
{ {
if (pltgot) if (_pltgot)
Plt_got r(dep, pltgot); Plt_got r(*_dep, _pltgot);
} }
void relocate_non_plt(bool second_pass = false) void relocate_non_plt(Bind bind, Pass pass)
{ {
if (reloca) if (_reloca)
Reloc_non_plt r(dep, reloca, reloca_size); Reloc_non_plt r(*_dep, _reloca, _reloca_size);
if (rel) if (_rel)
Reloc_non_plt r(dep, rel, rel_size, second_pass); Reloc_non_plt r(*_dep, _rel, _rel_size, pass == SECOND_PASS);
if (bind_now) if (bind == BIND_NOW)
Reloc_bind_now r(dep, pltrel, pltrel_size); 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_ */ #endif /* _INCLUDE__DYNAMIC_H_ */

View File

@ -1,4 +1,4 @@
/** /*
* \brief ELF file setup * \brief ELF file setup
* \author Sebastian Sumpf * \author Sebastian Sumpf
* \date 2015-03-12 * \date 2015-03-12
@ -14,23 +14,20 @@
#ifndef _INCLUDE__FILE_H_ #ifndef _INCLUDE__FILE_H_
#define _INCLUDE__FILE_H_ #define _INCLUDE__FILE_H_
/* Genode includes */
#include <os/attached_rom_dataspace.h>
/* local includes */
#include <util.h>
#include <debug.h>
#include <region_map.h>
namespace Linker { namespace Linker {
struct Phdr; struct Phdr;
struct File; struct File;
struct Elf_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);
} }
@ -47,7 +44,7 @@ struct Linker::Phdr
/** /**
* Loaded ELF file * ELF file info
*/ */
struct Linker::File struct Linker::File
{ {
@ -72,4 +69,208 @@ struct Linker::File
unsigned elf_phdr_count() const { return phdr.count; } 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<Elf::Ehdr>();
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_ */ #endif /* _INCLUDE__FILE_H_ */

View File

@ -25,7 +25,7 @@ namespace Linker {
/** /**
* Handle static construction and relocation of ELF files * Handle static construction and relocation of ELF files
*/ */
struct Linker::Init : Genode::List<Object> struct Linker::Init : List<Object>
{ {
bool in_progress = false; bool in_progress = false;
bool restart = false; bool restart = false;
@ -39,7 +39,7 @@ struct Linker::Init : Genode::List<Object>
Object *contains(char const *file) Object *contains(char const *file)
{ {
for (Object *elf = first(); elf; elf = elf->next_init()) for (Object *elf = first(); elf; elf = elf->next_init())
if (!Genode::strcmp(file, elf->name())) if (!strcmp(file, elf->name()))
return elf; return elf;
return nullptr; return nullptr;
@ -52,24 +52,25 @@ struct Linker::Init : Genode::List<Object>
insert(elf); insert(elf);
/* re-order dependencies */ /* re-order dependencies */
for (Dynamic::Needed *n = elf->dynamic()->needed.head(); n; n = n->next()) { elf->dynamic().for_each_dependency([&] (char const *path) {
char const *path = n->path(elf->dynamic()->strtab);
Object *e;
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); reorder(e);
} });
} }
void initialize() void initialize(Bind bind)
{ {
Object *obj = first(); Object *obj = first();
/* relocate */ /* relocate */
for (; obj; obj = obj->next_init()) { for (; obj; obj = obj->next_init()) {
if (verbose_relocation) if (verbose_relocation)
Genode::log("Relocate ", obj->name()); log("Relocate ", obj->name());
obj->relocate(); obj->relocate(bind);
} }
/* /*
@ -91,13 +92,7 @@ struct Linker::Init : Genode::List<Object>
Object *next = obj->next_init(); Object *next = obj->next_init();
remove(obj); remove(obj);
if (obj->dynamic()->init_function) { obj->dynamic().call_init_function();
if (verbose_relocation)
Genode::log(obj->name(), " init func ", obj->dynamic()->init_function);
obj->dynamic()->init_function();
}
obj = restart ? first() : next; obj = restart ? first() : next;
restart = false; restart = false;

View File

@ -1,4 +1,4 @@
/** /*
* \brief Generic linker definitions * \brief Generic linker definitions
* \author Sebastian Sumpf * \author Sebastian Sumpf
* \date 2014-10-24 * \date 2014-10-24
@ -14,28 +14,12 @@
#ifndef _INCLUDE__LINKER_H_ #ifndef _INCLUDE__LINKER_H_
#define _INCLUDE__LINKER_H_ #define _INCLUDE__LINKER_H_
#include <base/exception.h> #include <types.h>
#include <base/env.h>
#include <base/shared_object.h>
#include <util/fifo.h>
#include <util/misc_math.h>
#include <util/string.h>
#include <debug.h> #include <debug.h>
#include <elf.h> #include <elf.h>
#include <file.h> #include <file.h>
#include <util.h> #include <util.h>
/**
* 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 * Forward declartions and helpers
*/ */
@ -48,11 +32,6 @@ namespace Linker {
typedef void (*Func)(void); typedef void (*Func)(void);
/**
* Eager binding enable
*/
extern bool bind_now;
/** /**
* Print diagnostic information * Print diagnostic information
* *
@ -75,7 +54,7 @@ namespace Linker {
* *
* \return Symbol information * \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); bool undef = false, bool other = false);
/** /**
@ -93,20 +72,22 @@ namespace Linker {
* *
* \return Symbol information * \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); bool undef = false, bool other = false);
/** /**
* Load an ELF (setup segments and map program header) * Load an ELF (setup segments and map program header)
* *
* \param path File to load * \param md_alloc allocator used for dyamically allocater meta data
* \param dep Dependency entry for new object * \param path rom module to load
* \param flags 'Genode::Shared_object::KEEP' will not unload the ELF, if the * \param dep dependency entry for new object
* reference count reaches zero * \param flags 'Shared_object::KEEP' will not unload the ELF,
* if the reference count reaches zero
* *
* \return Linker::Object * \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 * Returns the head of the global object list
@ -119,16 +100,9 @@ namespace Linker {
Dependency *binary_root_dep(); Dependency *binary_root_dep();
/** /**
* Force to map the program header of the dynamic linker * Global ELF access lock
*/ */
void load_linker_phdr(); Lock &lock();
/**
* Exceptions
*/
class Incompatible : Genode::Exception { };
class Invalid_file : Genode::Exception { };
class Not_found : Genode::Exception { };
/** /**
* Invariants * Invariants
@ -141,42 +115,45 @@ namespace Linker {
/** /**
* Shared object or binary * Shared object or binary
*/ */
class Linker::Object : public Genode::Fifo<Object>::Element, class Linker::Object : public Fifo<Object>::Element,
public Genode::List<Object>::Element public List<Object>::Element
{ {
public:
typedef String<128> Name;
protected: protected:
enum { MAX_PATH = 128 }; Name _name;
char _name[MAX_PATH];
File const *_file = nullptr; File const *_file = nullptr;
Elf::Addr _reloc_base = 0; Elf::Addr _reloc_base = 0;
public: public:
Object(Elf::Addr reloc_base) : _reloc_base(reloc_base) { } void init(Name const &name, Elf::Addr reloc_base)
Object(char const *path, File const *file)
: _file(file), _reloc_base(file->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) _name = name;
destroy(Genode::env()->heap(), const_cast<File *>(_file)); _file = &file;
_reloc_base = file.reloc_base;
} }
virtual ~Object() { }
Elf::Addr reloc_base() const { return _reloc_base; } Elf::Addr reloc_base() const { return _reloc_base; }
char const *name() const { return _name; } char const *name() const { return _name.string(); }
File const *file() const { return _file; }
File const *file() { return _file; }
Elf::Size const size() const { return _file ? _file->size : 0; } Elf::Size const size() const { return _file ? _file->size : 0; }
virtual bool is_linker() const = 0; virtual bool is_linker() const = 0;
virtual bool is_binary() const = 0; virtual bool is_binary() const = 0;
virtual void relocate() = 0; virtual void relocate(Bind) = 0;
virtual void load() = 0; virtual void load() = 0;
virtual bool unload() { return false;} virtual bool unload() { return false;}
@ -194,79 +171,104 @@ class Linker::Object : public Genode::Fifo<Object>::Element,
/** /**
* Return dynamic section of ELF * Return dynamic section of ELF
*/ */
virtual Dynamic *dynamic() = 0; virtual Dynamic const &dynamic() const = 0;
/** /**
* Return link map for ELF * 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 * Return address info for symboal at addr
*/ */
virtual void info(Genode::addr_t addr, Genode::Address_info &info) = 0; virtual Symbol_info symbol_at_address(addr_t addr) const = 0;
/**
* Global ELF access lock
*/
static Genode::Lock & lock()
{
static Genode::Lock _lock;
return _lock;
}
}; };
/** /**
* Dependency of object * Dependency of object
*/ */
struct Linker::Dependency : Genode::Fifo<Dependency>::Element class Linker::Dependency : public Fifo<Dependency>::Element, Noncopyable
{ {
Object *obj = nullptr; private:
Root_object *root = nullptr;
Dependency(Object *obj, Root_object *root) : obj(obj), root(root) { } Object &_obj;
Root_object *_root = nullptr;
Allocator *_md_alloc = nullptr;
/**
* Check if file is in this dependency tree
*/
bool in_dep(char const *file, Fifo<Dependency> const &);
public:
/*
* Called by 'Ld' constructor
*/
Dependency(Object &obj, Root_object *root) : _obj(obj), _root(root) { }
Dependency(Env &, Allocator &, char const *path, Root_object *,
Fifo<Dependency> &, Keep);
Dependency(char const *path, Root_object *root, Genode::Fifo<Dependency> * const dep,
unsigned flags = 0);
~Dependency(); ~Dependency();
/** /**
* Load dependent ELF object * Load dependent ELF object
*/ */
void load_needed(Genode::Fifo<Dependency> * const dep, unsigned flags = 0); void load_needed(Env &, Allocator &, Fifo<Dependency> &, Keep);
bool root() const { return _root != nullptr; }
Object const &obj() const { return _obj; }
/** /**
* Check if file is in this dependency tree * Return first element of dependency list
*/ */
bool in_dep(char const *file, Genode::Fifo<Dependency> *const dep); Dependency const &first() const;
}; };
/** /**
* Root of dependencies * Root of dependencies
*/ */
struct Linker::Root_object class Linker::Root_object
{ {
Genode::Fifo<Dependency> dep; private:
Fifo<Dependency> _deps;
Allocator &_md_alloc;
public:
/* main root */ /* main root */
Root_object() { }; Root_object(Allocator &md_alloc) : _md_alloc(md_alloc) { };
/* runtime loaded root components */ /* runtime loaded root components */
Root_object(char const *path, unsigned flags = 0); Root_object(Env &, Allocator &, char const *path, Bind, Keep);
~Root_object() ~Root_object()
{ {
Dependency *d; while (Dependency *d = _deps.dequeue())
while ((d = dep.dequeue())) destroy(_md_alloc, d);
destroy(Genode::env()->heap(), d);
} }
Link_map const *link_map() const Link_map const &link_map() const
{ {
return dep.head()->obj->link_map(); return _deps.head()->obj().link_map();
} }
Dependency const *first_dep() const { return _deps.head(); }
void enqueue(Dependency &dep) { _deps.enqueue(&dep); }
Fifo<Dependency> &deps() { return _deps; }
}; };
#endif /* _INCLUDE__LINKER_H_ */ #endif /* _INCLUDE__LINKER_H_ */

View File

@ -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 <base/env.h>
#include <region_map/client.h>
#include <base/allocator_avl.h>
#include <util/retry.h>
#include <util/volatile_object.h>
/* base-internal includes */
#include <base/internal/page_size.h>
/* local includes */
#include <linker.h>
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<Region_map> 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<Genode::Region_map::Out_of_metadata>(
[&] () {
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<Genode::Region_map::Out_of_metadata>(
[&] () {
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_ */

View File

@ -18,9 +18,9 @@
constexpr bool verbose_relocation = false; 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 struct Linker::Plt_got
{ {
Plt_got(Dependency const *dep, Elf::Addr *pltgot) Plt_got(Dependency const &dep, Elf::Addr *pltgot)
{ {
if (verbose_relocation) 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 */ pltgot[2] = (Elf::Addr) &_jmp_slot; /* Linker entry */
} }
}; };
@ -62,11 +62,11 @@ struct Linker::Plt_got
template<typename REL, unsigned TYPE, unsigned JMPSLOT> template<typename REL, unsigned TYPE, unsigned JMPSLOT>
struct Linker::Reloc_plt_generic 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) Elf::Rel const *start, unsigned long size)
{ {
if (type != TYPE) { if (type != TYPE) {
Genode::error("LD: Unsupported PLT relocation type: ", (int)type); error("LD: Unsupported PLT relocation type: ", (int)type);
throw Incompatible(); throw Incompatible();
} }
@ -75,13 +75,13 @@ struct Linker::Reloc_plt_generic
for (; rel < end; rel++) { for (; rel < end; rel++) {
if (rel->type() != JMPSLOT) { if (rel->type() != JMPSLOT) {
Genode::error("LD: Unsupported PLT relocation ", (int)rel->type()); error("LD: Unsupported PLT relocation ", (int)rel->type());
throw Incompatible(); throw Incompatible();
} }
/* find relocation address and add relocation base */ /* find relocation address and add relocation base */
Elf::Addr *addr = (Elf::Addr *)(obj->reloc_base() + rel->offset); Elf::Addr *addr = (Elf::Addr *)(obj.reloc_base() + rel->offset);
*addr += obj->reloc_base(); *addr += obj.reloc_base();
} }
} }
}; };
@ -91,7 +91,7 @@ class Linker::Reloc_non_plt_generic
{ {
protected: protected:
Dependency const *_dep; Dependency const &_dep;
/** /**
* Copy relocations, these are just for the main program, we can do them * Copy relocations, these are just for the main program, we can do them
@ -101,9 +101,9 @@ class Linker::Reloc_non_plt_generic
template <typename REL> template <typename REL>
void _copy(REL const *rel, Elf::Addr *addr) void _copy(REL const *rel, Elf::Addr *addr)
{ {
if (!_dep->obj->is_binary()) { if (!_dep.obj().is_binary()) {
Genode::error("LD: copy relocation in DSO " error("LD: copy relocation in DSO "
"(", _dep->obj->name(), " at ", addr, ")"); "(", _dep.obj().name(), " at ", addr, ")");
throw Incompatible(); throw Incompatible();
} }
@ -112,22 +112,22 @@ class Linker::Reloc_non_plt_generic
/* search symbol in other objects, do not return undefined symbols */ /* search symbol in other objects, do not return undefined symbols */
if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base, false, true))) { if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base, false, true))) {
Genode::warning("LD: symbol not found"); warning("LD: symbol not found");
return; return;
} }
Elf::Addr src = reloc_base + sym->st_value; 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) if (verbose_relocation)
Genode::log("Copy relocation: ", Genode::Hex(src), log("Copy relocation: ", Hex(src),
" -> ", addr, " (", Genode::Hex(sym->st_size), " bytes)" " -> ", addr, " (", Hex(sym->st_size), " bytes)"
" val: ", Genode::Hex(sym->st_value)); " val: ", Hex(sym->st_value));
} }
public: 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: 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) Elf::Size const index)
{ {
if (type != TYPE) { if (type != TYPE) {
Genode::error("LD: unsupported JMP relocation type: ", (int)type); error("LD: unsupported JMP relocation type: ", (int)type);
throw Incompatible(); throw Incompatible();
} }
@ -154,19 +154,19 @@ class Linker::Reloc_jmpslot_generic
Elf::Addr reloc_base; Elf::Addr reloc_base;
if (!(sym = lookup_symbol(rel->sym(), dep, &reloc_base))) { if (!(sym = lookup_symbol(rel->sym(), dep, &reloc_base))) {
Genode::warning("LD: symbol not found"); warning("LD: symbol not found");
return; return;
} }
/* write address of symbol to jump slot */ /* 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; *_addr = reloc_base + sym->st_value;
if (verbose_relocation) { if (verbose_relocation) {
Genode::log("jmp: rbase ", Genode::Hex(reloc_base), log("jmp: rbase ", Hex(reloc_base),
" s: ", sym, " sval: ", Genode::Hex(sym->st_value)); " s: ", sym, " sval: ", Hex(sym->st_value));
Genode::log("jmp_slot at ", _addr, " -> ", *_addr); log("jmp_slot at ", _addr, " -> ", *_addr);
} }
} }
@ -180,7 +180,7 @@ class Linker::Reloc_jmpslot_generic
template <typename REL, unsigned TYPE> template <typename REL, unsigned TYPE>
struct Linker::Reloc_bind_now_generic 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); Elf::Size last_index = size / sizeof(REL);

View File

@ -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 <base/exception.h>
#include <base/env.h>
#include <base/shared_object.h>
#include <util/volatile_object.h>
#include <util/fifo.h>
#include <util/misc_math.h>
#include <util/string.h>
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_ */

View File

@ -21,11 +21,11 @@ namespace Linker {
*/ */
template <typename T> template <typename T>
static inline T trunc_page(T addr) { static inline T trunc_page(T addr) {
return addr & Genode::_align_mask((T)12); } return addr & _align_mask((T)12); }
template <typename T> template <typename T>
static inline T round_page(T addr) { 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 * Extract file name from path

View File

@ -18,10 +18,16 @@
#include <util/list.h> #include <util/list.h>
#include <util/string.h> #include <util/string.h>
#include <base/thread.h> #include <base/thread.h>
#include <base/heap.h>
/* base-internal includes */
#include <base/internal/unmanaged_singleton.h>
#include <base/internal/globals.h>
/* local includes */ /* local includes */
#include <dynamic.h> #include <dynamic.h>
#include <init.h> #include <init.h>
#include <region_map.h>
using namespace Linker; using namespace Linker;
@ -32,11 +38,10 @@ namespace Linker {
struct Binary; struct Binary;
struct Link_map; struct Link_map;
struct Debug; struct Debug;
struct Config;
}; };
static Binary *binary = 0; static Binary *binary_ptr = nullptr;
bool Linker::bind_now = false;
bool Linker::verbose = false; bool Linker::verbose = false;
Link_map *Link_map::first; Link_map *Link_map::first;
@ -46,6 +51,25 @@ Link_map *Link_map::first;
int genode_atexit(Linker::Func); 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<Constructible_region_map>();
}
Genode::Lock &Linker::lock()
{
static Lock _lock;
return _lock;
}
/************************************************************** /**************************************************************
** ELF object types (shared object, dynamic binaries, ldso ** ** ELF object types (shared object, dynamic binaries, ldso **
**************************************************************/ **************************************************************/
@ -53,22 +77,47 @@ int genode_atexit(Linker::Func);
/** /**
* The actual ELF object, one per file * The actual ELF object, one per file
*/ */
struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element class Linker::Elf_object : public Object, public Fifo<Elf_object>::Element
{ {
Dynamic dyn; private:
Link_map map;
unsigned ref_count = 1;
unsigned flags = 0;
bool relocated = false;
Elf_object(Dependency const *dep, Elf::Addr reloc_base) Link_map _map;
: Object(reloc_base), dyn(dep) unsigned _ref_count = 1;
{ } unsigned const _keep = KEEP;
bool _relocated = false;
Elf_object(char const *path, Dependency const *dep, unsigned flags = 0) /*
* Optional ELF file, skipped for initial 'Ld' initialization
*/
Lazy_volatile_object<Elf_file> _elf_file;
bool _init_elf_file(Env &env, Allocator &md_alloc, char const *path)
{
_elf_file.construct(env, md_alloc, Linker::file(path), true);
Object::init(Linker::file(path), *_elf_file);
return true;
}
bool const _elf_file_initialized;
Dynamic _dyn;
public:
Elf_object(Dependency const &dep, Object::Name const &name,
Elf::Addr reloc_base)
: :
Object(path, Linker::load(Linker::file(path))), dyn(dep, this, &_file->phdr), _elf_file_initialized(false), _dyn(dep)
flags(flags) {
Object::init(name, reloc_base);
}
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 */ /* register for static construction and relocation */
Init::list()->insert(this); Init::list()->insert(this);
@ -77,7 +126,7 @@ struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element
/* add to link map */ /* add to link map */
Debug::state_change(Debug::ADD, nullptr); Debug::state_change(Debug::ADD, nullptr);
setup_link_map(); setup_link_map();
Debug::state_change(Debug::CONSISTENT, &map); Debug::state_change(Debug::CONSISTENT, &_map);
} }
virtual ~Elf_object() virtual ~Elf_object()
@ -86,11 +135,11 @@ struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element
return; return;
if (verbose_loading) if (verbose_loading)
Genode::log("LD: destroy ELF object: ", name()); log("LD: destroy ELF object: ", name());
/* remove from link map */ /* remove from link map */
Debug::state_change(Debug::DELETE, &map); Debug::state_change(Debug::DELETE, &_map);
Link_map::remove(&map); Link_map::remove(&_map);
Debug::state_change(Debug::CONSISTENT, nullptr); Debug::state_change(Debug::CONSISTENT, nullptr);
/* remove from loaded objects list */ /* remove from loaded objects list */
@ -102,56 +151,23 @@ struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element
*/ */
Elf::Sym const *symbol(unsigned sym_index) const Elf::Sym const *symbol(unsigned sym_index) const
{ {
if (sym_index > dyn.hash_table->nchains()) return _dyn.symbol(sym_index);
return 0;
return dyn.symtab + sym_index;
} }
// XXX remove this accessor?
void link_map_addr(addr_t addr) { _map.addr = addr; }
/** /**
* Return name of given symbol * Return name of given symbol
*/ */
char const *symbol_name(Elf::Sym const *sym) const { char const *symbol_name(Elf::Sym const &sym) const
return dyn.strtab + sym->st_name; {
return _dyn.symbol_name(sym);
} }
/**
* Lookup symbol name in this ELF
*/
Elf::Sym const *lookup_symbol(char const *name, unsigned long hash) const Elf::Sym const *lookup_symbol(char const *name, unsigned long hash) const
{ {
Hash_table *h = dyn.hash_table; return _dyn.lookup_symbol(name, hash);
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] || Genode::strcmp(name, sym_name))
continue;
return sym;
}
return nullptr;
} }
/** /**
@ -159,82 +175,64 @@ struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element
*/ */
void setup_link_map() void setup_link_map()
{ {
map.addr = _file ? _file->start + reloc_base() : reloc_base(); _map.addr = _file ? _file->start + reloc_base() : reloc_base();
map.path = name(); _map.path = name();
map.dynamic = (void *)dyn.dynamic; _map.dynamic = _dyn.dynamic_ptr();
Link_map::add(&map); Link_map::add(&_map);
}; };
Link_map const &link_map() const override { return _map; }
Dynamic const &dynamic() const override { return _dyn; }
Link_map *link_map() override { return &map; } void relocate_global() { _dyn.relocate_non_plt(BIND_NOW, Dynamic::SECOND_PASS); }
Dynamic *dynamic() override { return &dyn; }
void relocate() override void plt_setup() { _dyn.plt_setup(); }
void update_dependency(Dependency const &dep) { _dyn.dep(dep); }
void relocate(Bind bind) override
{ {
if (!relocated) if (!_relocated)
dyn.relocate(); _dyn.relocate(bind);
relocated = true; _relocated = true;
} }
void info(Genode::addr_t addr, Genode::Address_info &info) override addr_t base_addr() const { return _map.addr; }
Symbol_info symbol_at_address(addr_t addr) const override
{ {
info.path = name(); Elf::Sym const sym = _dyn.symbol_by_addr(addr);
info.base = map.addr;
info.addr = 0;
Hash_table *h = dyn.hash_table; return { _reloc_base + sym.st_value, _dyn.symbol_name(sym) };
for (unsigned long sym_index = 0; sym_index < h->nchains(); sym_index++)
{
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;
}
if (!info.addr)
throw Genode::Address_info::Invalid_address();
} }
/** /**
* Next in initializion list * Next in initializion list
*/ */
Object *next_init() const override { Object *next_init() const override {
return Genode::List<Object>::Element::next(); return List<Object>::Element::next();
} }
/** /**
* Next in object list * Next in object list
*/ */
Object *next_obj() const override { Object *next_obj() const override {
return Genode::Fifo<Elf_object>::Element::next(); return Fifo<Elf_object>::Element::next();
} }
/** /**
* Object list * Object list
*/ */
static Genode::Fifo<Elf_object> *obj_list() static Fifo<Elf_object> *obj_list()
{ {
static Genode::Fifo<Elf_object> _list; static Fifo<Elf_object> _list;
return &_list; return &_list;
} }
void load() override { _ref_count++; }
void load() override { ref_count++; } bool unload() override { return (_keep == DONT_KEEP) && !(--_ref_count); }
bool unload() override { return !(--ref_count) && !(flags & Genode::Shared_object::KEEP); }
bool is_linker() const override { return false; } bool is_linker() const override { return false; }
bool is_binary() const override { return false; } bool is_binary() const override { return false; }
@ -246,32 +244,24 @@ struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element
*/ */
struct Linker::Ld : Dependency, Elf_object struct Linker::Ld : Dependency, Elf_object
{ {
Ld() Ld() :
: Dependency(this, nullptr), Elf_object(this, relocation_address()) Dependency(*this, nullptr),
{ Elf_object(*this, linker_name(), relocation_address())
Genode::strncpy(_name, linker_name(), Object::MAX_PATH); { }
}
void setup_link_map() void setup_link_map()
{ {
Elf_object::setup_link_map(); Elf_object::setup_link_map();
/** link_map_addr(dynamic().link_map_addr());
* 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);
} }
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); } static Ld &linker();
void update_dependency(Dependency const *dep) { dynamic()->dep = dep; }
static Ld *linker();
bool is_linker() const override { return true; } 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 * Entry point for jump relocations, it is called from assembly code and is implemented
* right below) * 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) if (verbose_relocation)
Genode::log("LD: SLOT ", dep->obj, " ", Genode::Hex(index)); log("LD: SLOT ", &dep.obj(), " ", Hex(index));
try { try {
Reloc_jmpslot slot(dep, dep->obj->dynamic()->pltrel_type, Reloc_jmpslot slot(dep, dep.obj().dynamic().pltrel_type(),
dep->obj->dynamic()->pltrel, index); dep.obj().dynamic().pltrel(), index);
return slot.target_addr(); return slot.target_addr();
} catch (...) { Genode::error("LD: jump slot relocation failed. FATAL!"); } } catch (...) { error("LD: jump slot relocation failed. FATAL!"); }
return 0; return 0;
} }
/**
* Linker object used during bootstrapping on stack (see: 'init_rtld')
*/
Linker::Ld &Linker::Ld::linker()
{
/** /**
* Ld object with different vtable typeinfo * Ld object with different vtable typeinfo
*/ */
struct Linker::Ld_vtable : Ld struct Ld_vtable : Ld
{ {
Ld_vtable() Ld_vtable()
{ {
Elf_object::obj_list()->enqueue(this); Elf_object::obj_list()->enqueue(this);
plt_setup();
} }
}; };
/**
* Linker object used during bootstrapping on stack (see: 'init_rtld')
*/
Linker::Ld *Linker::Ld::linker()
{
static Ld_vtable _linker; static Ld_vtable _linker;
return &_linker; return _linker;
} }
@ -326,26 +316,28 @@ Linker::Ld *Linker::Ld::linker()
*/ */
struct Linker::Binary : Root_object, Elf_object struct Linker::Binary : Root_object, Elf_object
{ {
Binary() Binary(Env &env, Allocator &md_alloc, Bind bind)
: Elf_object(binary_name(), new (Genode::env()->heap()) Dependency(this, this)) :
Root_object(md_alloc),
Elf_object(env, md_alloc, binary_name(),
*new (md_alloc) Dependency(*this, this), KEEP)
{ {
/* create dep for binary and linker */ /* create dep for binary and linker */
Dependency *binary = const_cast<Dependency *>(dynamic()->dep); Dependency *binary = const_cast<Dependency *>(&dynamic().dep());
dep.enqueue(binary); Root_object::enqueue(*binary);
Dependency *linker = new (Genode::env()->heap()) Dependency(Ld::linker(), this); Dependency *linker = new (md_alloc) Dependency(Ld::linker(), this);
dep.enqueue(linker); 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 */ /* place linker on second place in link map */
Ld::linker()->setup_link_map(); Ld::linker().setup_link_map();
/* load dependencies */ /* load dependencies */
binary->load_needed(&dep); binary->load_needed(env, md_alloc, deps(), DONT_KEEP);
/* relocate and call constructors */ /* relocate and call constructors */
Init::list()->initialize(); Init::list()->initialize(bind);
} }
Elf::Addr lookup_symbol(char const *name) Elf::Addr lookup_symbol(char const *name)
@ -358,7 +350,7 @@ struct Linker::Binary : Root_object, Elf_object
return 0; return 0;
} }
void call_entry_point(Genode::Env &env) void call_entry_point(Env &env)
{ {
/* call static construtors and register destructors */ /* call static construtors and register destructors */
Func * const ctors_start = (Func *)lookup_symbol("_ctors_start"); Func * const ctors_start = (Func *)lookup_symbol("_ctors_start");
@ -372,16 +364,16 @@ struct Linker::Binary : Root_object, Elf_object
/* call component entry point */ /* call component entry point */
/* XXX the function type for call_component_construct() is a candidate /* XXX the function type for call_component_construct() is a candidate
* for a base-internal header */ * for a base-internal header */
typedef void (*Entry)(Genode::Env &); typedef void (*Entry)(Env &);
Entry const entry = reinterpret_cast<Entry>(_file->entry); Entry const entry = reinterpret_cast<Entry>(_file->entry);
entry(env); entry(env);
} }
void relocate() override void relocate(Bind bind) override
{ {
/* relocate ourselves */ /* relocate ourselves */
Elf_object::relocate(); Elf_object::relocate(bind);
/* /*
* After having loaded the main program, we relocate the linker's * 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 * also present within the main program, become relocated to the correct
* positions * positions
*/ */
Ld::linker()->relocate_global(); Ld::linker().relocate_global();
} }
bool is_binary() const override { return true; } bool is_binary() const override { return true; }
@ -400,22 +392,21 @@ struct Linker::Binary : Root_object, Elf_object
** Global Linker namespace functions ** ** 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()) { for (Object *e = Elf_object::obj_list()->head(); e; e = e->next_obj()) {
if (verbose_loading) 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(); e->load();
return e; return *e;
} }
} }
Elf_object *e = new (Genode::env()->heap()) Elf_object(path, dep, flags); return *new (md_alloc) Elf_object(env, md_alloc, path, dep, keep);
dep->obj = e;
return e;
} }
@ -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::Addr *base, bool undef, bool other)
{ {
Elf_object const *e = static_cast<Elf_object *>(dep->obj); Elf_object const &elf = static_cast<Elf_object const &>(dep.obj());
Elf::Sym const *symbol = e->symbol(sym_index); Elf::Sym const *symbol = elf.symbol(sym_index);
if (!symbol) { if (!symbol) {
Genode::warning("LD: unknown symbol index ", Genode::Hex(sym_index)); warning("LD: unknown symbol index ", Hex(sym_index));
return 0; return 0;
} }
if (symbol->bind() == STB_LOCAL) { if (symbol->bind() == STB_LOCAL) {
*base = dep->obj->reloc_base(); *base = dep.obj().reloc_base();
return symbol; 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) 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); unsigned long hash = Hash_table::hash(name);
Elf::Sym const *weak_symbol = 0; Elf::Sym const *weak_symbol = 0;
Elf::Addr weak_base = 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 //TODO: handle vertab and search in object list
for (;curr; curr = curr->next()) { for (;curr; curr = curr->next()) {
if (other && curr == dep) if (other && curr == &dep)
continue; continue;
Elf_object const *elf = static_cast<Elf_object *>(curr->obj); Elf_object const &elf = static_cast<Elf_object const &>(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) if (dep.root() && verbose_lookup)
Genode::log("LD: lookup ", name, " obj_src ", elf->name(), log("LD: lookup ", name, " obj_src ", elf.name(),
" st ", symbol, " info ", Genode::Hex(symbol->st_info), " st ", symbol, " info ", Hex(symbol->st_info),
" weak: ", symbol->weak()); " weak: ", symbol->weak());
if (!undef && symbol->st_shndx == SHN_UNDEF) if (!undef && symbol->st_shndx == SHN_UNDEF)
continue; continue;
if (!symbol->weak() && symbol->st_shndx != SHN_UNDEF) { if (!symbol->weak() && symbol->st_shndx != SHN_UNDEF) {
*base = elf->reloc_base(); *base = elf.reloc_base();
return symbol; return symbol;
} }
if (!weak_symbol) { if (!weak_symbol) {
weak_symbol = symbol; weak_symbol = symbol;
weak_base = elf->reloc_base(); weak_base = elf.reloc_base();
} }
} }
} }
/* try searching binary's dependencies */ /* try searching binary's dependencies */
if (!weak_symbol && dep->root) { if (!weak_symbol && dep.root()) {
if (binary && dep != binary->dep.head()) { if (binary_ptr && &dep != binary_ptr->first_dep()) {
return lookup_symbol(name, binary->dep.head(), base, undef, other); return lookup_symbol(name, *binary_ptr->first_dep(), base, undef, other);
} else { } else {
Genode::error("LD: could not lookup symbol \"", name, "\""); error("LD: could not lookup symbol \"", name, "\"");
throw Not_found(); throw Not_found();
} }
} }
if (dep->root && verbose_lookup) if (dep.root() && verbose_lookup)
Genode::log("LD: return ", weak_symbol); log("LD: return ", weak_symbol);
if (!weak_symbol) if (!weak_symbol)
throw Not_found(); 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 ** ** Initialization **
********************/ ********************/
@ -524,49 +508,77 @@ extern "C" void init_rtld()
{ {
/* /*
* Allocate on stack, since the linker has not been relocated yet, the vtable * 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 * type relocation might produce a wrong vtable pointer (at least on ARM), do
* not call any virtual funtions of this object * not call any virtual funtions of this object.
*/ */
Ld linker_stack; Ld linker_on_stack;
linker_stack.relocate(); linker_on_stack.relocate(BIND_LAZY);
/* make sure this does not get destroyed the usual way */
linker_stack.ref_count++;
/* /*
* Create actual linker object with different vtable type and set PLT to new * Create actual linker object with different vtable type and set PLT to new
* DAG. * DAG.
*/ */
Ld::linker()->dynamic()->plt_setup(); Ld::linker();
} }
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); } 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> &heap()
{
return *unmanaged_singleton<Lazy_volatile_object<Heap>>();
}
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) void Component::construct(Genode::Env &env)
{ {
/* load program headers of linker now */ /* read configuration */
if (!Ld::linker()->file()) static Config config(env);
Ld::linker()->load_phdr(); verbose = config.verbose();
/* 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) { }
/* load binary and all dependencies */ /* load binary and all dependencies */
try { try {
binary = new(Genode::env()->heap()) Binary(); binary_ptr = unmanaged_singleton<Binary>(env, *heap(), config.bind());
} catch (...) { } catch (...) {
Genode::error("LD: failed to load program"); error("LD: failed to load program");
throw Failed_to_load_program(); throw;
} }
/* print loaded object information */ /* print loaded object information */
@ -577,7 +589,7 @@ void Component::construct(Genode::Env &env)
" .. ", Hex(Thread::stack_area_virtual_base() + " .. ", Hex(Thread::stack_area_virtual_base() +
Thread::stack_area_virtual_size() - 1), Thread::stack_area_virtual_size() - 1),
": stack area"); ": stack area");
dump_link_map(Elf_object::obj_list()->head()); dump_link_map(*Elf_object::obj_list()->head());
} }
} catch (...) { } } catch (...) { }
@ -586,5 +598,5 @@ void Component::construct(Genode::Env &env)
binary_ready_hook_for_gdb(); binary_ready_hook_for_gdb();
/* start binary */ /* start binary */
binary->call_entry_point(env); binary_ptr->call_entry_point(env);
} }

View File

@ -19,9 +19,9 @@
** Helpers ** ** Helpers **
*************/ *************/
static Linker::Root_object *to_root(void *h) static Linker::Root_object const &to_root(void *h)
{ {
return static_cast<Linker::Root_object *>(h); return *static_cast<Linker::Root_object const *>(h);
} }
@ -39,7 +39,7 @@ static Genode::Lock & shared_object_lock()
static Linker::Object *find_obj(Genode::addr_t addr) static Linker::Object *find_obj(Genode::addr_t addr)
{ {
for (Linker::Object *e = Linker::obj_list_head(); e; e = e->next_obj()) 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; return e;
throw Genode::Address_info::Invalid_address(); throw Genode::Address_info::Invalid_address();
@ -50,25 +50,28 @@ static Linker::Object *find_obj(Genode::addr_t addr)
** API ** ** 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; using namespace Linker;
if (verbose_shared) if (verbose_shared)
Genode::log("LD: open '", file ? file : "binary", "'"); log("LD: open '", file ? file : "binary", "'");
try { try {
Genode::Lock::Guard guard(shared_object_lock()); Lock::Guard guard(shared_object_lock());
/* update bind now variable */ _handle = new (md_alloc)
bind_now = (flags & Shared_object::NOW) ? true : false; Root_object(env, md_alloc, file ? file : binary_name(),
bind == BIND_NOW ? Linker::BIND_NOW : Linker::BIND_LAZY,
_handle = (Root_object *)new (Genode::env()->heap()) Root_object(file ? file : binary_name(), flags); keep == KEEP ? Linker::KEEP : Linker::DONT_KEEP);
/* print loaded object information */ /* print loaded object information */
try { try {
if (Linker::verbose) 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 (...) { }
} catch (...) { throw Invalid_file(); } } catch (...) { throw Invalid_file(); }
@ -80,23 +83,24 @@ void *Genode::Shared_object::_lookup(const char *name) const
using namespace Linker; using namespace Linker;
if (verbose_shared) if (verbose_shared)
Genode::log("LD: shared object lookup '", name, "'"); log("LD: shared object lookup '", name, "'");
try { try {
Genode::Lock::Guard guard(Object::lock()); Lock::Guard guard(Linker::lock());
Root_object const &root = to_root(_handle);
Elf::Addr base; Elf::Addr base;
Root_object *root = to_root(_handle); Elf::Sym const *symbol = lookup_symbol(name, *root.first_dep(), &base, true);
Elf::Sym const *symbol = lookup_symbol(name, root->dep.head(), &base, true);
return (void *)(base + symbol->st_value); return (void *)(base + symbol->st_value);
} catch (...) { throw Shared_object::Invalid_symbol(); } } 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; using namespace Linker;
if (verbose_shared) if (verbose_shared)
Genode::log("LD: close shared object"); log("LD: close shared object");
Genode::Lock::Guard guard(shared_object_lock()); Lock::Guard guard(shared_object_lock());
destroy(Genode::env()->heap(), to_root(_handle)); destroy(_md_alloc, &const_cast<Root_object &>(to_root(_handle)));
} }
Genode::Address_info::Address_info(Genode::addr_t address) Genode::Address_info::Address_info(addr_t address)
{ {
using namespace Genode; using namespace Genode;
if (verbose_shared) 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); 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) if (verbose_shared)
Genode::log("LD: found address info: obj: ", path, " sym: ", name, log("LD: found address info: obj: ", path, " sym: ", name,
" addr: ", Genode::Hex(addr)); " addr: ", Hex(addr));
} }

View File

@ -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 * relocations within its text-segment (e.g., 'initial_sp' and friends), which
* we cannot write to from here). * we cannot write to from here).
*/ */
if (_dep->obj->reloc_base()) if (_dep.obj().reloc_base())
*addr += _dep->obj->reloc_base(); *addr += _dep.obj().reloc_base();
} }
public: 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) : Reloc_non_plt_generic(dep)
{ {
Genode::error("LD: DT_RELA not supported"); error("LD: DT_RELA not supported");
throw Incompatible(); 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) bool second_pass)
: Reloc_non_plt_generic(dep) : Reloc_non_plt_generic(dep)
{ {
Elf::Rel const *end = rel + (size / sizeof(Elf::Rel)); Elf::Rel const *end = rel + (size / sizeof(Elf::Rel));
for (; rel < end; 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) if (second_pass && rel->type() != R_GLOB_DAT)
continue; 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_GLOB_DAT: _glob_dat(rel, addr, second_pass); break;
case R_RELATIVE: _relative(addr); break; case R_RELATIVE: _relative(addr); break;
default: default:
if (_dep->root) { if (_dep.root()) {
Genode::warning("LD: Unkown relocation ", (int)rel->type()); warning("LD: Unkown relocation ", (int)rel->type());
throw Incompatible(); throw Incompatible();
} }
break; break;

View File

@ -51,7 +51,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
*/ */
void _relative(Elf::Rela const *rel, Elf::Addr *addr) 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); *addr = reloc_base + sym->st_value + (addend ? rel->addend : 0);
if (verbose_reloc(_dep)) if (verbose_reloc(_dep))
Genode::log("LD: GLOB DAT ", addr, " -> ", Genode::Hex(*addr), log("LD: GLOB DAT ", addr, " -> ", Hex(*addr),
" r ", Genode::Hex(reloc_base), " r ", Hex(reloc_base),
" v ", Genode::Hex(sym->st_value)); " v ", Hex(sym->st_value));
} }
public: 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) : Reloc_non_plt_generic(dep)
{ {
Elf::Rela const *end = rel + (size / sizeof(Elf::Rela)); Elf::Rela const *end = rel + (size / sizeof(Elf::Rela));
for (; rel < end; 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 (verbose_reloc(_dep)) if (verbose_reloc(_dep))
Genode::log("LD: reloc: ", rel, " type: ", (int)rel->type()); log("LD: reloc: ", rel, " type: ", (int)rel->type());
switch(rel->type()) { switch(rel->type()) {
case R_JMPSLOT: _glob_dat_64(rel, addr, false); break; 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; case R_RELATIVE: _relative(rel, addr); break;
default: default:
if (!_dep->obj->is_linker()) { if (!_dep.obj().is_linker()) {
Genode::warning("LD: unkown relocation ", (int)rel->type()); warning("LD: unkown relocation ", (int)rel->type());
throw Incompatible(); throw Incompatible();
} }
break; 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) : Reloc_non_plt_generic(dep)
{ {
Genode::error("LD: DT_REL not supported"); error("LD: DT_REL not supported");
throw Incompatible(); throw Incompatible();
} }
}; };

View File

@ -52,27 +52,27 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
void _relative(Elf::Rel const *rel, Elf::Addr *addr) void _relative(Elf::Rel const *rel, Elf::Addr *addr)
{ {
if (_dep->obj->reloc_base()) if (_dep.obj().reloc_base())
*addr += _dep->obj->reloc_base(); *addr += _dep.obj().reloc_base();
} }
public: 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) : Reloc_non_plt_generic(dep)
{ {
Genode::error("LD: DT_RELA not supported"); error("LD: DT_RELA not supported");
throw Incompatible(); 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) bool second_pass)
: Reloc_non_plt_generic(dep) : Reloc_non_plt_generic(dep)
{ {
Elf::Rel const *end = rel + (size / sizeof(Elf::Rel)); Elf::Rel const *end = rel + (size / sizeof(Elf::Rel));
for (; rel < end; 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) if (second_pass && rel->type() != R_GLOB_DAT)
continue; continue;
@ -84,8 +84,8 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
case R_COPY : _copy<Elf::Rel>(rel, addr); break; case R_COPY : _copy<Elf::Rel>(rel, addr); break;
case R_RELATIVE: _relative(rel, addr); break; case R_RELATIVE: _relative(rel, addr); break;
default: default:
if (_dep->root) { if (_dep.root()) {
Genode::warning("LD: Unkown relocation ", (int)rel->type()); warning("LD: Unkown relocation ", (int)rel->type());
throw Incompatible(); throw Incompatible();
} }
break; break;

View File

@ -45,7 +45,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
*/ */
void _relative(Elf::Rela const *rel, Elf::Addr *addr) 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); *addr = reloc_base + sym->st_value + (addend ? rel->addend : 0);
if (verbose_reloc(_dep)) if (verbose_reloc(_dep))
Genode::log("GLOB DAT ", addr, " -> ", *addr, log("GLOB DAT ", addr, " -> ", *addr,
" r ", reloc_base, " v ", sym->st_value); " r ", reloc_base, " v ", sym->st_value);
} }
public: 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) : Reloc_non_plt_generic(dep)
{ {
Elf::Rela const *end = rel + (size / sizeof(Elf::Rela)); Elf::Rela const *end = rel + (size / sizeof(Elf::Rela));
for (; rel < end; 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);
switch(rel->type()) { switch(rel->type()) {
case R_64: _glob_dat_64(rel, addr, true); break; 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; case R_RELATIVE: _relative(rel, addr); break;
default: default:
if (!_dep->obj->is_linker()) { if (!_dep.obj().is_linker()) {
Genode::warning("LD: Unkown relocation ", (int)rel->type()); warning("LD: Unkown relocation ", (int)rel->type());
throw Incompatible(); throw Incompatible();
} }
break; 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) : Reloc_non_plt_generic(dep)
{ {
Genode::error("LD: DT_REL not supported"); error("LD: DT_REL not supported");
throw Incompatible(); throw Incompatible();
} }
}; };

View File

@ -94,28 +94,6 @@ extern "C" void init_main_thread()
(void*)env(); (void*)env();
init_log(); 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 */ /* create a thread object for the main thread */
main_thread(); main_thread();

View File

@ -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 <base/env.h>
#include <base/allocator.h>
void rump_bootstrap_init(Genode::Env &env, Genode::Allocator &heap);
#endif /* _INCLUDE__RUMP__BOOTSTRAP_H_ */

View File

@ -1,4 +1,4 @@
/** /*
* \brief Definitions for FS front-end * \brief Definitions for FS front-end
* \author Sebastian Sumpf * \author Sebastian Sumpf
* \date 2014-01-22 * \date 2014-01-22

View File

@ -17,7 +17,7 @@ extern "C" {
#include <elf.h> #include <elf.h>
} }
#include <base/env.h> #include <rump/bootstrap.h>
#include <base/log.h> #include <base/log.h>
#include <base/shared_object.h> #include <base/shared_object.h>
#include <util/string.h> #include <util/string.h>
@ -36,6 +36,45 @@ 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 struct Sym_tab
{ {
@ -187,9 +226,13 @@ static void _dl_init(Genode::Shared_object::Link_map const *map,
rump_compload_fn comp_init) rump_compload_fn comp_init)
{ {
using namespace Genode; using namespace Genode;
Shared_object *obj; Shared_object *obj = nullptr;
try { obj = new (Genode::env()->heap()) Shared_object(map->path); } try {
catch (...) { error("Could not dlopen ", map->path); return; } 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 modinfo **mi_start, **mi_end;
struct rump_component **rc_start, **rc_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 */ /* open main program and request link map */
using namespace Genode; 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) ; for (; map->next; map = map->next) ;
Shared_object::Link_map const *curr_map; Shared_object::Link_map const *curr_map;

View File

@ -13,11 +13,12 @@
#include "file_system.h" #include "file_system.h"
#include <os/config.h> #include <rump/bootstrap.h>
#include <rump_fs/fs.h> #include <rump_fs/fs.h>
#include <util/string.h> #include <util/string.h>
#include <util/hard_context.h> #include <util/hard_context.h>
#include <base/log.h> #include <base/log.h>
#include <base/attached_rom_dataspace.h>
/** /**
* We define our own fs arg structure to fit all sizes, we assume that 'fspec' * 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)); } 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, static char const *fs_types[] = { RUMP_MOUNT_CD9660, RUMP_MOUNT_EXT2FS,
RUMP_MOUNT_FFS, RUMP_MOUNT_MSDOS, RUMP_MOUNT_FFS, RUMP_MOUNT_MSDOS,
RUMP_MOUNT_NTFS, RUMP_MOUNT_UDF, 0 }; RUMP_MOUNT_NTFS, RUMP_MOUNT_UDF, 0 };
typedef Genode::String<16> Fs_type; 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 _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++) 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 true;
return false; 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 (fs_type == RUMP_MOUNT_EXT2FS)
return true; || (fs_type == RUMP_MOUNT_FFS);
if (!Genode::strcmp(fs_type().string(), RUMP_MOUNT_FFS))
return true;
return false;
} }
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 fs_type == RUMP_MOUNT_CD9660;
return true;
return false;
} }
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 \'<config fs=\"<fs type>\"/>)"); Genode::error("Invalid or no file system given (use \'<config fs=\"<fs type>\"/>)");
_print_types(); _print_types();
throw Genode::Exception(); 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 */ /* start rump kernel */
rump_init(); rump_init();
@ -104,16 +98,16 @@ void File_system::init()
/* mount into extra-terrestrial-file system */ /* mount into extra-terrestrial-file system */
struct fs_args args; 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; args.fspec = (char *)GENODE_DEVICE;
if (rump_sys_mount(fs_type().string(), "/", opts, &args, sizeof(args)) == -1) { if (rump_sys_mount(fs_type.string(), "/", opts, &args, sizeof(args)) == -1) {
Genode::error("Mounting '", fs_type().string(), "' file system failed (errno ", errno, " )"); Genode::error("Mounting '", fs_type, "' file system failed (errno ", errno, " )");
throw Genode::Exception(); throw Genode::Exception();
} }
/* check support for symlinks */ /* check support for symlinks */
_supports_symlinks = check_symlinks(); _supports_symlinks = check_symlinks(fs_type);
} }

View File

@ -13,6 +13,11 @@
#ifndef _FILE_SYSTEM_H_ #ifndef _FILE_SYSTEM_H_
#define _FILE_SYSTEM_H_ #define _FILE_SYSTEM_H_
/* Genode includes */
#include <util/xml_node.h>
#include <base/env.h>
#include <base/allocator.h>
extern "C" { extern "C" {
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include <sys/errno.h> #include <sys/errno.h>
@ -26,7 +31,7 @@ extern "C" {
} }
namespace File_system { namespace File_system {
void init(); void init(Genode::Env &, Genode::Allocator &heap, Genode::Xml_node config);
bool supports_symlinks(); bool supports_symlinks();
} }

View File

@ -15,6 +15,7 @@
/* Genode includes */ /* Genode includes */
#include <file_system/node_handle_registry.h> #include <file_system/node_handle_registry.h>
#include <file_system_session/rpc_object.h> #include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <os/session_policy.h> #include <os/session_policy.h>
#include <root/component.h> #include <root/component.h>
@ -481,16 +482,20 @@ struct File_system::Main
Genode::Signal_handler<Main> sync_handler Genode::Signal_handler<Main> sync_handler
{ env.ep(), *this, &Main::sync }; { env.ep(), *this, &Main::sync };
Heap heap { env.ram(), env.rm() };
/* /*
* Initialize root interface * 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) Main(Genode::Env &env) : env(env)
{ {
File_system::init(); File_system::init(env, heap, config.xml());
/* set all bits but the stickies */ /* set all bits but the stickies */
rump_sys_umask(S_ISUID|S_ISGID|S_ISVTX); rump_sys_umask(S_ISUID|S_ISGID|S_ISVTX);

View File

@ -11,6 +11,9 @@
#include <base/shared_object.h> #include <base/shared_object.h>
#include <base/snprintf.h> #include <base/snprintf.h>
/* libc-internal includes */
#include <libc_init.h>
extern "C" { extern "C" {
#include <dlfcn.h> #include <dlfcn.h>
} }
@ -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) static Shared_object *to_object(void *handle)
{ {
return static_cast<Shared_object *>(handle); return static_cast<Shared_object *>(handle);
@ -39,21 +55,28 @@ void *dlopen(const char *name, int mode)
/* error on unsupported mode values */ /* error on unsupported mode values */
if (mode & ~supported) { if (mode & ~supported) {
snprintf(err_str, MAX_ERR, "Unsupported mode 0x%x\n", 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; return nullptr;
} }
Shared_object *obj = 0; Shared_object::Bind const bind =
unsigned flags = mode & RTLD_NOW ? Shared_object::NOW : Shared_object::LAZY; (mode & RTLD_NOW) ? Shared_object::BIND_NOW : Shared_object::BIND_LAZY;
flags |= mode & RTLD_NODELETE ? Shared_object::KEEP : 0;
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 { try {
obj = new (env()->heap()) Shared_object(name, flags); return new (env()->heap())
Shared_object(*genode_env, *env()->heap(), name, bind, keep);
} catch (...) { } catch (...) {
snprintf(err_str, MAX_ERR, "Unable to open file %s\n", name); snprintf(err_str, MAX_ERR, "Unable to open file %s\n", name);
} }
return nullptr;
return (void *)obj;
} }

View File

@ -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 <base/env.h>
namespace Libc {
/**
* Support for shared libraries
*/
void init_dl(Genode::Env &env);
}
#endif /* _LIBC_INIT_H_ */

View File

@ -23,6 +23,7 @@
#include <internal/call_func.h> #include <internal/call_func.h>
#include <base/internal/unmanaged_singleton.h> #include <base/internal/unmanaged_singleton.h>
#include "vfs_plugin.h" #include "vfs_plugin.h"
#include "libc_init.h"
/* escape sequences for highlighting debug message prefixes */ /* 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) void Libc::call_component_construct(Genode::Env &env)
{ {
/* pass Genode::Env to libc subsystems that depend on it */
init_dl(env);
task = unmanaged_singleton<Libc::Task>(env); task = unmanaged_singleton<Libc::Task>(env);
task->run(); task->run();
} }

View File

@ -14,6 +14,8 @@
#include <base/printf.h> #include <base/printf.h>
#include <rom_session/connection.h> #include <rom_session/connection.h>
#include <base/env.h> #include <base/env.h>
#include <base/heap.h>
#include <base/component.h>
#include <base/shared_object.h> #include <base/shared_object.h>
using namespace Genode; using namespace Genode;
@ -166,7 +168,7 @@ static void test_dynamic_cast()
** Shared-object API ** ** 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 * 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 * 'lib_dl_so' is a local variable such that its destructor is called
* when leaving the scope of the function. * 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 * 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("\n");
printf("Dynamic-linker test\n"); printf("Dynamic-linker test\n");
printf("===================\n"); printf("===================\n");
@ -250,12 +255,11 @@ int main(int argc, char **argv)
printf("Shared-object API\n"); printf("Shared-object API\n");
printf("-----------------\n"); printf("-----------------\n");
test_shared_object_api(); test_shared_object_api(env, heap);
printf("\n"); printf("\n");
printf("Destruction\n"); printf("Destruction\n");
printf("-----------\n"); printf("-----------\n");
/* test if return value is propagated correctly by dynamic linker */ Libc::exit(123);
return 123;
} }

View File

@ -132,14 +132,17 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
/** /**
* \throw Factory_not_available * \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) Library_name const &lib_name)
{ {
Genode::Shared_object *shared_object = nullptr; Genode::Shared_object *shared_object = nullptr;
try { try {
shared_object = new (alloc) 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)(); 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(); return *query_fn();
} catch (Genode::Shared_object::Invalid_file) { } catch (Genode::Shared_object::Invalid_rom_module) {
PWRN("could not open '%s'", lib_name.string()); PWRN("could not open '%s'", lib_name.string());
throw Factory_not_available(); 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)); Library_name const lib_name = _library_name(_node_name(node));
try { try {
_list.insert(new (alloc) _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; return true;
} catch (Factory_not_available) { return false; } } catch (Factory_not_available) { return false; }
@ -187,7 +192,7 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
try { try {
/* probe for file system implementation available as shared lib */ /* 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 */ /* try again with the new file system type loaded */
if (Vfs::File_system *fs = _try_create(env, alloc, node)) if (Vfs::File_system *fs = _try_create(env, alloc, node))
return fs; return fs;