summaryrefslogtreecommitdiff
path: root/Userland/DynamicLoader/main.cpp
diff options
context:
space:
mode:
authorItamar <itamar8910@gmail.com>2020-10-17 14:39:36 +0300
committerAndreas Kling <kling@serenityos.org>2020-12-14 23:05:53 +0100
commitefe4da57dfc4d820062455f41fb5f16842268d40 (patch)
tree35a2958a7ad4d4029403287fc9c612db6c892227 /Userland/DynamicLoader/main.cpp
parentc917fcbac40cb1f02a0bb88534c702c712168d8a (diff)
downloadserenity-efe4da57dfc4d820062455f41fb5f16842268d40.zip
Loader: Stabilize loader & Use shared libraries everywhere :^)
The dynamic loader is now stable enough to be used everywhere in the system - so this commit does just that. No More .a Files, Long Live .so's!
Diffstat (limited to 'Userland/DynamicLoader/main.cpp')
-rw-r--r--Userland/DynamicLoader/main.cpp126
1 files changed, 92 insertions, 34 deletions
diff --git a/Userland/DynamicLoader/main.cpp b/Userland/DynamicLoader/main.cpp
index 981ecf763d..8bd5e74798 100644
--- a/Userland/DynamicLoader/main.cpp
+++ b/Userland/DynamicLoader/main.cpp
@@ -63,6 +63,7 @@ static HashMap<String, NonnullRefPtr<ELF::DynamicObject>> g_loaded_objects;
static size_t g_current_tls_offset = 0;
static size_t g_total_tls_size = 0;
+static char** g_envp = nullptr;
static void init_libc()
{
@@ -72,30 +73,37 @@ static void init_libc()
__malloc_init();
}
-static void perform_self_relocations()
+static void perform_self_relocations(auxv_t* auxvp)
{
// We need to relocate ourselves.
// (these relocations seem to be generated because of our vtables)
- // TODO: Pass this address in the Auxiliary Vector
- u32 base = 0x08000000;
- Elf32_Ehdr* header = (Elf32_Ehdr*)(base);
- Elf32_Phdr* pheader = (Elf32_Phdr*)(base + header->e_phoff);
+ FlatPtr base_address = 0;
+ bool found_base_address = false;
+ for (; auxvp->a_type != AT_NULL; ++auxvp) {
+ if (auxvp->a_type == AuxiliaryValue::BaseAddress) {
+ base_address = auxvp->a_un.a_val;
+ found_base_address = true;
+ }
+ }
+ ASSERT(found_base_address);
+ Elf32_Ehdr* header = (Elf32_Ehdr*)(base_address);
+ Elf32_Phdr* pheader = (Elf32_Phdr*)(base_address + header->e_phoff);
u32 dynamic_section_addr = 0;
for (size_t i = 0; i < (size_t)header->e_phnum; ++i, ++pheader) {
if (pheader->p_type != PT_DYNAMIC)
continue;
- dynamic_section_addr = pheader->p_vaddr + base;
+ dynamic_section_addr = pheader->p_vaddr + base_address;
}
if (!dynamic_section_addr)
exit(1);
- auto dynamic_object = ELF::DynamicObject::construct((VirtualAddress(base)), (VirtualAddress(dynamic_section_addr)));
+ auto dynamic_object = ELF::DynamicObject::construct((VirtualAddress(base_address)), (VirtualAddress(dynamic_section_addr)));
- dynamic_object->relocation_section().for_each_relocation([base](auto& reloc) {
+ dynamic_object->relocation_section().for_each_relocation([base_address](auto& reloc) {
if (reloc.type() != R_386_RELATIVE)
return IterationDecision::Continue;
- *(u32*)reloc.address().as_ptr() += base;
+ *(u32*)reloc.address().as_ptr() += base_address;
return IterationDecision::Continue;
});
}
@@ -110,7 +118,7 @@ static ELF::DynamicObject::SymbolLookupResult global_symbol_lookup(const char* s
continue;
return res.value();
}
- ASSERT_NOT_REACHED();
+ // ASSERT_NOT_REACHED();
return {};
}
@@ -122,7 +130,7 @@ static void map_library(const String& name, int fd)
auto loader = ELF::DynamicLoader::construct(name.characters(), fd, lib_stat.st_size);
loader->set_tls_offset(g_current_tls_offset);
- loader->m_global_symbol_lookup_func = global_symbol_lookup;
+ loader->set_global_symbol_lookup_function(global_symbol_lookup);
g_loaders.set(name, loader);
@@ -143,51 +151,94 @@ static String get_library_name(const StringView& path)
return LexicalPath(path).basename();
}
-static void map_dependencies(const String& name)
+static Vector<String> get_dependencies(const String& name)
{
- dbg() << "mapping dependencies for: " << name;
auto lib = g_loaders.get(name).value();
- lib->for_each_needed_library([](auto needed_name) {
- dbg() << "needed library: " << needed_name;
+ Vector<String> dependencies;
+
+ lib->for_each_needed_library([&dependencies](auto needed_name) {
+ dependencies.append(needed_name);
+ return IterationDecision::Continue;
+ });
+ return dependencies;
+}
+
+static void map_dependencies(const String& name)
+{
+ VERBOSE("mapping dependencies for: %s", name.characters());
+
+ for (const auto& needed_name : get_dependencies(name)) {
+ VERBOSE("needed library: %s", needed_name.characters());
String library_name = get_library_name(needed_name);
if (!g_loaders.contains(library_name)) {
map_library(library_name);
map_dependencies(library_name);
}
- return IterationDecision::Continue;
- });
+ }
}
static void allocate_tls()
{
size_t total_tls_size = 0;
for (const auto& data : g_loaders) {
+ VERBOSE("%s: TLS Size: %u\n", data.key.characters(), data.value->tls_size());
total_tls_size += data.value->tls_size();
}
if (total_tls_size) {
void* tls_address = allocate_tls(total_tls_size);
- dbg() << "from userspace, tls_address: " << tls_address;
+ (void)tls_address;
+ VERBOSE("from userspace, tls_address: %p", tls_address);
}
g_total_tls_size = total_tls_size;
}
+static void initialize_libc()
+{
+ // Traditionally, `_start` of the main program initializes libc.
+ // However, since some libs use malloc() and getenv() in global constructors,
+ // we have to initialize libc just after it is loaded.
+ // Also, we can't just mark `__libc_init` with "__attribute__((constructor))"
+ // because it uses getenv() internally, so `environ` has to be initialized before we call `__libc_init`.
+ auto res = global_symbol_lookup("environ");
+ *((char***)res.address) = g_envp;
+ ASSERT(res.found);
+ res = global_symbol_lookup("__environ_is_malloced");
+ ASSERT(res.found);
+ *((bool*)res.address) = false;
+
+ res = global_symbol_lookup("__libc_init");
+ ASSERT(res.found);
+ typedef void libc_init_func(void);
+ ((libc_init_func*)res.address)();
+}
+
static void load_elf(const String& name)
{
- dbg() << "load_elf: " << name;
+ VERBOSE("load_elf: %s", name.characters());
auto loader = g_loaders.get(name).value();
- loader->for_each_needed_library([](auto needed_name) {
- dbg() << "needed library: " << needed_name;
+ for (const auto& needed_name : get_dependencies(name)) {
+ VERBOSE("needed library: %s", needed_name.characters());
String library_name = get_library_name(needed_name);
if (!g_loaded_objects.contains(library_name)) {
load_elf(library_name);
}
- return IterationDecision::Continue;
- });
+ }
- auto dynamic_object = loader->load_from_image(RTLD_GLOBAL, g_total_tls_size);
+ VERBOSE("loading: %s", name.characters());
+ auto dynamic_object = loader->load_from_image(RTLD_GLOBAL | RTLD_LAZY, g_total_tls_size);
ASSERT(!dynamic_object.is_null());
g_loaded_objects.set(name, dynamic_object.release_nonnull());
+
+ if (name == "libc.so") {
+ initialize_libc();
+ }
+}
+
+static void clear_temporary_objects_mappings()
+{
+
+ g_loaders.clear();
}
static FlatPtr loader_main(auxv_t* auxvp)
@@ -205,9 +256,10 @@ static FlatPtr loader_main(auxv_t* auxvp)
map_library(main_program_name, main_program_fd);
map_dependencies(main_program_name);
- dbg() << "loaded all dependencies";
+ VERBOSE("loaded all dependencies");
for (auto& lib : g_loaders) {
- dbg() << lib.key << "- tls size: " << lib.value->tls_size() << ", tls offset: " << lib.value->tls_offset();
+ (void)lib;
+ VERBOSE("%s - tls size: $u, tls offset: %u", lib.key.characters(), lib.value->tls_size(), lib.value->tls_offset());
}
allocate_tls();
@@ -216,10 +268,10 @@ static FlatPtr loader_main(auxv_t* auxvp)
auto main_program_lib = g_loaders.get(main_program_name).value();
FlatPtr entry_point = reinterpret_cast<FlatPtr>(main_program_lib->image().entry().as_ptr() + (FlatPtr)main_program_lib->text_segment_load_address().as_ptr());
- dbg() << "entry point: " << (void*)entry_point;
+ VERBOSE("entry point: %p", entry_point);
// This will unmap the temporary memory maps we had for loading the libraries
- g_loaders.clear();
+ clear_temporary_objects_mappings();
return entry_point;
}
@@ -233,20 +285,26 @@ using MainFunction = int (*)(int, char**, char**);
void _start(int argc, char** argv, char** envp)
{
- perform_self_relocations();
- init_libc();
-
+ g_envp = envp;
char** env;
for (env = envp; *env; ++env) {
}
auxv_t* auxvp = (auxv_t*)++env;
+ perform_self_relocations(auxvp);
+ init_libc();
+
FlatPtr entry = loader_main(auxvp);
+ VERBOSE("Loaded libs:\n");
+ for (auto& obj : g_loaded_objects) {
+ (void)obj;
+ VERBOSE("%s: %p\n", obj.key.characters(), obj.value->base_address().as_ptr());
+ }
+
MainFunction main_function = (MainFunction)(entry);
- dbg() << "jumping to main program entry point: " << (void*)main_function;
+ VERBOSE("jumping to main program entry point: %p", main_function);
int rc = main_function(argc, argv, envp);
- dbg() << "rc: " << rc;
- sleep(100);
+ VERBOSE("rc: %d", rc);
_exit(rc);
}
}