diff --git a/repos/base/src/lib/ldso/README b/repos/base/src/lib/ldso/README index 73b47adaf..10776d822 100644 --- a/repos/base/src/lib/ldso/README +++ b/repos/base/src/lib/ldso/README @@ -15,10 +15,9 @@ 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. +binary. The configuration option 'ld_bind_now="yes"' prompts the linker to +resolve all symbol references on program loading. 'ld_verbose="yes"' outputs +library load information before starting the program. Configuration snippet: @@ -29,6 +28,21 @@ Configuration snippet: ! ! +Preloading libraries +-------------------- + +The dynamic linker supports the preloading of libraries according to its +configuration. The list of libraries must be specified within an '' +sub node of the configuration: + +! +! ... +! +! +! +! ... +! + Debugging dynamic binaries with GDB stubs ----------------------------------------- diff --git a/repos/base/src/lib/ldso/dependency.cc b/repos/base/src/lib/ldso/dependency.cc index 7fbfe1eb9..cb66211c4 100644 --- a/repos/base/src/lib/ldso/dependency.cc +++ b/repos/base/src/lib/ldso/dependency.cc @@ -58,18 +58,31 @@ bool Linker::Dependency::in_dep(char const *file, Fifo const &dep) } +void Linker::Dependency::_load(Env &env, Allocator &alloc, char const *path, + Fifo &deps, Keep keep) +{ + if (!in_dep(Linker::file(path), deps)) + new (alloc) Dependency(env, alloc, path, _root, deps, keep); + + /* re-order initializer list, if needed object has been already added */ + else if (Object *o = Init::list()->contains(Linker::file(path))) + Init::list()->reorder(o); +} + + +void Linker::Dependency::preload(Env &env, Allocator &alloc, + Fifo &deps, Config const &config) +{ + config.for_each_library([&] (Config::Rom_name const &rom, Keep keep) { + _load(env, alloc, rom.string(), deps, keep); }); +} + + void Linker::Dependency::load_needed(Env &env, Allocator &md_alloc, Fifo &deps, Keep keep) { _obj.dynamic().for_each_dependency([&] (char const *path) { - - if (!in_dep(Linker::file(path), deps)) - new (md_alloc) Dependency(env, md_alloc, path, _root, deps, keep); - - /* re-order initializer list, if needed object has been already added */ - else if (Object *o = Init::list()->contains(Linker::file(path))) - Init::list()->reorder(o); - }); + _load(env, md_alloc, path, deps, keep); }); } diff --git a/repos/base/src/lib/ldso/include/config.h b/repos/base/src/lib/ldso/include/config.h new file mode 100644 index 000000000..f5bd99b19 --- /dev/null +++ b/repos/base/src/lib/ldso/include/config.h @@ -0,0 +1,84 @@ +/* + * \brief Linker configuration + * \author Norman Feske + * \date 2019-08-13 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__CONFIG_H_ +#define _INCLUDE__CONFIG_H_ + +#include +#include + +namespace Linker { class Config; } + + +class Linker::Config : Noncopyable +{ + private: + + /* + * Helper to transparently handle the case where no "config" ROM is + * available. + */ + struct Xml_config : Xml_node + { + Constructible _rom { }; + + Xml_config(Env &env) : Xml_node("") + { + try { + _rom.construct(env, "config"); + static_cast(*this) = _rom->xml(); + } + catch (...) { } + } + }; + + Xml_config const _config; + + Bind const _bind = _config.attribute_value("ld_bind_now", false) + ? BIND_NOW : BIND_LAZY; + + bool const _verbose = _config.attribute_value("ld_verbose", false); + + public: + + Config(Env &env) : _config(env) { } + + Bind bind() const { return _bind; } + bool verbose() const { return _verbose; } + + typedef String<100> Rom_name; + + /** + * Call fn for each library specified in the configuration + * + * The functor 'fn' is called with 'Rom_name', 'Keep' as arguments. + */ + template + void for_each_library(FN const &fn) const + { + _config.with_sub_node("ld", [&] (Xml_node ld) { + + ld.for_each_sub_node("library", [&] (Xml_node lib) { + + Rom_name const rom = lib.attribute_value("rom", Rom_name()); + + Keep const keep = lib.attribute_value("keep", false) + ? DONT_KEEP : KEEP; + + fn(rom, keep); + }); + }); + } +}; + +#endif /* _INCLUDE__CONFIG_H_ */ diff --git a/repos/base/src/lib/ldso/include/linker.h b/repos/base/src/lib/ldso/include/linker.h index bb3ca7e4e..8ce581902 100644 --- a/repos/base/src/lib/ldso/include/linker.h +++ b/repos/base/src/lib/ldso/include/linker.h @@ -19,6 +19,7 @@ #include #include #include +#include /* * Mark functions that are used during the linkers self-relocation phase as @@ -224,6 +225,8 @@ class Linker::Dependency : public Fifo::Element, Noncopyable */ bool in_dep(char const *file, Fifo const &); + void _load(Env &, Allocator &, char const *, Fifo &, Keep); + public: /* @@ -241,6 +244,11 @@ class Linker::Dependency : public Fifo::Element, Noncopyable */ void load_needed(Env &, Allocator &, Fifo &, Keep); + /** + * Preload ELF object + */ + void preload(Env &, Allocator &, Fifo &, Config const &); + bool root() const { return _root != nullptr; } Object const &obj() const { return _obj; } diff --git a/repos/base/src/lib/ldso/main.cc b/repos/base/src/lib/ldso/main.cc index bc7490dbb..4d05713ba 100644 --- a/repos/base/src/lib/ldso/main.cc +++ b/repos/base/src/lib/ldso/main.cc @@ -28,6 +28,7 @@ #include #include #include +#include using namespace Linker; @@ -346,7 +347,7 @@ struct Linker::Binary : private Root_object, public Elf_object bool static_construction_finished = false; - Binary(Env &env, Allocator &md_alloc, Bind bind) + Binary(Env &env, Allocator &md_alloc, Config const &config) : Root_object(md_alloc), Elf_object(env, md_alloc, binary_name(), @@ -363,11 +364,14 @@ struct Linker::Binary : private Root_object, public Elf_object /* place linker on second place in link map */ Ld::linker().setup_link_map(); + /* preload libraries specified in the configuration */ + binary->preload(env, md_alloc, deps(), config); + /* load dependencies */ binary->load_needed(env, md_alloc, deps(), DONT_KEEP); /* relocate and call constructors */ - Init::list()->initialize(bind, STAGE_BINARY); + Init::list()->initialize(config.bind(), STAGE_BINARY); } Elf::Addr lookup_symbol(char const *name) @@ -634,32 +638,6 @@ extern "C" void init_rtld() } -class Linker::Config -{ - private: - - Bind _bind = BIND_LAZY; - bool _verbose = false; - - public: - - Config(Env &env) - { - try { - Attached_rom_dataspace config(env, "config"); - - if (config.xml().attribute_value("ld_bind_now", false)) - _bind = BIND_NOW; - - _verbose = config.xml().attribute_value("ld_verbose", false); - } catch (Rom_connection::Rom_connection_failed) { } - } - - Bind bind() const { return _bind; } - bool verbose() const { return _verbose; } -}; - - static Genode::Constructible &heap() { return *unmanaged_singleton>(); @@ -684,12 +662,13 @@ void Genode::exec_static_constructors() void Component::construct(Genode::Env &env) { /* read configuration */ - static Config config(env); + Config const config(env); + verbose = config.verbose(); /* load binary and all dependencies */ try { - binary_ptr = unmanaged_singleton(env, *heap(), config.bind()); + binary_ptr = unmanaged_singleton(env, *heap(), config); } catch(Linker::Not_found &symbol) { error("LD: symbol not found: '", symbol, "'"); throw;