diff --git a/repos/base/include/base/shared_object.h b/repos/base/include/base/shared_object.h
new file mode 100644
index 0000000000..68ff4ba941
--- /dev/null
+++ b/repos/base/include/base/shared_object.h
@@ -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
+#include
+
+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 T lookup(const char *symbol) const
+ {
+ return static_cast(_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_ */
diff --git a/repos/base/lib/mk/arm/ld.mk b/repos/base/lib/mk/arm/ld.mk
new file mode 100644
index 0000000000..e189f7d5d3
--- /dev/null
+++ b/repos/base/lib/mk/arm/ld.mk
@@ -0,0 +1,6 @@
+REQUIRES = arm
+
+include $(REP_DIR)/lib/mk/ldso.inc
+
+INC_DIR += $(DIR)/arm
+vpath %.s $(DIR)/arm
diff --git a/repos/os/lib/mk/arm/ldso-startup.mk b/repos/base/lib/mk/arm/ldso-startup.mk
similarity index 100%
rename from repos/os/lib/mk/arm/ldso-startup.mk
rename to repos/base/lib/mk/arm/ldso-startup.mk
diff --git a/repos/os/lib/mk/ldso-startup.mk b/repos/base/lib/mk/ldso-startup.mk
similarity index 100%
rename from repos/os/lib/mk/ldso-startup.mk
rename to repos/base/lib/mk/ldso-startup.mk
diff --git a/repos/base/lib/mk/ldso.inc b/repos/base/lib/mk/ldso.inc
new file mode 100644
index 0000000000..ab0c2fa9a0
--- /dev/null
+++ b/repos/base/lib/mk/ldso.inc
@@ -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
+
diff --git a/repos/base/lib/mk/x86_32/ld.mk b/repos/base/lib/mk/x86_32/ld.mk
new file mode 100644
index 0000000000..4c99f61e28
--- /dev/null
+++ b/repos/base/lib/mk/x86_32/ld.mk
@@ -0,0 +1,6 @@
+REQUIRES = x86 32bit
+
+include $(REP_DIR)/lib/mk/ldso.inc
+
+INC_DIR += $(DIR)/x86_32
+vpath %.s $(DIR)/x86_32
diff --git a/repos/base/lib/mk/x86_64/ld.mk b/repos/base/lib/mk/x86_64/ld.mk
new file mode 100644
index 0000000000..e11a925b7a
--- /dev/null
+++ b/repos/base/lib/mk/x86_64/ld.mk
@@ -0,0 +1,6 @@
+REQUIRES = x86 64bit
+
+include $(REP_DIR)/lib/mk/ldso.inc
+
+INC_DIR += $(DIR)/x86_64
+vpath %.s $(DIR)/x86_64
diff --git a/repos/base/mk/lib.mk b/repos/base/mk/lib.mk
index d51d7a1757..1683d34ff3 100644
--- a/repos/base/mk/lib.mk
+++ b/repos/base/mk/lib.mk
@@ -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
diff --git a/repos/os/src/lib/ldso/README b/repos/base/src/lib/ldso/README
similarity index 54%
rename from repos/os/src/lib/ldso/README
rename to repos/base/src/lib/ldso/README
index 10afb4688b..73b47adaf0 100644
--- a/repos/os/src/lib/ldso/README
+++ b/repos/base/src/lib/ldso/README
@@ -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 '' 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:
+
+!
+!
+!
+!
+!
+!
+
Debugging dynamic binaries with GDB stubs
-----------------------------------------
+! # go to directory containing the binaries
+! cd /bin
+!
! # start GDB with binary to debug
-! gdb
+! gdb
!
! # 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
diff --git a/repos/base/src/lib/ldso/arm/jmp_slot.s b/repos/base/src/lib/ldso/arm/jmp_slot.s
new file mode 100644
index 0000000000..833e4e5358
--- /dev/null
+++ b/repos/base/src/lib/ldso/arm/jmp_slot.s
@@ -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 */
diff --git a/repos/base/src/lib/ldso/arm/relocation.h b/repos/base/src/lib/ldso/arm/relocation.h
new file mode 100644
index 0000000000..fba36fb425
--- /dev/null
+++ b/repos/base/src/lib/ldso/arm/relocation.h
@@ -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
+
+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 Reloc_plt;
+ typedef Reloc_jmpslot_generic Reloc_jmpslot;
+ typedef Reloc_bind_now_generic 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(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_ */
diff --git a/repos/base/src/lib/ldso/file.cc b/repos/base/src/lib/ldso/file.cc
new file mode 100644
index 0000000000..8a523581e0
--- /dev/null
+++ b/repos/base/src/lib/ldso/file.cc
@@ -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
+
+#include
+#include
+#include
+#include
+
+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(placeholder, base);
+ constructed = 1;
+ }
+ return reinterpret_cast(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;
+}
+
diff --git a/repos/base/src/lib/ldso/include/elf.h b/repos/base/src/lib/ldso/include/elf.h
new file mode 100644
index 0000000000..8df92968b8
--- /dev/null
+++ b/repos/base/src/lib/ldso/include/elf.h
@@ -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
+
+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_ */
diff --git a/repos/base/src/lib/ldso/include/linker.h b/repos/base/src/lib/ldso/include/linker.h
new file mode 100644
index 0000000000..bf378e0760
--- /dev/null
+++ b/repos/base/src/lib/ldso/include/linker.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
+#include
+#include
+#include
+#include
+#include
+#include
+
+/**
+ * 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
+ static inline T trunc_page(T addr) {
+ return addr & Genode::_align_mask((T)12); }
+
+ template
+ 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