mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-18 07:08:18 +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:
committed by
Christian Helmuth
parent
e74b53d5dd
commit
41b9f6bd03
@ -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,8 +189,8 @@ 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; }
|
||||
char const *name() const { return _name; }
|
||||
Elf::Addr reloc_base() const { return _reloc_base; }
|
||||
char const *name() const { return _name; }
|
||||
|
||||
File const *file() { return _file; }
|
||||
Elf::Size const size() const { return _file ? _file->size : 0; }
|
||||
@ -168,7 +200,7 @@ class Linker::Object : public Genode::Fifo<Object>::Element,
|
||||
|
||||
virtual void relocate() = 0;
|
||||
|
||||
virtual void load() = 0;
|
||||
virtual void load() = 0;
|
||||
virtual bool unload() { return false;}
|
||||
|
||||
/**
|
||||
|
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);
|
||||
}
|
||||
@ -525,7 +527,7 @@ extern "C" void init_rtld()
|
||||
linker_stack.ref_count++;
|
||||
|
||||
/*
|
||||
* Create actual linker object with different vtable type and set PLT to new
|
||||
* Create actual linker object with different vtable type and set PLT to new
|
||||
* DAG.
|
||||
*/
|
||||
Ld::linker()->dynamic()->plt_setup();
|
||||
@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user