mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:48:12 +00:00
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!
This commit is contained in:
parent
c917fcbac4
commit
efe4da57df
28 changed files with 401 additions and 173 deletions
|
@ -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 Vector<String> get_dependencies(const String& name)
|
||||
{
|
||||
auto lib = g_loaders.get(name).value();
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue