mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-18 07:08:18 +00:00
ldso: defer execution of static constructors
Ldso now does not automatically execute static constructors of the binary and shared libraries the binary depends on. If static construction is required (e.g., if a shared library with constructor is used or a compilation unit contains global statics) the component needs to execute the constructors explicitly in Component::construct() via Genode::Env::exec_static_constructors(). In the case of libc components this is done by the libc startup code (i.e., the Component::construct() implementation in the libc). The loading of shared objects at runtime is not affected by this change and constructors of those objects are executed immediately. Fixes #2332
This commit is contained in:
@ -91,5 +91,5 @@ Linker::Root_object::Root_object(Env &env, Allocator &md_alloc,
|
||||
new (md_alloc) Dependency(env, md_alloc, linker_name(), this, _deps, DONT_KEEP);
|
||||
|
||||
/* relocate and call constructors */
|
||||
Init::list()->initialize(bind);
|
||||
Init::list()->initialize(bind, STAGE_SO);
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ class Linker::Dynamic
|
||||
{
|
||||
if (!_md_alloc) {
|
||||
error("unexpected call of section_dt_needed");
|
||||
return;
|
||||
throw Fatal();
|
||||
}
|
||||
Needed *n = new (*_md_alloc) Needed(d->un.ptr);
|
||||
_needed.enqueue(n);
|
||||
|
@ -36,6 +36,18 @@ struct Linker::Init : List<Object>
|
||||
return &_list;
|
||||
}
|
||||
|
||||
bool contains_deps() const
|
||||
{
|
||||
for (Object const *obj = first(); obj; obj = obj->next_init()) {
|
||||
if (obj->is_linker()) continue;
|
||||
if (obj->is_binary()) continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Object *contains(char const *file)
|
||||
{
|
||||
for (Object *elf = first(); elf; elf = elf->next_init())
|
||||
@ -62,7 +74,7 @@ struct Linker::Init : List<Object>
|
||||
});
|
||||
}
|
||||
|
||||
void initialize(Bind bind)
|
||||
void initialize(Bind bind, Stage stage)
|
||||
{
|
||||
Object *obj = first();
|
||||
|
||||
@ -74,7 +86,7 @@ struct Linker::Init : List<Object>
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursive initialization call is not allowed here. This might happend
|
||||
* Recursive initialization call is not allowed here. This might happen
|
||||
* when Shared_objects (e.g. dlopen and friends) are constructed from within
|
||||
* global constructors (ctors).
|
||||
*/
|
||||
@ -83,10 +95,21 @@ struct Linker::Init : List<Object>
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We do not call static constructors in the binary stage as this must
|
||||
* be done by the component itself. Later for shared objects, the
|
||||
* constructors are executed immediately.
|
||||
*/
|
||||
if (stage != STAGE_BINARY)
|
||||
exec_static_constructors();
|
||||
}
|
||||
|
||||
void exec_static_constructors()
|
||||
{
|
||||
in_progress = true;
|
||||
|
||||
/* call static constructors */
|
||||
obj = first();
|
||||
Object *obj = first();
|
||||
while (obj) {
|
||||
|
||||
Object *next = obj->next_init();
|
||||
|
@ -32,6 +32,7 @@ namespace Linker {
|
||||
class Incompatible : Exception { };
|
||||
class Invalid_file : Exception { };
|
||||
class Not_found : Exception { };
|
||||
class Fatal : Exception { };
|
||||
|
||||
enum Keep { DONT_KEEP = Shared_object::DONT_KEEP,
|
||||
KEEP = Shared_object::KEEP };
|
||||
@ -39,6 +40,8 @@ namespace Linker {
|
||||
enum Bind { BIND_LAZY = Shared_object::BIND_LAZY,
|
||||
BIND_NOW = Shared_object::BIND_NOW };
|
||||
|
||||
enum Stage { STAGE_BINARY, STAGE_SO };
|
||||
|
||||
/**
|
||||
* Invariants
|
||||
*/
|
||||
|
@ -290,7 +290,10 @@ Elf::Addr Ld::jmp_slot(Dependency const &dep, Elf::Size index)
|
||||
Reloc_jmpslot slot(dep, dep.obj().dynamic().pltrel_type(),
|
||||
dep.obj().dynamic().pltrel(), index);
|
||||
return slot.target_addr();
|
||||
} catch (...) { error("LD: jump slot relocation failed. FATAL!"); }
|
||||
} catch (...) {
|
||||
error("LD: jump slot relocation failed. FATAL!");
|
||||
throw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -336,6 +339,8 @@ static void exit_on_suspended() { genode_exit(exit_status); }
|
||||
*/
|
||||
struct Linker::Binary : Root_object, Elf_object
|
||||
{
|
||||
bool static_construction_finished = false;
|
||||
|
||||
Binary(Env &env, Allocator &md_alloc, Bind bind)
|
||||
:
|
||||
Root_object(md_alloc),
|
||||
@ -357,7 +362,7 @@ struct Linker::Binary : Root_object, Elf_object
|
||||
binary->load_needed(env, md_alloc, deps(), DONT_KEEP);
|
||||
|
||||
/* relocate and call constructors */
|
||||
Init::list()->initialize(bind);
|
||||
Init::list()->initialize(bind, STAGE_BINARY);
|
||||
}
|
||||
|
||||
Elf::Addr lookup_symbol(char const *name)
|
||||
@ -370,6 +375,32 @@ struct Linker::Binary : Root_object, Elf_object
|
||||
catch (Linker::Not_found) { return 0; }
|
||||
}
|
||||
|
||||
bool static_construction_pending()
|
||||
{
|
||||
if (static_construction_finished) return false;
|
||||
|
||||
Func * const ctors_start = (Func *)lookup_symbol("_ctors_start");
|
||||
Func * const ctors_end = (Func *)lookup_symbol("_ctors_end");
|
||||
|
||||
return (ctors_end != ctors_start) || Init::list()->contains_deps();
|
||||
}
|
||||
|
||||
void finish_static_construction()
|
||||
{
|
||||
Init::list()->exec_static_constructors();
|
||||
|
||||
/* call static construtors and register destructors */
|
||||
Func * const ctors_start = (Func *)lookup_symbol("_ctors_start");
|
||||
Func * const ctors_end = (Func *)lookup_symbol("_ctors_end");
|
||||
for (Func * ctor = ctors_end; ctor != ctors_start; (*--ctor)());
|
||||
|
||||
Func * const dtors_start = (Func *)lookup_symbol("_dtors_start");
|
||||
Func * const dtors_end = (Func *)lookup_symbol("_dtors_end");
|
||||
for (Func * dtor = dtors_start; dtor != dtors_end; genode_atexit(*dtor++));
|
||||
|
||||
static_construction_finished = true;
|
||||
}
|
||||
|
||||
void call_entry_point(Env &env)
|
||||
{
|
||||
/* apply the component-provided stack size */
|
||||
@ -382,18 +413,16 @@ struct Linker::Binary : Root_object, Elf_object
|
||||
Thread::myself()->stack_size(stack_size);
|
||||
}
|
||||
|
||||
/* call static construtors and register destructors */
|
||||
Func * const ctors_start = (Func *)lookup_symbol("_ctors_start");
|
||||
Func * const ctors_end = (Func *)lookup_symbol("_ctors_end");
|
||||
for (Func * ctor = ctors_end; ctor != ctors_start; (*--ctor)());
|
||||
|
||||
Func * const dtors_start = (Func *)lookup_symbol("_dtors_start");
|
||||
Func * const dtors_end = (Func *)lookup_symbol("_dtors_end");
|
||||
for (Func * dtor = dtors_start; dtor != dtors_end; genode_atexit(*dtor++));
|
||||
|
||||
/* call 'Component::construct' function if present */
|
||||
if (Elf::Addr addr = lookup_symbol("_ZN9Component9constructERN6Genode3EnvE")) {
|
||||
((void(*)(Env &))addr)(env);
|
||||
|
||||
if (static_construction_pending()) {
|
||||
error("Component::construct() returned without executing "
|
||||
"pending static constructors (fix by calling "
|
||||
"Genode::Env::exec_static_constructors())");
|
||||
throw Fatal();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -406,6 +435,9 @@ struct Linker::Binary : Root_object, Elf_object
|
||||
if (Elf::Addr addr = lookup_symbol("main")) {
|
||||
warning("using legacy main function, please convert to 'Component::construct'");
|
||||
|
||||
/* execute static constructors before calling legacy 'main' */
|
||||
finish_static_construction();
|
||||
|
||||
exit_status = ((int (*)(int, char **, char **))addr)(genode_argc,
|
||||
genode_argv,
|
||||
genode_envp);
|
||||
@ -418,6 +450,7 @@ struct Linker::Binary : Root_object, Elf_object
|
||||
}
|
||||
|
||||
error("dynamic linker: component-entrypoint lookup failed");
|
||||
throw Fatal();
|
||||
}
|
||||
|
||||
void relocate(Bind bind) override
|
||||
@ -612,6 +645,11 @@ void Genode::init_ldso_phdr(Env &env)
|
||||
Ld::linker().load_phdr(env, *heap());
|
||||
}
|
||||
|
||||
void Genode::exec_static_constructors()
|
||||
{
|
||||
binary_ptr->finish_static_construction();
|
||||
}
|
||||
|
||||
|
||||
void Component::construct(Genode::Env &env)
|
||||
{
|
||||
|
Reference in New Issue
Block a user