genode/repos/base/src/lib/ldso/main.cc

787 lines
19 KiB
C++
Raw Normal View History

/**
* \brief Genode's dynamic linker
* \author Sebastian Sumpf
* \date 2014-10-26
*/
/*
* Copyright (C) 2014-2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/component.h>
#include <base/log.h>
#include <base/attached_rom_dataspace.h>
#include <util/list.h>
#include <util/string.h>
#include <base/thread.h>
#include <base/heap.h>
2020-01-11 15:13:40 +01:00
#include <base/sleep.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>
#include <config.h>
using namespace Linker;
namespace Linker {
class Dynamic;
struct Ld;
struct Ld_vtable;
struct Binary;
struct Link_map;
struct Debug;
class Config;
};
static Binary *binary_ptr = nullptr;
bool Linker::verbose = false;
Stage Linker::stage = STAGE_BINARY;
Link_map *Link_map::first;
/**
* Registers dtors
*/
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 **
**************************************************************/
/**
* The actual ELF object, one per file
*/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
class Linker::Elf_object : public Object, private Fifo<Elf_object>::Element
{
private:
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
friend class Fifo<Elf_object>;
Link_map _map { };
unsigned _ref_count { 1 };
Keep _keep { KEEP };
bool _relocated { false };
/*
* Optional ELF file, skipped for initial 'Ld' initialization
*/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Constructible<Elf_file> _elf_file { };
bool _object_init(Object::Name const &name, Elf::Addr reloc_base)
{
Object::init(name, reloc_base);
return true;
}
bool _init_elf_file(Env &env, Allocator &md_alloc, char const *path)
{
_elf_file.construct(env, md_alloc, path, true);
Object::init(Linker::file(path), *_elf_file);
return true;
}
bool const _elf_object_initialized;
Dynamic _dyn;
public:
Elf_object(Dependency const &dep, Object::Name const &name,
Elf::Addr reloc_base)
:
_elf_object_initialized(_object_init(name, reloc_base)),
_dyn(dep)
{ }
Elf_object(Env &env, Allocator &md_alloc, char const *path,
Dependency const &dep, Keep keep)
:
_keep(keep),
_elf_object_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);
/* 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)
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);
Init::list()->remove(this);
}
/**
* 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);
};
void force_keep() { _keep = KEEP; }
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 SELF_RELOC
{
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
*/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
Object *next_init() const override { return _next_object(); }
/**
* 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 keep() const override { return _keep == KEEP; }
bool is_linker() const override { return false; }
bool is_binary() const override { return false; }
};
/**
* The dynamic linker object (ld.lib.so)
*/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
struct Linker::Ld : private Dependency, Elf_object
{
Ld() :
Dependency(*this, nullptr),
Elf_object(*this, linker_name(), relocation_address())
{ }
void setup_link_map()
{
Elf_object::setup_link_map();
link_map_addr(dynamic().link_map_addr());
}
void load_phdr(Env &env, Allocator &md_alloc)
{
_file = new (md_alloc) Elf_file(env, md_alloc, name(), false);
}
static Ld &linker();
bool is_linker() const override { return true; }
bool keep() const override { return true; }
/**
* 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");
};
Elf::Addr Ld::jmp_slot(Dependency const &dep, Elf::Size index)
{
Lock::Guard guard(lock());
if (verbose_relocation)
log("LD: SLOT ", &dep.obj(), " ", Hex(index));
try {
Reloc_jmpslot slot(dep, dep.obj().dynamic().pltrel_type(),
dep.obj().dynamic().pltrel(), index);
return slot.target_addr();
} catch (Linker::Not_found &symbol) {
error("LD: jump slot relocation failed for symbol: '", symbol, "'");
throw;
} catch (...) {
error("LD: jump slot relocation failed:: '", Current_exception(), "'");
throw;
}
return 0;
}
/**
* Linker object used during bootstrapping on stack (see: 'init_rtld')
*/
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;
}
/*
* Defined in the startup library, passed to legacy main functions.
*/
extern char **genode_argv;
extern int genode_argc;
extern char **genode_envp;
void genode_exit(int status);
static int exit_status;
static void exit_on_suspended() { genode_exit(exit_status); }
/**
* The dynamic binary to load
*/
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
struct Linker::Binary : private Root_object, public Elf_object
{
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
using Root_object::first_dep;
bool const _check_ctors;
bool static_construction_finished = false;
Binary(Env &env, Allocator &md_alloc, Config const &config, char const *name)
:
Root_object(md_alloc),
Elf_object(env, md_alloc, name,
*new (md_alloc) Dependency(*this, this), DONT_KEEP),
_check_ctors(config.check_ctors())
{
/* create dep for binary and 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);
Ld::linker().update_dependency(*linker);
/* place linker on second place in link map */
Ld::linker().setup_link_map();
/* preload libraries specified in the configuration */
binary->preload(env, md_alloc, deps(), config);
/* load dependencies */
binary->load_needed(env, md_alloc, deps(), DONT_KEEP);
/* relocate and call constructors */
Init::list()->initialize(config.bind(), STAGE_BINARY);
}
Elf::Addr lookup_symbol(char const *name)
{
try {
Elf::Addr base = 0;
Elf::Sym const *sym = Linker::lookup_symbol(name, dynamic().dep(), &base);
return base + sym->st_value;
}
catch (Linker::Not_found) { return 0; }
}
bool static_construction_pending()
{
if (static_construction_finished) return false;
return Init::list()->needs_static_construction();
}
void finish_static_construction()
{
Init::list()->exec_static_constructors();
/* call static constructors and register destructors */
Func * const ctors_start = (Func *)lookup_symbol("_ctors_start");
Func * const ctors_end = (Func *)lookup_symbol("_ctors_end");
for (Func * ctor = ctors_end; ctor != ctors_start; (*--ctor)());
Func * const dtors_start = (Func *)lookup_symbol("_dtors_start");
Func * const dtors_end = (Func *)lookup_symbol("_dtors_end");
for (Func * dtor = dtors_start; dtor != dtors_end; genode_atexit(*dtor++));
static_construction_finished = true;
stage = STAGE_SO;
}
void call_entry_point(Env &env)
{
/* apply the component-provided stack size */
if (Elf::Addr addr = lookup_symbol("_ZN9Component10stack_sizeEv")) {
/* call 'Component::stack_size()' */
size_t const stack_size = ((size_t(*)())addr)();
/* expand stack according to the component's needs */
Thread::myself()->stack_size(stack_size);
}
/* call 'Component::construct' function if present */
if (Elf::Addr addr = lookup_symbol("_ZN9Component9constructERN6Genode3EnvE")) {
((void(*)(Env &))addr)(env);
if (_check_ctors && static_construction_pending()) {
error("Component::construct() returned without executing "
"pending static constructors (fix by calling "
"Genode::Env::exec_static_constructors())");
throw Fatal();
}
stage = STAGE_SO;
return;
}
/*
* The 'Component::construct' function is missing. This may be the
* case for legacy components that still implement a 'main' function.
*
* \deprecated the handling of legacy 'main' functions will be removed
*/
if (Elf::Addr addr = lookup_symbol("main")) {
warning("using legacy main function, please convert to 'Component::construct'");
/* execute static constructors before calling legacy 'main' */
finish_static_construction();
exit_status = ((int (*)(int, char **, char **))addr)(genode_argc,
genode_argv,
genode_envp);
/* trigger suspend in the entry point */
env.ep().schedule_suspend(exit_on_suspended, nullptr);
/* return to entrypoint and exit via exit_on_suspended() */
return;
}
error("dynamic linker: component-entrypoint lookup failed");
throw Fatal();
}
void relocate(Bind bind) override
{
/* relocate ourselves */
Elf_object::relocate(bind);
/*
* After having loaded the main program, we relocate the linker's
* symbols again such that, for example type informations, which are
* also present within the main program, become relocated to the correct
* positions
*/
Ld::linker().relocate_global();
}
bool is_binary() const override { return true; }
};
/**********************************
** Linker object implementation **
**********************************/
Elf::Addr Linker::Object::_symbol_address(char const *name)
{
unsigned long hash = Hash_table::hash(name);
Elf::Sym const *sym = dynamic().lookup_symbol(name, hash);
if (sym)
return reloc_base() + sym->st_value;
else
return Elf::Addr(0);
}
bool Linker::Object::needs_static_construction()
{
return _symbol_address("_ctors_end") != _symbol_address("_ctors_start");
}
/***************************************
** Global Linker namespace functions **
***************************************/
Object &Linker::load(Env &env, Allocator &md_alloc, char const *path,
Dependency &dep, Keep keep)
{
Object *result = nullptr;
Elf_object::obj_list()->for_each([&] (Object &e) {
if (result == nullptr) {
if (verbose_loading)
log("LOAD: ", Linker::file(path), " == ", e.name());
if (!strcmp(Linker::file(path), e.name())) {
e.load();
result = &e;
}
}
});
if (result == nullptr)
result = new (md_alloc) Elf_object(env, md_alloc, path, dep, keep);
return *result;
}
Object *Linker::obj_list_head()
{
Object *result = nullptr;
Elf_object::obj_list()->head([&result] (Object &obj) {
result = &obj; });
return result;
}
Elf::Sym const *Linker::lookup_symbol(unsigned sym_index, Dependency const &dep,
Elf::Addr *base, bool undef, bool other)
{
Elf_object const &elf = static_cast<Elf_object const &>(dep.obj());
Elf::Sym const *symbol = elf.symbol(sym_index);
if (!symbol) {
warning("LD: unknown symbol index ", Hex(sym_index));
return 0;
}
if (symbol->bind() == STB_LOCAL) {
*base = dep.obj().reloc_base();
return symbol;
}
return lookup_symbol(elf.symbol_name(*symbol), dep, base, undef, other);
}
Elf::Sym const *Linker::lookup_symbol(char const *name, Dependency const &dep,
Elf::Addr *base, bool undef, bool other)
{
Dependency const *curr = &dep.first();
unsigned long hash = Hash_table::hash(name);
Elf::Sym const *weak_symbol = 0;
Elf::Addr weak_base = 0;
Elf::Sym const *symbol = 0;
//TODO: handle vertab and search in object list
for (;curr; curr = curr->next()) {
if (other && curr == &dep)
continue;
Elf_object const &elf = static_cast<Elf_object const &>(curr->obj());
if ((symbol = elf.lookup_symbol(name, hash)) && (symbol->st_value || undef)) {
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();
return symbol;
}
if (!weak_symbol) {
weak_symbol = symbol;
weak_base = elf.reloc_base();
}
}
}
/* try searching binary's dependencies */
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 {
throw Not_found(name);
}
}
if (dep.root() && verbose_lookup)
log("LD: return ", weak_symbol);
if (!weak_symbol)
throw Not_found(name);
*base = weak_base;
return weak_symbol;
}
/********************
** Initialization **
********************/
/**
* Called before anything else, even '_main', we cannot access any global data
* here, we have to relocate our own ELF first
*/
extern "C" void init_rtld()
{
/*
* Allocate on stack, since the linker has not been relocated yet, the vtable
* type relocation might produce a wrong vtable pointer (at least on ARM), do
* not call any virtual funtions of this object.
*/
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();
}
static Genode::Constructible<Heap> &heap()
{
return *unmanaged_singleton<Constructible<Heap>>();
}
void Genode::init_ldso_phdr(Env &env)
{
/*
* Use a statically allocated initial block to make the first dynamic
* allocations deterministic. This assumption is required by the libc's
* fork mechanism on Linux. Without the initial block, the Linux kernel
* would attach the heap's backing-store dataspaces to differently
* randomized addresses in the new process. The binary's GOT (containing
* pointers to the linker's heap-allocated objects) of the new process,
* however, is copied from the parent process. So the pointed-to objects
* must reside on the same addresses in the parent and child.
*/
static char initial_block[4*1024];
heap().construct(&env.ram(), &env.rm(), Heap::UNLIMITED,
initial_block, sizeof(initial_block));
/* load program headers of linker now */
if (!Ld::linker().file())
Ld::linker().load_phdr(env, *heap());
}
void Genode::exec_static_constructors()
{
binary_ptr->finish_static_construction();
}
void Genode::Dynamic_linker::_for_each_loaded_object(Env &, For_each_fn const &fn)
{
Elf_object::obj_list()->for_each([&] (Object const &obj) {
Elf_file const *elf_file_ptr =
obj.file() ? dynamic_cast<Elf_file const *>(obj.file()) : nullptr;
if (!elf_file_ptr)
return;
elf_file_ptr->with_rw_phdr([&] (Elf::Phdr const &phdr) {
Object_info info { .name = obj.name(),
.ds_cap = elf_file_ptr->rom_cap,
.rw_start = (void *)(obj.reloc_base() + phdr.p_vaddr),
.rw_size = phdr.p_memsz };
fn.supply_object_info(info);
});
});
}
void Dynamic_linker::keep(Env &, char const *binary)
{
Elf_object::obj_list()->for_each([&] (Elf_object &obj) {
if (Object::Name(binary) == obj.name())
obj.force_keep(); });
}
void *Dynamic_linker::_respawn(Env &env, char const *binary, char const *entry_name)
{
Object::Name const name(binary);
/* unload original binary */
binary_ptr->~Binary();
Config const config(env);
/* load new binary */
construct_at<Binary>(binary_ptr, env, *heap(), config, name.string());
try {
return (void *)binary_ptr->lookup_symbol(entry_name);
}
catch (...) { }
throw Dynamic_linker::Invalid_symbol();
}
void Component::construct(Genode::Env &env)
{
/* read configuration */
Config const config(env);
verbose = config.verbose();
/* load binary and all dependencies */
try {
binary_ptr = unmanaged_singleton<Binary>(env, *heap(), config, binary_name());
} catch(Linker::Not_found &symbol) {
error("LD: symbol not found: '", symbol, "'");
throw;
} catch (...) {
error("LD: exception during program load: '", Current_exception(), "'");
throw;
}
/* print loaded object information */
try {
if (verbose) {
using namespace Genode;
log(" ", Hex(Thread::stack_area_virtual_base()),
" .. ", Hex(Thread::stack_area_virtual_base() +
Thread::stack_area_virtual_size() - 1),
": stack area");
Elf_object::obj_list()->for_each([] (Object const &obj) {
dump_link_map(obj); });
}
} catch (...) { }
Link_map::dump();
binary_ready_hook_for_gdb();
/* start binary */
binary_ptr->call_entry_point(env);
}
2020-01-11 15:13:40 +01:00
extern "C" int main(int, char **, char **)
{
Genode::error("LD: dummy \"main\" procedure invoked!");
Genode::sleep_forever();
return ~0;
}