mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 06:33:31 +00:00
ldso: Make truly self relocatable
On Linux the linker can now be loaded at arbitrary addresses, this became necessary for newer kernel versions. The 'linux_arm' target is not supported. Issue #1728
This commit is contained in:
parent
e74b53d5dd
commit
41b9f6bd03
@ -20,12 +20,14 @@
|
||||
|
||||
/*
|
||||
* We cannot just include <semaphore.h> and <pthread.h> here
|
||||
* because this would impy the nested inclusion of a myriad
|
||||
* because this would imply the nested inclusion of a myriad
|
||||
* of Linux types and would pollute the namespace for everyone
|
||||
* who includes this header file. We want to cleanly separate
|
||||
* Genode from POSIX.
|
||||
*/
|
||||
|
||||
extern Genode::addr_t _context_area_start;
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
@ -129,10 +131,11 @@ namespace Genode {
|
||||
* Thread-context area configuration.
|
||||
*
|
||||
* Please update platform-specific files after changing these
|
||||
* values, e.g., 'base-linux/src/platform/context_area.*.ld'.
|
||||
* functions, e.g., 'base-linux/src/ld/context_area.*.ld'.
|
||||
*/
|
||||
static constexpr addr_t context_area_virtual_base() {
|
||||
return 0x40000000UL; }
|
||||
static addr_t context_area_virtual_base() {
|
||||
return align_addr((addr_t)&_context_area_start, 20); }
|
||||
|
||||
static constexpr addr_t context_area_virtual_size() {
|
||||
return 0x10000000UL; }
|
||||
|
||||
|
@ -20,6 +20,9 @@ SECTIONS
|
||||
{
|
||||
. = 0x40000000;
|
||||
_context_area_start = .;
|
||||
.context_area : { . += 0x10000000; } : context_area
|
||||
_context_area_end = .;
|
||||
/*
|
||||
* Since Linux loads ldso page aligned, we align the context area after
|
||||
* loading to a 1 MiB boundary, therefore we reserve one MiB more here.
|
||||
*/
|
||||
.context_area : { . += 0x10100000; } : context_area
|
||||
}
|
||||
|
@ -16,5 +16,4 @@ SECTIONS
|
||||
. = 0x40000000;
|
||||
_context_area_start = .;
|
||||
.context_area : { . += 0x10000000; }
|
||||
_context_area_end = .;
|
||||
}
|
||||
|
@ -19,6 +19,12 @@
|
||||
|
||||
extern "C" int raw_write_str(const char *str);
|
||||
|
||||
/**
|
||||
* Define context area
|
||||
*/
|
||||
Genode::addr_t _context_area_start;
|
||||
|
||||
|
||||
enum { verbose_atexit = false };
|
||||
|
||||
|
||||
|
@ -9,11 +9,18 @@ SRC_CC = main.cc test.cc exception.cc file.cc dependency.cc debug.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/ld/context_area.nostdlib.ld)
|
||||
|
||||
ENTRY_POINT = _start_initial_stack
|
||||
LD_OPT += -T$(call select_from_repositories,src/ld/context_area.nostdlib.ld) \
|
||||
|
||||
ifneq ($(filter x86_32, $(SPECS)),)
|
||||
LD_OPT += -T$(DIR)/linux-32.ld
|
||||
endif
|
||||
|
||||
else
|
||||
ENTRY_POINT = _start
|
||||
LD_OPT += -T$(DIR)/linker.ld
|
||||
endif
|
||||
|
||||
|
@ -42,7 +42,6 @@ void Thread_base::Context::stack_size(size_t const size)
|
||||
/* check if the stack enhancement fits the context region */
|
||||
enum {
|
||||
CONTEXT_SIZE = Native_config::context_virtual_size(),
|
||||
CONTEXT_AREA_BASE = Native_config::context_area_virtual_base(),
|
||||
UTCB_SIZE = sizeof(Native_utcb),
|
||||
PAGE_SIZE_LOG2 = 12,
|
||||
PAGE_SIZE = (1UL << PAGE_SIZE_LOG2),
|
||||
@ -52,7 +51,8 @@ void Thread_base::Context::stack_size(size_t const size)
|
||||
if (stack_base - ds_size < context_base) { throw Stack_too_large(); }
|
||||
|
||||
/* allocate and attach backing store for the stack enhancement */
|
||||
addr_t const ds_addr = stack_base - ds_size - CONTEXT_AREA_BASE;
|
||||
addr_t const ds_addr = stack_base - ds_size -
|
||||
Native_config::context_area_virtual_base();
|
||||
try {
|
||||
Ram_session * const ram = env_context_area_ram_session();
|
||||
Ram_dataspace_capability const ds_cap = ram->alloc(ds_size);
|
||||
|
@ -21,13 +21,6 @@ namespace Linker {
|
||||
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
|
||||
*/
|
||||
@ -108,7 +101,7 @@ struct Linker::Dynamic
|
||||
|
||||
Dynamic(Dependency const *dep)
|
||||
:
|
||||
dep(dep), obj(dep->obj), dynamic((Elf::Dyn *)(obj->reloc_base() + &_DYNAMIC))
|
||||
dep(dep), obj(dep->obj), dynamic((Elf::Dyn *)dynamic_address())
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
@ -34,6 +34,11 @@ constexpr bool verbose_exception = false;
|
||||
constexpr bool verbose_shared = false;
|
||||
constexpr bool verbose_loading = false;
|
||||
|
||||
|
||||
extern const unsigned long _GLOBAL_OFFSET_TABLE_[] __attribute__((visibility("hidden")));
|
||||
extern unsigned long _DYNAMIC[] __attribute__((visibility("hidden")));
|
||||
extern Elf::Addr etext;
|
||||
|
||||
/**
|
||||
* Forward declartions and helpers
|
||||
*/
|
||||
@ -126,6 +131,32 @@ namespace Linker {
|
||||
*/
|
||||
constexpr char const *binary_name() { return "binary"; }
|
||||
constexpr char const *linker_name() { return "ld.lib.so"; }
|
||||
|
||||
/**
|
||||
* Address of .dynamic section in GOT
|
||||
*/
|
||||
static inline unsigned long dynamic_address_got()
|
||||
{
|
||||
return _GLOBAL_OFFSET_TABLE_[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Address of .dynamic section from symbol
|
||||
*/
|
||||
static inline unsigned long dynamic_address()
|
||||
{
|
||||
return (unsigned long)&_DYNAMIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the run-time load address of the shared object.
|
||||
*/
|
||||
static inline unsigned long relocation_address(void)
|
||||
{
|
||||
return dynamic_address() < dynamic_address_got() ?
|
||||
dynamic_address_got() - dynamic_address() :
|
||||
dynamic_address() - dynamic_address_got();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -141,12 +172,13 @@ class Linker::Object : public Genode::Fifo<Object>::Element,
|
||||
|
||||
char _name[MAX_PATH];
|
||||
File const *_file = nullptr;
|
||||
Elf::Addr _reloc_base = 0;
|
||||
|
||||
public:
|
||||
|
||||
Object() { }
|
||||
Object(Elf::Addr reloc_base) : _reloc_base(reloc_base) { }
|
||||
Object(char const *path, File const *file)
|
||||
: _file(file)
|
||||
: _file(file), _reloc_base(file->reloc_base)
|
||||
{
|
||||
Genode::strncpy(_name, Linker::file(path), MAX_PATH);
|
||||
}
|
||||
@ -157,7 +189,7 @@ class Linker::Object : public Genode::Fifo<Object>::Element,
|
||||
destroy(Genode::env()->heap(), const_cast<File *>(_file));
|
||||
}
|
||||
|
||||
Elf::Addr reloc_base() const { return _file ? _file->reloc_base : 0; }
|
||||
Elf::Addr reloc_base() const { return _reloc_base; }
|
||||
char const *name() const { return _name; }
|
||||
|
||||
File const *file() { return _file; }
|
||||
|
20
repos/base/src/lib/ldso/linux-32.ld
Normal file
20
repos/base/src/lib/ldso/linux-32.ld
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* \brief Linker script for Linux
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-12-08
|
||||
*
|
||||
* On Linux 32 bit, we remove the ".text.crt0" section because it contains a
|
||||
* text relocation and is not used as startup code for the dynamic linker.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-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.
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/DISCARD/ : { *(.text.crt0) }
|
||||
}
|
@ -64,7 +64,8 @@ struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element
|
||||
unsigned flags = 0;
|
||||
bool relocated = false;
|
||||
|
||||
Elf_object(Dependency const *dep) : dyn(dep)
|
||||
Elf_object(Dependency const *dep, Elf::Addr reloc_base)
|
||||
: Object(reloc_base), dyn(dep)
|
||||
{ }
|
||||
|
||||
Elf_object(char const *path, Dependency const *dep, unsigned flags = 0)
|
||||
@ -248,7 +249,8 @@ struct Linker::Elf_object : Object, Genode::Fifo<Elf_object>::Element
|
||||
*/
|
||||
struct Linker::Ld : Dependency, Elf_object
|
||||
{
|
||||
Ld() : Dependency(this, nullptr), Elf_object(this)
|
||||
Ld()
|
||||
: Dependency(this, nullptr), Elf_object(this, relocation_address())
|
||||
{
|
||||
Genode::strncpy(_name, linker_name(), Object::MAX_PATH);
|
||||
}
|
||||
@ -569,8 +571,12 @@ int main()
|
||||
|
||||
/* print loaded object information */
|
||||
try {
|
||||
if (Genode::config()->xml_node().attribute("ld_verbose").has_value("yes"))
|
||||
if (Genode::config()->xml_node().attribute("ld_verbose").has_value("yes")) {
|
||||
PINF(" %lx .. %lx: context area", Genode::Native_config::context_area_virtual_base(),
|
||||
Genode::Native_config::context_area_virtual_base() +
|
||||
Genode::Native_config::context_area_virtual_size() - 1);
|
||||
dump_loaded();
|
||||
}
|
||||
} catch (...) { }
|
||||
|
||||
Link_map::dump();
|
||||
|
@ -22,6 +22,8 @@
|
||||
/* program entry-point */
|
||||
.global _start
|
||||
_start:
|
||||
.global _start_initial_stack
|
||||
_start_initial_stack:
|
||||
|
||||
/* make initial value of some registers available to higher-level code */
|
||||
ldr r4, =__initial_sp
|
||||
|
@ -17,6 +17,26 @@
|
||||
** .text (program code) **
|
||||
**************************/
|
||||
|
||||
.section ".text.crt0.ld"
|
||||
|
||||
/* ld.lib.so entry point for Linux */
|
||||
.global _start_initial_stack
|
||||
_start_initial_stack:
|
||||
|
||||
/* set GOT */
|
||||
call 1f
|
||||
1:
|
||||
pop %ebx
|
||||
addl $_GLOBAL_OFFSET_TABLE_ + 1, %ebx
|
||||
|
||||
/* init_rtld relocates the linker */
|
||||
call init_rtld
|
||||
|
||||
/* the address of __initial_sp is now correct */
|
||||
movl %esp, __initial_sp@GOTOFF(%ebx)
|
||||
|
||||
jmp 2f
|
||||
|
||||
.section ".text.crt0"
|
||||
|
||||
/* program entry-point */
|
||||
@ -44,11 +64,16 @@
|
||||
/* if this is the dynamic linker, init_rtld relocates the linker */
|
||||
call init_rtld
|
||||
|
||||
jmp 2f
|
||||
|
||||
.section ".text.crt0.common"
|
||||
2:
|
||||
|
||||
/* create proper environment for the main thread */
|
||||
call init_main_thread
|
||||
|
||||
/* apply environment that was created by init_main_thread */
|
||||
movl init_main_thread_result, %esp
|
||||
movl init_main_thread_result@GOTOFF(%ebx), %esp
|
||||
|
||||
/* clear the base pointer in order that stack backtraces will work */
|
||||
xor %ebp, %ebp
|
||||
|
@ -19,6 +19,22 @@
|
||||
|
||||
.section ".text.crt0"
|
||||
|
||||
/* ld.lib.so entry point for Linux */
|
||||
.global _start_initial_stack
|
||||
_start_initial_stack:
|
||||
|
||||
/* initialize GLOBAL OFFSET TABLE */
|
||||
leaq _GLOBAL_OFFSET_TABLE_(%rip), %r15
|
||||
|
||||
/* init_rtld relocates the linker */
|
||||
call init_rtld
|
||||
|
||||
/* the address of __initial_sp is now correct */
|
||||
movq __initial_sp@GOTPCREL(%rip), %rax
|
||||
movq %rsp, (%rax)
|
||||
|
||||
jmp 1f
|
||||
|
||||
/* program entry-point */
|
||||
.global _start
|
||||
_start:
|
||||
@ -41,9 +57,10 @@
|
||||
leaq _stack_high@GOTPCREL(%rip),%rax
|
||||
movq (%rax), %rsp
|
||||
|
||||
/* if this is the dynamic linker, init_rtld relocates the linker */
|
||||
/* init_rtld relocates the linker */
|
||||
call init_rtld
|
||||
|
||||
1:
|
||||
/* create proper environment for the main thread */
|
||||
call init_main_thread
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user