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:
Christian Helmuth
2017-03-15 15:40:55 +01:00
parent 67ac0dde6e
commit cb43e04691
36 changed files with 310 additions and 87 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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();

View File

@ -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
*/

View File

@ -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)
{