parent
8738673625
commit
5a821d4c92
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* \brief Dynamic linker interface
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-10-09
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__BASE__SHARED_OBJECT_H_
|
||||
#define _INCLUDE__BASE__SHARED_OBJECT_H_
|
||||
|
||||
#include <base/exception.h>
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Genode {
|
||||
class Shared_object;
|
||||
struct Address_info;
|
||||
};
|
||||
|
||||
class Genode::Shared_object
|
||||
{
|
||||
private:
|
||||
|
||||
void *_handle = nullptr;
|
||||
|
||||
void *_lookup(const char *symbol) const;
|
||||
|
||||
public:
|
||||
|
||||
class Invalid_file : public Genode::Exception { };
|
||||
class Invalid_symbol : public Genode::Exception { };
|
||||
|
||||
enum open_flags {
|
||||
NOW = 0x1,
|
||||
LAZY = 0x2,
|
||||
KEEP = 0x4, /* do not unload on destruction */
|
||||
};
|
||||
|
||||
/**
|
||||
* Load shared object and dependencies
|
||||
*
|
||||
* \param file Shared object to load
|
||||
* \param flags LAZY for lazy function binding, NOW for immediate binding
|
||||
*
|
||||
* \throw Invalid_file
|
||||
*/
|
||||
Shared_object(char const *file = nullptr, unsigned flags = LAZY);
|
||||
|
||||
/**
|
||||
* Close and unload shared object
|
||||
*/
|
||||
~Shared_object();
|
||||
|
||||
/**
|
||||
* Lookup a symbol in shared object and it's dependencies
|
||||
*
|
||||
* \param symbol Symbol name
|
||||
*
|
||||
* \throw Invalid_symbol
|
||||
*
|
||||
* \return Symbol address
|
||||
*/
|
||||
template<typename T = void *> T lookup(const char *symbol) const
|
||||
{
|
||||
return static_cast<T>(_lookup(symbol));
|
||||
}
|
||||
|
||||
/**
|
||||
* Link information
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return link map of shared object
|
||||
*/
|
||||
Link_map const * link_map() const;
|
||||
};
|
||||
|
||||
|
||||
struct Genode::Address_info
|
||||
{
|
||||
char const *path; /* path of shared object */
|
||||
Genode::addr_t base; /* base of shared object */
|
||||
char const *name; /* name of symbol */
|
||||
Genode::addr_t addr; /* address of symbol */
|
||||
|
||||
class Invalid_address : public Genode::Exception { };
|
||||
|
||||
Address_info(Genode::addr_t addr);
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BASE__SHARED_OBJECT_H_ */
|
|
@ -0,0 +1,6 @@
|
|||
REQUIRES = arm
|
||||
|
||||
include $(REP_DIR)/lib/mk/ldso.inc
|
||||
|
||||
INC_DIR += $(DIR)/arm
|
||||
vpath %.s $(DIR)/arm
|
|
@ -0,0 +1,22 @@
|
|||
SHARED_LIB = yes
|
||||
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_S = jmp_slot.s
|
||||
INC_DIR += $(DIR)/include
|
||||
LD_OPT += -Bsymbolic-functions --version-script=$(DIR)/symbol.map
|
||||
ENTRY_POINT = _start
|
||||
|
||||
ifneq ($(filter linux, $(SPECS)),)
|
||||
LD_OPT += -T$(call select_from_repositories,src/platform/context_area.nostdlib.ld)
|
||||
else
|
||||
LD_OPT += -T$(DIR)/linker.ld
|
||||
endif
|
||||
|
||||
vpath %.cc $(DIR)
|
||||
|
||||
# vi:ft=make
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
REQUIRES = x86 32bit
|
||||
|
||||
include $(REP_DIR)/lib/mk/ldso.inc
|
||||
|
||||
INC_DIR += $(DIR)/x86_32
|
||||
vpath %.s $(DIR)/x86_32
|
|
@ -0,0 +1,6 @@
|
|||
REQUIRES = x86 64bit
|
||||
|
||||
include $(REP_DIR)/lib/mk/ldso.inc
|
||||
|
||||
INC_DIR += $(DIR)/x86_64
|
||||
vpath %.s $(DIR)/x86_64
|
|
@ -139,7 +139,7 @@ $(LIB_A): $(OBJECTS)
|
|||
# Don't link base libraries against shared libraries except for ld.lib.so
|
||||
#
|
||||
ifdef SHARED_LIB
|
||||
ifneq ($(LIB),ld)
|
||||
ifneq ($(LIB),$(DYNAMIC_LINKER))
|
||||
override DEPS := $(filter-out $(BASE_LIBS:=.lib),$(DEPS))
|
||||
endif
|
||||
endif
|
||||
|
@ -173,7 +173,7 @@ USED_SO_FILES := $(foreach s,$(USED_SHARED_LIBS),$(LIB_CACHE_DIR)/$s/$s.lib.s
|
|||
#
|
||||
# Don't link ld libary against shared objects
|
||||
#
|
||||
USED_SO_FILES := $(filter-out %ld.lib.so,$(USED_SO_FILES))
|
||||
USED_SO_FILES := $(filter-out %$(DYNAMIC_LINKER).lib.so,$(USED_SO_FILES))
|
||||
|
||||
#
|
||||
# Default entry point of shared libraries
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
This directory contains the port of the dynamic linker (ldso) from FreeBSD.
|
||||
This directory contains Genode's dynamic linker (ldso)
|
||||
|
||||
|
||||
Usage
|
||||
|
@ -11,14 +11,32 @@ declare 'SHARED_LIB = yes' in the library-description file. When doing so, a
|
|||
library, no special precautions are needed. The build system will automatically
|
||||
detect the use of shared libraries, concludes that the binary must be
|
||||
dynamically linked, and will use the correct linker script. When loading a
|
||||
dynamically linked program, the dynamic linker 'lsdo' and all used shared
|
||||
dynamically linked program, the dynamic linker 'ldso.lib.so' and all used shared
|
||||
objects must be loaded as well.
|
||||
|
||||
The linker can be configured through the '<config>' node when loading a dynamic
|
||||
binary. Currently there are to configurations options, 'ld_bind_now="yes"'
|
||||
causes the linker to resolve all symbol references on program loading.
|
||||
'ld_verbose="yes"' outputs library load informations before starting the
|
||||
program.
|
||||
|
||||
Configuration snippet:
|
||||
|
||||
!<!-- bind immediately, no library informations -->
|
||||
!<start name="dynamic_binary">
|
||||
! <resource name="RAM" quantum="1M" />
|
||||
! <config ld_bind_now="yes" ld_verbose="no">
|
||||
! </config>
|
||||
!</start>
|
||||
|
||||
Debugging dynamic binaries with GDB stubs
|
||||
-----------------------------------------
|
||||
|
||||
! # go to directory containing the binaries
|
||||
! cd <build/dir>/bin
|
||||
!
|
||||
! # start GDB with binary to debug
|
||||
! gdb <path to binary>
|
||||
! gdb <binary name>
|
||||
!
|
||||
! # break in main routine
|
||||
! b main
|
||||
|
@ -26,7 +44,7 @@ Debugging dynamic binaries with GDB stubs
|
|||
! # inspect loaded shared libraries
|
||||
! info sharedlibrary
|
||||
!
|
||||
! # load shared symbols of shared libaries
|
||||
! # load shared symbols of shared libraries (if not already loaded)
|
||||
! share
|
||||
!
|
||||
! # from here you can debug within libraries
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* \brief Jump slot entry code for ARM platforms
|
||||
* \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.
|
||||
*/
|
||||
|
||||
.text
|
||||
.globl _jmp_slot
|
||||
.type _jmp_slot,%function
|
||||
/*
|
||||
* stack[0] = RA
|
||||
* ip = &GOT[n+3]
|
||||
* lr = &GOT[2]
|
||||
*/
|
||||
_jmp_slot:
|
||||
|
||||
stmdb sp!,{r0-r4,sl,fp}
|
||||
|
||||
/* retrieve relocation index */
|
||||
sub r1, ip, lr /* r1 = 4 * (n + 1) */
|
||||
sub r1, r1, #4 /* r1 = 4 * n */
|
||||
lsr r1, r1, #2 /* r1 = n */
|
||||
|
||||
ldr r0, [lr, #-4] /* obj pointer from PLOTGOT[1] */
|
||||
mov r4, ip /* safe got location */
|
||||
|
||||
bl jmp_slot /* call linker(obj, index) */
|
||||
|
||||
str r0, [r4] /* save symbol value in GOT */
|
||||
mov ip, r0
|
||||
ldmia sp!,{r0-r4,sl,fp,lr} /* restore the stack */
|
||||
mov pc, ip /* jump to symbol address */
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* \brief ARM specific relocations
|
||||
* \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__ARM__RELOCATION_H_
|
||||
#define _INCLUDE__ARM__RELOCATION_H_
|
||||
|
||||
#include <relocation_generic.h>
|
||||
|
||||
namespace Linker {
|
||||
enum Reloc_types {
|
||||
R_ABS32 = 2,
|
||||
R_REL32 = 3,
|
||||
R_COPY = 20,
|
||||
R_GLOB_DAT = 21,
|
||||
R_JMPSLOT = 22,
|
||||
R_RELATIVE = 23,
|
||||
};
|
||||
|
||||
class Reloc_non_plt;
|
||||
|
||||
typedef Reloc_plt_generic<Elf::Rel, DT_REL, R_JMPSLOT> Reloc_plt;
|
||||
typedef Reloc_jmpslot_generic<Elf::Rel, DT_REL, false> Reloc_jmpslot;
|
||||
typedef Reloc_bind_now_generic<Elf::Rel, DT_REL> Reloc_bind_now;
|
||||
};
|
||||
|
||||
|
||||
class Linker::Reloc_non_plt : public Reloc_non_plt_generic
|
||||
{
|
||||
private:
|
||||
|
||||
void _rel32(Elf::Rel const *rel, Elf::Addr *addr)
|
||||
{
|
||||
Elf::Addr reloc_base;
|
||||
Elf::Sym const *sym;
|
||||
|
||||
if (!(sym = locate_symbol(rel->sym(), _dag, &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)
|
||||
{
|
||||
Elf::Addr reloc_base;
|
||||
Elf::Sym const *sym;
|
||||
|
||||
if (!(sym = locate_symbol(rel->sym(), _dag, &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)
|
||||
{
|
||||
/*
|
||||
* This ommits the linker and the binary, the linker has relative
|
||||
* 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();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt(Dag const *dag, Elf::Rela const *, unsigned long)
|
||||
: Reloc_non_plt_generic(dag)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Elf::Rel const *end = rel + (size / sizeof(Elf::Rel));
|
||||
for (; rel < end; rel++) {
|
||||
Elf::Addr *addr = (Elf::Addr *)(_dag->obj->reloc_base() + rel->offset);
|
||||
|
||||
if (second_pass && rel->type() != R_GLOB_DAT)
|
||||
continue;
|
||||
|
||||
switch (rel->type()) {
|
||||
|
||||
case R_REL32 : _rel32(rel, addr); break;
|
||||
case R_COPY : _copy<Elf::Rel>(rel, addr); break;
|
||||
case R_ABS32 :
|
||||
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) {
|
||||
PWRN("LD: Unkown relocation %u", rel->type());
|
||||
throw Incompatible();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__ARM__RELOCATION_H_ */
|
|
@ -0,0 +1,307 @@
|
|||
/**
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#include <linker.h>
|
||||
|
||||
#include <base/allocator_avl.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
#include <rm_session/connection.h>
|
||||
#include <util/construct_at.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 Rm_connection
|
||||
{
|
||||
private:
|
||||
|
||||
/* size of dataspace */
|
||||
enum { RESERVATION = 160 * 1024 * 1024 };
|
||||
|
||||
addr_t _base; /* base address of dataspace */
|
||||
Allocator_avl _range; /* VM range allocator */
|
||||
|
||||
protected:
|
||||
|
||||
Rm_area(addr_t base)
|
||||
: Rm_connection(0, RESERVATION), _range(env()->heap())
|
||||
{
|
||||
on_destruction(KEEP_OPEN);
|
||||
|
||||
_base = (addr_t) env()->rm_session()->attach_at(dataspace(), base);
|
||||
_range.add_range(base, RESERVATION);
|
||||
}
|
||||
|
||||
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).is_error()))
|
||||
throw Region_conflict();
|
||||
else if (!addr && _range.alloc_aligned(size, (void **)&addr, 12).is_error())
|
||||
throw Region_conflict();
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void free_region(addr_t vaddr) { _range.free((void *)vaddr); }
|
||||
|
||||
/**
|
||||
* Overwritten from 'Rm_connection'
|
||||
*/
|
||||
Local_addr attach_at(Dataspace_capability ds, addr_t local_addr,
|
||||
size_t size = 0, off_t offset = 0) {
|
||||
return Rm_connection::attach_at(ds, local_addr - _base, size, offset); }
|
||||
|
||||
/**
|
||||
* Overwritten from 'Rm_connection'
|
||||
*/
|
||||
Local_addr attach_executable(Dataspace_capability ds, addr_t local_addr,
|
||||
size_t size = 0, off_t offset = 0) {
|
||||
return Rm_connection::attach_executable(ds, local_addr - _base, size, offset); }
|
||||
|
||||
void detach(Local_addr local_addr) {
|
||||
Rm_connection::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) {
|
||||
PERR("LD: binary is not an ELF");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ehdr->e_ident[EI_CLASS] != ELFCLASS) {
|
||||
PERR("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)) {
|
||||
PERR("LD: Unsupported alignment %p", (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)
|
||||
PDBG("reloc_base: " EFMT " start: " EFMT " end: " EFMT,
|
||||
reloc_base, start, 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 {
|
||||
PERR("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)
|
||||
PDBG("loading: %s (PHDRS only: %s)", path, load ? "no" : "yes");
|
||||
|
||||
Elf_file *file = new(env()->heap()) Elf_file(Linker::file(path), load);
|
||||
return file;
|
||||
}
|
||||
|
|
@ -0,0 +1,458 @@
|
|||
/**
|
||||
* \brief ELF binary definitions
|
||||
* \author Christian Helmuth
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-05-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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__ELF_H_
|
||||
#define _INCLUDE__ELF_H_
|
||||
|
||||
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Linker {
|
||||
|
||||
/* standard ELF types. */
|
||||
|
||||
/* type for a 16-bit quantity. */
|
||||
typedef genode_uint16_t Elf32_Half;
|
||||
typedef genode_uint16_t Elf64_Half;
|
||||
|
||||
/* types for signed and unsigned 32-bit quantities */
|
||||
typedef genode_uint32_t Elf32_Word;
|
||||
typedef genode_int32_t Elf32_Sword;
|
||||
typedef genode_uint32_t Elf64_Word;
|
||||
typedef genode_int32_t Elf64_Sword;
|
||||
|
||||
/* types for signed and unsigned 64-bit quantities */
|
||||
typedef genode_uint64_t Elf32_Xword;
|
||||
typedef genode_int64_t Elf32_Sxword;
|
||||
typedef genode_uint64_t Elf64_Xword;
|
||||
typedef genode_int64_t Elf64_Sxword;
|
||||
|
||||
/* type of addresses */
|
||||
typedef genode_uint32_t Elf32_Addr;
|
||||
typedef genode_uint64_t Elf64_Addr;
|
||||
|
||||
/* type of file offsets */
|
||||
typedef genode_uint32_t Elf32_Off;
|
||||
typedef genode_uint64_t Elf64_Off;
|
||||
|
||||
/* type for section indices, which are 16-bit quantities */
|
||||
typedef genode_uint16_t Elf32_Section;
|
||||
typedef genode_uint16_t Elf64_Section;
|
||||
|
||||
/* type for version symbol information */
|
||||
typedef Elf32_Half Elf32_Versym;
|
||||
typedef Elf64_Half Elf64_Versym;
|
||||
|
||||
/**
|
||||
* Fields in the e_ident array of ELF file header The EI_* macros are indices
|
||||
* into the array. The macros under each EI_* macro are the values the byte
|
||||
* may have.
|
||||
*/
|
||||
enum {
|
||||
EI_NIDENT = 16, /* size of e_ident array in ELF header */
|
||||
|
||||
EI_MAG0 = 0, /* file identification byte 0 index */
|
||||
ELFMAG0 = 0x7f, /* magic number byte 0 */
|
||||
|
||||
EI_MAG1 = 1, /* file identification byte 1 index */
|
||||
ELFMAG1 = 'E', /* magic number byte 1 */
|
||||
|
||||
EI_MAG2 = 2, /* file identification byte 2 index */
|
||||
ELFMAG2 = 'L', /* magic number byte 2 */
|
||||
|
||||
EI_MAG3 = 3, /* file identification byte 3 index */
|
||||
ELFMAG3 = 'F', /* magic number byte 3 */
|
||||
};
|
||||
|
||||
/**
|
||||
* Conglomeration of the identification bytes, for easy testing as a word
|
||||
*/
|
||||
extern const char *ELFMAG;
|
||||
|
||||
enum {
|
||||
SELFMAG = 4,
|
||||
|
||||
EI_CLASS = 4, /* file class byte index */
|
||||
ELFCLASSNONE = 0, /* invalid class */
|
||||
ELFCLASS32 = 1, /* 32-bit objects */
|
||||
ELFCLASS64 = 2, /* 64-bit objects */
|
||||
ELFCLASSNUM = 3,
|
||||
|
||||
EI_DATA = 5, /* data encoding byte index */
|
||||
ELFDATANONE = 0, /* invalid data encoding */
|
||||
ELFDATA2LSB = 1, /* 2's complement, little endian */
|
||||
ELFDATA2MSB = 2, /* 2's complement, big endian */
|
||||
ELFDATANUM = 3,
|
||||
|
||||
EI_ABIVERSION = 8, /* ABI version */
|
||||
|
||||
EI_PAD = 9, /* byte index of padding bytes */
|
||||
};
|
||||
|
||||
/**
|
||||
* Legal values for e_type (object file type)
|
||||
*/
|
||||
enum {
|
||||
ET_NONE = 0, /* no file type */
|
||||
ET_EXEC = 2, /* executable file */
|
||||
ET_DYN = 3, /* shared object file */
|
||||
};
|
||||
|
||||
/**
|
||||
* Legal values for e_machine (architecture)
|
||||
*/
|
||||
enum {
|
||||
EM_NONE = 0, /* no machine */
|
||||
EM_386 = 3, /* intel 80386 */
|
||||
};
|
||||
|
||||
/**
|
||||
* Legal values for e_version (version)
|
||||
*/
|
||||
enum {
|
||||
EV_NONE = 0, /* invalid ELF version */
|
||||
EV_CURRENT = 1, /* current version */
|
||||
EV_NUM = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Legal values for p_type (segment type)
|
||||
*/
|
||||
enum {
|
||||
PT_NULL = 0, /* program header table entry unused */
|
||||
PT_LOAD = 1, /* loadable program segment */
|
||||
PT_DYNAMIC = 2, /* dynamic linking information */
|
||||
PT_INTERP = 3, /* program interpreter */
|
||||
PT_NOTE = 4, /* auxiliary information */
|
||||
PT_SHLIB = 5, /* reserved */
|
||||
PT_PHDR = 6, /* entry for header table itself */
|
||||
PT_TLS = 7, /* thread-local storage segment */
|
||||
PT_NUM = 8, /* number of defined types */
|
||||
PT_LOOS = 0x60000000, /* start of OS-specific */
|
||||
PT_GNU_EH_FRAME = 0x6474e550, /* gcc .eh_frame_hdr segment */
|
||||
PT_GNU_STACK = 0x6474e551, /* indicates stack executability */
|
||||
PT_GNU_RELRO = 0x6474e552, /* read-only after relocation */
|
||||
PT_LOPROC = 0x70000000, /* first processor-specific type */
|
||||
PT_ARM_EXIDX = 0x70000001, /* location of exception tables */
|
||||
PT_HIPROC = 0x7fffffff, /* last processor-specific type */
|
||||
};
|
||||
|
||||
/**
|
||||
* Legal values for p_flags (segment flags)
|
||||
*/
|
||||
enum {
|
||||
PF_X = (1 << 0), /* segment is executable */
|
||||
PF_W = (1 << 1), /* segment is writable */
|
||||
PF_R = (1 << 2), /* segment is readable */
|
||||
PF_MASK = 0x7,
|
||||
};
|
||||
|
||||
/**
|
||||
* Tag value for Elf::Dyn
|
||||
*/
|
||||
enum D_tag
|
||||
{
|
||||
DT_NULL = 0,
|
||||
DT_NEEDED = 1, /* dependend libraries */
|
||||
DT_PLTRELSZ = 2, /* size of PLT relocations */
|
||||
DT_PLTGOT = 3, /* processor dependent address */
|
||||
DT_HASH = 4, /* address of symbol hash table */
|
||||
DT_STRTAB = 5, /* string table */
|
||||
DT_SYMTAB = 6, /* address of symbol table */
|
||||
DT_RELA = 7, /* ELF relocation with addend */
|
||||
DT_RELASZ = 8, /* total size of RELA reolcations */
|
||||
DT_STRSZ = 10, /* size of string table */
|
||||
DT_INIT = 12, /* ctors */
|
||||
DT_REL = 17, /* address of Elf::Rel relocations */
|
||||
DT_RELSZ = 18, /* sizof Elf::Rel relocation */
|
||||
DT_PLTREL = 20, /* PLT relcation */
|
||||
DT_DEBUG = 21, /* debug structure location */
|
||||
DT_JMPREL = 23, /* address of PLT relocation */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Symbol table
|
||||
*/
|
||||
enum Symbol_table {
|
||||
/* Termination symbol for hash chains */
|
||||
STN_UNDEF = 0,
|
||||
|
||||
/* Bindings */
|
||||
STB_LOCAL = 0, /* local symbol */
|
||||
STB_WEAK = 2, /* weak symbol */
|
||||
|
||||
/* Types */
|
||||
STT_NOTYPE = 0, /* type unspecified */
|
||||
STT_OBJECT = 1, /* data */
|
||||
STT_FUNC = 2, /* function */
|
||||
|
||||
/* Section table index */
|
||||
SHN_UNDEF = 0, /* undefined */
|
||||
SHN_COMMON = 0xfff2, /* common data */
|
||||
};
|
||||
|
||||
|
||||
/********************************
|
||||
** 32-Bit non-POD definitions **
|
||||
********************************/
|
||||
|
||||
namespace Elf32 {
|
||||
|
||||
typedef Elf32_Addr Addr;
|
||||
typedef Elf32_Word Hashelt;
|
||||
typedef Elf32_Word Size;
|
||||
typedef Elf32_Half Half;
|
||||
|
||||
/**
|
||||
* The ELF file header
|
||||
*/
|
||||
struct Ehdr
|
||||
{
|
||||
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
|
||||
Elf32_Half e_type; /* Object file type */
|
||||
Elf32_Half e_machine; /* Architecture */
|
||||
Elf32_Word e_version; /* Object file version */
|
||||
Elf32_Addr e_entry; /* Entry point virtual address */
|
||||
Elf32_Off e_phoff; /* Program header table file offset */
|
||||
Elf32_Off e_shoff; /* Section header table file offset */
|
||||
Elf32_Word e_flags; /* Processor-specific flags */
|
||||
Elf32_Half e_ehsize; /* ELF header size in bytes */
|
||||
Elf32_Half e_phentsize; /* Program header table entry size */
|
||||
Elf32_Half e_phnum; /* Program header table entry count */
|
||||
Elf32_Half e_shentsize; /* Section header table entry size */
|
||||
Elf32_Half e_shnum; /* Section header table entry count */
|
||||
Elf32_Half e_shstrndx; /* Section header string table index */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Program segment header
|
||||
*/
|
||||
struct Phdr
|
||||
{
|
||||
Elf32_Word p_type; /* segment type */
|
||||
Elf32_Off p_offset; /* segment file offset */
|
||||
Elf32_Addr p_vaddr; /* segment virtual address */
|
||||
Elf32_Addr p_paddr; /* segment physical address */
|
||||
Elf32_Word p_filesz; /* segment size in file */
|
||||
Elf32_Word p_memsz; /* segment size in memory */
|
||||
Elf32_Word p_flags; /* segment flags */
|
||||
Elf32_Word p_align; /* segment alignment */
|
||||
};
|
||||
|
||||
/**
|
||||
* Dynamic structure (section .dynamic)
|
||||
*/
|
||||
struct Dyn
|
||||
{
|
||||
Elf32_Sword tag; /* entry type */
|
||||
union {
|
||||
Elf32_Word val; /* integer value */
|
||||
Elf32_Addr ptr; /* address value */
|
||||
} un;
|
||||
};
|
||||
|
||||
/**
|
||||
* Relocation
|
||||
*/
|
||||
struct Rel
|
||||
{
|
||||
Elf32_Addr offset; /* location to be relocated */
|
||||
Elf32_Word info; /* relocation type and symbol index */
|
||||
|
||||
/**
|
||||
* Relocation type
|
||||
*/
|
||||
int type() const { return info & 0xff; }
|
||||
|
||||
/**
|
||||
* Symbol table index
|
||||
*/
|
||||
unsigned sym() const { return info >> 8; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Relocations that need an addend field
|
||||
*/
|
||||
struct Rela
|
||||
{
|
||||
Elf32_Addr r_offset; /* location to be relocated */
|
||||
Elf32_Word r_info; /* relocation type and symbol index */
|
||||
Elf32_Sword r_addend; /* addend */
|
||||
};
|
||||
|
||||
/**
|
||||
* Symbol table entry
|
||||
*/
|
||||
struct Sym
|
||||
{
|
||||
Elf32_Word st_name; /* string table index of name */
|
||||
Elf32_Addr st_value; /* symbol value */
|
||||
Elf32_Word st_size; /* size of associated object */
|
||||
unsigned char st_info; /* type and binding information */
|
||||
unsigned char st_other; /* reserved (not used) */
|
||||
Elf32_Half st_shndx; /* section index of symbol */
|
||||
|
||||
/**
|
||||
* Binding information
|
||||
*/
|
||||
unsigned char bind() const { return st_info >> 4; }
|
||||
|
||||
/**
|
||||
* Type information
|
||||
*/
|
||||
unsigned char type() const { return st_info & 0xf; }
|
||||
|
||||
/**
|
||||
* Check for weak symbol
|
||||
*/
|
||||
bool weak() const { return bind() == STB_WEAK; }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/********************************
|
||||
** 64-Bit non-POD definitions **
|
||||
********************************/
|
||||
|
||||
namespace Elf64 {
|
||||
|
||||
typedef Elf64_Addr Addr;
|
||||
typedef Elf64_Word Hashelt;
|
||||
typedef Elf64_Xword Size;
|
||||
typedef Elf64_Half Half;
|
||||
|
||||
/**
|
||||
* ELF header
|
||||
*/
|
||||
struct Ehdr
|
||||
{
|
||||
unsigned char e_ident[EI_NIDENT]; /* magic number and other info */
|
||||
Elf64_Half e_type; /* object file type */
|
||||
Elf64_Half e_machine; /* architecture */
|
||||
Elf64_Word e_version; /* object file version */
|
||||
Elf64_Addr e_entry; /* entry point virtual address */
|
||||
Elf64_Off e_phoff; /* program header table file offset */
|
||||
Elf64_Off e_shoff; /* section header table file offset */
|
||||
Elf64_Word e_flags; /* processor-specific flags */
|
||||
Elf64_Half e_ehsize; /* eLF header size in bytes */
|
||||
Elf64_Half e_phentsize; /* program header table entry size */
|
||||
Elf64_Half e_phnum; /* program header table entry count */
|
||||
Elf64_Half e_shentsize; /* section header table entry size */
|
||||
Elf64_Half e_shnum; /* section header table entry count */
|
||||
Elf64_Half e_shstrndx; /* section header string table index */
|
||||
};
|
||||
|
||||
/**
|
||||
* Program header
|
||||
*/
|
||||
struct Phdr
|
||||
{
|
||||
Elf64_Word p_type; /* segment type */
|
||||
Elf64_Word p_flags; /* segment flags */
|
||||
Elf64_Off p_offset; /* segment file offset */
|
||||
Elf64_Addr p_vaddr; /* segment virtual address */
|
||||
Elf64_Addr p_paddr; /* segment physical address */
|
||||
Elf64_Xword p_filesz; /* segment size in file */
|
||||
Elf64_Xword p_memsz; /* segment size in memory */
|
||||
Elf64_Xword p_align; /* segment alignment */
|
||||
};
|
||||
|
||||
/**
|
||||
* Dynamic structure (section .dynamic)
|
||||
*/
|
||||
struct Dyn
|
||||
{
|
||||
Elf64_Sxword tag; /* entry type. */
|
||||
union
|
||||
{
|
||||
Elf64_Xword val; /* integer value. */
|
||||
Elf64_Addr ptr; /* address value. */
|
||||
} un;
|
||||
};
|
||||
|
||||
/**
|
||||
* Relocation
|
||||
*/
|
||||
struct Rel
|
||||
{
|
||||
Elf64_Addr r_offset; /* location to be relocated. */
|
||||
Elf64_Xword r_info; /* relocation type and symbol index. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Relocations that need an addend field
|
||||
*/
|
||||
struct Rela
|
||||
{
|
||||
Elf64_Addr offset; /* location to be relocated */
|
||||
Elf64_Xword info; /* relocation type and symbol index */
|
||||
Elf64_Sxword addend; /* addend */
|
||||
|
||||
/**
|
||||
* Relocation type
|
||||
*/
|
||||
int type() const { return info & 0xffffffffL; }
|
||||
|
||||
/**
|
||||
* Symbol table index
|
||||
*/
|
||||
unsigned sym() const { return (info >> 16) >> 16; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Symbol table entry
|
||||
*/
|
||||
struct Sym
|
||||
{
|
||||
Elf64_Word st_name; /* string table index of name */
|
||||
unsigned char st_info; /* type and binding information */
|
||||
unsigned char st_other; /* reserved (not used) */
|
||||
Elf64_Half st_shndx; /* section index of symbol */
|
||||
Elf64_Addr st_value; /* symbol value */
|
||||
Elf64_Xword st_size; /* size of associated object */
|
||||
|
||||
/**
|
||||
* Binding information
|
||||
*/
|
||||
unsigned char bind() const { return st_info >> 4; }
|
||||
|
||||
/**
|
||||
* Type information
|
||||
*/
|
||||
unsigned char type() const { return st_info & 0xf; }
|
||||
|
||||
/**
|
||||
* Check for weak symbol
|
||||
*/
|
||||
bool weak() const { return bind() == STB_WEAK; }
|
||||
};
|
||||
} /* namespace Elf64 */
|
||||
} /* namespace Linker" */
|
||||
|
||||
/**
|
||||
* Define bit-width independent types
|
||||
*/
|
||||
#ifdef __x86_64__
|
||||
namespace Elf = Linker::Elf64;
|
||||
#define ELFCLASS ELFCLASS64
|
||||
#define EFMT "%llx"
|
||||
#else
|
||||
namespace Elf = Linker::Elf32;
|
||||
#define ELFCLASS ELFCLASS32
|
||||
#define EFMT "%x"
|
||||
#endif /* _LP64 */
|
||||
|
||||
#endif /* _INCLUDE__ELF_H_ */
|
|
@ -0,0 +1,230 @@
|
|||
/**
|
||||
* \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_ */
|
|
@ -0,0 +1,176 @@
|
|||
/**
|
||||
* \brief Generic relocation classes
|
||||
* \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__RELOCATION_GENERIC_H_
|
||||
#define _INCLUDE__RELOCATION_GENERIC_H_
|
||||
|
||||
#include <linker.h>
|
||||
|
||||
namespace Linker
|
||||
{
|
||||
struct Plt_got;
|
||||
template <typename REL, unsigned TYPE, bool DIV> class Reloc_jmpslot_generic;
|
||||
template <typename REL, unsigned TYPE, unsigned JMPSLOT> struct Reloc_plt_generic;
|
||||
template <typename REL, unsigned TYPE> struct Reloc_bind_now_generic;
|
||||
class Reloc_non_plt_generic;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set 2nd and 3rd GOT entry (see: SYSTEM V APPLICATION BINARY INTERFACE
|
||||
* Intel386 Architecture Processor Supplement - 5.9
|
||||
*/
|
||||
struct Linker::Plt_got
|
||||
{
|
||||
Plt_got(Dag const *dag, Elf::Addr *pltgot)
|
||||
{
|
||||
if (verbose_relocation)
|
||||
PDBG("OBJ: %s (%p)", dag->obj->name(), dag);
|
||||
|
||||
pltgot[1] = (Elf::Addr) dag; /* ELF object */
|
||||
pltgot[2] = (Elf::Addr) &_jmp_slot; /* Linker entry */
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* PLT relocations
|
||||
*/
|
||||
template<typename REL, unsigned TYPE, unsigned JMPSLOT>
|
||||
struct Linker::Reloc_plt_generic
|
||||
{
|
||||
Reloc_plt_generic(Object const *obj, D_tag const type,
|
||||
Elf::Rel const *start, unsigned long size)
|
||||
{
|
||||
if (type != TYPE) {
|
||||
PERR("LD: Unsupported PLT relocation type: %u", type);
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
REL const *rel = (REL const *)start;
|
||||
REL const *end = rel + (size / sizeof(REL));
|
||||
for (; rel < end; rel++) {
|
||||
|
||||
if (rel->type() != JMPSLOT) {
|
||||
PERR("LD: Unsupported PLT relocation %u", 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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Linker::Reloc_non_plt_generic
|
||||
{
|
||||
protected:
|
||||
|
||||
Dag const *_dag;
|
||||
|
||||
/**
|
||||
* Copy relocations, these are just for the main program, we can do them
|
||||
* safely here since all other DSO are loaded, relocated, and constructed at
|
||||
* this point
|
||||
*/
|
||||
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);
|
||||
throw Incompatible();
|
||||
}
|
||||
|
||||
Elf::Sym const *sym;
|
||||
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))) {
|
||||
PWRN("LD: Symbol not found");
|
||||
return;
|
||||
}
|
||||
|
||||
Elf::Addr src = reloc_base + sym->st_value;
|
||||
Genode::memcpy(addr, (void *)src, sym->st_size);
|
||||
|
||||
if (verbose_relocation)
|
||||
PDBG("Copy relocation: " EFMT " -> %p (0x" EFMT " bytes) val: " EFMT "\n",
|
||||
src, addr, sym->st_size, sym->st_value);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reloc_non_plt_generic(Dag const *dag) : _dag(dag) { }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generic jmp slot handling
|
||||
*/
|
||||
template <typename REL, unsigned TYPE, bool DIV>
|
||||
class Linker::Reloc_jmpslot_generic
|
||||
{
|
||||
Elf::Addr *_addr = 0;
|
||||
|
||||