diff options
author | Itamar <itamar8910@gmail.com> | 2020-10-17 14:39:36 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-12-14 23:05:53 +0100 |
commit | efe4da57dfc4d820062455f41fb5f16842268d40 (patch) | |
tree | 35a2958a7ad4d4029403287fc9c612db6c892227 /Userland/DynamicLoader/main.cpp | |
parent | c917fcbac40cb1f02a0bb88534c702c712168d8a (diff) | |
download | serenity-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.cpp | 126 |
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); } } |