mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-29 15:44:02 +00:00
parent
20faa8b84e
commit
784e728727
@ -87,6 +87,13 @@ namespace Genode {
|
||||
*/
|
||||
|
||||
extern void (*call_component_construct)(Genode::Env &) __attribute__((weak));
|
||||
|
||||
/*
|
||||
* This function is normally provided by the cxx library, which is not
|
||||
* used for lx_hybrid programs. For lx_hybrid programs, the exception
|
||||
* handling is initialized by the host system's regular startup code.
|
||||
*/
|
||||
void init_exception_handling(Env &) { }
|
||||
}
|
||||
|
||||
static void lx_hybrid_component_construct(Genode::Env &env)
|
||||
|
@ -18,8 +18,8 @@
|
||||
#include <base/entrypoint.h>
|
||||
#include <ram_session/capability.h>
|
||||
#include <cpu_session/capability.h>
|
||||
#include <pd_session/capability.h>
|
||||
#include <rm_session/rm_session.h>
|
||||
#include <pd_session/pd_session.h>
|
||||
|
||||
/* maintain compatibility to deprecated API */
|
||||
#include <deprecated/env.h>
|
||||
@ -64,6 +64,15 @@ struct Genode::Env
|
||||
|
||||
virtual Ram_session_capability ram_session_cap() = 0;
|
||||
virtual Cpu_session_capability cpu_session_cap() = 0;
|
||||
|
||||
/*
|
||||
* XXX temporary
|
||||
*
|
||||
* The PD session capability is solely used for upgrading the PD session,
|
||||
* e.g., when the dynamic linker attaches dataspaces to the linker area.
|
||||
* Once we add 'Env::upgrade', we can remove this accessor.
|
||||
*/
|
||||
virtual Pd_session_capability pd_session_cap() = 0;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BASE__ENV_H_ */
|
||||
|
@ -29,29 +29,36 @@ class Genode::Shared_object
|
||||
private:
|
||||
|
||||
void *_handle = nullptr;
|
||||
|
||||
void *_lookup(const char *symbol) const;
|
||||
|
||||
Allocator &_md_alloc;
|
||||
|
||||
public:
|
||||
|
||||
class Invalid_file : public Genode::Exception { };
|
||||
class Invalid_symbol : public Genode::Exception { };
|
||||
class Invalid_rom_module : public Genode::Exception { };
|
||||
class Invalid_symbol : public Genode::Exception { };
|
||||
|
||||
enum open_flags {
|
||||
NOW = 0x1,
|
||||
LAZY = 0x2,
|
||||
KEEP = 0x4, /* do not unload on destruction */
|
||||
};
|
||||
enum Keep { DONT_KEEP, KEEP };
|
||||
enum Bind { BIND_LAZY, BIND_NOW };
|
||||
|
||||
/**
|
||||
* Load shared object and dependencies
|
||||
*
|
||||
* \param file Shared object to load
|
||||
* \param flags LAZY for lazy function binding, NOW for immediate binding
|
||||
* \param env Genode environment, needed to obtain the ROM module
|
||||
* for the shared object and to populate the linker
|
||||
* area of the component's address space
|
||||
* \param md_alloc backing store for the linker's dynamically allocated
|
||||
* meta data
|
||||
* \param name ROM module name of shared object to load
|
||||
* \param bind bind functions immediately (BIND_NOW) or on
|
||||
* demand (BIND_LAZY)
|
||||
* \param keep unload ELF object if no longer needed (DONT_KEEP),
|
||||
* or keep ELF object loaded at all times (KEEP)
|
||||
*
|
||||
* \throw Invalid_file
|
||||
* \throw Invalid_rom_module
|
||||
*/
|
||||
Shared_object(char const *file = nullptr, unsigned flags = LAZY);
|
||||
Shared_object(Env &, Allocator &md_alloc, char const *name,
|
||||
Bind bind, Keep keep);
|
||||
|
||||
/**
|
||||
* Close and unload shared object
|
||||
@ -78,16 +85,16 @@ class Genode::Shared_object
|
||||
struct Link_map
|
||||
{
|
||||
Genode::addr_t addr; /* load address */
|
||||
char const *path; /* object path */
|
||||
void const *dynamic; /* pointer to DYNAMIC section */
|
||||
Link_map *next;
|
||||
Link_map *prev;
|
||||
char const *path; /* object path */
|
||||
void const *dynamic; /* pointer to DYNAMIC section */
|
||||
Link_map const *next;
|
||||
Link_map const *prev;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return link map of shared object
|
||||
*/
|
||||
Link_map const * link_map() const;
|
||||
Link_map const &link_map() const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
CXX_SRC_CC += misc.cc new_delete.cc malloc_free.cc exception.cc guard.cc
|
||||
INC_DIR += $(REP_DIR)/src/include
|
||||
# We need the libsupc++ include directory
|
||||
STDINC = yes
|
||||
|
||||
|
@ -4,7 +4,7 @@ DIR = $(REP_DIR)/src/lib/ldso
|
||||
include $(BASE_DIR)/mk/base-libs.mk
|
||||
|
||||
LIBS = $(BASE_LIBS)
|
||||
SRC_CC = main.cc test.cc exception.cc file.cc dependency.cc debug.cc \
|
||||
SRC_CC = main.cc test.cc exception.cc dependency.cc debug.cc \
|
||||
shared_object.cc
|
||||
SRC_S = jmp_slot.s
|
||||
INC_DIR += $(DIR)/include
|
||||
|
@ -26,6 +26,9 @@ namespace Genode {
|
||||
extern Region_map *env_stack_area_region_map;
|
||||
extern Ram_session *env_stack_area_ram_session;
|
||||
|
||||
void init_exception_handling(Env &);
|
||||
void init_cxx_heap(Env &);
|
||||
void init_ldso_phdr(Env &);
|
||||
void init_signal_thread(Env &);
|
||||
void init_log();
|
||||
}
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include <base/component.h>
|
||||
#include <base/env.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/globals.h>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
@ -41,6 +44,11 @@ namespace {
|
||||
{
|
||||
return Genode::env()->cpu_session_cap();
|
||||
}
|
||||
|
||||
Genode::Pd_session_capability pd_session_cap() override
|
||||
{
|
||||
return Genode::env()->pd_session_cap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -61,6 +69,8 @@ struct Genode::Startup
|
||||
{
|
||||
::Env env { ep };
|
||||
|
||||
bool const exception_handling = (init_exception_handling(env), true);
|
||||
|
||||
/*
|
||||
* The construction of the main entrypoint does never return.
|
||||
*/
|
||||
|
@ -19,6 +19,9 @@
|
||||
#include <base/log.h>
|
||||
#include <util/string.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/globals.h>
|
||||
|
||||
extern "C" char __eh_frame_start__[]; /* from linker script */
|
||||
extern "C" void __register_frame (const void *begin); /* from libgcc_eh */
|
||||
extern "C" char *__cxa_demangle(const char *mangled_name,
|
||||
@ -69,13 +72,46 @@ void terminate_handler()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Init program headers of the dynamic linker
|
||||
*
|
||||
* The weak function is used for statically linked binaries. The
|
||||
* dynamic linker provides an implementation that loads the program
|
||||
* headers of the linker. This must be done before the first exception
|
||||
* is thrown.
|
||||
*/
|
||||
void Genode::init_ldso_phdr(Env &) __attribute__((weak));
|
||||
void Genode::init_ldso_phdr(Env &) { }
|
||||
|
||||
|
||||
/*
|
||||
* Initialization
|
||||
*/
|
||||
|
||||
void init_exception_handling()
|
||||
void Genode::init_exception_handling(Env &env)
|
||||
{
|
||||
init_ldso_phdr(env);
|
||||
init_cxx_heap(env);
|
||||
|
||||
__register_frame(__eh_frame_start__);
|
||||
|
||||
std::set_terminate(terminate_handler);
|
||||
|
||||
/*
|
||||
* Trigger first exception. This step has two purposes.
|
||||
* First, it enables us to detect problems related to exception handling as
|
||||
* early as possible. If there are problems with the C++ support library,
|
||||
* it is much easier to debug them at this early stage. Otherwise problems
|
||||
* with half-working exception handling cause subtle failures that are hard
|
||||
* to interpret.
|
||||
*
|
||||
* Second, the C++ support library allocates data structures lazily on the
|
||||
* first occurrence of an exception. In some corner cases, this allocation
|
||||
* consumes several KB of stack. This is usually not a problem when the
|
||||
* first exception is triggered from the main thread but it becomes an
|
||||
* issue when the first exception is thrown from the stack of a thread with
|
||||
* a specially tailored (and otherwise sufficient) stack size. By throwing
|
||||
* an exception here, we mitigate this issue by eagerly performing those
|
||||
* allocations.
|
||||
*/
|
||||
try { throw 1; } catch (...) { }
|
||||
}
|
||||
|
@ -14,37 +14,44 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/env.h>
|
||||
#include <base/heap.h>
|
||||
#include <util/string.h>
|
||||
#include <util/volatile_object.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/globals.h>
|
||||
|
||||
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.
|
||||
*
|
||||
* If we used the 'env()->heap()' with the C++ runtime, we would run into a
|
||||
* deadlock when a 'Ram_session::Alloc_failed' exception is thrown from within
|
||||
* 'Heap::alloc'. For creating the exception object, the C++ runtime calls
|
||||
* '__cxa_allocate_exception', which, in turn, calls 'malloc'. If our 'malloc'
|
||||
* implementation called 'env()->heap()->alloc()', we would end up in a
|
||||
* recursive attempt to obtain the 'env()->heap()' lock.
|
||||
*
|
||||
* By using a dedicated heap instance for the cxx library, we avoid this
|
||||
* circular condition.
|
||||
* For creating the exception object, the C++ runtime calls
|
||||
* '__cxa_allocate_exception', which, in turn, calls 'malloc'. The cxx library
|
||||
* uses a local implementation of 'malloc' using a dedicated heap instance.
|
||||
*/
|
||||
static Heap *cxx_heap()
|
||||
void Genode::init_cxx_heap(Env &env)
|
||||
{
|
||||
if (cxx_heap().constructed()) return;
|
||||
|
||||
/*
|
||||
* Exception frames are small. Hence, a small static backing store suffices
|
||||
* for the cxx heap partition in the normal case. The 'env()->ram_session'
|
||||
* for the cxx heap partition in the normal case. The 'env.ram()' session
|
||||
* is used only if the demand exceeds the capacity of the 'initial_block'.
|
||||
*/
|
||||
static char initial_block[1024*sizeof(long)];
|
||||
static Heap heap(env()->ram_session(), env()->rm_session(),
|
||||
Heap::UNLIMITED, initial_block, sizeof(initial_block));
|
||||
return &heap;
|
||||
cxx_heap().construct(&env.ram(), &env.rm(),
|
||||
Heap::UNLIMITED, initial_block, sizeof(initial_block));
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,15 +26,15 @@ void binary_ready_hook_for_gdb() { }
|
||||
extern "C" void brk(Linker::Debug *, Linker::Link_map *) { }
|
||||
|
||||
|
||||
void Linker::dump_link_map(Object *o)
|
||||
void Linker::dump_link_map(Object const &obj)
|
||||
{
|
||||
for (; o; o = o->next_obj()) {
|
||||
for (Object const *o = &obj; o; o = o->next_obj()) {
|
||||
|
||||
if (o->is_binary())
|
||||
continue;
|
||||
|
||||
Genode::log(" ", Genode::Hex(o->link_map()->addr),
|
||||
" .. ", Genode::Hex(o->link_map()->addr + o->size() - 1),
|
||||
": ", o->name());
|
||||
log(" ", Hex(o->link_map().addr),
|
||||
" .. ", Hex(o->link_map().addr + o->size() - 1),
|
||||
": ", o->name());
|
||||
}
|
||||
}
|
||||
|
@ -19,63 +19,77 @@
|
||||
/**
|
||||
* Dependency node
|
||||
*/
|
||||
Linker::Dependency::Dependency(char const *path, Root_object *root,
|
||||
Genode::Fifo<Dependency> * const dep,
|
||||
unsigned flags)
|
||||
: obj(load(path, this, flags)), root(root)
|
||||
Linker::Dependency::Dependency(Env &env, Allocator &md_alloc,
|
||||
char const *path, Root_object *root,
|
||||
Fifo<Dependency> &deps,
|
||||
Keep keep)
|
||||
:
|
||||
_obj(load(env, md_alloc, path, *this, keep)),
|
||||
_root(root),
|
||||
_md_alloc(&md_alloc)
|
||||
{
|
||||
dep->enqueue(this);
|
||||
load_needed(dep, flags);
|
||||
deps.enqueue(this);
|
||||
load_needed(env, *_md_alloc, deps, keep);
|
||||
}
|
||||
|
||||
|
||||
Linker::Dependency::~Dependency()
|
||||
{
|
||||
if (obj->unload()) {
|
||||
if (!_obj.unload())
|
||||
return;
|
||||
|
||||
if (verbose_loading)
|
||||
Genode::log("Destroy: ", obj->name());
|
||||
if (verbose_loading)
|
||||
log("Destroy: ", _obj.name());
|
||||
|
||||
destroy(Genode::env()->heap(), obj);
|
||||
}
|
||||
destroy(_md_alloc, &_obj);
|
||||
}
|
||||
|
||||
|
||||
bool Linker::Dependency::in_dep(char const *file,
|
||||
Genode::Fifo<Dependency> * const dep)
|
||||
bool Linker::Dependency::in_dep(char const *file, Fifo<Dependency> const &dep)
|
||||
{
|
||||
for (Dependency *d = dep->head(); d; d = d->next())
|
||||
if (!Genode::strcmp(file, d->obj->name()))
|
||||
for (Dependency const *d = dep.head(); d; d = d->next())
|
||||
if (!strcmp(file, d->obj().name()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Linker::Dependency::load_needed(Genode::Fifo<Dependency> * const dep,
|
||||
unsigned flags)
|
||||
void Linker::Dependency::load_needed(Env &env, Allocator &md_alloc,
|
||||
Fifo<Dependency> &deps, Keep keep)
|
||||
{
|
||||
for (Dynamic::Needed *n = obj->dynamic()->needed.head(); n; n = n->next()) {
|
||||
char const *path = n->path(obj->dynamic()->strtab);
|
||||
_obj.dynamic().for_each_dependency([&] (char const *path) {
|
||||
|
||||
Object *o;
|
||||
if (!in_dep(Linker::file(path), dep))
|
||||
new (Genode::env()->heap()) Dependency(path, root, dep, flags);
|
||||
if (!in_dep(Linker::file(path), deps))
|
||||
new (md_alloc) Dependency(env, md_alloc, path, _root, deps, keep);
|
||||
|
||||
/* re-order initializer list, if needed object has been already added */
|
||||
else if ((o = Init::list()->contains(Linker::file(path))))
|
||||
else if (Object *o = Init::list()->contains(Linker::file(path)))
|
||||
Init::list()->reorder(o);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Linker::Root_object::Root_object(char const *path, unsigned flags)
|
||||
Linker::Dependency const &Linker::Dependency::first() const
|
||||
{
|
||||
new (Genode::env()->heap()) Dependency(path, this, &dep, flags);
|
||||
return _root ? *_root->first_dep() : *this;
|
||||
}
|
||||
|
||||
|
||||
Linker::Root_object::Root_object(Env &env, Allocator &md_alloc,
|
||||
char const *path, Bind bind, Keep keep)
|
||||
:
|
||||
_md_alloc(md_alloc)
|
||||
{
|
||||
/*
|
||||
* The life time of 'Dependency' objects is managed via reference
|
||||
* counting. Hence, we don't need to remember them here.
|
||||
*/
|
||||
new (md_alloc) Dependency(env, md_alloc, path, this, _deps, keep);
|
||||
|
||||
/* provide Genode base library access */
|
||||
new (Genode::env()->heap()) Dependency(linker_name(), this, &dep);
|
||||
new (md_alloc) Dependency(env, md_alloc, linker_name(), this, _deps, DONT_KEEP);
|
||||
|
||||
/* relocate and call constructors */
|
||||
Init::list()->initialize();
|
||||
Init::list()->initialize(bind);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/log.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;
|
||||
Phdr_info info;
|
||||
|
||||
Genode::Lock::Guard guard(Object::lock());
|
||||
Lock::Guard guard(lock());
|
||||
|
||||
for (Object *e = obj_list_head();e; e = e->next_obj()) {
|
||||
|
||||
@ -47,7 +48,7 @@ extern "C" int dl_iterate_phdr(int (*callback) (Phdr_info *info, Genode::size_t
|
||||
info.phnum = e->file()->phdr.count;
|
||||
|
||||
if (verbose_exception)
|
||||
Genode::log(e->name(), " reloc ", Genode::Hex(e->reloc_base()));
|
||||
log(e->name(), " reloc ", Hex(e->reloc_base()));
|
||||
|
||||
if ((err = callback(&info, sizeof(Phdr_info), data)))
|
||||
break;
|
||||
@ -87,16 +88,10 @@ extern "C" unsigned long dl_unwind_find_exidx(unsigned long pc, int *pcount)
|
||||
enum { EXIDX_ENTRY_SIZE = 8 };
|
||||
*pcount = 0;
|
||||
|
||||
/*
|
||||
* Since this function may be called before the main function, load linker's
|
||||
* program header now
|
||||
*/
|
||||
load_linker_phdr();
|
||||
for (Object *e = obj_list_head(); e; e = e->next_obj()) {
|
||||
|
||||
for (Object *e = obj_list_head(); e; e = e->next_obj())
|
||||
{
|
||||
/* address of first PT_LOAD header */
|
||||
Genode::addr_t base = e->reloc_base() + e->file()->start;
|
||||
addr_t base = e->reloc_base() + e->file()->start;
|
||||
|
||||
/* is the 'pc' somewhere within this ELF image */
|
||||
if ((pc < base) || (pc >= base + e->file()->size))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -18,14 +18,21 @@
|
||||
#include <base/log.h>
|
||||
#include <elf.h>
|
||||
|
||||
constexpr bool verbose_link_map = false;
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
|
||||
constexpr bool verbose_link_map = false;
|
||||
constexpr bool verbose_lookup = false;
|
||||
constexpr bool verbose_exception = false;
|
||||
constexpr bool verbose_shared = false;
|
||||
constexpr bool verbose_loading = false;
|
||||
|
||||
namespace Linker {
|
||||
struct Debug;
|
||||
struct Link_map;
|
||||
|
||||
struct Object;
|
||||
void dump_link_map(Object *o);
|
||||
void dump_link_map(Object const &);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -128,9 +135,9 @@ struct Linker::Link_map
|
||||
return;
|
||||
|
||||
for (Link_map *m = first; m; m = m->next)
|
||||
Genode::log("MAP: addr: ", Genode::Hex(m->addr),
|
||||
" dynamic: ", m->dynamic, " ", Genode::Cstring(m->path),
|
||||
" m: ", m, " p: ", m->prev, " n: ", m->next);
|
||||
log("MAP: addr: ", Hex(m->addr),
|
||||
" dynamic: ", m->dynamic, " ", Cstring(m->path),
|
||||
" m: ", m, " p: ", m->prev, " n: ", m->next);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
#ifndef _INCLUDE__DYNAMIC_H_
|
||||
#define _INCLUDE__DYNAMIC_H_
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
#include <relocation.h>
|
||||
|
||||
namespace Linker {
|
||||
@ -54,162 +56,297 @@ struct Linker::Hash_table
|
||||
/**
|
||||
* .dynamic section entries
|
||||
*/
|
||||
struct Linker::Dynamic
|
||||
class Linker::Dynamic
|
||||
{
|
||||
struct Needed : Genode::Fifo<Needed>::Element
|
||||
{
|
||||
Genode::off_t offset;
|
||||
public:
|
||||
|
||||
Needed(Genode::off_t offset) : offset(offset) { }
|
||||
class Dynamic_section_missing { };
|
||||
|
||||
char const *path(char const *strtab)
|
||||
private:
|
||||
|
||||
struct Needed : Fifo<Needed>::Element
|
||||
{
|
||||
return ((char const *)(strtab + offset));
|
||||
off_t offset;
|
||||
|
||||
Needed(off_t offset) : offset(offset) { }
|
||||
|
||||
char const *path(char const *strtab)
|
||||
{
|
||||
return ((char const *)(strtab + offset));
|
||||
}
|
||||
|
||||
char const *name(char const *strtab)
|
||||
{
|
||||
return file(path(strtab));
|
||||
}
|
||||
};
|
||||
|
||||
Dependency const *_dep;
|
||||
Object const &_obj;
|
||||
Elf::Dyn const &_dynamic;
|
||||
|
||||
Allocator *_md_alloc = nullptr;
|
||||
|
||||
Hash_table *_hash_table = nullptr;
|
||||
|
||||
Elf::Rela *_reloca = nullptr;
|
||||
unsigned long _reloca_size = 0;
|
||||
|
||||
Elf::Sym *_symtab = nullptr;
|
||||
char *_strtab = nullptr;
|
||||
unsigned long _strtab_size = 0;
|
||||
|
||||
Elf::Addr *_pltgot = nullptr;
|
||||
|
||||
Elf::Rel *_pltrel = nullptr;
|
||||
unsigned long _pltrel_size = 0;
|
||||
D_tag _pltrel_type = DT_NULL;
|
||||
|
||||
Func _init_function = nullptr;
|
||||
|
||||
Elf::Rel *_rel = nullptr;
|
||||
unsigned long _rel_size = 0;
|
||||
|
||||
Fifo<Needed> _needed;
|
||||
|
||||
/**
|
||||
* \throw Dynamic_section_missing
|
||||
*/
|
||||
Elf::Dyn const &_find_dynamic(Linker::Phdr const *p)
|
||||
{
|
||||
for (unsigned i = 0; i < p->count; i++)
|
||||
if (p->phdr[i].p_type == PT_DYNAMIC)
|
||||
return *reinterpret_cast<Elf::Dyn const *>
|
||||
(p->phdr[i].p_vaddr + _obj.reloc_base());
|
||||
|
||||
throw Dynamic_section_missing();
|
||||
}
|
||||
|
||||
char const *name(char const *strtab)
|
||||
void _section_dt_needed(Elf::Dyn const *d)
|
||||
{
|
||||
return file(path(strtab));
|
||||
if (!_md_alloc) {
|
||||
error("unexpected call of section_dt_needed");
|
||||
return;
|
||||
}
|
||||
Needed *n = new (*_md_alloc) Needed(d->un.ptr);
|
||||
_needed.enqueue(n);
|
||||
}
|
||||
};
|
||||
|
||||
Dependency const *dep;
|
||||
Object const *obj;
|
||||
Elf::Dyn const *dynamic;
|
||||
template <typename T>
|
||||
void _section(T *member, Elf::Dyn const *d)
|
||||
{
|
||||
*member = (T)(_obj.reloc_base() + d->un.ptr);
|
||||
}
|
||||
|
||||
Hash_table *hash_table = nullptr;
|
||||
void _section_dt_debug(Elf::Dyn const *d)
|
||||
{
|
||||
Elf::Dyn *_d = const_cast<Elf::Dyn *>(d);
|
||||
_d->un.ptr = (Elf::Addr)Debug::d();
|
||||
}
|
||||
|
||||
Elf::Rela *reloca = nullptr;
|
||||
unsigned long reloca_size = 0;
|
||||
|
||||
Elf::Sym *symtab = nullptr;
|
||||
char *strtab = nullptr;
|
||||
unsigned long strtab_size = 0;
|
||||
|
||||
Elf::Addr *pltgot = nullptr;
|
||||
|
||||
Elf::Rel *pltrel = nullptr;
|
||||
unsigned long pltrel_size = 0;
|
||||
D_tag pltrel_type = DT_NULL;
|
||||
|
||||
Func init_function = nullptr;
|
||||
|
||||
Elf::Rel *rel = nullptr;
|
||||
unsigned long rel_size = 0;
|
||||
|
||||
Genode::Fifo<Needed> needed;
|
||||
|
||||
Dynamic(Dependency const *dep)
|
||||
:
|
||||
dep(dep), obj(dep->obj), dynamic((Elf::Dyn *)dynamic_address())
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
Dynamic(Dependency const *dep, Object const *obj, Linker::Phdr const *phdr)
|
||||
:
|
||||
dep(dep), obj(obj), dynamic(find_dynamic(phdr))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
~Dynamic()
|
||||
{
|
||||
Needed *n;
|
||||
while ((n = needed.dequeue()))
|
||||
destroy(Genode::env()->heap(), n);
|
||||
}
|
||||
|
||||
Elf::Dyn const *find_dynamic(Linker::Phdr const *p)
|
||||
{
|
||||
for (unsigned i = 0; i < p->count; i++)
|
||||
if (p->phdr[i].p_type == PT_DYNAMIC)
|
||||
return reinterpret_cast<Elf::Dyn const *>(p->phdr[i].p_vaddr + obj->reloc_base());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void section_dt_needed(Elf::Dyn const *d)
|
||||
{
|
||||
Needed *n = new(Genode::env()->heap()) Needed(d->un.ptr);
|
||||
needed.enqueue(n);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void section(T *member, Elf::Dyn const *d)
|
||||
{
|
||||
*member = (T)(obj->reloc_base() + d->un.ptr);
|
||||
}
|
||||
|
||||
void section_dt_debug(Elf::Dyn const *d)
|
||||
{
|
||||
Elf::Dyn *_d = const_cast<Elf::Dyn *>(d);
|
||||
_d->un.ptr = (Elf::Addr)Debug::d();
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
for (Elf::Dyn const *d = dynamic; d->tag != DT_NULL; d++) {
|
||||
switch (d->tag) {
|
||||
|
||||
case DT_NEEDED : section_dt_needed(d); break;
|
||||
case DT_PLTRELSZ: pltrel_size = d->un.val; break;
|
||||
case DT_PLTGOT : section<typeof(pltgot)>(&pltgot, d); break;
|
||||
case DT_HASH : section<typeof(hash_table)>(&hash_table, d); break;
|
||||
case DT_RELA : section<typeof(reloca)>(&reloca, d); break;
|
||||
case DT_RELASZ : reloca_size = d->un.val; break;
|
||||
case DT_SYMTAB : section<typeof(symtab)>(&symtab, d); break;
|
||||
case DT_STRTAB : section<typeof(strtab)>(&strtab, d); break;
|
||||
case DT_STRSZ : strtab_size = d->un.val; 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_JMPREL : section<typeof(pltrel)>(&pltrel, d); break;
|
||||
case DT_REL : section<typeof(rel)>(&rel, d); break;
|
||||
case DT_RELSZ : rel_size = d->un.val; break;
|
||||
case DT_DEBUG : section_dt_debug(d); break;
|
||||
void _init()
|
||||
{
|
||||
for (Elf::Dyn const *d = &_dynamic; d->tag != DT_NULL; d++) {
|
||||
switch (d->tag) {
|
||||
case DT_NEEDED : _section_dt_needed(d); break;
|
||||
case DT_PLTRELSZ: _pltrel_size = d->un.val; break;
|
||||
case DT_PLTGOT : _section<typeof(_pltgot)>(&_pltgot, d); break;
|
||||
case DT_HASH : _section<typeof(_hash_table)>(&_hash_table, d); break;
|
||||
case DT_RELA : _section<typeof(_reloca)>(&_reloca, d); break;
|
||||
case DT_RELASZ : _reloca_size = d->un.val; break;
|
||||
case DT_SYMTAB : _section<typeof(_symtab)>(&_symtab, d); break;
|
||||
case DT_STRTAB : _section<typeof(_strtab)>(&_strtab, d); break;
|
||||
case DT_STRSZ : _strtab_size = d->un.val; 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_JMPREL : _section<typeof(_pltrel)>(&_pltrel, d); break;
|
||||
case DT_REL : _section<typeof(_rel)>(&_rel, d); break;
|
||||
case DT_RELSZ : _rel_size = d->un.val; break;
|
||||
case DT_DEBUG : _section_dt_debug(d); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void relocate()
|
||||
{
|
||||
plt_setup();
|
||||
public:
|
||||
|
||||
if (pltrel_size) {
|
||||
switch (pltrel_type) {
|
||||
enum Pass { FIRST_PASS, SECOND_PASS };
|
||||
|
||||
Dynamic(Dependency const &dep)
|
||||
:
|
||||
_dep(&dep), _obj(dep.obj()), _dynamic(*(Elf::Dyn *)dynamic_address())
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
Dynamic(Allocator &md_alloc, Dependency const &dep, Object const &obj,
|
||||
Linker::Phdr const *phdr)
|
||||
:
|
||||
_dep(&dep), _obj(obj), _dynamic(_find_dynamic(phdr)), _md_alloc(&md_alloc)
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
~Dynamic()
|
||||
{
|
||||
if (!_md_alloc)
|
||||
return;
|
||||
|
||||
while (Needed *n = _needed.dequeue())
|
||||
destroy(*_md_alloc, n);
|
||||
}
|
||||
|
||||
void call_init_function() const
|
||||
{
|
||||
if (!_init_function)
|
||||
return;
|
||||
|
||||
if (verbose_relocation)
|
||||
log(_obj.name(), " init func ", _init_function);
|
||||
|
||||
_init_function();
|
||||
}
|
||||
|
||||
Elf::Sym const *symbol(unsigned sym_index) const
|
||||
{
|
||||
if (sym_index > _hash_table->nchains())
|
||||
return nullptr;
|
||||
|
||||
return _symtab + sym_index;
|
||||
}
|
||||
|
||||
char const *symbol_name(Elf::Sym const &sym) const
|
||||
{
|
||||
return _strtab + sym.st_name;
|
||||
}
|
||||
|
||||
void const *dynamic_ptr() const { return &_dynamic; }
|
||||
|
||||
void dep(Dependency const &dep) { _dep = &dep; }
|
||||
|
||||
Dependency const &dep() const { return *_dep; }
|
||||
|
||||
/*
|
||||
* Use DT_HASH table address for linker, assuming that it will always be at
|
||||
* the beginning of the file
|
||||
*/
|
||||
Elf::Addr link_map_addr() const { return trunc_page((Elf::Addr)_hash_table); }
|
||||
|
||||
/**
|
||||
* Lookup symbol name in this ELF
|
||||
*/
|
||||
Elf::Sym const *lookup_symbol(char const *name, unsigned long hash) const
|
||||
{
|
||||
Hash_table *h = _hash_table;
|
||||
|
||||
if (!h->buckets())
|
||||
return nullptr;
|
||||
|
||||
unsigned long sym_index = h->buckets()[hash % h->nbuckets()];
|
||||
|
||||
/* traverse hash chain */
|
||||
for (; sym_index != STN_UNDEF; sym_index = h->chains()[sym_index])
|
||||
{
|
||||
/* bad object */
|
||||
if (sym_index > h->nchains())
|
||||
return nullptr;
|
||||
|
||||
Elf::Sym const *sym = symbol(sym_index);
|
||||
char const *sym_name = symbol_name(*sym);
|
||||
|
||||
/* this omitts everything but 'NOTYPE', 'OBJECT', and 'FUNC' */
|
||||
if (sym->type() > STT_FUNC)
|
||||
continue;
|
||||
|
||||
if (sym->st_value == 0)
|
||||
continue;
|
||||
|
||||
/* check for symbol name */
|
||||
if (name[0] != sym_name[0] || strcmp(name, sym_name))
|
||||
continue;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* \throw Address_info::Invalid_address
|
||||
*/
|
||||
Elf::Sym const &symbol_by_addr(addr_t addr) const
|
||||
{
|
||||
addr_t const reloc_base = _obj.reloc_base();
|
||||
|
||||
for (unsigned long i = 0; i < _hash_table->nchains(); i++)
|
||||
{
|
||||
Elf::Sym const *sym = symbol(i);
|
||||
if (!sym)
|
||||
continue;
|
||||
|
||||
/* skip */
|
||||
if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)
|
||||
continue;
|
||||
|
||||
addr_t const sym_addr = reloc_base + sym->st_value;
|
||||
if (addr < sym_addr || addr >= sym_addr + sym->st_size)
|
||||
continue;
|
||||
|
||||
return *sym;
|
||||
}
|
||||
throw Address_info::Invalid_address();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call functor for each dependency, passing the path as argument
|
||||
*/
|
||||
template <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();
|
||||
|
||||
if (_pltrel_size) {
|
||||
switch (_pltrel_type) {
|
||||
case DT_RELA:
|
||||
case DT_REL:
|
||||
Reloc_plt(obj, pltrel_type, pltrel, pltrel_size);
|
||||
Reloc_plt(_obj, _pltrel_type, _pltrel, _pltrel_size);
|
||||
break;
|
||||
default:
|
||||
Genode::error("LD: Invalid PLT relocation ", (int)pltrel_type);
|
||||
error("LD: Invalid PLT relocation ", (int)_pltrel_type);
|
||||
throw Incompatible();
|
||||
}
|
||||
}
|
||||
|
||||
relocate_non_plt(bind, FIRST_PASS);
|
||||
}
|
||||
|
||||
relocate_non_plt();
|
||||
}
|
||||
void plt_setup()
|
||||
{
|
||||
if (_pltgot)
|
||||
Plt_got r(*_dep, _pltgot);
|
||||
}
|
||||
|
||||
void plt_setup()
|
||||
{
|
||||
if (pltgot)
|
||||
Plt_got r(dep, pltgot);
|
||||
}
|
||||
void relocate_non_plt(Bind bind, Pass pass)
|
||||
{
|
||||
if (_reloca)
|
||||
Reloc_non_plt r(*_dep, _reloca, _reloca_size);
|
||||
|
||||
void relocate_non_plt(bool second_pass = false)
|
||||
{
|
||||
if (reloca)
|
||||
Reloc_non_plt r(dep, reloca, reloca_size);
|
||||
if (_rel)
|
||||
Reloc_non_plt r(*_dep, _rel, _rel_size, pass == SECOND_PASS);
|
||||
|
||||
if (rel)
|
||||
Reloc_non_plt r(dep, rel, rel_size, second_pass);
|
||||
if (bind == BIND_NOW)
|
||||
Reloc_bind_now r(*_dep, _pltrel, _pltrel_size);
|
||||
}
|
||||
|
||||
if (bind_now)
|
||||
Reloc_bind_now r(dep, pltrel, pltrel_size);
|
||||
}
|
||||
Elf::Rel const *pltrel() const { return _pltrel; }
|
||||
D_tag pltrel_type() const { return _pltrel_type; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__DYNAMIC_H_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* \brief ELF file setup
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-12
|
||||
@ -14,23 +14,20 @@
|
||||
#ifndef _INCLUDE__FILE_H_
|
||||
#define _INCLUDE__FILE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
|
||||
/* local includes */
|
||||
#include <util.h>
|
||||
#include <debug.h>
|
||||
#include <region_map.h>
|
||||
|
||||
|
||||
namespace Linker {
|
||||
|
||||
struct Phdr;
|
||||
struct File;
|
||||
|
||||
/**
|
||||
* Load object
|
||||
*
|
||||
* \param path Path of object
|
||||
* \param load True, load binary; False, load ELF header only
|
||||
*
|
||||
* \throw Invalid_file Segment is neither read-only/executable or read/write
|
||||
* \throw Region_conflict There is already something at the given address
|
||||
* \throw Incompatible Not an ELF
|
||||
*
|
||||
* \return File descriptor
|
||||
*/
|
||||
File const *load(char const *path, bool load = true);
|
||||
struct Elf_file;
|
||||
}
|
||||
|
||||
|
||||
@ -47,7 +44,7 @@ struct Linker::Phdr
|
||||
|
||||
|
||||
/**
|
||||
* Loaded ELF file
|
||||
* ELF file info
|
||||
*/
|
||||
struct Linker::File
|
||||
{
|
||||
@ -72,4 +69,208 @@ struct Linker::File
|
||||
unsigned elf_phdr_count() const { return phdr.count; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mapped ELF file
|
||||
*/
|
||||
struct Linker::Elf_file : File
|
||||
{
|
||||
Env &env;
|
||||
Rom_connection rom;
|
||||
Ram_dataspace_capability ram_cap[Phdr::MAX_PHDR];
|
||||
bool const loaded;
|
||||
|
||||
Elf_file(Env &env, Allocator &md_alloc, char const *name, bool load)
|
||||
:
|
||||
env(env), rom(env, name), loaded(load)
|
||||
{
|
||||
load_phdr();
|
||||
|
||||
/*
|
||||
* Initialize the linker area at the link address of the binary,
|
||||
* which happens to be the first loaded 'Elf_file'.
|
||||
*
|
||||
* XXX Move this initialization to the linker's 'construct' function
|
||||
* once we use relocatable binaries.
|
||||
*/
|
||||
if (load && !Region_map::r().constructed())
|
||||
Region_map::r().construct(env, md_alloc, start);
|
||||
|
||||
if (load)
|
||||
load_segments();
|
||||
}
|
||||
|
||||
virtual ~Elf_file()
|
||||
{
|
||||
if (loaded)
|
||||
unload_segments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if ELF is sane
|
||||
*/
|
||||
bool check_compat(Elf::Ehdr const &ehdr)
|
||||
{
|
||||
char const * const ELFMAG = "\177ELF";
|
||||
if (memcmp(&ehdr, ELFMAG, SELFMAG) != 0) {
|
||||
error("LD: binary is not an ELF");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ehdr.e_ident[EI_CLASS] != ELFCLASS) {
|
||||
error("LD: support for 32/64-bit objects only");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy program headers and read entry point
|
||||
*/
|
||||
void load_phdr()
|
||||
{
|
||||
{
|
||||
/* temporary map the binary to read the program header */
|
||||
Attached_dataspace ds(env.rm(), rom.dataspace());
|
||||
|
||||
Elf::Ehdr const &ehdr = *ds.local_addr<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_ */
|
||||
|
@ -25,7 +25,7 @@ namespace Linker {
|
||||
/**
|
||||
* Handle static construction and relocation of ELF files
|
||||
*/
|
||||
struct Linker::Init : Genode::List<Object>
|
||||
struct Linker::Init : List<Object>
|
||||
{
|
||||
bool in_progress = false;
|
||||
bool restart = false;
|
||||
@ -39,7 +39,7 @@ struct Linker::Init : Genode::List<Object>
|
||||
Object *contains(char const *file)
|
||||
{
|
||||
for (Object *elf = first(); elf; elf = elf->next_init())
|
||||
if (!Genode::strcmp(file, elf->name()))
|
||||
if (!strcmp(file, elf->name()))
|
||||
return elf;
|
||||
|
||||
return nullptr;
|
||||
@ -52,24 +52,25 @@ struct Linker::Init : Genode::List<Object>
|
||||
insert(elf);
|
||||
|
||||
/* re-order dependencies */
|
||||
for (Dynamic::Needed *n = elf->dynamic()->needed.head(); n; n = n->next()) {
|
||||
char const *path = n->path(elf->dynamic()->strtab);
|
||||
Object *e;
|
||||
elf->dynamic().for_each_dependency([&] (char const *path) {
|
||||
|
||||
if ((e = contains(Linker::file(path))))
|
||||
// for (Dynamic::Needed *n = elf->dynamic().needed.head(); n; n = n->next()) {
|
||||
// char const *path = n->path(elf->dynamic().strtab);
|
||||
|
||||
if (Object *e = contains(Linker::file(path)))
|
||||
reorder(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void initialize()
|
||||
void initialize(Bind bind)
|
||||
{
|
||||
Object *obj = first();
|
||||
|
||||
/* relocate */
|
||||
for (; obj; obj = obj->next_init()) {
|
||||
if (verbose_relocation)
|
||||
Genode::log("Relocate ", obj->name());
|
||||
obj->relocate();
|
||||
log("Relocate ", obj->name());
|
||||
obj->relocate(bind);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -91,13 +92,7 @@ struct Linker::Init : Genode::List<Object>
|
||||
Object *next = obj->next_init();
|
||||
remove(obj);
|
||||
|
||||
if (obj->dynamic()->init_function) {
|
||||
|
||||
if (verbose_relocation)
|
||||
Genode::log(obj->name(), " init func ", obj->dynamic()->init_function);
|
||||
|
||||
obj->dynamic()->init_function();
|
||||
}
|
||||
obj->dynamic().call_init_function();
|
||||
|
||||
obj = restart ? first() : next;
|
||||
restart = false;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* \brief Generic linker definitions
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-10-24
|
||||
@ -14,28 +14,12 @@
|
||||
#ifndef _INCLUDE__LINKER_H_
|
||||
#define _INCLUDE__LINKER_H_
|
||||
|
||||
#include <base/exception.h>
|
||||
#include <base/env.h>
|
||||
#include <base/shared_object.h>
|
||||
#include <util/fifo.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <util/string.h>
|
||||
|
||||
#include <types.h>
|
||||
#include <debug.h>
|
||||
#include <elf.h>
|
||||
#include <file.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
|
||||
*/
|
||||
@ -48,11 +32,6 @@ namespace Linker {
|
||||
|
||||
typedef void (*Func)(void);
|
||||
|
||||
/**
|
||||
* Eager binding enable
|
||||
*/
|
||||
extern bool bind_now;
|
||||
|
||||
/**
|
||||
* Print diagnostic information
|
||||
*
|
||||
@ -75,7 +54,7 @@ namespace Linker {
|
||||
*
|
||||
* \return Symbol information
|
||||
*/
|
||||
Elf::Sym const *lookup_symbol(unsigned sym_index, Dependency const *, Elf::Addr *base,
|
||||
Elf::Sym const *lookup_symbol(unsigned sym_index, Dependency const &, Elf::Addr *base,
|
||||
bool undef = false, bool other = false);
|
||||
|
||||
/**
|
||||
@ -93,20 +72,22 @@ namespace Linker {
|
||||
*
|
||||
* \return Symbol information
|
||||
*/
|
||||
Elf::Sym const *lookup_symbol(char const *name, Dependency const *dep, Elf::Addr *base,
|
||||
Elf::Sym const *lookup_symbol(char const *name, Dependency const &dep, Elf::Addr *base,
|
||||
bool undef = false, bool other = false);
|
||||
|
||||
/**
|
||||
* Load an ELF (setup segments and map program header)
|
||||
*
|
||||
* \param path File to load
|
||||
* \param dep Dependency entry for new object
|
||||
* \param flags 'Genode::Shared_object::KEEP' will not unload the ELF, if the
|
||||
* reference count reaches zero
|
||||
* \param md_alloc allocator used for dyamically allocater meta data
|
||||
* \param path rom module to load
|
||||
* \param dep dependency entry for new object
|
||||
* \param flags 'Shared_object::KEEP' will not unload the ELF,
|
||||
* if the reference count reaches zero
|
||||
*
|
||||
* \return Linker::Object
|
||||
*/
|
||||
Object *load(char const *path, Dependency *dep, unsigned flags = 0);
|
||||
Object &load(Env &, Allocator &md_alloc, char const *path, Dependency &dep,
|
||||
Keep keep);
|
||||
|
||||
/**
|
||||
* Returns the head of the global object list
|
||||
@ -119,16 +100,9 @@ namespace Linker {
|
||||
Dependency *binary_root_dep();
|
||||
|
||||
/**
|
||||
* Force to map the program header of the dynamic linker
|
||||
* Global ELF access lock
|
||||
*/
|
||||
void load_linker_phdr();
|
||||
|
||||
/**
|
||||
* Exceptions
|
||||
*/
|
||||
class Incompatible : Genode::Exception { };
|
||||
class Invalid_file : Genode::Exception { };
|
||||
class Not_found : Genode::Exception { };
|
||||
Lock &lock();
|
||||
|
||||
/**
|
||||
* Invariants
|
||||
@ -141,42 +115,45 @@ namespace Linker {
|
||||
/**
|
||||
* Shared object or binary
|
||||
*/
|
||||
class Linker::Object : public Genode::Fifo<Object>::Element,
|
||||
public Genode::List<Object>::Element
|
||||
class Linker::Object : public Fifo<Object>::Element,
|
||||
public List<Object>::Element
|
||||
{
|
||||
public:
|
||||
|
||||
typedef String<128> Name;
|
||||
|
||||
protected:
|
||||
|
||||
enum { MAX_PATH = 128 };
|
||||
|
||||
char _name[MAX_PATH];
|
||||
Name _name;
|
||||
File const *_file = nullptr;
|
||||
Elf::Addr _reloc_base = 0;
|
||||
|
||||
public:
|
||||
|
||||
Object(Elf::Addr reloc_base) : _reloc_base(reloc_base) { }
|
||||
Object(char const *path, File const *file)
|
||||
: _file(file), _reloc_base(file->reloc_base)
|
||||
void init(Name const &name, Elf::Addr reloc_base)
|
||||
{
|
||||
Genode::strncpy(_name, Linker::file(path), MAX_PATH);
|
||||
_name = name;
|
||||
_reloc_base = reloc_base;
|
||||
}
|
||||
|
||||
virtual ~Object()
|
||||
void init(Name const &name, File const &file)
|
||||
{
|
||||
if (_file)
|
||||
destroy(Genode::env()->heap(), const_cast<File *>(_file));
|
||||
_name = name;
|
||||
_file = &file;
|
||||
_reloc_base = file.reloc_base;
|
||||
}
|
||||
|
||||
Elf::Addr reloc_base() const { return _reloc_base; }
|
||||
char const *name() const { return _name; }
|
||||
virtual ~Object() { }
|
||||
|
||||
File const *file() { return _file; }
|
||||
Elf::Size const size() const { return _file ? _file->size : 0; }
|
||||
Elf::Addr reloc_base() const { return _reloc_base; }
|
||||
char const *name() const { return _name.string(); }
|
||||
File const *file() const { return _file; }
|
||||
Elf::Size const size() const { return _file ? _file->size : 0; }
|
||||
|
||||
virtual bool is_linker() const = 0;
|
||||
virtual bool is_binary() const = 0;
|
||||
|
||||
virtual void relocate() = 0;
|
||||
virtual void relocate(Bind) = 0;
|
||||
|
||||
virtual void load() = 0;
|
||||
virtual bool unload() { return false;}
|
||||
@ -184,7 +161,7 @@ class Linker::Object : public Genode::Fifo<Object>::Element,
|
||||
/**
|
||||
* Next object in global object list
|
||||
*/
|
||||
virtual Object *next_obj() const = 0;
|
||||
virtual Object *next_obj() const = 0;
|
||||
|
||||
/**
|
||||
* Next object in initialization list
|
||||
@ -194,79 +171,104 @@ class Linker::Object : public Genode::Fifo<Object>::Element,
|
||||
/**
|
||||
* Return dynamic section of ELF
|
||||
*/
|
||||
virtual Dynamic *dynamic() = 0;
|
||||
virtual Dynamic const &dynamic() const = 0;
|
||||
|
||||
/**
|
||||
* Return link map for ELF
|
||||
*/
|
||||
virtual Link_map *link_map() = 0;
|
||||
virtual Link_map const &link_map() const = 0;
|
||||
|
||||
/**
|
||||
* Return type of 'symbol_at_address'
|
||||
*/
|
||||
struct Symbol_info { addr_t addr; char const *name; };
|
||||
|
||||
/**
|
||||
* Return address info for symboal at addr
|
||||
*/
|
||||
virtual void info(Genode::addr_t addr, Genode::Address_info &info) = 0;
|
||||
|
||||
/**
|
||||
* Global ELF access lock
|
||||
*/
|
||||
static Genode::Lock & lock()
|
||||
{
|
||||
static Genode::Lock _lock;
|
||||
return _lock;
|
||||
}
|
||||
virtual Symbol_info symbol_at_address(addr_t addr) const = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dependency of object
|
||||
*/
|
||||
struct Linker::Dependency : Genode::Fifo<Dependency>::Element
|
||||
class Linker::Dependency : public Fifo<Dependency>::Element, Noncopyable
|
||||
{
|
||||
Object *obj = nullptr;
|
||||
Root_object *root = nullptr;
|
||||
private:
|
||||
|
||||
Dependency(Object *obj, Root_object *root) : obj(obj), root(root) { }
|
||||
Object &_obj;
|
||||
Root_object *_root = nullptr;
|
||||
Allocator *_md_alloc = nullptr;
|
||||
|
||||
Dependency(char const *path, Root_object *root, Genode::Fifo<Dependency> * const dep,
|
||||
unsigned flags = 0);
|
||||
~Dependency();
|
||||
/**
|
||||
* Check if file is in this dependency tree
|
||||
*/
|
||||
bool in_dep(char const *file, Fifo<Dependency> const &);
|
||||
|
||||
/**
|
||||
* Load dependent ELF object
|
||||
*/
|
||||
void load_needed(Genode::Fifo<Dependency> * const dep, unsigned flags = 0);
|
||||
public:
|
||||
|
||||
/**
|
||||
* Check if file is in this dependency tree
|
||||
*/
|
||||
bool in_dep(char const *file, Genode::Fifo<Dependency> *const dep);
|
||||
/*
|
||||
* Called by 'Ld' constructor
|
||||
*/
|
||||
Dependency(Object &obj, Root_object *root) : _obj(obj), _root(root) { }
|
||||
|
||||
Dependency(Env &, Allocator &, char const *path, Root_object *,
|
||||
Fifo<Dependency> &, Keep);
|
||||
|
||||
~Dependency();
|
||||
|
||||
/**
|
||||
* Load dependent ELF object
|
||||
*/
|
||||
void load_needed(Env &, Allocator &, Fifo<Dependency> &, Keep);
|
||||
|
||||
bool root() const { return _root != nullptr; }
|
||||
|
||||
Object const &obj() const { return _obj; }
|
||||
|
||||
/**
|
||||
* Return first element of dependency list
|
||||
*/
|
||||
Dependency const &first() const;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Root of dependencies
|
||||
*/
|
||||
struct Linker::Root_object
|
||||
class Linker::Root_object
|
||||
{
|
||||
Genode::Fifo<Dependency> dep;
|
||||
private:
|
||||
|
||||
/* main root */
|
||||
Root_object() { };
|
||||
Fifo<Dependency> _deps;
|
||||
|
||||
/* runtime loaded root components */
|
||||
Root_object(char const *path, unsigned flags = 0);
|
||||
Allocator &_md_alloc;
|
||||
|
||||
~Root_object()
|
||||
{
|
||||
Dependency *d;
|
||||
while ((d = dep.dequeue()))
|
||||
destroy(Genode::env()->heap(), d);
|
||||
}
|
||||
public:
|
||||
|
||||
Link_map const *link_map() const
|
||||
{
|
||||
return dep.head()->obj->link_map();
|
||||
}
|
||||
/* main root */
|
||||
Root_object(Allocator &md_alloc) : _md_alloc(md_alloc) { };
|
||||
|
||||
/* runtime loaded root components */
|
||||
Root_object(Env &, Allocator &, char const *path, Bind, Keep);
|
||||
|
||||
~Root_object()
|
||||
{
|
||||
while (Dependency *d = _deps.dequeue())
|
||||
destroy(_md_alloc, d);
|
||||
}
|
||||
|
||||
Link_map const &link_map() const
|
||||
{
|
||||
return _deps.head()->obj().link_map();
|
||||
}
|
||||
|
||||
Dependency const *first_dep() const { return _deps.head(); }
|
||||
|
||||
void enqueue(Dependency &dep) { _deps.enqueue(&dep); }
|
||||
|
||||
Fifo<Dependency> &deps() { return _deps; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__LINKER_H_ */
|
||||
|
118
repos/base/src/lib/ldso/include/region_map.h
Normal file
118
repos/base/src/lib/ldso/include/region_map.h
Normal 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_ */
|
@ -18,9 +18,9 @@
|
||||
|
||||
constexpr bool verbose_relocation = false;
|
||||
|
||||
static inline bool verbose_reloc(Linker::Dependency const *d)
|
||||
static inline bool verbose_reloc(Linker::Dependency const &d)
|
||||
{
|
||||
return d->root && verbose_relocation;
|
||||
return d.root() && verbose_relocation;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,12 +45,12 @@ namespace Linker
|
||||
*/
|
||||
struct Linker::Plt_got
|
||||
{
|
||||
Plt_got(Dependency const *dep, Elf::Addr *pltgot)
|
||||
Plt_got(Dependency const &dep, Elf::Addr *pltgot)
|
||||
{
|
||||
if (verbose_relocation)
|
||||
Genode::log("OBJ: ", dep->obj->name(), " (", dep, ")");
|
||||
log("OBJ: ", dep.obj().name(), " (", &dep, ")");
|
||||
|
||||
pltgot[1] = (Elf::Addr) dep; /* ELF object */
|
||||
pltgot[1] = (Elf::Addr) &dep; /* ELF object */
|
||||
pltgot[2] = (Elf::Addr) &_jmp_slot; /* Linker entry */
|
||||
}
|
||||
};
|
||||
@ -62,11 +62,11 @@ struct Linker::Plt_got
|
||||
template<typename REL, unsigned TYPE, unsigned JMPSLOT>
|
||||
struct Linker::Reloc_plt_generic
|
||||
{
|
||||
Reloc_plt_generic(Object const *obj, D_tag const type,
|
||||
Reloc_plt_generic(Object const &obj, D_tag const type,
|
||||
Elf::Rel const *start, unsigned long size)
|
||||
{
|
||||
if (type != TYPE) {
|
||||
Genode::error("LD: Unsupported PLT relocation type: ", (int)type);
|
||||
error("LD: Unsupported PLT relocation type: ", (int)type);
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
@ -75,13 +75,13 @@ struct Linker::Reloc_plt_generic
|
||||
for (; rel < end; rel++) {
|
||||
|
||||
if (rel->type() != JMPSLOT) {
|
||||
Genode::error("LD: Unsupported PLT relocation ", (int)rel->type());
|
||||
error("LD: Unsupported PLT relocation ", (int)rel->type());
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
/* find relocation address and add relocation base */
|
||||
Elf::Addr *addr = (Elf::Addr *)(obj->reloc_base() + rel->offset);
|
||||
*addr += obj->reloc_base();
|
||||
Elf::Addr *addr = (Elf::Addr *)(obj.reloc_base() + rel->offset);
|
||||
*addr += obj.reloc_base();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -91,7 +91,7 @@ class Linker::Reloc_non_plt_generic
|
||||
{
|
||||
protected:
|
||||
|
||||
Dependency const *_dep;
|
||||
Dependency const &_dep;
|
||||
|
||||
/**
|
||||
* Copy relocations, these are just for the main program, we can do them
|
||||
@ -101,9 +101,9 @@ class Linker::Reloc_non_plt_generic
|
||||
template <typename REL>
|
||||
void _copy(REL const *rel, Elf::Addr *addr)
|
||||
{
|
||||
if (!_dep->obj->is_binary()) {
|
||||
Genode::error("LD: copy relocation in DSO "
|
||||
"(", _dep->obj->name(), " at ", addr, ")");
|
||||
if (!_dep.obj().is_binary()) {
|
||||
error("LD: copy relocation in DSO "
|
||||
"(", _dep.obj().name(), " at ", addr, ")");
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
@ -112,22 +112,22 @@ class Linker::Reloc_non_plt_generic
|
||||
|
||||
/* search symbol in other objects, do not return undefined symbols */
|
||||
if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base, false, true))) {
|
||||
Genode::warning("LD: symbol not found");
|
||||
warning("LD: symbol not found");
|
||||
return;
|
||||
}
|
||||
|
||||
Elf::Addr src = reloc_base + sym->st_value;
|
||||
Genode::memcpy(addr, (void *)src, sym->st_size);
|
||||
memcpy(addr, (void *)src, sym->st_size);
|
||||
|
||||
if (verbose_relocation)
|
||||
Genode::log("Copy relocation: ", Genode::Hex(src),
|
||||
" -> ", addr, " (", Genode::Hex(sym->st_size), " bytes)"
|
||||
" val: ", Genode::Hex(sym->st_value));
|
||||
log("Copy relocation: ", Hex(src),
|
||||
" -> ", addr, " (", Hex(sym->st_size), " bytes)"
|
||||
" val: ", Hex(sym->st_value));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt_generic(Dependency const *dep) : _dep(dep) { }
|
||||
Reloc_non_plt_generic(Dependency const &dep) : _dep(dep) { }
|
||||
};
|
||||
|
||||
|
||||
@ -141,11 +141,11 @@ class Linker::Reloc_jmpslot_generic
|
||||
|
||||
public:
|
||||
|
||||
Reloc_jmpslot_generic(Dependency const *dep, unsigned const type, Elf::Rel const* pltrel,
|
||||
Reloc_jmpslot_generic(Dependency const &dep, unsigned const type, Elf::Rel const* pltrel,
|
||||
Elf::Size const index)
|
||||
{
|
||||
if (type != TYPE) {
|
||||
Genode::error("LD: unsupported JMP relocation type: ", (int)type);
|
||||
error("LD: unsupported JMP relocation type: ", (int)type);
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
@ -154,19 +154,19 @@ class Linker::Reloc_jmpslot_generic
|
||||
Elf::Addr reloc_base;
|
||||
|
||||
if (!(sym = lookup_symbol(rel->sym(), dep, &reloc_base))) {
|
||||
Genode::warning("LD: symbol not found");
|
||||
warning("LD: symbol not found");
|
||||
return;
|
||||
}
|
||||
|
||||
/* write address of symbol to jump slot */
|
||||
_addr = (Elf::Addr *)(dep->obj->reloc_base() + rel->offset);
|
||||
_addr = (Elf::Addr *)(dep.obj().reloc_base() + rel->offset);
|
||||
*_addr = reloc_base + sym->st_value;
|
||||
|
||||
|
||||
if (verbose_relocation) {
|
||||
Genode::log("jmp: rbase ", Genode::Hex(reloc_base),
|
||||
" s: ", sym, " sval: ", Genode::Hex(sym->st_value));
|
||||
Genode::log("jmp_slot at ", _addr, " -> ", *_addr);
|
||||
log("jmp: rbase ", Hex(reloc_base),
|
||||
" s: ", sym, " sval: ", Hex(sym->st_value));
|
||||
log("jmp_slot at ", _addr, " -> ", *_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +180,7 @@ class Linker::Reloc_jmpslot_generic
|
||||
template <typename REL, unsigned TYPE>
|
||||
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);
|
||||
|
||||
|
43
repos/base/src/lib/ldso/include/types.h
Normal file
43
repos/base/src/lib/ldso/include/types.h
Normal 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_ */
|
@ -21,11 +21,11 @@ namespace Linker {
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T trunc_page(T addr) {
|
||||
return addr & Genode::_align_mask((T)12); }
|
||||
return addr & _align_mask((T)12); }
|
||||
|
||||
template <typename T>
|
||||
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
|
||||
|
@ -18,10 +18,16 @@
|
||||
#include <util/list.h>
|
||||
#include <util/string.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 */
|
||||
#include <dynamic.h>
|
||||
#include <init.h>
|
||||
#include <region_map.h>
|
||||
|
||||
using namespace Linker;
|
||||
|
||||
@ -32,11 +38,10 @@ namespace Linker {
|
||||
struct Binary;
|
||||
struct Link_map;
|
||||
struct Debug;
|
||||
|
||||
struct Config;
|
||||
};
|
||||
|
||||
static Binary *binary = 0;
|
||||
bool Linker::bind_now = false;
|
||||
static Binary *binary_ptr = nullptr;
|
||||
bool Linker::verbose = false;
|
||||
Link_map *Link_map::first;
|
||||
|
||||
@ -46,6 +51,25 @@ Link_map *Link_map::first;
|
||||
int genode_atexit(Linker::Func);
|
||||
|
||||
|
||||
Linker::Region_map::Constructible_region_map &Linker::Region_map::r()
|
||||
{
|
||||
/*
|
||||
* The capabilities in this class become invalid when doing a
|
||||
* fork in the noux environment. Hence avoid destruction of
|
||||
* the singleton object as the destructor would try to access
|
||||
* the capabilities also in the forked process.
|
||||
*/
|
||||
return *unmanaged_singleton<Constructible_region_map>();
|
||||
}
|
||||
|
||||
|
||||
Genode::Lock &Linker::lock()
|
||||
{
|
||||
static Lock _lock;
|
||||
return _lock;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
** ELF object types (shared object, dynamic binaries, ldso **
|
||||
**************************************************************/
|
||||
@ -53,191 +77,165 @@ int genode_atexit(Linker::Func);
|
||||
/**
|
||||
* The actual ELF object, one per file
|
||||
*/
|
||||
struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element
|
||||
class Linker::Elf_object : public Object, public Fifo<Elf_object>::Element
|
||||
{
|
||||
Dynamic dyn;
|
||||
Link_map map;
|
||||
unsigned ref_count = 1;
|
||||
unsigned flags = 0;
|
||||
bool relocated = false;
|
||||
private:
|
||||
|
||||
Elf_object(Dependency const *dep, Elf::Addr reloc_base)
|
||||
: Object(reloc_base), dyn(dep)
|
||||
{ }
|
||||
Link_map _map;
|
||||
unsigned _ref_count = 1;
|
||||
unsigned const _keep = KEEP;
|
||||
bool _relocated = false;
|
||||
|
||||
Elf_object(char const *path, Dependency const *dep, unsigned flags = 0)
|
||||
:
|
||||
Object(path, Linker::load(Linker::file(path))), dyn(dep, this, &_file->phdr),
|
||||
flags(flags)
|
||||
{
|
||||
/* register for static construction and relocation */
|
||||
Init::list()->insert(this);
|
||||
obj_list()->enqueue(this);
|
||||
/*
|
||||
* Optional ELF file, skipped for initial 'Ld' initialization
|
||||
*/
|
||||
Lazy_volatile_object<Elf_file> _elf_file;
|
||||
|
||||
/* add to link map */
|
||||
Debug::state_change(Debug::ADD, nullptr);
|
||||
setup_link_map();
|
||||
Debug::state_change(Debug::CONSISTENT, &map);
|
||||
}
|
||||
|
||||
virtual ~Elf_object()
|
||||
{
|
||||
if (!_file)
|
||||
return;
|
||||
|
||||
if (verbose_loading)
|
||||
Genode::log("LD: destroy ELF object: ", name());
|
||||
|
||||
/* remove from link map */
|
||||
Debug::state_change(Debug::DELETE, &map);
|
||||
Link_map::remove(&map);
|
||||
Debug::state_change(Debug::CONSISTENT, nullptr);
|
||||
|
||||
/* remove from loaded objects list */
|
||||
obj_list()->remove(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return symbol of given number from ELF
|
||||
*/
|
||||
Elf::Sym const *symbol(unsigned sym_index) const
|
||||
{
|
||||
if (sym_index > dyn.hash_table->nchains())
|
||||
return 0;
|
||||
|
||||
return dyn.symtab + sym_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return name of given symbol
|
||||
*/
|
||||
char const *symbol_name(Elf::Sym const *sym) const {
|
||||
return dyn.strtab + sym->st_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup symbol name in this ELF
|
||||
*/
|
||||
Elf::Sym const *lookup_symbol(char const *name, unsigned long hash) const
|
||||
{
|
||||
Hash_table *h = dyn.hash_table;
|
||||
|
||||
if (!h->buckets())
|
||||
return nullptr;
|
||||
|
||||
unsigned long sym_index = h->buckets()[hash % h->nbuckets()];
|
||||
|
||||
/* traverse hash chain */
|
||||
for (; sym_index != STN_UNDEF; sym_index = h->chains()[sym_index])
|
||||
bool _init_elf_file(Env &env, Allocator &md_alloc, char const *path)
|
||||
{
|
||||
/* bad object */
|
||||
if (sym_index > h->nchains())
|
||||
return nullptr;
|
||||
|
||||
Elf::Sym const *sym = symbol(sym_index);
|
||||
char const *sym_name = symbol_name(sym);
|
||||
|
||||
/* this omitts everything but 'NOTYPE', 'OBJECT', and 'FUNC' */
|
||||
if (sym->type() > STT_FUNC)
|
||||
continue;
|
||||
|
||||
if (sym->st_value == 0)
|
||||
continue;
|
||||
|
||||
/* check for symbol name */
|
||||
if (name[0] != sym_name[0] || Genode::strcmp(name, sym_name))
|
||||
continue;
|
||||
|
||||
return sym;
|
||||
_elf_file.construct(env, md_alloc, Linker::file(path), true);
|
||||
Object::init(Linker::file(path), *_elf_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
bool const _elf_file_initialized;
|
||||
|
||||
/**
|
||||
* Fill-out link map infos for this ELF
|
||||
*/
|
||||
void setup_link_map()
|
||||
{
|
||||
map.addr = _file ? _file->start + reloc_base() : reloc_base();
|
||||
map.path = name();
|
||||
map.dynamic = (void *)dyn.dynamic;
|
||||
Dynamic _dyn;
|
||||
|
||||
Link_map::add(&map);
|
||||
};
|
||||
public:
|
||||
|
||||
|
||||
Link_map *link_map() override { return ↦ }
|
||||
Dynamic *dynamic() override { return &dyn; }
|
||||
|
||||
void relocate() override
|
||||
{
|
||||
if (!relocated)
|
||||
dyn.relocate();
|
||||
|
||||
relocated = true;
|
||||
}
|
||||
|
||||
void info(Genode::addr_t addr, Genode::Address_info &info) override
|
||||
{
|
||||
info.path = name();
|
||||
info.base = map.addr;
|
||||
info.addr = 0;
|
||||
|
||||
Hash_table *h = dyn.hash_table;
|
||||
|
||||
for (unsigned long sym_index = 0; sym_index < h->nchains(); sym_index++)
|
||||
Elf_object(Dependency const &dep, Object::Name const &name,
|
||||
Elf::Addr reloc_base)
|
||||
:
|
||||
_elf_file_initialized(false), _dyn(dep)
|
||||
{
|
||||
Elf::Sym const *sym = symbol(sym_index);
|
||||
|
||||
/* skip */
|
||||
if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)
|
||||
continue;
|
||||
|
||||
Genode::addr_t sym_addr = reloc_base() + sym->st_value;
|
||||
if (sym_addr > addr || sym_addr < info.addr)
|
||||
continue;
|
||||
|
||||
info.addr = sym_addr;
|
||||
info.name = symbol_name(sym);
|
||||
|
||||
if (info.addr == addr)
|
||||
break;
|
||||
Object::init(name, reloc_base);
|
||||
}
|
||||
|
||||
if (!info.addr)
|
||||
throw Genode::Address_info::Invalid_address();
|
||||
}
|
||||
Elf_object(Env &env, Allocator &md_alloc, char const *path,
|
||||
Dependency const &dep, Keep keep)
|
||||
:
|
||||
_keep(keep),
|
||||
_elf_file_initialized(_init_elf_file(env, md_alloc, path)),
|
||||
_dyn(md_alloc, dep, *this, &_elf_file->phdr)
|
||||
{
|
||||
/* register for static construction and relocation */
|
||||
Init::list()->insert(this);
|
||||
obj_list()->enqueue(this);
|
||||
|
||||
/**
|
||||
* Next in initializion list
|
||||
*/
|
||||
Object *next_init() const override {
|
||||
return Genode::List<Object>::Element::next();
|
||||
}
|
||||
/* add to link map */
|
||||
Debug::state_change(Debug::ADD, nullptr);
|
||||
setup_link_map();
|
||||
Debug::state_change(Debug::CONSISTENT, &_map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Next in object list
|
||||
*/
|
||||
Object *next_obj() const override {
|
||||
return Genode::Fifo<Elf_object>::Element::next();
|
||||
}
|
||||
virtual ~Elf_object()
|
||||
{
|
||||
if (!_file)
|
||||
return;
|
||||
|
||||
/**
|
||||
* Object list
|
||||
*/
|
||||
static Genode::Fifo<Elf_object> *obj_list()
|
||||
{
|
||||
static Genode::Fifo<Elf_object> _list;
|
||||
return &_list;
|
||||
}
|
||||
if (verbose_loading)
|
||||
log("LD: destroy ELF object: ", name());
|
||||
|
||||
/* remove from link map */
|
||||
Debug::state_change(Debug::DELETE, &_map);
|
||||
Link_map::remove(&_map);
|
||||
Debug::state_change(Debug::CONSISTENT, nullptr);
|
||||
|
||||
void load() override { ref_count++; }
|
||||
bool unload() override { return !(--ref_count) && !(flags & Genode::Shared_object::KEEP); }
|
||||
/* remove from loaded objects list */
|
||||
obj_list()->remove(this);
|
||||
}
|
||||
|
||||
bool is_linker() const override { return false; }
|
||||
bool is_binary() const override { return false; }
|
||||
/**
|
||||
* Return symbol of given number from ELF
|
||||
*/
|
||||
Elf::Sym const *symbol(unsigned sym_index) const
|
||||
{
|
||||
return _dyn.symbol(sym_index);
|
||||
}
|
||||
|
||||
// XXX remove this accessor?
|
||||
void link_map_addr(addr_t addr) { _map.addr = addr; }
|
||||
|
||||
/**
|
||||
* Return name of given symbol
|
||||
*/
|
||||
char const *symbol_name(Elf::Sym const &sym) const
|
||||
{
|
||||
return _dyn.symbol_name(sym);
|
||||
}
|
||||
|
||||
Elf::Sym const *lookup_symbol(char const *name, unsigned long hash) const
|
||||
{
|
||||
return _dyn.lookup_symbol(name, hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill-out link map infos for this ELF
|
||||
*/
|
||||
void setup_link_map()
|
||||
{
|
||||
_map.addr = _file ? _file->start + reloc_base() : reloc_base();
|
||||
_map.path = name();
|
||||
_map.dynamic = _dyn.dynamic_ptr();
|
||||
|
||||
Link_map::add(&_map);
|
||||
};
|
||||
|
||||
Link_map const &link_map() const override { return _map; }
|
||||
Dynamic const &dynamic() const override { return _dyn; }
|
||||
|
||||
void relocate_global() { _dyn.relocate_non_plt(BIND_NOW, Dynamic::SECOND_PASS); }
|
||||
|
||||
void plt_setup() { _dyn.plt_setup(); }
|
||||
|
||||
void update_dependency(Dependency const &dep) { _dyn.dep(dep); }
|
||||
|
||||
void relocate(Bind bind) override
|
||||
{
|
||||
if (!_relocated)
|
||||
_dyn.relocate(bind);
|
||||
|
||||
_relocated = true;
|
||||
}
|
||||
|
||||
addr_t base_addr() const { return _map.addr; }
|
||||
|
||||
Symbol_info symbol_at_address(addr_t addr) const override
|
||||
{
|
||||
Elf::Sym const sym = _dyn.symbol_by_addr(addr);
|
||||
|
||||
return { _reloc_base + sym.st_value, _dyn.symbol_name(sym) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Next in initializion list
|
||||
*/
|
||||
Object *next_init() const override {
|
||||
return List<Object>::Element::next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Next in object list
|
||||
*/
|
||||
Object *next_obj() const override {
|
||||
return Fifo<Elf_object>::Element::next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Object list
|
||||
*/
|
||||
static Fifo<Elf_object> *obj_list()
|
||||
{
|
||||
static Fifo<Elf_object> _list;
|
||||
return &_list;
|
||||
}
|
||||
|
||||
void load() override { _ref_count++; }
|
||||
bool unload() override { return (_keep == DONT_KEEP) && !(--_ref_count); }
|
||||
|
||||
bool is_linker() const override { return false; }
|
||||
bool is_binary() const override { return false; }
|
||||
};
|
||||
|
||||
|
||||
@ -246,32 +244,24 @@ struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element
|
||||
*/
|
||||
struct Linker::Ld : Dependency, Elf_object
|
||||
{
|
||||
Ld()
|
||||
: Dependency(this, nullptr), Elf_object(this, relocation_address())
|
||||
{
|
||||
Genode::strncpy(_name, linker_name(), Object::MAX_PATH);
|
||||
}
|
||||
Ld() :
|
||||
Dependency(*this, nullptr),
|
||||
Elf_object(*this, linker_name(), relocation_address())
|
||||
{ }
|
||||
|
||||
void setup_link_map()
|
||||
{
|
||||
Elf_object::setup_link_map();
|
||||
|
||||
/**
|
||||
* Use DT_HASH table address for linker, assuming that it will always be at
|
||||
* the beginning of the file
|
||||
*/
|
||||
map.addr = trunc_page((Elf::Addr)dynamic()->hash_table);
|
||||
link_map_addr(dynamic().link_map_addr());
|
||||
}
|
||||
|
||||
void load_phdr()
|
||||
void load_phdr(Env &env, Allocator &md_alloc)
|
||||
{
|
||||
_file = Linker::load(name(), false);
|
||||
_file = new (md_alloc) Elf_file(env, md_alloc, name(), false);
|
||||
}
|
||||
|
||||
void relocate_global() { dynamic()->relocate_non_plt(true); }
|
||||
void update_dependency(Dependency const *dep) { dynamic()->dep = dep; }
|
||||
|
||||
static Ld *linker();
|
||||
static Ld &linker();
|
||||
|
||||
bool is_linker() const override { return true; }
|
||||
|
||||
@ -279,45 +269,45 @@ struct Linker::Ld : Dependency, Elf_object
|
||||
* Entry point for jump relocations, it is called from assembly code and is implemented
|
||||
* right below)
|
||||
*/
|
||||
static Elf::Addr jmp_slot(Dependency const *dep, Elf::Size index) asm("jmp_slot");
|
||||
static Elf::Addr jmp_slot(Dependency const &dep, Elf::Size index) asm("jmp_slot");
|
||||
};
|
||||
|
||||
|
||||
Elf::Addr Ld::jmp_slot(Dependency const *dep, Elf::Size index)
|
||||
Elf::Addr Ld::jmp_slot(Dependency const &dep, Elf::Size index)
|
||||
{
|
||||
Genode::Lock::Guard guard(Elf_object::lock());
|
||||
Lock::Guard guard(lock());
|
||||
|
||||
if (verbose_relocation)
|
||||
Genode::log("LD: SLOT ", dep->obj, " ", Genode::Hex(index));
|
||||
log("LD: SLOT ", &dep.obj(), " ", Hex(index));
|
||||
|
||||
try {
|
||||
Reloc_jmpslot slot(dep, dep->obj->dynamic()->pltrel_type,
|
||||
dep->obj->dynamic()->pltrel, index);
|
||||
Reloc_jmpslot slot(dep, dep.obj().dynamic().pltrel_type(),
|
||||
dep.obj().dynamic().pltrel(), index);
|
||||
return slot.target_addr();
|
||||
} catch (...) { Genode::error("LD: jump slot relocation failed. FATAL!"); }
|
||||
} catch (...) { error("LD: jump slot relocation failed. FATAL!"); }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ld object with different vtable typeinfo
|
||||
*/
|
||||
struct Linker::Ld_vtable : Ld
|
||||
{
|
||||
Ld_vtable()
|
||||
{
|
||||
Elf_object::obj_list()->enqueue(this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Linker object used during bootstrapping on stack (see: 'init_rtld')
|
||||
*/
|
||||
Linker::Ld *Linker::Ld::linker()
|
||||
Linker::Ld &Linker::Ld::linker()
|
||||
{
|
||||
/**
|
||||
* Ld object with different vtable typeinfo
|
||||
*/
|
||||
struct Ld_vtable : Ld
|
||||
{
|
||||
Ld_vtable()
|
||||
{
|
||||
Elf_object::obj_list()->enqueue(this);
|
||||
plt_setup();
|
||||
}
|
||||
};
|
||||
static Ld_vtable _linker;
|
||||
return &_linker;
|
||||
return _linker;
|
||||
}
|
||||
|
||||
|
||||
@ -326,26 +316,28 @@ Linker::Ld *Linker::Ld::linker()
|
||||
*/
|
||||
struct Linker::Binary : Root_object, Elf_object
|
||||
{
|
||||
Binary()
|
||||
: Elf_object(binary_name(), new (Genode::env()->heap()) Dependency(this, this))
|
||||
Binary(Env &env, Allocator &md_alloc, Bind bind)
|
||||
:
|
||||
Root_object(md_alloc),
|
||||
Elf_object(env, md_alloc, binary_name(),
|
||||
*new (md_alloc) Dependency(*this, this), KEEP)
|
||||
{
|
||||
/* create dep for binary and linker */
|
||||
Dependency *binary = const_cast<Dependency *>(dynamic()->dep);
|
||||
dep.enqueue(binary);
|
||||
Dependency *linker = new (Genode::env()->heap()) Dependency(Ld::linker(), this);
|
||||
dep.enqueue(linker);
|
||||
Dependency *binary = const_cast<Dependency *>(&dynamic().dep());
|
||||
Root_object::enqueue(*binary);
|
||||
Dependency *linker = new (md_alloc) Dependency(Ld::linker(), this);
|
||||
Root_object::enqueue(*linker);
|
||||
|
||||
/* update linker dep */
|
||||
Ld::linker()->update_dependency(linker);
|
||||
Ld::linker().update_dependency(*linker);
|
||||
|
||||
/* place linker on second place in link map as well */
|
||||
Ld::linker()->setup_link_map();
|
||||
/* place linker on second place in link map */
|
||||
Ld::linker().setup_link_map();
|
||||
|
||||
/* load dependencies */
|
||||
binary->load_needed(&dep);
|
||||
binary->load_needed(env, md_alloc, deps(), DONT_KEEP);
|
||||
|
||||
/* relocate and call constructors */
|
||||
Init::list()->initialize();
|
||||
Init::list()->initialize(bind);
|
||||
}
|
||||
|
||||
Elf::Addr lookup_symbol(char const *name)
|
||||
@ -358,7 +350,7 @@ struct Linker::Binary : Root_object, Elf_object
|
||||
return 0;
|
||||
}
|
||||
|
||||
void call_entry_point(Genode::Env &env)
|
||||
void call_entry_point(Env &env)
|
||||
{
|
||||
/* call static construtors and register destructors */
|
||||
Func * const ctors_start = (Func *)lookup_symbol("_ctors_start");
|
||||
@ -372,16 +364,16 @@ struct Linker::Binary : Root_object, Elf_object
|
||||
/* call component entry point */
|
||||
/* XXX the function type for call_component_construct() is a candidate
|
||||
* for a base-internal header */
|
||||
typedef void (*Entry)(Genode::Env &);
|
||||
typedef void (*Entry)(Env &);
|
||||
Entry const entry = reinterpret_cast<Entry>(_file->entry);
|
||||
|
||||
entry(env);
|
||||
}
|
||||
|
||||
void relocate() override
|
||||
void relocate(Bind bind) override
|
||||
{
|
||||
/* relocate ourselves */
|
||||
Elf_object::relocate();
|
||||
Elf_object::relocate(bind);
|
||||
|
||||
/*
|
||||
* After having loaded the main program, we relocate the linker's
|
||||
@ -389,7 +381,7 @@ struct Linker::Binary : Root_object, Elf_object
|
||||
* also present within the main program, become relocated to the correct
|
||||
* positions
|
||||
*/
|
||||
Ld::linker()->relocate_global();
|
||||
Ld::linker().relocate_global();
|
||||
}
|
||||
|
||||
bool is_binary() const override { return true; }
|
||||
@ -400,22 +392,21 @@ struct Linker::Binary : Root_object, Elf_object
|
||||
** Global Linker namespace functions **
|
||||
***************************************/
|
||||
|
||||
Object *Linker::load(char const *path, Dependency *dep, unsigned flags)
|
||||
Object &Linker::load(Env &env, Allocator &md_alloc, char const *path,
|
||||
Dependency &dep, Keep keep)
|
||||
{
|
||||
for (Object *e = Elf_object::obj_list()->head(); e; e = e->next_obj()) {
|
||||
|
||||
if (verbose_loading)
|
||||
Genode::log("LOAD: ", Linker::file(path), " == ", e->name());
|
||||
log("LOAD: ", Linker::file(path), " == ", e->name());
|
||||
|
||||
if (!Genode::strcmp(Linker::file(path), e->name())) {
|
||||
if (!strcmp(Linker::file(path), e->name())) {
|
||||
e->load();
|
||||
return e;
|
||||
return *e;
|
||||
}
|
||||
}
|
||||
|
||||
Elf_object *e = new (Genode::env()->heap()) Elf_object(path, dep, flags);
|
||||
dep->obj = e;
|
||||
return e;
|
||||
return *new (md_alloc) Elf_object(env, md_alloc, path, dep, keep);
|
||||
}
|
||||
|
||||
|
||||
@ -425,30 +416,30 @@ Object *Linker::obj_list_head()
|
||||
}
|
||||
|
||||
|
||||
Elf::Sym const *Linker::lookup_symbol(unsigned sym_index, Dependency const *dep,
|
||||
Elf::Sym const *Linker::lookup_symbol(unsigned sym_index, Dependency const &dep,
|
||||
Elf::Addr *base, bool undef, bool other)
|
||||
{
|
||||
Elf_object const *e = static_cast<Elf_object *>(dep->obj);
|
||||
Elf::Sym const *symbol = e->symbol(sym_index);
|
||||
Elf_object const &elf = static_cast<Elf_object const &>(dep.obj());
|
||||
Elf::Sym const *symbol = elf.symbol(sym_index);
|
||||
|
||||
if (!symbol) {
|
||||
Genode::warning("LD: unknown symbol index ", Genode::Hex(sym_index));
|
||||
warning("LD: unknown symbol index ", Hex(sym_index));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (symbol->bind() == STB_LOCAL) {
|
||||
*base = dep->obj->reloc_base();
|
||||
*base = dep.obj().reloc_base();
|
||||
return symbol;
|
||||
}
|
||||
|
||||
return lookup_symbol(e->symbol_name(symbol), dep, base, undef, other);
|
||||
return lookup_symbol(elf.symbol_name(*symbol), dep, base, undef, other);
|
||||
}
|
||||
|
||||
|
||||
Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const *dep,
|
||||
Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const &dep,
|
||||
Elf::Addr *base, bool undef, bool other)
|
||||
{
|
||||
Dependency const *curr = dep->root ? dep->root->dep.head() : dep;
|
||||
Dependency const *curr = &dep.first();
|
||||
unsigned long hash = Hash_table::hash(name);
|
||||
Elf::Sym const *weak_symbol = 0;
|
||||
Elf::Addr weak_base = 0;
|
||||
@ -457,45 +448,45 @@ Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const *dep,
|
||||
//TODO: handle vertab and search in object list
|
||||
for (;curr; curr = curr->next()) {
|
||||
|
||||
if (other && curr == dep)
|
||||
if (other && curr == &dep)
|
||||
continue;
|
||||
|
||||
Elf_object const *elf = static_cast<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)
|
||||
Genode::log("LD: lookup ", name, " obj_src ", elf->name(),
|
||||
" st ", symbol, " info ", Genode::Hex(symbol->st_info),
|
||||
" weak: ", symbol->weak());
|
||||
if (dep.root() && verbose_lookup)
|
||||
log("LD: lookup ", name, " obj_src ", elf.name(),
|
||||
" st ", symbol, " info ", Hex(symbol->st_info),
|
||||
" weak: ", symbol->weak());
|
||||
|
||||
if (!undef && symbol->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
|
||||
if (!symbol->weak() && symbol->st_shndx != SHN_UNDEF) {
|
||||
*base = elf->reloc_base();
|
||||
*base = elf.reloc_base();
|
||||
return symbol;
|
||||
}
|
||||
|
||||
if (!weak_symbol) {
|
||||
weak_symbol = symbol;
|
||||
weak_base = elf->reloc_base();
|
||||
weak_base = elf.reloc_base();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* try searching binary's dependencies */
|
||||
if (!weak_symbol && dep->root) {
|
||||
if (binary && dep != binary->dep.head()) {
|
||||
return lookup_symbol(name, binary->dep.head(), base, undef, other);
|
||||
if (!weak_symbol && dep.root()) {
|
||||
if (binary_ptr && &dep != binary_ptr->first_dep()) {
|
||||
return lookup_symbol(name, *binary_ptr->first_dep(), base, undef, other);
|
||||
} else {
|
||||
Genode::error("LD: could not lookup symbol \"", name, "\"");
|
||||
error("LD: could not lookup symbol \"", name, "\"");
|
||||
throw Not_found();
|
||||
}
|
||||
}
|
||||
|
||||
if (dep->root && verbose_lookup)
|
||||
Genode::log("LD: return ", weak_symbol);
|
||||
if (dep.root() && verbose_lookup)
|
||||
log("LD: return ", weak_symbol);
|
||||
|
||||
if (!weak_symbol)
|
||||
throw Not_found();
|
||||
@ -505,13 +496,6 @@ Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const *dep,
|
||||
}
|
||||
|
||||
|
||||
void Linker::load_linker_phdr()
|
||||
{
|
||||
if (!Ld::linker()->file())
|
||||
Ld::linker()->load_phdr();
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** Initialization **
|
||||
********************/
|
||||
@ -524,49 +508,77 @@ extern "C" void init_rtld()
|
||||
{
|
||||
/*
|
||||
* Allocate on stack, since the linker has not been relocated yet, the vtable
|
||||
* type relocation might prdouce a wrong vtable pointer (at least on ARM), do
|
||||
* not call any virtual funtions of this object
|
||||
* type relocation might produce a wrong vtable pointer (at least on ARM), do
|
||||
* not call any virtual funtions of this object.
|
||||
*/
|
||||
Ld linker_stack;
|
||||
linker_stack.relocate();
|
||||
|
||||
/* make sure this does not get destroyed the usual way */
|
||||
linker_stack.ref_count++;
|
||||
Ld linker_on_stack;
|
||||
linker_on_stack.relocate(BIND_LAZY);
|
||||
|
||||
/*
|
||||
* Create actual linker object with different vtable type and set PLT to new
|
||||
* DAG.
|
||||
*/
|
||||
Ld::linker()->dynamic()->plt_setup();
|
||||
Ld::linker();
|
||||
}
|
||||
|
||||
|
||||
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
|
||||
|
||||
|
||||
struct Failed_to_load_program { };
|
||||
class Linker::Config
|
||||
{
|
||||
private:
|
||||
|
||||
Bind _bind = BIND_LAZY;
|
||||
bool _verbose = false;
|
||||
|
||||
public:
|
||||
|
||||
Config(Env &env)
|
||||
{
|
||||
try {
|
||||
Attached_rom_dataspace config(env, "config");
|
||||
|
||||
if (config.xml().attribute_value("ld_bind_now", false))
|
||||
_bind = BIND_NOW;
|
||||
|
||||
_verbose = config.xml().attribute_value("ld_verbose", false);
|
||||
} catch (Rom_connection::Rom_connection_failed) { }
|
||||
}
|
||||
|
||||
Bind bind() const { return _bind; }
|
||||
bool verbose() const { return _verbose; }
|
||||
};
|
||||
|
||||
|
||||
static Genode::Lazy_volatile_object<Heap> &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)
|
||||
{
|
||||
/* load program headers of linker now */
|
||||
if (!Ld::linker()->file())
|
||||
Ld::linker()->load_phdr();
|
||||
|
||||
/* read configuration, release ROM afterwards */
|
||||
try {
|
||||
Genode::Attached_rom_dataspace config(env, "config");
|
||||
|
||||
bind_now = config.xml().attribute_value("ld_bind_now", false);
|
||||
verbose = config.xml().attribute_value("ld_verbose", false);
|
||||
} catch (Genode::Rom_connection::Rom_connection_failed) { }
|
||||
/* read configuration */
|
||||
static Config config(env);
|
||||
verbose = config.verbose();
|
||||
|
||||
/* load binary and all dependencies */
|
||||
try {
|
||||
binary = new(Genode::env()->heap()) Binary();
|
||||
binary_ptr = unmanaged_singleton<Binary>(env, *heap(), config.bind());
|
||||
} catch (...) {
|
||||
Genode::error("LD: failed to load program");
|
||||
throw Failed_to_load_program();
|
||||
error("LD: failed to load program");
|
||||
throw;
|
||||
}
|
||||
|
||||
/* print loaded object information */
|
||||
@ -577,7 +589,7 @@ void Component::construct(Genode::Env &env)
|
||||
" .. ", Hex(Thread::stack_area_virtual_base() +
|
||||
Thread::stack_area_virtual_size() - 1),
|
||||
": stack area");
|
||||
dump_link_map(Elf_object::obj_list()->head());
|
||||
dump_link_map(*Elf_object::obj_list()->head());
|
||||
}
|
||||
} catch (...) { }
|
||||
|
||||
@ -586,5 +598,5 @@ void Component::construct(Genode::Env &env)
|
||||
binary_ready_hook_for_gdb();
|
||||
|
||||
/* start binary */
|
||||
binary->call_entry_point(env);
|
||||
binary_ptr->call_entry_point(env);
|
||||
}
|
||||
|
@ -19,9 +19,9 @@
|
||||
** Helpers **
|
||||
*************/
|
||||
|
||||
static Linker::Root_object *to_root(void *h)
|
||||
static Linker::Root_object const &to_root(void *h)
|
||||
{
|
||||
return static_cast<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)
|
||||
{
|
||||
for (Linker::Object *e = Linker::obj_list_head(); e; e = e->next_obj())
|
||||
if (addr >= e->link_map()->addr && addr < e->link_map()->addr + e->size())
|
||||
if (addr >= e->link_map().addr && addr < e->link_map().addr + e->size())
|
||||
return e;
|
||||
|
||||
throw Genode::Address_info::Invalid_address();
|
||||
@ -50,25 +50,28 @@ static Linker::Object *find_obj(Genode::addr_t addr)
|
||||
** API **
|
||||
*********/
|
||||
|
||||
Genode::Shared_object::Shared_object(char const *file, unsigned flags)
|
||||
Genode::Shared_object::Shared_object(Env &env, Allocator &md_alloc,
|
||||
char const *file, Bind bind, Keep keep)
|
||||
:
|
||||
_md_alloc(md_alloc)
|
||||
{
|
||||
using namespace Linker;
|
||||
|
||||
if (verbose_shared)
|
||||
Genode::log("LD: open '", file ? file : "binary", "'");
|
||||
log("LD: open '", file ? file : "binary", "'");
|
||||
|
||||
try {
|
||||
Genode::Lock::Guard guard(shared_object_lock());
|
||||
Lock::Guard guard(shared_object_lock());
|
||||
|
||||
/* update bind now variable */
|
||||
bind_now = (flags & Shared_object::NOW) ? true : false;
|
||||
|
||||
_handle = (Root_object *)new (Genode::env()->heap()) Root_object(file ? file : binary_name(), flags);
|
||||
_handle = new (md_alloc)
|
||||
Root_object(env, md_alloc, file ? file : binary_name(),
|
||||
bind == BIND_NOW ? Linker::BIND_NOW : Linker::BIND_LAZY,
|
||||
keep == KEEP ? Linker::KEEP : Linker::DONT_KEEP);
|
||||
|
||||
/* print loaded object information */
|
||||
try {
|
||||
if (Linker::verbose)
|
||||
Linker::dump_link_map(to_root(_handle)->dep.head()->obj);
|
||||
Linker::dump_link_map(to_root(_handle).first_dep()->obj());
|
||||
} catch (...) { }
|
||||
|
||||
} catch (...) { throw Invalid_file(); }
|
||||
@ -80,23 +83,24 @@ void *Genode::Shared_object::_lookup(const char *name) const
|
||||
using namespace Linker;
|
||||
|
||||
if (verbose_shared)
|
||||
Genode::log("LD: shared object lookup '", name, "'");
|
||||
log("LD: shared object lookup '", name, "'");
|
||||
|
||||
try {
|
||||
Genode::Lock::Guard guard(Object::lock());
|
||||
Lock::Guard guard(Linker::lock());
|
||||
|
||||
Elf::Addr base;
|
||||
Root_object *root = to_root(_handle);
|
||||
Elf::Sym const *symbol = lookup_symbol(name, root->dep.head(), &base, true);
|
||||
Root_object const &root = to_root(_handle);
|
||||
|
||||
Elf::Addr base;
|
||||
Elf::Sym const *symbol = lookup_symbol(name, *root.first_dep(), &base, true);
|
||||
|
||||
return (void *)(base + symbol->st_value);
|
||||
} catch (...) { throw Shared_object::Invalid_symbol(); }
|
||||
}
|
||||
|
||||
|
||||
Genode::Shared_object::Link_map const * Genode::Shared_object::link_map() const
|
||||
Genode::Shared_object::Link_map const &Genode::Shared_object::link_map() const
|
||||
{
|
||||
return (Link_map const *)to_root(_handle)->link_map();
|
||||
return (Link_map const &)to_root(_handle).link_map();
|
||||
}
|
||||
|
||||
|
||||
@ -105,26 +109,33 @@ Genode::Shared_object::~Shared_object()
|
||||
using namespace Linker;
|
||||
|
||||
if (verbose_shared)
|
||||
Genode::log("LD: close shared object");
|
||||
log("LD: close shared object");
|
||||
|
||||
Genode::Lock::Guard guard(shared_object_lock());
|
||||
destroy(Genode::env()->heap(), to_root(_handle));
|
||||
Lock::Guard guard(shared_object_lock());
|
||||
destroy(_md_alloc, &const_cast<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;
|
||||
|
||||
if (verbose_shared)
|
||||
Genode::log("LD: address-info request: ", Genode::Hex(address));
|
||||
log("LD: address-info request: ", Hex(address));
|
||||
|
||||
Linker::Object *e = find_obj(address);
|
||||
e->info(address, *this);
|
||||
|
||||
path = e->name();
|
||||
base = e->reloc_base();
|
||||
|
||||
Linker::Object::Symbol_info const symbol = e->symbol_at_address(address);
|
||||
|
||||
addr = symbol.addr;
|
||||
name = symbol.name;
|
||||
|
||||
if (verbose_shared)
|
||||
Genode::log("LD: found address info: obj: ", path, " sym: ", name,
|
||||
" addr: ", Genode::Hex(addr));
|
||||
log("LD: found address info: obj: ", path, " sym: ", name,
|
||||
" addr: ", Hex(addr));
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,26 +72,26 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
* relocations within its text-segment (e.g., 'initial_sp' and friends), which
|
||||
* we cannot write to from here).
|
||||
*/
|
||||
if (_dep->obj->reloc_base())
|
||||
*addr += _dep->obj->reloc_base();
|
||||
if (_dep.obj().reloc_base())
|
||||
*addr += _dep.obj().reloc_base();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rela const *, unsigned long)
|
||||
Reloc_non_plt(Dependency const &dep, Elf::Rela const *, unsigned long)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
Genode::error("LD: DT_RELA not supported");
|
||||
error("LD: DT_RELA not supported");
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rel const *rel, unsigned long size,
|
||||
Reloc_non_plt(Dependency const &dep, Elf::Rel const *rel, unsigned long size,
|
||||
bool second_pass)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
Elf::Rel const *end = rel + (size / sizeof(Elf::Rel));
|
||||
for (; rel < end; rel++) {
|
||||
Elf::Addr *addr = (Elf::Addr *)(_dep->obj->reloc_base() + rel->offset);
|
||||
Elf::Addr *addr = (Elf::Addr *)(_dep.obj().reloc_base() + rel->offset);
|
||||
|
||||
if (second_pass && rel->type() != R_GLOB_DAT)
|
||||
continue;
|
||||
@ -104,8 +104,8 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
case R_GLOB_DAT: _glob_dat(rel, addr, second_pass); break;
|
||||
case R_RELATIVE: _relative(addr); break;
|
||||
default:
|
||||
if (_dep->root) {
|
||||
Genode::warning("LD: Unkown relocation ", (int)rel->type());
|
||||
if (_dep.root()) {
|
||||
warning("LD: Unkown relocation ", (int)rel->type());
|
||||
throw Incompatible();
|
||||
}
|
||||
break;
|
||||
|
@ -51,7 +51,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
*/
|
||||
void _relative(Elf::Rela const *rel, Elf::Addr *addr)
|
||||
{
|
||||
*addr = _dep->obj->reloc_base() + rel->addend;
|
||||
*addr = _dep.obj().reloc_base() + rel->addend;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,23 +68,23 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
|
||||
*addr = reloc_base + sym->st_value + (addend ? rel->addend : 0);
|
||||
if (verbose_reloc(_dep))
|
||||
Genode::log("LD: GLOB DAT ", addr, " -> ", Genode::Hex(*addr),
|
||||
" r ", Genode::Hex(reloc_base),
|
||||
" v ", Genode::Hex(sym->st_value));
|
||||
log("LD: GLOB DAT ", addr, " -> ", Hex(*addr),
|
||||
" r ", Hex(reloc_base),
|
||||
" v ", Hex(sym->st_value));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rela const *rel, unsigned long size)
|
||||
Reloc_non_plt(Dependency const &dep, Elf::Rela const *rel, unsigned long size)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
Elf::Rela const *end = rel + (size / sizeof(Elf::Rela));
|
||||
|
||||
for (; rel < end; rel++) {
|
||||
Elf::Addr *addr = (Elf::Addr *)(_dep->obj->reloc_base() + rel->offset);
|
||||
Elf::Addr *addr = (Elf::Addr *)(_dep.obj().reloc_base() + rel->offset);
|
||||
|
||||
if (verbose_reloc(_dep))
|
||||
Genode::log("LD: reloc: ", rel, " type: ", (int)rel->type());
|
||||
log("LD: reloc: ", rel, " type: ", (int)rel->type());
|
||||
|
||||
switch(rel->type()) {
|
||||
case R_JMPSLOT: _glob_dat_64(rel, addr, false); break;
|
||||
@ -92,8 +92,8 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
case R_RELATIVE: _relative(rel, addr); break;
|
||||
|
||||
default:
|
||||
if (!_dep->obj->is_linker()) {
|
||||
Genode::warning("LD: unkown relocation ", (int)rel->type());
|
||||
if (!_dep.obj().is_linker()) {
|
||||
warning("LD: unkown relocation ", (int)rel->type());
|
||||
throw Incompatible();
|
||||
}
|
||||
break;
|
||||
@ -101,10 +101,10 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
}
|
||||
}
|
||||
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rel const *, unsigned long, bool)
|
||||
Reloc_non_plt(Dependency const &dep, Elf::Rel const *, unsigned long, bool)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
Genode::error("LD: DT_REL not supported");
|
||||
error("LD: DT_REL not supported");
|
||||
throw Incompatible();
|
||||
}
|
||||
};
|
||||
|
@ -52,27 +52,27 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
|
||||
void _relative(Elf::Rel const *rel, Elf::Addr *addr)
|
||||
{
|
||||
if (_dep->obj->reloc_base())
|
||||
*addr += _dep->obj->reloc_base();
|
||||
if (_dep.obj().reloc_base())
|
||||
*addr += _dep.obj().reloc_base();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rela const *, unsigned long)
|
||||
Reloc_non_plt(Dependency const &dep, Elf::Rela const *, unsigned long)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
Genode::error("LD: DT_RELA not supported");
|
||||
error("LD: DT_RELA not supported");
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rel const *rel, unsigned long size,
|
||||
Reloc_non_plt(Dependency const &dep, Elf::Rel const *rel, unsigned long size,
|
||||
bool second_pass)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
Elf::Rel const *end = rel + (size / sizeof(Elf::Rel));
|
||||
|
||||
for (; rel < end; rel++) {
|
||||
Elf::Addr *addr = (Elf::Addr *)(_dep->obj->reloc_base() + rel->offset);
|
||||
Elf::Addr *addr = (Elf::Addr *)(_dep.obj().reloc_base() + rel->offset);
|
||||
|
||||
if (second_pass && rel->type() != R_GLOB_DAT)
|
||||
continue;
|
||||
@ -84,8 +84,8 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
case R_COPY : _copy<Elf::Rel>(rel, addr); break;
|
||||
case R_RELATIVE: _relative(rel, addr); break;
|
||||
default:
|
||||
if (_dep->root) {
|
||||
Genode::warning("LD: Unkown relocation ", (int)rel->type());
|
||||
if (_dep.root()) {
|
||||
warning("LD: Unkown relocation ", (int)rel->type());
|
||||
throw Incompatible();
|
||||
}
|
||||
break;
|
||||
|
@ -45,7 +45,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
*/
|
||||
void _relative(Elf::Rela const *rel, Elf::Addr *addr)
|
||||
{
|
||||
*addr = _dep->obj->reloc_base() + rel->addend;
|
||||
*addr = _dep.obj().reloc_base() + rel->addend;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,19 +62,19 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
|
||||
*addr = reloc_base + sym->st_value + (addend ? rel->addend : 0);
|
||||
if (verbose_reloc(_dep))
|
||||
Genode::log("GLOB DAT ", addr, " -> ", *addr,
|
||||
" r ", reloc_base, " v ", sym->st_value);
|
||||
log("GLOB DAT ", addr, " -> ", *addr,
|
||||
" r ", reloc_base, " v ", sym->st_value);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rela const *rel, unsigned long size)
|
||||
Reloc_non_plt(Dependency const &dep, Elf::Rela const *rel, unsigned long size)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
Elf::Rela const *end = rel + (size / sizeof(Elf::Rela));
|
||||
|
||||
for (; rel < end; rel++) {
|
||||
Elf::Addr *addr = (Elf::Addr *)(_dep->obj->reloc_base() + rel->offset);
|
||||
Elf::Addr *addr = (Elf::Addr *)(_dep.obj().reloc_base() + rel->offset);
|
||||
|
||||
switch(rel->type()) {
|
||||
case R_64: _glob_dat_64(rel, addr, true); break;
|
||||
@ -83,8 +83,8 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
case R_RELATIVE: _relative(rel, addr); break;
|
||||
|
||||
default:
|
||||
if (!_dep->obj->is_linker()) {
|
||||
Genode::warning("LD: Unkown relocation ", (int)rel->type());
|
||||
if (!_dep.obj().is_linker()) {
|
||||
warning("LD: Unkown relocation ", (int)rel->type());
|
||||
throw Incompatible();
|
||||
}
|
||||
break;
|
||||
@ -92,10 +92,10 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
}
|
||||
}
|
||||
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rel const *, unsigned long, bool)
|
||||
Reloc_non_plt(Dependency const &dep, Elf::Rel const *, unsigned long, bool)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
Genode::error("LD: DT_REL not supported");
|
||||
error("LD: DT_REL not supported");
|
||||
throw Incompatible();
|
||||
}
|
||||
};
|
||||
|
@ -94,28 +94,6 @@ extern "C" void init_main_thread()
|
||||
(void*)env();
|
||||
init_log();
|
||||
|
||||
/* initialize exception handling */
|
||||
init_exception_handling();
|
||||
|
||||
/*
|
||||
* Trigger first exception. This step has two purposes.
|
||||
* First, it enables us to detect problems related to exception handling as
|
||||
* early as possible. If there are problems with the C++ support library,
|
||||
* it is much easier to debug them at this early stage. Otherwise problems
|
||||
* with half-working exception handling cause subtle failures that are hard
|
||||
* to interpret.
|
||||
*
|
||||
* Second, the C++ support library allocates data structures lazily on the
|
||||
* first occurrence of an exception. This allocation traverses into
|
||||
* Genode's heap and, in some corner cases, consumes several KB of stack.
|
||||
* This is usually not a problem when the first exception is triggered from
|
||||
* the main thread but it becomes an issue when the first exception is
|
||||
* thrown from the stack of a thread with a specially tailored (and
|
||||
* otherwise sufficient) stack size. By throwing an exception here, we
|
||||
* mitigate this issue by eagerly performing those allocations.
|
||||
*/
|
||||
try { throw 1; } catch (...) { }
|
||||
|
||||
/* create a thread object for the main thread */
|
||||
main_thread();
|
||||
|
||||
|
21
repos/dde_rump/include/rump/bootstrap.h
Normal file
21
repos/dde_rump/include/rump/bootstrap.h
Normal 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_ */
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* \brief Definitions for FS front-end
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-01-22
|
||||
|
@ -17,7 +17,7 @@ extern "C" {
|
||||
#include <elf.h>
|
||||
}
|
||||
|
||||
#include <base/env.h>
|
||||
#include <rump/bootstrap.h>
|
||||
#include <base/log.h>
|
||||
#include <base/shared_object.h>
|
||||
#include <util/string.h>
|
||||
@ -35,7 +35,46 @@ typedef Elf32_Sym Elf_Sym;
|
||||
static bool const verbose = false;
|
||||
|
||||
|
||||
static Genode::Shared_object *obj_main;
|
||||
static Genode::Shared_object *obj_main;
|
||||
static Genode::Env *env_ptr;
|
||||
static Genode::Allocator *heap_ptr;
|
||||
|
||||
|
||||
void rump_bootstrap_init(Genode::Env &env, Genode::Allocator &alloc)
|
||||
{
|
||||
/* ignore subsequent calls */
|
||||
if (env_ptr)
|
||||
return;
|
||||
|
||||
env_ptr = &env;
|
||||
heap_ptr = &alloc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exception type
|
||||
*/
|
||||
class Missing_call_of_rump_bootstrap_init { };
|
||||
|
||||
|
||||
static Genode::Env &env()
|
||||
{
|
||||
if (!env_ptr)
|
||||
throw Missing_call_of_rump_bootstrap_init();
|
||||
|
||||
return *env_ptr;
|
||||
}
|
||||
|
||||
|
||||
static Genode::Allocator &heap()
|
||||
{
|
||||
if (!heap_ptr)
|
||||
throw Missing_call_of_rump_bootstrap_init();
|
||||
|
||||
return *heap_ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Sym_tab
|
||||
{
|
||||
@ -183,13 +222,17 @@ struct Sym_tab
|
||||
* Call init functions of libraries
|
||||
*/
|
||||
static void _dl_init(Genode::Shared_object::Link_map const *map,
|
||||
rump_modinit_fn mod_init,
|
||||
rump_compload_fn comp_init)
|
||||
rump_modinit_fn mod_init,
|
||||
rump_compload_fn comp_init)
|
||||
{
|
||||
using namespace Genode;
|
||||
Shared_object *obj;
|
||||
try { obj = new (Genode::env()->heap()) Shared_object(map->path); }
|
||||
catch (...) { error("Could not dlopen ", map->path); return; }
|
||||
Shared_object *obj = nullptr;
|
||||
try {
|
||||
obj = new (heap()) Shared_object(::env(), heap(), map->path,
|
||||
Shared_object::BIND_LAZY,
|
||||
Shared_object::DONT_KEEP);
|
||||
}
|
||||
catch (...) { error("could not dlopen ", map->path); return; }
|
||||
|
||||
struct modinfo **mi_start, **mi_end;
|
||||
struct rump_component **rc_start, **rc_end;
|
||||
@ -218,9 +261,14 @@ void rumpuser_dl_bootstrap(rump_modinit_fn domodinit, rump_symload_fn symload,
|
||||
/* open main program and request link map */
|
||||
using namespace Genode;
|
||||
|
||||
obj_main = new (env()->heap()) Shared_object(nullptr, Shared_object::NOW);
|
||||
try {
|
||||
obj_main = new (heap()) Shared_object(::env(), heap(), nullptr,
|
||||
Shared_object::BIND_NOW,
|
||||
Shared_object::KEEP);
|
||||
}
|
||||
catch (...) { error("could not dlopen the main executable"); return; }
|
||||
|
||||
Shared_object::Link_map const *map = obj_main->link_map();
|
||||
Shared_object::Link_map const *map = &obj_main->link_map();
|
||||
for (; map->next; map = map->next) ;
|
||||
|
||||
Shared_object::Link_map const *curr_map;
|
||||
|
@ -13,11 +13,12 @@
|
||||
|
||||
#include "file_system.h"
|
||||
|
||||
#include <os/config.h>
|
||||
#include <rump/bootstrap.h>
|
||||
#include <rump_fs/fs.h>
|
||||
#include <util/string.h>
|
||||
#include <util/hard_context.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'
|
||||
@ -31,28 +32,24 @@ struct fs_args
|
||||
fs_args() { Genode::memset(pad, 0, sizeof(pad)); }
|
||||
};
|
||||
|
||||
namespace File_system {
|
||||
class Sync;
|
||||
};
|
||||
|
||||
namespace File_system { class Sync; };
|
||||
|
||||
|
||||
static char const *fs_types[] = { RUMP_MOUNT_CD9660, RUMP_MOUNT_EXT2FS,
|
||||
RUMP_MOUNT_FFS, RUMP_MOUNT_MSDOS,
|
||||
RUMP_MOUNT_NTFS, RUMP_MOUNT_UDF, 0 };
|
||||
|
||||
typedef Genode::String<16> Fs_type;
|
||||
static Fs_type & fs_type()
|
||||
{
|
||||
static Fs_type inst = Genode::config()->xml_node().attribute_value("fs", Fs_type());
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
static bool _supports_symlinks;
|
||||
|
||||
static bool _check_type(char const *type)
|
||||
|
||||
static bool _check_type(Fs_type const &type)
|
||||
{
|
||||
for (int i = 0; fs_types[i]; i++)
|
||||
if (!Genode::strcmp(type, fs_types[i]))
|
||||
if (!Genode::strcmp(type.string(), fs_types[i]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -66,35 +63,32 @@ static void _print_types()
|
||||
}
|
||||
|
||||
|
||||
static bool check_symlinks()
|
||||
static bool check_symlinks(Fs_type const &fs_type)
|
||||
{
|
||||
if (!Genode::strcmp(fs_type().string(), RUMP_MOUNT_EXT2FS))
|
||||
return true;
|
||||
|
||||
if (!Genode::strcmp(fs_type().string(), RUMP_MOUNT_FFS))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return (fs_type == RUMP_MOUNT_EXT2FS)
|
||||
|| (fs_type == RUMP_MOUNT_FFS);
|
||||
}
|
||||
|
||||
|
||||
static bool check_read_only()
|
||||
static bool check_read_only(Fs_type const &fs_type)
|
||||
{
|
||||
if (!Genode::strcmp(fs_type().string(), RUMP_MOUNT_CD9660))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return fs_type == RUMP_MOUNT_CD9660;
|
||||
}
|
||||
|
||||
|
||||
void File_system::init()
|
||||
void File_system::init(Genode::Env &env, Genode::Allocator &alloc, Genode::Xml_node config)
|
||||
{
|
||||
if (!_check_type(fs_type().string())) {
|
||||
Fs_type const fs_type = config.attribute_value("fs", Fs_type());
|
||||
|
||||
if (!_check_type(fs_type)) {
|
||||
Genode::error("Invalid or no file system given (use \'<config fs=\"<fs type>\"/>)");
|
||||
_print_types();
|
||||
throw Genode::Exception();
|
||||
}
|
||||
Genode::log("Using ", fs_type().string(), " as file system");
|
||||
Genode::log("Using ", fs_type, " as file system");
|
||||
|
||||
/* make Genode env and heap known to the rump kernel */
|
||||
rump_bootstrap_init(env, alloc);
|
||||
|
||||
/* start rump kernel */
|
||||
rump_init();
|
||||
@ -104,16 +98,16 @@ void File_system::init()
|
||||
|
||||
/* mount into extra-terrestrial-file system */
|
||||
struct fs_args args;
|
||||
int opts = check_read_only() ? RUMP_MNT_RDONLY : 0;
|
||||
int opts = check_read_only(fs_type) ? RUMP_MNT_RDONLY : 0;
|
||||
|
||||
args.fspec = (char *)GENODE_DEVICE;
|
||||
if (rump_sys_mount(fs_type().string(), "/", opts, &args, sizeof(args)) == -1) {
|
||||
Genode::error("Mounting '", fs_type().string(), "' file system failed (errno ", errno, " )");
|
||||
if (rump_sys_mount(fs_type.string(), "/", opts, &args, sizeof(args)) == -1) {
|
||||
Genode::error("Mounting '", fs_type, "' file system failed (errno ", errno, " )");
|
||||
throw Genode::Exception();
|
||||
}
|
||||
|
||||
/* check support for symlinks */
|
||||
_supports_symlinks = check_symlinks();
|
||||
_supports_symlinks = check_symlinks(fs_type);
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,6 +13,11 @@
|
||||
#ifndef _FILE_SYSTEM_H_
|
||||
#define _FILE_SYSTEM_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/xml_node.h>
|
||||
#include <base/env.h>
|
||||
#include <base/allocator.h>
|
||||
|
||||
extern "C" {
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/errno.h>
|
||||
@ -26,7 +31,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
namespace File_system {
|
||||
void init();
|
||||
void init(Genode::Env &, Genode::Allocator &heap, Genode::Xml_node config);
|
||||
bool supports_symlinks();
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
/* Genode includes */
|
||||
#include <file_system/node_handle_registry.h>
|
||||
#include <file_system_session/rpc_object.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <os/session_policy.h>
|
||||
#include <root/component.h>
|
||||
@ -481,16 +482,20 @@ struct File_system::Main
|
||||
Genode::Signal_handler<Main> sync_handler
|
||||
{ env.ep(), *this, &Main::sync };
|
||||
|
||||
Heap heap { env.ram(), env.rm() };
|
||||
|
||||
/*
|
||||
* Initialize root interface
|
||||
*/
|
||||
Sliced_heap sliced_heap = { env.ram(), env.rm() };
|
||||
Sliced_heap sliced_heap { env.ram(), env.rm() };
|
||||
|
||||
Root fs_root = { env, sliced_heap };
|
||||
Root fs_root { env, sliced_heap };
|
||||
|
||||
Attached_rom_dataspace config { env, "config" };
|
||||
|
||||
Main(Genode::Env &env) : env(env)
|
||||
{
|
||||
File_system::init();
|
||||
File_system::init(env, heap, config.xml());
|
||||
|
||||
/* set all bits but the stickies */
|
||||
rump_sys_umask(S_ISUID|S_ISGID|S_ISVTX);
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include <base/shared_object.h>
|
||||
#include <base/snprintf.h>
|
||||
|
||||
/* libc-internal includes */
|
||||
#include <libc_init.h>
|
||||
|
||||
extern "C" {
|
||||
#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)
|
||||
{
|
||||
return static_cast<Shared_object *>(handle);
|
||||
@ -39,21 +55,28 @@ void *dlopen(const char *name, int mode)
|
||||
/* error on unsupported mode values */
|
||||
if (mode & ~supported) {
|
||||
snprintf(err_str, MAX_ERR, "Unsupported mode 0x%x\n", mode & ~supported);
|
||||
error("dlopen: ", Cstring(err_str));
|
||||
error(__func__, ": ", Cstring(err_str));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Shared_object *obj = 0;
|
||||
unsigned flags = mode & RTLD_NOW ? Shared_object::NOW : Shared_object::LAZY;
|
||||
flags |= mode & RTLD_NODELETE ? Shared_object::KEEP : 0;
|
||||
Shared_object::Bind const bind =
|
||||
(mode & RTLD_NOW) ? Shared_object::BIND_NOW : Shared_object::BIND_LAZY;
|
||||
|
||||
Shared_object::Keep const keep =
|
||||
(mode & RTLD_NODELETE) ? Shared_object::KEEP : Shared_object::DONT_KEEP;
|
||||
|
||||
if (!genode_env) {
|
||||
error(__func__, ": support for dynamic linking not initialized");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
obj = new (env()->heap()) Shared_object(name, flags);
|
||||
return new (env()->heap())
|
||||
Shared_object(*genode_env, *env()->heap(), name, bind, keep);
|
||||
} catch (...) {
|
||||
snprintf(err_str, MAX_ERR, "Unable to open file %s\n", name);
|
||||
}
|
||||
|
||||
return (void *)obj;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
28
repos/libports/src/lib/libc/libc_init.h
Normal file
28
repos/libports/src/lib/libc/libc_init.h
Normal 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_ */
|
@ -23,6 +23,7 @@
|
||||
#include <internal/call_func.h>
|
||||
#include <base/internal/unmanaged_singleton.h>
|
||||
#include "vfs_plugin.h"
|
||||
#include "libc_init.h"
|
||||
|
||||
|
||||
/* escape sequences for highlighting debug message prefixes */
|
||||
@ -203,6 +204,9 @@ namespace Genode { extern void (*call_component_construct)(Genode::Env &); }
|
||||
|
||||
void Libc::call_component_construct(Genode::Env &env)
|
||||
{
|
||||
/* pass Genode::Env to libc subsystems that depend on it */
|
||||
init_dl(env);
|
||||
|
||||
task = unmanaged_singleton<Libc::Task>(env);
|
||||
task->run();
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <base/printf.h>
|
||||
#include <rom_session/connection.h>
|
||||
#include <base/env.h>
|
||||
#include <base/heap.h>
|
||||
#include <base/component.h>
|
||||
#include <base/shared_object.h>
|
||||
|
||||
using namespace Genode;
|
||||
@ -166,7 +168,7 @@ static void test_dynamic_cast()
|
||||
** Shared-object API **
|
||||
***********************/
|
||||
|
||||
static void test_shared_object_api()
|
||||
static void test_shared_object_api(Env &env, Allocator &alloc)
|
||||
{
|
||||
/*
|
||||
* When loading the shared object, we expect the global constructor
|
||||
@ -175,15 +177,18 @@ static void test_shared_object_api()
|
||||
* 'lib_dl_so' is a local variable such that its destructor is called
|
||||
* when leaving the scope of the function.
|
||||
*/
|
||||
Shared_object lib_dl_so("test-ldso_lib_dl.lib.so");
|
||||
Shared_object lib_dl_so(env, alloc, "test-ldso_lib_dl.lib.so",
|
||||
Shared_object::BIND_LAZY, Shared_object::DONT_KEEP);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main function of LDSO test
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
void Component::construct(Genode::Env &env)
|
||||
{
|
||||
static Heap heap(env.ram(), env.rm());
|
||||
|
||||
printf("\n");
|
||||
printf("Dynamic-linker test\n");
|
||||
printf("===================\n");
|
||||
@ -250,12 +255,11 @@ int main(int argc, char **argv)
|
||||
|
||||
printf("Shared-object API\n");
|
||||
printf("-----------------\n");
|
||||
test_shared_object_api();
|
||||
test_shared_object_api(env, heap);
|
||||
printf("\n");
|
||||
|
||||
printf("Destruction\n");
|
||||
printf("-----------\n");
|
||||
|
||||
/* test if return value is propagated correctly by dynamic linker */
|
||||
return 123;
|
||||
Libc::exit(123);
|
||||
}
|
||||
|
@ -132,14 +132,17 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
|
||||
/**
|
||||
* \throw Factory_not_available
|
||||
*/
|
||||
Vfs::File_system_factory &_load_factory(Genode::Allocator &alloc,
|
||||
Vfs::File_system_factory &_load_factory(Genode::Env &env,
|
||||
Genode::Allocator &alloc,
|
||||
Library_name const &lib_name)
|
||||
{
|
||||
Genode::Shared_object *shared_object = nullptr;
|
||||
|
||||
try {
|
||||
shared_object = new (alloc)
|
||||
Genode::Shared_object(lib_name.string());
|
||||
Genode::Shared_object(env, alloc, lib_name.string(),
|
||||
Genode::Shared_object::BIND_LAZY,
|
||||
Genode::Shared_object::DONT_KEEP);
|
||||
|
||||
typedef Vfs::File_system_factory *(*Query_fn)();
|
||||
|
||||
@ -147,7 +150,7 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
|
||||
|
||||
return *query_fn();
|
||||
|
||||
} catch (Genode::Shared_object::Invalid_file) {
|
||||
} catch (Genode::Shared_object::Invalid_rom_module) {
|
||||
PWRN("could not open '%s'", lib_name.string());
|
||||
throw Factory_not_available();
|
||||
|
||||
@ -160,13 +163,15 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
|
||||
}
|
||||
}
|
||||
|
||||
bool _probe_external_factory(Genode::Allocator &alloc, Genode::Xml_node node)
|
||||
bool _probe_external_factory(Genode::Env &env, Genode::Allocator &alloc,
|
||||
Genode::Xml_node node)
|
||||
{
|
||||
Library_name const lib_name = _library_name(_node_name(node));
|
||||
|
||||
try {
|
||||
_list.insert(new (alloc)
|
||||
External_entry(_node_name(node).string(), _load_factory(alloc, lib_name)));
|
||||
External_entry(_node_name(node).string(),
|
||||
_load_factory(env, alloc, lib_name)));
|
||||
return true;
|
||||
|
||||
} catch (Factory_not_available) { return false; }
|
||||
@ -187,7 +192,7 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory
|
||||
|
||||
try {
|
||||
/* probe for file system implementation available as shared lib */
|
||||
if (_probe_external_factory(alloc, node)) {
|
||||
if (_probe_external_factory(env, alloc, node)) {
|
||||
/* try again with the new file system type loaded */
|
||||
if (Vfs::File_system *fs = _try_create(env, alloc, node))
|
||||
return fs;
|
||||
|
Loading…
x
Reference in New Issue
Block a user