/**
* \brief Genode's dynamic linker
* \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.
*/
/* Genode includes */
#include
#include
#include
#include
#include
#include
#include
/* base-internal includes */
#include
#include
/* local includes */
#include
#include
#include
using namespace Linker;
namespace Linker {
struct Dynamic;
struct Ld;
struct Ld_vtable;
struct Binary;
struct Link_map;
struct Debug;
struct Config;
};
static Binary *binary_ptr = nullptr;
bool Linker::verbose = false;
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();
}
Genode::Lock &Linker::lock()
{
static Lock _lock;
return _lock;
}
/**************************************************************
** ELF object types (shared object, dynamic binaries, ldso **
**************************************************************/
/**
* The actual ELF object, one per file
*/
class Linker::Elf_object : public Object, public Fifo::Element
{
private:
Link_map _map;
unsigned _ref_count = 1;
unsigned const _keep = KEEP;
bool _relocated = false;
/*
* Optional ELF file, skipped for initial 'Ld' initialization
*/
Constructible _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, Linker::file(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);
}
/**
* 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