diff --git a/repos/base-linux/include/base/native_types.h b/repos/base-linux/include/base/native_types.h index 3f99ab4fd..da9b9d171 100644 --- a/repos/base-linux/include/base/native_types.h +++ b/repos/base-linux/include/base/native_types.h @@ -20,12 +20,14 @@ /* * We cannot just include and 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; } diff --git a/repos/base-linux/src/ld/context_area.nostdlib.ld b/repos/base-linux/src/ld/context_area.nostdlib.ld index a88f4b4e5..2496139d4 100644 --- a/repos/base-linux/src/ld/context_area.nostdlib.ld +++ b/repos/base-linux/src/ld/context_area.nostdlib.ld @@ -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 } diff --git a/repos/base-linux/src/ld/context_area.stdlib.ld b/repos/base-linux/src/ld/context_area.stdlib.ld index 45d147668..b846c154c 100644 --- a/repos/base-linux/src/ld/context_area.stdlib.ld +++ b/repos/base-linux/src/ld/context_area.stdlib.ld @@ -16,5 +16,4 @@ SECTIONS . = 0x40000000; _context_area_start = .; .context_area : { . += 0x10000000; } - _context_area_end = .; } diff --git a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc index ba8241ded..5eb3ddb26 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -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 }; diff --git a/repos/base/lib/mk/ldso.inc b/repos/base/lib/mk/ldso.inc index 4b11c3181..1ae57f3ea 100644 --- a/repos/base/lib/mk/ldso.inc +++ b/repos/base/lib/mk/ldso.inc @@ -9,12 +9,19 @@ 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 -LD_OPT += -T$(DIR)/linker.ld +ENTRY_POINT = _start +LD_OPT += -T$(DIR)/linker.ld endif vpath %.cc $(DIR) diff --git a/repos/base/src/base/thread/thread.cc b/repos/base/src/base/thread/thread.cc index 3a6a06c2d..9ff2713cd 100644 --- a/repos/base/src/base/thread/thread.cc +++ b/repos/base/src/base/thread/thread.cc @@ -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); diff --git a/repos/base/src/lib/ldso/include/dynamic.h b/repos/base/src/lib/ldso/include/dynamic.h index d11576fdb..354617105 100644 --- a/repos/base/src/lib/ldso/include/dynamic.h +++ b/repos/base/src/lib/ldso/include/dynamic.h @@ -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(); } diff --git a/repos/base/src/lib/ldso/include/linker.h b/repos/base/src/lib/ldso/include/linker.h index ccc6c4b9a..f0f7e2f84 100644 --- a/repos/base/src/lib/ldso/include/linker.h +++ b/repos/base/src/lib/ldso/include/linker.h @@ -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::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::Element, destroy(Genode::env()->heap(), const_cast(_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::Element, virtual void relocate() = 0; - virtual void load() = 0; + virtual void load() = 0; virtual bool unload() { return false;} /** diff --git a/repos/base/src/lib/ldso/linux-32.ld b/repos/base/src/lib/ldso/linux-32.ld new file mode 100644 index 000000000..4e1d54bd6 --- /dev/null +++ b/repos/base/src/lib/ldso/linux-32.ld @@ -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) } +} diff --git a/repos/base/src/lib/ldso/main.cc b/repos/base/src/lib/ldso/main.cc index 0787bbad3..110f4d826 100644 --- a/repos/base/src/lib/ldso/main.cc +++ b/repos/base/src/lib/ldso/main.cc @@ -64,7 +64,8 @@ struct Linker::Elf_object : Object, Genode::Fifo::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::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(); diff --git a/repos/base/src/lib/startup/spec/arm/crt0.s b/repos/base/src/lib/startup/spec/arm/crt0.s index 704980ade..2444dea7e 100644 --- a/repos/base/src/lib/startup/spec/arm/crt0.s +++ b/repos/base/src/lib/startup/spec/arm/crt0.s @@ -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 diff --git a/repos/base/src/lib/startup/spec/x86_32/crt0.s b/repos/base/src/lib/startup/spec/x86_32/crt0.s index 9b1dbd86c..fd37573cc 100644 --- a/repos/base/src/lib/startup/spec/x86_32/crt0.s +++ b/repos/base/src/lib/startup/spec/x86_32/crt0.s @@ -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 diff --git a/repos/base/src/lib/startup/spec/x86_64/crt0.s b/repos/base/src/lib/startup/spec/x86_64/crt0.s index 0a2392d32..dc6a10906 100644 --- a/repos/base/src/lib/startup/spec/x86_64/crt0.s +++ b/repos/base/src/lib/startup/spec/x86_64/crt0.s @@ -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