mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
parent
c94145f74d
commit
36e01b720e
@ -4,7 +4,8 @@ DIR = $(REP_DIR)/src/lib/ldso
|
||||
include $(BASE_DIR)/mk/base-libs.mk
|
||||
|
||||
LIBS = $(BASE_LIBS)
|
||||
SRC_CC = main.cc test.cc file.cc
|
||||
SRC_CC = main.cc test.cc exception.cc file.cc dependency.cc debug.cc \
|
||||
shared_object.cc
|
||||
SRC_S = jmp_slot.s
|
||||
INC_DIR += $(DIR)/include
|
||||
LD_OPT += -Bsymbolic-functions --version-script=$(DIR)/symbol.map
|
||||
|
@ -43,12 +43,11 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
Elf::Addr reloc_base;
|
||||
Elf::Sym const *sym;
|
||||
|
||||
if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base)))
|
||||
if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base)))
|
||||
return;
|
||||
|
||||
/* S + A - P */
|
||||
*addr = reloc_base + sym->st_value - (Elf::Addr)addr + *addr;
|
||||
trace("REL32", (unsigned long)addr, *addr, 0);
|
||||
}
|
||||
|
||||
void _glob_dat(Elf::Rel const *rel, Elf::Addr *addr, bool no_addend)
|
||||
@ -56,14 +55,13 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
Elf::Addr reloc_base;
|
||||
Elf::Sym const *sym;
|
||||
|
||||
if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base)))
|
||||
if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base)))
|
||||
return;
|
||||
|
||||
Elf::Addr addend = no_addend ? 0 : *addr;
|
||||
|
||||
/* S + A */
|
||||
*addr = addend + reloc_base + sym->st_value;
|
||||
trace("GLOB_DAT", (unsigned long)addr, *addr, 0);
|
||||
}
|
||||
|
||||
void _relative(Elf::Addr *addr)
|
||||
@ -73,25 +71,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 (_dag->obj->reloc_base())
|
||||
*addr += _dag->obj->reloc_base();
|
||||
if (_dep->obj->reloc_base())
|
||||
*addr += _dep->obj->reloc_base();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt(Dag const *dag, Elf::Rela const *, unsigned long)
|
||||
: Reloc_non_plt_generic(dag)
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rela const *, unsigned long)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
PERR("LD: DT_RELA not supported");
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
Reloc_non_plt(Dag const *dag, Elf::Rel const *rel, unsigned long size, bool second_pass)
|
||||
: Reloc_non_plt_generic(dag)
|
||||
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 *)(_dag->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 +103,7 @@ 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:
|
||||
trace("UNKREL", rel->type(), 0, 0);
|
||||
if (_dag->root) {
|
||||
if (_dep->root) {
|
||||
PWRN("LD: Unkown relocation %u", rel->type());
|
||||
throw Incompatible();
|
||||
}
|
||||
|
19
repos/base/src/lib/ldso/debug.cc
Normal file
19
repos/base/src/lib/ldso/debug.cc
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* \brief GDB debugging support
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
/**
|
||||
* C-break function for GDB
|
||||
*/
|
||||
extern "C" void brk(Linker::Debug *, Linker::Link_map *) { }
|
81
repos/base/src/lib/ldso/dependency.cc
Normal file
81
repos/base/src/lib/ldso/dependency.cc
Normal file
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* \brief Manage object dependencies
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#include <linker.h>
|
||||
#include <dynamic.h>
|
||||
#include <init.h>
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
dep->enqueue(this);
|
||||
load_needed(dep, flags);
|
||||
}
|
||||
|
||||
|
||||
Linker::Dependency::~Dependency()
|
||||
{
|
||||
if (obj->unload()) {
|
||||
|
||||
if (verbose_loading)
|
||||
PDBG("Destroy: %s\n", obj->name());
|
||||
|
||||
destroy(Genode::env()->heap(), obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Linker::Dependency::in_dep(char const *file,
|
||||
Genode::Fifo<Dependency> * const dep)
|
||||
{
|
||||
for (Dependency *d = dep->head(); d; d = d->next())
|
||||
if (!Genode::strcmp(file, d->obj->name()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Linker::Dependency::load_needed(Genode::Fifo<Dependency> * const dep,
|
||||
unsigned flags)
|
||||
{
|
||||
for (Dynamic::Needed *n = obj->dynamic()->needed.head(); n; n = n->next()) {
|
||||
char const *path = n->path(obj->dynamic()->strtab);
|
||||
|
||||
Object *o;
|
||||
if (!in_dep(Linker::file(path), dep))
|
||||
new (Genode::env()->heap()) Dependency(path, root, dep, flags);
|
||||
|
||||
/* re-order initializer list, if needed object has been already added */
|
||||
else if ((o = Init::list()->contains(Linker::file(path))))
|
||||
Init::list()->reorder(o);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Linker::Root_object::Root_object(char const *path, unsigned flags)
|
||||
{
|
||||
new (Genode::env()->heap()) Dependency(path, this, &dep, flags);
|
||||
|
||||
/* provide Genode base library access */
|
||||
new (Genode::env()->heap()) Dependency(linker_name(), this, &dep);;
|
||||
|
||||
/* relocate and call constructors */
|
||||
Init::list()->initialize();
|
||||
}
|
116
repos/base/src/lib/ldso/exception.cc
Normal file
116
repos/base/src/lib/ldso/exception.cc
Normal file
@ -0,0 +1,116 @@
|
||||
/**
|
||||
* \brief GCC excption handling support
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#include <linker.h>
|
||||
|
||||
|
||||
using namespace Linker;
|
||||
|
||||
/*********
|
||||
** x86 **
|
||||
*********/
|
||||
|
||||
/**
|
||||
* "Walk through shared objects" support, see man page of 'dl_iterate_phdr'
|
||||
*/
|
||||
struct Phdr_info
|
||||
{
|
||||
Elf::Addr addr; /* module relocation base */
|
||||
char const *name; /* module name */
|
||||
Elf::Phdr const *phdr; /* pointer to module's phdr */
|
||||
Elf::Half phnum; /* number of entries in phdr */
|
||||
};
|
||||
|
||||
|
||||
extern "C" int dl_iterate_phdr(int (*callback) (Phdr_info *info, Genode::size_t size, void *data), void *data)
|
||||
{
|
||||
int err = 0;
|
||||
Phdr_info info;
|
||||
|
||||
Genode::Lock::Guard guard(Object::lock());
|
||||
|
||||
for (Object *e = obj_list_head();e; e = e->next_obj()) {
|
||||
|
||||
info.addr = e->reloc_base();
|
||||
info.name = e->name();
|
||||
info.phdr = e->file()->phdr.phdr;
|
||||
info.phnum = e->file()->phdr.count;
|
||||
|
||||
if (verbose_exception)
|
||||
PDBG("%s reloc " EFMT, e->name(), e->reloc_base());
|
||||
|
||||
if ((err = callback(&info, sizeof(Phdr_info), data)))
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** ARM **
|
||||
*********/
|
||||
|
||||
/**
|
||||
* Return EXIDX program header
|
||||
*/
|
||||
static Elf::Phdr const *phdr_exidx(File const *file)
|
||||
{
|
||||
for (unsigned i = 0; i < file->elf_phdr_count(); i++) {
|
||||
Elf::Phdr const *ph = file->elf_phdr(i);
|
||||
|
||||
if (ph->p_type == PT_ARM_EXIDX)
|
||||
return ph;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find ELF and exceptions table segment that that is located under 'pc',
|
||||
* address of exception table and number of entries 'pcount'
|
||||
*/
|
||||
extern "C" unsigned long dl_unwind_find_exidx(unsigned long pc, int *pcount)
|
||||
{
|
||||
/* size of exception table entries */
|
||||
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())
|
||||
{
|
||||
/* address of first PT_LOAD header */
|
||||
Genode::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))
|
||||
continue;
|
||||
|
||||
/* retrieve PHDR of exception-table segment */
|
||||
Elf::Phdr const *exidx = phdr_exidx(e->file());
|
||||
if (!exidx)
|
||||
continue;
|
||||
|
||||
*pcount = exidx->p_memsz / EXIDX_ENTRY_SIZE;
|
||||
return exidx->p_vaddr + e->reloc_base();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
126
repos/base/src/lib/ldso/include/debug.h
Normal file
126
repos/base/src/lib/ldso/include/debug.h
Normal file
@ -0,0 +1,126 @@
|
||||
/**
|
||||
* \brief Debugger support
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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__DEBUG_H_
|
||||
#define _INCLUDE__DEBUG_H_
|
||||
|
||||
#include <base/printf.h>
|
||||
#include <elf.h>
|
||||
|
||||
constexpr bool verbose_link_map = false;
|
||||
|
||||
namespace Linker {
|
||||
struct Debug;
|
||||
struct Link_map;
|
||||
}
|
||||
|
||||
/**
|
||||
* LIBC debug support
|
||||
*/
|
||||
extern "C" void brk(Linker::Debug *, Linker::Link_map *);
|
||||
|
||||
struct Linker::Debug
|
||||
{
|
||||
/*
|
||||
* This state value describes the mapping change taking place when
|
||||
* the brk address is called.
|
||||
*/
|
||||
enum State {
|
||||
CONSISTENT, /* mapping change is complete */
|
||||
ADD, /* beginning to add a new object */
|
||||
DELETE /* beginning to remove an object mapping */
|
||||
};
|
||||
|
||||
Debug() : Brk(brk) { }
|
||||
|
||||
int version = 1; /* unused */
|
||||
struct Link_map *map = nullptr;; /* start of link map */
|
||||
|
||||
/*
|
||||
* This is the address of a function internal to the run-time linker, that
|
||||
* will always be called when the linker begins to map in a library or unmap
|
||||
* it, and again when the mapping change is complete. The debugger can set a
|
||||
* breakpoint at this address if it wants to notice shared object mapping
|
||||
* changes.
|
||||
*/
|
||||
void (*Brk)(Debug *, Link_map *);
|
||||
State state = CONSISTENT;
|
||||
|
||||
static void state_change(State s, Link_map *m)
|
||||
{
|
||||
d()->state = s;
|
||||
d()->Brk(d(), m);
|
||||
}
|
||||
|
||||
static Debug *d()
|
||||
{
|
||||
static Debug _d;
|
||||
return &_d;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Link map
|
||||
*/
|
||||
struct Linker::Link_map
|
||||
{
|
||||
Elf::Addr addr; /* base address of library */
|
||||
char const *path; /* path */
|
||||
void const *dynamic; /* DYNAMIC section */
|
||||
|
||||
Link_map *next = nullptr;
|
||||
Link_map *prev = nullptr;
|
||||
|
||||
static Link_map *first;
|
||||
|
||||
static void add(Link_map *map)
|
||||
{
|
||||
map->next = nullptr;;
|
||||
if (!first) {
|
||||
first = map;
|
||||
Debug::d()->map = map;
|
||||
return;
|
||||
}
|
||||
|
||||
Link_map *m;
|
||||
for (m = first; m->next; m = m->next) ;
|
||||
|
||||
m->next = map;
|
||||
map->prev = m;
|
||||
}
|
||||
|
||||
static void remove(Link_map *map)
|
||||
{
|
||||
if (map->prev)
|
||||
map->prev->next = map->next;
|
||||
|
||||
if (map->next)
|
||||
map->next->prev = map->prev;
|
||||
|
||||
if (map == first)
|
||||
first = map->next;
|
||||
}
|
||||
|
||||
static void dump()
|
||||
{
|
||||
if (!verbose_link_map)
|
||||
return;
|
||||
|
||||
for (Link_map *m = first; m; m = m->next)
|
||||
PINF("MAP: addr: " EFMT " dynamic: %p %s m: %p p: %p n: %p",
|
||||
m->addr, m->dynamic, m->path, m, m->prev, m->next);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__DEBUG_H_ */
|
222
repos/base/src/lib/ldso/include/dynamic.h
Normal file
222
repos/base/src/lib/ldso/include/dynamic.h
Normal file
@ -0,0 +1,222 @@
|
||||
/**
|
||||
* \brief ELF-dynamic section (see ELF ABI)
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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__DYNAMIC_H_
|
||||
#define _INCLUDE__DYNAMIC_H_
|
||||
|
||||
#include <relocation.h>
|
||||
|
||||
namespace Linker {
|
||||
struct Hash_table;
|
||||
struct Dynamic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset of dynamic section of this ELF. This is filled out during linkage by
|
||||
* static linker.
|
||||
*/
|
||||
extern Genode::addr_t _DYNAMIC;
|
||||
|
||||
|
||||
/**
|
||||
* ELF hash table and hash function
|
||||
*/
|
||||
struct Linker::Hash_table
|
||||
{
|
||||
unsigned long nbuckets() const { return *((Elf::Hashelt *)this); }
|
||||
unsigned long nchains() const { return *(((Elf::Hashelt *)this) + 1); }
|
||||
|
||||
Elf::Hashelt const *buckets() { return ((Elf::Hashelt *)this + 2); }
|
||||
Elf::Hashelt const *chains() { return buckets() + nbuckets(); }
|
||||
|
||||
/**
|
||||
* ELF hash function Figure 5.12 of the 'System V ABI'
|
||||
*/
|
||||
static unsigned long hash(char const *name)
|
||||
{
|
||||
unsigned const char *p = (unsigned char const *)name;
|
||||
unsigned long h = 0, g;
|
||||
|
||||
while (*p) {
|
||||
h = (h << 4) + *p++;
|
||||
if ((g = h & 0xf0000000) != 0)
|
||||
h ^= g >> 24;
|
||||
h &= ~g;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* .dynamic section entries
|
||||
*/
|
||||
struct Linker::Dynamic
|
||||
{
|
||||
struct Needed : Genode::Fifo<Needed>::Element
|
||||
{
|
||||
Genode::off_t offset;
|
||||
|
||||
Needed(Genode::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;
|
||||
|
||||
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;
|
||||
|
||||
Genode::Fifo<Needed> needed;
|
||||
|
||||
Dynamic(Dependency const *dep)
|
||||
:
|
||||
dep(dep), obj(dep->obj), dynamic((Elf::Dyn *)(obj->reloc_base() + &_DYNAMIC))
|
||||
{
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void relocate()
|
||||
{
|
||||
plt_setup();
|
||||
|
||||
if (pltrel_size) {
|
||||
switch (pltrel_type) {
|
||||
|
||||
case DT_RELA:
|
||||
case DT_REL:
|
||||
Reloc_plt(obj, pltrel_type, pltrel, pltrel_size);
|
||||
break;
|
||||
default:
|
||||
PERR("LD: Invalid PLT relocation %u", pltrel_type);
|
||||
throw Incompatible();
|
||||
}
|
||||
}
|
||||
|
||||
relocate_non_plt();
|
||||
}
|
||||
|
||||
void plt_setup()
|
||||
{
|
||||
if (pltgot)
|
||||
Plt_got r(dep, pltgot);
|
||||
}
|
||||
|
||||
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, second_pass);
|
||||
|
||||
if (bind_now)
|
||||
Reloc_bind_now r(dep, pltrel, pltrel_size);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__DYNAMIC_H_ */
|
75
repos/base/src/lib/ldso/include/file.h
Normal file
75
repos/base/src/lib/ldso/include/file.h
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* \brief ELF file setup
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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__FILE_H_
|
||||
#define _INCLUDE__FILE_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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Program header
|
||||
*/
|
||||
struct Linker::Phdr
|
||||
{
|
||||
enum { MAX_PHDR = 10 };
|
||||
|
||||
Elf::Phdr phdr[MAX_PHDR];
|
||||
unsigned count = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Loaded ELF file
|
||||
*/
|
||||
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; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__FILE_H_ */
|
110
repos/base/src/lib/ldso/include/init.h
Normal file
110
repos/base/src/lib/ldso/include/init.h
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* \brief Initialization list (calls ctors)
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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__INIT_H_
|
||||
#define _INCLUDE__INIT_H_
|
||||
|
||||
#include <linker.h>
|
||||
|
||||
|
||||
namespace Linker {
|
||||
struct Init;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle static construction and relocation of ELF files
|
||||
*/
|
||||
struct Linker::Init : Genode::List<Object>
|
||||
{
|
||||
bool in_progress = false;
|
||||
bool restart = false;
|
||||
|
||||
static Init *list()
|
||||
{
|
||||
static Init _list;
|
||||
return &_list;
|
||||
}
|
||||
|
||||
Object *contains(char const *file)
|
||||
{
|
||||
for (Object *elf = first(); elf; elf = elf->next_init())
|
||||
if (!Genode::strcmp(file, elf->name()))
|
||||
return elf;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void reorder(Object *elf)
|
||||
{
|
||||
/* put in front of initializer list */
|
||||
remove(elf);
|
||||
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;
|
||||
|
||||
if ((e = contains(Linker::file(path))))
|
||||
reorder(e);
|
||||
}
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
Object *obj = first();
|
||||
|
||||
/* relocate */
|
||||
for (; obj; obj = obj->next_init()) {
|
||||
if (verbose_relocation)
|
||||
PDBG("Relocate %s", obj->name());
|
||||
obj->relocate();
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursive initialization call is not allowed here. This might happend
|
||||
* when Shared_objects (e.g. dlopen and friends) are constructed from within
|
||||
* global constructors (ctors).
|
||||
*/
|
||||
if (in_progress) {
|
||||
restart = true;
|
||||
return;
|
||||
}
|
||||
|
||||
in_progress = true;
|
||||
|
||||
/* call static constructors */
|
||||
obj = first();
|
||||
while (obj) {
|
||||
|
||||
Object *next = obj->next_init();
|
||||
remove(obj);
|
||||
|
||||
if (obj->dynamic()->init_function) {
|
||||
|
||||
if (verbose_relocation)
|
||||
PDBG("%s init func %p", obj->name(), obj->dynamic()->init_function);
|
||||
|
||||
obj->dynamic()->init_function();
|
||||
}
|
||||
|
||||
obj = restart ? first() : next;
|
||||
restart = false;
|
||||
}
|
||||
|
||||
in_progress = false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__INIT_H_ */
|
@ -16,18 +16,20 @@
|
||||
|
||||
#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 <debug.h>
|
||||
#include <elf.h>
|
||||
#include <trace.h>
|
||||
#include <file.h>
|
||||
#include <util.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;
|
||||
@ -35,20 +37,25 @@ constexpr bool verbose_loading = false;
|
||||
/**
|
||||
* Forward declartions and helpers
|
||||
*/
|
||||
namespace Linker
|
||||
{
|
||||
namespace Linker {
|
||||
class Object;
|
||||
struct Phdr;
|
||||
struct File;
|
||||
struct Root_object;
|
||||
struct Dag;
|
||||
struct Dependency;
|
||||
struct Elf_object;
|
||||
struct Dynamic;
|
||||
|
||||
typedef void (*Func)(void);
|
||||
|
||||
/**
|
||||
* Eager binding enable
|
||||
*/
|
||||
extern bool bind_now;
|
||||
|
||||
/**
|
||||
* Find symbol via index
|
||||
*
|
||||
* \param sym_index Symbol index within object
|
||||
* \param dag Directed acyclic graph of object
|
||||
* \param dep Dependency of object
|
||||
* \param base Returned address of symbol
|
||||
* \param undef True, return undefined symbol; False return defined
|
||||
* symbols only
|
||||
@ -59,15 +66,14 @@ namespace Linker
|
||||
*
|
||||
* \return Symbol information
|
||||
*/
|
||||
Elf::Sym const *locate_symbol(unsigned sym_index, Dag const *, Elf::Addr *base,
|
||||
Elf::Sym const *lookup_symbol(unsigned sym_index, Dependency 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 dep Dependency of object
|
||||
* \param base Returned address of symbol
|
||||
* \param undef True, return undefined symbol; False return defined
|
||||
* symbols only
|
||||
@ -78,22 +84,35 @@ namespace Linker
|
||||
*
|
||||
* \return Symbol information
|
||||
*/
|
||||
Elf::Sym const *search_symbol(char const *name, Dag const *dag, Elf::Addr *base,
|
||||
Elf::Sym const *lookup_symbol(char const *name, Dependency const *dep, Elf::Addr *base,
|
||||
bool undef = false, bool other = false);
|
||||
|
||||
/**
|
||||
* Load object
|
||||
* Load an ELF (setup segments and map program header)
|
||||
*
|
||||
* \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
|
||||
* \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
|
||||
*
|
||||
* \return File descriptor
|
||||
* \return Linker::Object
|
||||
*/
|
||||
File const *load(char const *path, bool load = true);
|
||||
Object *load(char const *path, Dependency *dep, unsigned flags = 0);
|
||||
|
||||
/**
|
||||
* Returns the head of the global object list
|
||||
*/
|
||||
Object *obj_list_head();
|
||||
|
||||
/**
|
||||
* Returns the root-dependeny of the dynamic binary
|
||||
*/
|
||||
Dependency *binary_root_dep();
|
||||
|
||||
/**
|
||||
* Force to map the program header of the dynamic linker
|
||||
*/
|
||||
void load_linker_phdr();
|
||||
|
||||
/**
|
||||
* Exceptions
|
||||
@ -102,30 +121,6 @@ namespace Linker
|
||||
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
|
||||
*/
|
||||
@ -134,41 +129,11 @@ namespace Linker
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
/**
|
||||
* Shared object or binary
|
||||
*/
|
||||
class Linker::Object : public Genode::Fifo<Object>::Element,
|
||||
public Genode::List<Object>::Element
|
||||
{
|
||||
protected:
|
||||
|
||||
@ -195,36 +160,103 @@ class Linker::Object : public Genode::Fifo<Object>::Element
|
||||
Elf::Addr reloc_base() const { return _file ? _file->reloc_base : 0; }
|
||||
char const *name() const { return _name; }
|
||||
|
||||
File const *file() { return _file; }
|
||||
File const *file() { return _file; }
|
||||
Elf::Size const size() const { return _file ? _file->size : 0; }
|
||||
|
||||
virtual bool is_linker() const = 0;
|
||||
virtual bool is_binary() const = 0;
|
||||
|
||||
Elf::Size const size() const { return _file ? _file->size : 0; }
|
||||
virtual void relocate() = 0;
|
||||
|
||||
virtual void load() = 0;
|
||||
virtual bool unload() { return false;}
|
||||
|
||||
/**
|
||||
* Next object in global object list
|
||||
*/
|
||||
virtual Object *next_obj() const = 0;
|
||||
|
||||
/**
|
||||
* Next object in initialization list
|
||||
*/
|
||||
virtual Object *next_init() const = 0;
|
||||
|
||||
/**
|
||||
* Return dynamic section of ELF
|
||||
*/
|
||||
virtual Dynamic *dynamic() = 0;
|
||||
|
||||
/**
|
||||
* Return link map for ELF
|
||||
*/
|
||||
virtual Link_map *link_map() = 0;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Linker::Dag : Genode::Fifo<Dag>::Element
|
||||
/**
|
||||
* Dependency of object
|
||||
*/
|
||||
struct Linker::Dependency : Genode::Fifo<Dependency>::Element
|
||||
{
|
||||
Object *obj = nullptr;
|
||||
Object *obj = nullptr;
|
||||
Root_object *root = nullptr;
|
||||
|
||||
Dag(Object *obj, Root_object *root) : obj(obj), root(root) { }
|
||||
Dependency(Object *obj, Root_object *root) : obj(obj), root(root) { }
|
||||
|
||||
Dag(char const *path, Root_object *root, Genode::Fifo<Dag> * const dag,
|
||||
Dependency(char const *path, Root_object *root, Genode::Fifo<Dependency> * const dep,
|
||||
unsigned flags = 0);
|
||||
~Dag();
|
||||
~Dependency();
|
||||
|
||||
void load_needed(Genode::Fifo<Dag> * const dag, unsigned flags = 0);
|
||||
bool in_dag(char const *file, Genode::Fifo<Dag> *const dag);
|
||||
/**
|
||||
* Load dependent ELF object
|
||||
*/
|
||||
void load_needed(Genode::Fifo<Dependency> * const dep, unsigned flags = 0);
|
||||
|
||||
/**
|
||||
* Check if file is in this dependency tree
|
||||
*/
|
||||
bool in_dep(char const *file, Genode::Fifo<Dependency> *const dep);
|
||||
};
|
||||
|
||||
|
||||
static inline bool verbose_reloc(Linker::Dag const *d)
|
||||
/**
|
||||
* Root of dependencies
|
||||
*/
|
||||
struct Linker::Root_object
|
||||
{
|
||||
return d->root && verbose_relocation;
|
||||
}
|
||||
Genode::Fifo<Dependency> dep;
|
||||
|
||||
extern "C" void _jmp_slot(void);
|
||||
/* main root */
|
||||
Root_object() { };
|
||||
|
||||
/* runtime loaded root components */
|
||||
Root_object(char const *path, unsigned flags = 0);
|
||||
|
||||
~Root_object()
|
||||
{
|
||||
Dependency *d;
|
||||
while ((d = dep.dequeue()))
|
||||
destroy(Genode::env()->heap(), d);
|
||||
}
|
||||
|
||||
Link_map const *link_map() const
|
||||
{
|
||||
return dep.head()->obj->link_map();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__LINKER_H_ */
|
||||
|
@ -16,6 +16,19 @@
|
||||
|
||||
#include <linker.h>
|
||||
|
||||
constexpr bool verbose_relocation = false;
|
||||
|
||||
static inline bool verbose_reloc(Linker::Dependency const *d)
|
||||
{
|
||||
return d->root && verbose_relocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Low level linker entry for jump slot relocations
|
||||
*/
|
||||
extern "C" void _jmp_slot(void);
|
||||
|
||||
|
||||
namespace Linker
|
||||
{
|
||||
struct Plt_got;
|
||||
@ -32,12 +45,12 @@ namespace Linker
|
||||
*/
|
||||
struct Linker::Plt_got
|
||||
{
|
||||
Plt_got(Dag const *dag, Elf::Addr *pltgot)
|
||||
Plt_got(Dependency const *dep, Elf::Addr *pltgot)
|
||||
{
|
||||
if (verbose_relocation)
|
||||
PDBG("OBJ: %s (%p)", dag->obj->name(), dag);
|
||||
PDBG("OBJ: %s (%p)", dep->obj->name(), dep);
|
||||
|
||||
pltgot[1] = (Elf::Addr) dag; /* ELF object */
|
||||
pltgot[1] = (Elf::Addr) dep; /* ELF object */
|
||||
pltgot[2] = (Elf::Addr) &_jmp_slot; /* Linker entry */
|
||||
}
|
||||
};
|
||||
@ -78,7 +91,7 @@ class Linker::Reloc_non_plt_generic
|
||||
{
|
||||
protected:
|
||||
|
||||
Dag const *_dag;
|
||||
Dependency const *_dep;
|
||||
|
||||
/**
|
||||
* Copy relocations, these are just for the main program, we can do them
|
||||
@ -88,8 +101,8 @@ class Linker::Reloc_non_plt_generic
|
||||
template <typename REL>
|
||||
void _copy(REL const *rel, Elf::Addr *addr)
|
||||
{
|
||||
if (!_dag->obj->is_binary()) {
|
||||
PERR("LD: Copy relocation in DSO (%s at %p)", _dag->obj->name(), addr);
|
||||
if (!_dep->obj->is_binary()) {
|
||||
PERR("LD: Copy relocation in DSO (%s at %p)", _dep->obj->name(), addr);
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
@ -97,7 +110,7 @@ class Linker::Reloc_non_plt_generic
|
||||
Elf::Addr reloc_base;
|
||||
|
||||
/* search symbol in other objects, do not return undefined symbols */
|
||||
if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base, false, true))) {
|
||||
if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base, false, true))) {
|
||||
PWRN("LD: Symbol not found");
|
||||
return;
|
||||
}
|
||||
@ -112,7 +125,7 @@ class Linker::Reloc_non_plt_generic
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt_generic(Dag const *dag) : _dag(dag) { }
|
||||
Reloc_non_plt_generic(Dependency const *dep) : _dep(dep) { }
|
||||
};
|
||||
|
||||
|
||||
@ -126,7 +139,7 @@ class Linker::Reloc_jmpslot_generic
|
||||
|
||||
public:
|
||||
|
||||
Reloc_jmpslot_generic(Dag const *dag, 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) {
|
||||
@ -138,13 +151,13 @@ class Linker::Reloc_jmpslot_generic
|
||||
Elf::Sym const *sym;
|
||||
Elf::Addr reloc_base;
|
||||
|
||||
if (!(sym = locate_symbol(rel->sym(), dag, &reloc_base))) {
|
||||
if (!(sym = lookup_symbol(rel->sym(), dep, &reloc_base))) {
|
||||
PWRN("LD: Symbol not found");
|
||||
return;
|
||||
}
|
||||
|
||||
/* write address of symbol to jump slot */
|
||||
_addr = (Elf::Addr *)(dag->obj->reloc_base() + rel->offset);
|
||||
_addr = (Elf::Addr *)(dep->obj->reloc_base() + rel->offset);
|
||||
*_addr = reloc_base + sym->st_value;
|
||||
|
||||
|
||||
@ -164,12 +177,12 @@ class Linker::Reloc_jmpslot_generic
|
||||
template <typename REL, unsigned TYPE>
|
||||
struct Linker::Reloc_bind_now_generic
|
||||
{
|
||||
Reloc_bind_now_generic(Dag const *dag, 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);
|
||||
|
||||
for (Elf::Size index = 0; index < last_index; index++)
|
||||
Reloc_jmpslot_generic<REL, TYPE, false> reloc(dag, TYPE, pltrel, index);
|
||||
Reloc_jmpslot_generic<REL, TYPE, false> reloc(dep, TYPE, pltrel, index);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,38 +0,0 @@
|
||||
/**
|
||||
* \brief Trace support for linker intialization
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__TRACE_H_
|
||||
#define _INCLUDE__TRACE_H_
|
||||
|
||||
#if 0
|
||||
typedef Genode::addr_t l4_umword_t;
|
||||
typedef Genode::addr_t l4_addr_t;
|
||||
|
||||
namespace Fiasco {
|
||||
#include <l4/sys/ktrace.h>
|
||||
}
|
||||
#else
|
||||
namespace Fiasco {
|
||||
inline void fiasco_tbuf_log_3val(char const *,unsigned, unsigned, unsigned) { }
|
||||
}
|
||||
extern "C" void wait_for_continue();
|
||||
#endif
|
||||
|
||||
namespace Linker {
|
||||
inline void trace(char const *str, unsigned v1, unsigned v2, unsigned v3)
|
||||
{
|
||||
Fiasco::fiasco_tbuf_log_3val(str, v1, v2, v3);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__TRACE_H_ */
|
44
repos/base/src/lib/ldso/include/util.h
Normal file
44
repos/base/src/lib/ldso/include/util.h
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* \brief Helper functions
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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__UTIL_H_
|
||||
#define _INCLUDE__UTIL_H_
|
||||
|
||||
namespace Linker {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__UTIL_H_ */
|
File diff suppressed because it is too large
Load Diff
121
repos/base/src/lib/ldso/shared_object.cc
Normal file
121
repos/base/src/lib/ldso/shared_object.cc
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* \brief Implentation of Genode's shared-object interface
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-03-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#include <linker.h>
|
||||
|
||||
|
||||
/*************
|
||||
** Helpers **
|
||||
*************/
|
||||
|
||||
static Linker::Root_object *to_root(void *h)
|
||||
{
|
||||
return static_cast<Linker::Root_object *>(h);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Needed during shared object creation and destruction, since global lists are
|
||||
* manipulated
|
||||
*/
|
||||
static Genode::Lock & shared_object_lock()
|
||||
{
|
||||
static Genode::Lock _lock;
|
||||
return _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())
|
||||
return e;
|
||||
|
||||
throw Genode::Address_info::Invalid_address();
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** API **
|
||||
*********/
|
||||
|
||||
Genode::Shared_object::Shared_object(char const *file, unsigned flags)
|
||||
{
|
||||
using namespace Linker;
|
||||
|
||||
if (verbose_shared)
|
||||
PDBG("open '%s'", file ? file : "binary");
|
||||
|
||||
try {
|
||||
Genode::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);
|
||||
} catch (...) { throw Invalid_file(); }
|
||||
}
|
||||
|
||||
|
||||
void *Genode::Shared_object::_lookup(const char *name) const
|
||||
{
|
||||
using namespace Linker;
|
||||
|
||||
if (verbose_shared)
|
||||
PDBG("lookup '%s'", name);
|
||||
|
||||
try {
|
||||
Genode::Lock::Guard guard(Object::lock());
|
||||
|
||||
Elf::Addr base;
|
||||
Root_object *root = to_root(_handle);
|
||||
Elf::Sym const *symbol = lookup_symbol(name, root->dep.head(), &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
|
||||
{
|
||||
return (Link_map const *)to_root(_handle)->link_map();
|
||||
}
|
||||
|
||||
|
||||
Genode::Shared_object::~Shared_object()
|
||||
{
|
||||
using namespace Linker;
|
||||
|
||||
if (verbose_shared)
|
||||
PDBG("close");
|
||||
|
||||
Genode::Lock::Guard guard(shared_object_lock());
|
||||
destroy(Genode::env()->heap(), to_root(_handle));
|
||||
}
|
||||
|
||||
|
||||
Genode::Address_info::Address_info(Genode::addr_t address)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (verbose_shared)
|
||||
PDBG("request: %lx", address);
|
||||
|
||||
Linker::Object *e = find_obj(address);
|
||||
e->info(address, *this);
|
||||
|
||||
if (verbose_shared)
|
||||
PDBG("Found: obj: %s sym: %s addr: %lx", path, name, addr);
|
||||
}
|
||||
|
||||
|
@ -43,36 +43,35 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
Elf::Addr reloc_base;
|
||||
Elf::Sym const *sym;
|
||||
|
||||
if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base)))
|
||||
if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base)))
|
||||
return;
|
||||
|
||||
*addr = (addend ? *addr : 0) + reloc_base + sym->st_value;
|
||||
trace("REL32", (unsigned long)addr, *addr, 0);
|
||||
}
|
||||
|
||||
void _relative(Elf::Rel const *rel, Elf::Addr *addr)
|
||||
{
|
||||
if (_dag->obj->reloc_base())
|
||||
*addr += _dag->obj->reloc_base();
|
||||
if (_dep->obj->reloc_base())
|
||||
*addr += _dep->obj->reloc_base();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt(Dag const *dag, Elf::Rela const *, unsigned long)
|
||||
: Reloc_non_plt_generic(dag)
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rela const *, unsigned long)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
PERR("LD: DT_RELA not supported");
|
||||
trace("Non_plt", 0, 0, 0);
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
Reloc_non_plt(Dag const *dag, Elf::Rel const *rel, unsigned long size, bool second_pass)
|
||||
: Reloc_non_plt_generic(dag)
|
||||
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 *)(_dag->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 +83,7 @@ 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:
|
||||
trace("UNKREL", rel->type(), 0, 0);
|
||||
if (_dag->root) {
|
||||
if (_dep->root) {
|
||||
PWRN("LD: Unkown relocation %u", rel->type());
|
||||
throw Incompatible();
|
||||
}
|
||||
|
@ -44,8 +44,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
*/
|
||||
void _relative(Elf::Rela const *rel, Elf::Addr *addr)
|
||||
{
|
||||
trace("64", _dag->obj->reloc_base(), rel->addend, 0);
|
||||
*addr = _dag->obj->reloc_base() + rel->addend;
|
||||
*addr = _dep->obj->reloc_base() + rel->addend;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,24 +56,24 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
Elf::Addr reloc_base;
|
||||
Elf::Sym const *sym;
|
||||
|
||||
if (!(sym = locate_symbol(rel->sym(), _dag, &reloc_base)))
|
||||
if (!(sym = lookup_symbol(rel->sym(), _dep, &reloc_base)))
|
||||
return;
|
||||
|
||||
*addr = reloc_base + sym->st_value + (addend ? rel->addend : 0);
|
||||
if (verbose_reloc(_dag))
|
||||
if (verbose_reloc(_dep))
|
||||
PDBG("GLOB DAT %p -> %llx r %llx v %llx", addr, *addr, reloc_base,
|
||||
sym->st_value);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt(Dag const *dag, Elf::Rela const *rel, unsigned long size)
|
||||
: Reloc_non_plt_generic(dag)
|
||||
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 *)(_dag->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 +82,7 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
case R_RELATIVE: _relative(rel, addr); break;
|
||||
|
||||
default:
|
||||
trace("UNKRELA", rel->type(), 0, 0);
|
||||
if (!_dag->obj->is_linker()) {
|
||||
if (!_dep->obj->is_linker()) {
|
||||
PWRN("LD: Unkown relocation %u", rel->type());
|
||||
throw Incompatible();
|
||||
}
|
||||
@ -93,8 +91,8 @@ class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
}
|
||||
}
|
||||
|
||||
Reloc_non_plt(Dag const *dag, Elf::Rel const *, unsigned long, bool)
|
||||
: Reloc_non_plt_generic(dag)
|
||||
Reloc_non_plt(Dependency const *dep, Elf::Rel const *, unsigned long, bool)
|
||||
: Reloc_non_plt_generic(dep)
|
||||
{
|
||||
PERR("LD: DT_REL not supported");
|
||||
throw Incompatible();
|
||||
|
Loading…
x
Reference in New Issue
Block a user