genode/repos/base/src/lib/ldso/include/linker.h

231 lines
5.2 KiB
C++

/**
* \brief Generic linker definitions
* \author Sebastian Sumpf
* \date 2014-10-24
*/
/*
* 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.
*/
#ifndef _INCLUDE__LINKER_H_
#define _INCLUDE__LINKER_H_
#include <base/exception.h>
#include <base/env.h>
#include <util/fifo.h>
#include <util/misc_math.h>
#include <util/string.h>
#include <elf.h>
#include <trace.h>
/**
* Debugging
*/
constexpr bool verbose_lookup = false;
constexpr bool verbose_link_map = false;
constexpr bool verbose_relocation = false;
constexpr bool verbose_exception = false;
constexpr bool verbose_shared = false;
constexpr bool verbose_loading = false;
/**
* Forward declartions and helpers
*/
namespace Linker
{
class Object;
struct Phdr;
struct File;
struct Root_object;
struct Dag;
struct Elf_object;
/**
* Find symbol via index
*
* \param sym_index Symbol index within object
* \param dag Directed acyclic graph of object
* \param base Returned address of symbol
* \param undef True, return undefined symbol; False return defined
* symbols only
* \param other True, search for symbol in other objects; False, search
* for symbol in given object as well.
*
* \throw Not_found Symbol not found
*
* \return Symbol information
*/
Elf::Sym const *locate_symbol(unsigned sym_index, Dag const *, Elf::Addr *base,
bool undef = false, bool other = false);
/**
* Find symbol via name
*
* \param name Symbol name
* \param dag Directed acyclic graph of object
* \param base Returned address of symbol
* \param undef True, return undefined symbol; False return defined
* symbols only
* \param other True, search for symbol in other objects; False, search
* for symbol in given object as well.
*
* \throw Not_found Symbol not found
*
* \return Symbol information
*/
Elf::Sym const *search_symbol(char const *name, Dag const *dag, Elf::Addr *base,
bool undef = false, bool other = false);
/**
* 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);
/**
* Exceptions
*/
class Incompatible : Genode::Exception { };
class Invalid_file : Genode::Exception { };
class Not_found : Genode::Exception { };
/**
* Page handling
*/
template <typename T>
static inline T trunc_page(T addr) {
return addr & Genode::_align_mask((T)12); }
template <typename T>
static inline T round_page(T addr) {
return Genode::align_addr(addr, (T)12); }
/**
* Extract file name from path
*/
inline char const *file(char const *path)
{
/* strip directories */
char const *f, *r = path;
for (f = r; *f; f++)
if (*f == '/')
r = f + 1;
return r;
}
/**
* Invariants
*/
constexpr char const *binary_name() { return "binary"; }
constexpr char const *linker_name() { return "ld.lib.so"; }
}
struct Linker::Phdr
{
enum { MAX_PHDR = 10 };
Elf::Phdr phdr[MAX_PHDR];
unsigned count = 0;
};
struct Linker::File
{
typedef void (*Entry)(void);
Phdr phdr;
Entry entry;
Elf::Addr reloc_base = 0;
Elf::Addr start = 0;
Elf::Size size = 0;
virtual ~File() { }
Elf::Phdr const *elf_phdr(unsigned index) const
{
if (index < phdr.count)
return &phdr.phdr[index];
return 0;
}
unsigned elf_phdr_count() const { return phdr.count; }
};
class Linker::Object : public Genode::Fifo<Object>::Element
{
protected:
enum { MAX_PATH = 128 };
char _name[MAX_PATH];
File const *_file = nullptr;
public:
Object() { }
Object(char const *path, File const *file)
: _file(file)
{
Genode::strncpy(_name, Linker::file(path), MAX_PATH);
}
virtual ~Object()
{
if (_file)
destroy(Genode::env()->heap(), const_cast<File *>(_file));
}
Elf::Addr reloc_base() const { return _file ? _file->reloc_base : 0; }
char const *name() const { return _name; }
File const *file() { return _file; }
virtual bool is_linker() const = 0;
virtual bool is_binary() const = 0;
Elf::Size const size() const { return _file ? _file->size : 0; }
};
struct Linker::Dag : Genode::Fifo<Dag>::Element
{
Object *obj = nullptr;
Root_object *root = nullptr;
Dag(Object *obj, Root_object *root) : obj(obj), root(root) { }
Dag(char const *path, Root_object *root, Genode::Fifo<Dag> * const dag,
unsigned flags = 0);
~Dag();
void load_needed(Genode::Fifo<Dag> * const dag, unsigned flags = 0);
bool in_dag(char const *file, Genode::Fifo<Dag> *const dag);
};
static inline bool verbose_reloc(Linker::Dag const *d)
{
return d->root && verbose_relocation;
}
extern "C" void _jmp_slot(void);
#endif /* _INCLUDE__LINKER_H_ */