Loader.so+LibELF: Move most of Loader.so's logic into ELF::DynamicLinker

Loader.so now just performs the initial self relocations and static
LibC initialisation before handing over to ELF::DynamicLinker::linker_main
to handle the rest of the process.

As a trade-off, ELF::DynamicLinker needs to be explicitly excluded from
Lagom unless we really want to try writing a cross platform dynamic loader
This commit is contained in:
William Marlow 2021-01-01 23:54:43 +00:00 committed by Andreas Kling
parent 4d32121293
commit 3e815ad5b1
Notes: sideshowbarker 2024-07-19 17:30:30 +09:00
8 changed files with 327 additions and 220 deletions

View file

@ -0,0 +1,250 @@
/*
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
* Copyright (c) 2021, the SerenityOS developers.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/HashMap.h>
#include <AK/HashTable.h>
#include <AK/LexicalPath.h>
#include <AK/LogStream.h>
#include <AK/ScopeGuard.h>
#include <LibC/mman.h>
#include <LibC/stdio.h>
#include <LibC/sys/internals.h>
#include <LibC/unistd.h>
#include <LibCore/File.h>
#include <LibELF/AuxiliaryVector.h>
#include <LibELF/DynamicLinker.h>
#include <LibELF/DynamicLoader.h>
#include <LibELF/DynamicObject.h>
#include <LibELF/Image.h>
#include <LibELF/exec_elf.h>
#include <dlfcn.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
// #define DYNAMIC_LOAD_VERBOSE
#ifdef DYNAMIC_LOAD_VERBOSE
# define VERBOSE(fmt, ...) dbgprintf(fmt, ##__VA_ARGS__)
#else
# define VERBOSE(fmt, ...) \
do { \
} while (0)
#endif
#define TLS_VERBOSE(fmt, ...) dbgprintf(fmt, ##__VA_ARGS__)
namespace ELF {
namespace {
HashMap<String, NonnullRefPtr<ELF::DynamicLoader>> g_loaders;
HashMap<String, NonnullRefPtr<ELF::DynamicObject>> g_loaded_objects;
Vector<NonnullRefPtr<ELF::DynamicObject>> g_global_objects;
using MainFunction = int (*)(int, char**, char**);
using LibCExitFunction = void (*)(int);
size_t g_current_tls_offset = 0;
size_t g_total_tls_size = 0;
char** g_envp = nullptr;
LibCExitFunction g_libc_exit = nullptr;
}
DynamicObject::SymbolLookupResult DynamicLinker::lookup_global_symbol(const char* symbol_name)
{
DynamicObject::SymbolLookupResult weak_result = {};
for (auto& lib : g_global_objects) {
auto res = lib->lookup_symbol(symbol_name);
if (res.found) {
if (res.bind == STB_GLOBAL) {
return res;
} else if (res.bind == STB_WEAK && !weak_result.found) {
weak_result = res;
}
// We don't want to allow local symbols to be pulled in to other modules
}
}
return weak_result;
}
static void map_library(const String& name, int fd)
{
struct stat lib_stat;
int rc = fstat(fd, &lib_stat);
ASSERT(!rc);
auto loader = ELF::DynamicLoader::construct(name.characters(), fd, lib_stat.st_size);
loader->set_tls_offset(g_current_tls_offset);
g_loaders.set(name, loader);
g_current_tls_offset += loader->tls_size();
}
static void map_library(const String& name)
{
// TODO: Do we want to also look for libs in other paths too?
String path = String::format("/usr/lib/%s", name.characters());
int fd = open(path.characters(), O_RDONLY);
ASSERT(fd >= 0);
map_library(name, fd);
}
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, &name](auto needed_name) {
if (name == needed_name)
return IterationDecision::Continue;
dependencies.append(needed_name);
return IterationDecision::Continue;
});
return dependencies;
}
static void map_dependencies(const String& name)
{
VERBOSE("mapping dependencies for: %s\n", name.characters());
for (const auto& needed_name : get_dependencies(name)) {
VERBOSE("needed library: %s\n", 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);
}
}
VERBOSE("mapped dependencies for %s\n", name.characters());
}
static void allocate_tls()
{
size_t total_tls_size = 0;
for (const auto& data : g_loaders) {
VERBOSE("%s: TLS Size: %zu\n", data.key.characters(), data.value->tls_size());
total_tls_size += data.value->tls_size();
}
if (total_tls_size) {
[[maybe_unused]] void* tls_address = ::allocate_tls(total_tls_size);
VERBOSE("from userspace, tls_address: %p\n", tls_address);
}
g_total_tls_size = total_tls_size;
}
static void initialize_libc(DynamicObject& 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 = libc.lookup_symbol("environ");
ASSERT(res.found);
*((char***)res.address) = g_envp;
res = libc.lookup_symbol("__environ_is_malloced");
ASSERT(res.found);
*((bool*)res.address) = false;
res = libc.lookup_symbol("exit");
ASSERT(res.found);
g_libc_exit = (LibCExitFunction)res.address;
res = libc.lookup_symbol("__libc_init");
ASSERT(res.found);
typedef void libc_init_func();
((libc_init_func*)res.address)();
}
static void load_elf(const String& name)
{
VERBOSE("load_elf: %s\n", name.characters());
auto loader = g_loaders.get(name).value();
VERBOSE("a1\n");
for (const auto& needed_name : get_dependencies(name)) {
VERBOSE("needed library: %s\n", needed_name.characters());
String library_name = get_library_name(needed_name);
if (!g_loaded_objects.contains(library_name)) {
load_elf(library_name);
}
}
auto dynamic_object = loader->load_from_image(RTLD_GLOBAL | RTLD_LAZY, g_total_tls_size);
ASSERT(dynamic_object);
g_loaded_objects.set(name, *dynamic_object);
g_global_objects.append(*dynamic_object);
VERBOSE("load_elf: done %s\n", name.characters());
if (name == "libc.so") {
initialize_libc(*dynamic_object);
}
}
void ELF::DynamicLinker::linker_main(String&& main_program_name, int main_program_fd, int argc, char** argv, char** envp)
{
g_envp = envp;
map_library(main_program_name, main_program_fd);
map_dependencies(main_program_name);
VERBOSE("loaded all dependencies");
for ([[maybe_unused]] auto& lib : g_loaders) {
VERBOSE("%s - tls size: %zu, tls offset: %zu\n", lib.key.characters(), lib.value->tls_size(), lib.value->tls_offset());
}
allocate_tls();
load_elf(main_program_name);
auto main_program_lib = g_loaders.get(main_program_name).value();
FlatPtr entry_point = reinterpret_cast<FlatPtr>(main_program_lib->image().entry().as_ptr());
if (main_program_lib->is_dynamic())
entry_point += reinterpret_cast<FlatPtr>(main_program_lib->text_segment_load_address().as_ptr());
VERBOSE("entry point: %p\n", (void*)entry_point);
g_loaders.clear();
MainFunction main_function = (MainFunction)(entry_point);
VERBOSE("jumping to main program entry point: %p\n", main_function);
int rc = main_function(argc, argv, envp);
VERBOSE("rc: %d\n", rc);
if (g_libc_exit != nullptr) {
g_libc_exit(rc);
} else {
_exit(rc);
}
ASSERT_NOT_REACHED();
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright 2021 (c), the SerenityOS developers.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/Result.h>
#include <AK/Vector.h>
#include <LibELF/DynamicObject.h>
namespace ELF {
class DynamicLinker {
public:
static DynamicObject::SymbolLookupResult lookup_global_symbol(const char* symbol);
[[noreturn]] static void linker_main(String&& main_program_name, int fd, int argc, char** argv, char** envp);
private:
DynamicLinker() = delete;
~DynamicLinker() = delete;
};
}

View file

@ -162,8 +162,6 @@ RefPtr<DynamicObject> DynamicLoader::load_from_image(unsigned flags, size_t tota
m_dynamic_object = DynamicObject::construct(m_text_segment_load_address, m_dynamic_section_address); m_dynamic_object = DynamicObject::construct(m_text_segment_load_address, m_dynamic_section_address);
m_dynamic_object->set_tls_offset(m_tls_offset); m_dynamic_object->set_tls_offset(m_tls_offset);
m_dynamic_object->set_tls_size(m_tls_size); m_dynamic_object->set_tls_size(m_tls_size);
ASSERT(m_global_symbol_lookup_func);
m_dynamic_object->m_global_symbol_lookup_func = m_global_symbol_lookup_func;
auto rc = load_stage_2(flags, total_tls_size); auto rc = load_stage_2(flags, total_tls_size);
if (!rc) { if (!rc) {

View file

@ -75,9 +75,6 @@ public:
template<typename F> template<typename F>
void for_each_needed_library(F) const; void for_each_needed_library(F) const;
DynamicObject::SymbolLookupFunction m_global_symbol_lookup_func { nullptr };
void set_global_symbol_lookup_function(DynamicObject::SymbolLookupFunction func) { m_global_symbol_lookup_func = func; }
VirtualAddress text_segment_load_address() const { return m_text_segment_load_address; } VirtualAddress text_segment_load_address() const { return m_text_segment_load_address; }
bool is_dynamic() const { return m_elf_image.is_dynamic(); } bool is_dynamic() const { return m_elf_image.is_dynamic(); }

View file

@ -27,6 +27,7 @@
#include <AK/String.h> #include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibELF/DynamicLinker.h>
#include <LibELF/DynamicObject.h> #include <LibELF/DynamicObject.h>
#include <LibELF/exec_elf.h> #include <LibELF/exec_elf.h>
#include <stdio.h> #include <stdio.h>
@ -406,12 +407,12 @@ static const char* name_for_dtag(Elf32_Sword d_tag)
} }
} }
Optional<DynamicObject::SymbolLookupResult> DynamicObject::lookup_symbol(const char* name) const DynamicObject::SymbolLookupResult DynamicObject::lookup_symbol(const char* name) const
{ {
auto res = hash_section().lookup_symbol(name); auto res = hash_section().lookup_symbol(name);
if (res.is_undefined()) if (res.is_undefined())
return {}; return {};
return SymbolLookupResult { true, res.value(), (FlatPtr)res.address().as_ptr(), this }; return SymbolLookupResult { true, res.value(), (FlatPtr)res.address().as_ptr(), res.bind(), this };
} }
NonnullRefPtr<DynamicObject> DynamicObject::construct(VirtualAddress base_address, VirtualAddress dynamic_section_address) NonnullRefPtr<DynamicObject> DynamicObject::construct(VirtualAddress base_address, VirtualAddress dynamic_section_address)
@ -450,10 +451,9 @@ DynamicObject::SymbolLookupResult DynamicObject::lookup_symbol(const ELF::Dynami
VERBOSE("looking up symbol: %s\n", symbol.name()); VERBOSE("looking up symbol: %s\n", symbol.name());
if (!symbol.is_undefined()) { if (!symbol.is_undefined()) {
VERBOSE("symbol is defined in its object\n"); VERBOSE("symbol is defined in its object\n");
return { true, symbol.value(), (FlatPtr)symbol.address().as_ptr(), &symbol.object() }; return { true, symbol.value(), (FlatPtr)symbol.address().as_ptr(), symbol.bind(), &symbol.object() };
} }
ASSERT(m_global_symbol_lookup_func); return DynamicLinker::lookup_global_symbol(symbol.name());
return m_global_symbol_lookup_func(symbol.name());
} }
} // end namespace ELF } // end namespace ELF

View file

@ -276,9 +276,10 @@ public:
bool found { false }; bool found { false };
FlatPtr value { 0 }; FlatPtr value { 0 };
FlatPtr address { 0 }; FlatPtr address { 0 };
unsigned bind { STB_LOCAL };
const ELF::DynamicObject* dynamic_object { nullptr }; // The object in which the symbol is defined const ELF::DynamicObject* dynamic_object { nullptr }; // The object in which the symbol is defined
}; };
Optional<SymbolLookupResult> lookup_symbol(const char* name) const; SymbolLookupResult lookup_symbol(const char* name) const;
// Will be called from _fixup_plt_entry, as part of the PLT trampoline // Will be called from _fixup_plt_entry, as part of the PLT trampoline
Elf32_Addr patch_plt_entry(u32 relocation_offset); Elf32_Addr patch_plt_entry(u32 relocation_offset);

View file

@ -44,6 +44,10 @@ file(GLOB LIBREGEX_LIBC_SOURCES "../../Libraries/LibRegex/C/Regex.cpp")
file(GLOB LIBREGEX_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibRegex/*.cpp") file(GLOB LIBREGEX_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibRegex/*.cpp")
file(GLOB LIBCORE_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibCore/*.cpp") file(GLOB LIBCORE_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibCore/*.cpp")
file(GLOB LIBELF_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibELF/*.cpp") file(GLOB LIBELF_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibELF/*.cpp")
# There's no way we can reliably make this cross platform
list(REMOVE_ITEM LIBELF_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../../Libraries/LibELF/DynamicLinker.cpp")
file(GLOB LIBGEMINI_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibGemini/*.cpp") file(GLOB LIBGEMINI_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibGemini/*.cpp")
file(GLOB LIBGFX_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibGfx/*.cpp") file(GLOB LIBGFX_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibGfx/*.cpp")
file(GLOB LIBHTTP_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibHTTP/*.cpp") file(GLOB LIBHTTP_SOURCES CONFIGURE_DEPENDS "../../Libraries/LibHTTP/*.cpp")

View file

@ -35,6 +35,7 @@
#include <LibC/unistd.h> #include <LibC/unistd.h>
#include <LibCore/File.h> #include <LibCore/File.h>
#include <LibELF/AuxiliaryVector.h> #include <LibELF/AuxiliaryVector.h>
#include <LibELF/DynamicLinker.h>
#include <LibELF/DynamicLoader.h> #include <LibELF/DynamicLoader.h>
#include <LibELF/DynamicObject.h> #include <LibELF/DynamicObject.h>
#include <LibELF/Image.h> #include <LibELF/Image.h>
@ -57,23 +58,14 @@
char* __static_environ[] = { nullptr }; // We don't get the environment without some libc workarounds.. char* __static_environ[] = { nullptr }; // We don't get the environment without some libc workarounds..
static HashMap<String, NonnullRefPtr<ELF::DynamicLoader>> g_loaders;
static HashMap<String, NonnullRefPtr<ELF::DynamicObject>> g_loaded_objects;
using MainFunction = int (*)(int, char**, char**);
using LibCExitFunction = void (*)(int);
static size_t g_current_tls_offset = 0;
static size_t g_total_tls_size = 0;
static char** g_envp = nullptr;
static LibCExitFunction g_libc_exit = nullptr;
static void init_libc() static void init_libc()
{ {
environ = __static_environ; environ = __static_environ;
__environ_is_malloced = false; __environ_is_malloced = false;
__stdio_is_initialized = false; __stdio_is_initialized = false;
__malloc_init(); // Initialise the copy of libc included statically in Loader.so,
// initialisation of the dynamic libc.so is done by the DynamicLinker
__libc_init();
} }
static void perform_self_relocations(auxv_t* auxvp) static void perform_self_relocations(auxv_t* auxvp)
@ -112,144 +104,6 @@ static void perform_self_relocations(auxv_t* auxvp)
}); });
} }
static ELF::DynamicObject::SymbolLookupResult global_symbol_lookup(const char* symbol_name)
{
VERBOSE("global symbol lookup: %s\n", symbol_name);
for (auto& lib : g_loaded_objects) {
VERBOSE("looking up in object: %s\n", lib.key.characters());
auto res = lib.value->lookup_symbol(symbol_name);
if (!res.has_value())
continue;
return res.value();
}
// ASSERT_NOT_REACHED();
return {};
}
static void map_library(const String& name, int fd)
{
struct stat lib_stat;
int rc = fstat(fd, &lib_stat);
ASSERT(!rc);
auto loader = ELF::DynamicLoader::construct(name.characters(), fd, lib_stat.st_size);
loader->set_tls_offset(g_current_tls_offset);
loader->set_global_symbol_lookup_function(global_symbol_lookup);
g_loaders.set(name, loader);
g_current_tls_offset += loader->tls_size();
}
static void map_library(const String& name)
{
// TODO: Do we want to also look for libs in other paths too?
String path = String::format("/usr/lib/%s", name.characters());
int fd = open(path.characters(), O_RDONLY);
ASSERT(fd >= 0);
map_library(name, fd);
}
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, &name](auto needed_name) {
if (name == needed_name)
return IterationDecision::Continue;
dependencies.append(needed_name);
return IterationDecision::Continue;
});
return dependencies;
}
static void map_dependencies(const String& name)
{
VERBOSE("mapping dependencies for: %s\n", name.characters());
for (const auto& needed_name : get_dependencies(name)) {
VERBOSE("needed library: %s\n", 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);
}
}
}
static void allocate_tls()
{
size_t total_tls_size = 0;
for (const auto& data : g_loaders) {
VERBOSE("%s: TLS Size: %zu\n", data.key.characters(), data.value->tls_size());
total_tls_size += data.value->tls_size();
}
if (total_tls_size) {
[[maybe_unused]] void* tls_address = allocate_tls(total_tls_size);
VERBOSE("from userspace, tls_address: %p\n", 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("exit");
ASSERT(res.found);
g_libc_exit = (LibCExitFunction)res.address;
res = global_symbol_lookup("__libc_init");
ASSERT(res.found);
typedef void libc_init_func();
((libc_init_func*)res.address)();
}
static void load_elf(const String& name)
{
VERBOSE("load_elf: %s\n", name.characters());
auto loader = g_loaders.get(name).value();
VERBOSE("a1\n");
for (const auto& needed_name : get_dependencies(name)) {
VERBOSE("needed library: %s\n", needed_name.characters());
String library_name = get_library_name(needed_name);
if (!g_loaded_objects.contains(library_name)) {
load_elf(library_name);
}
}
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 void display_help() static void display_help()
{ {
const char message[] = const char message[] =
@ -261,11 +115,24 @@ This helper program loads the shared libraries needed by the program,
prepares the program to run, and runs it. You do not need to invoke prepares the program to run, and runs it. You do not need to invoke
this helper program directly. this helper program directly.
)"; )";
write(1, message, sizeof(message)); fprintf(stderr, "%s", message);
} }
static FlatPtr loader_main(auxv_t* auxvp) extern "C" {
// The compiler expects a previous declaration
void _start(int, char**, char**);
void _start(int argc, char** argv, char** envp)
{ {
char** env;
for (env = envp; *env; ++env) {
}
auxv_t* auxvp = (auxv_t*)++env;
perform_self_relocations(auxvp);
init_libc();
int main_program_fd = -1; int main_program_fd = -1;
String main_program_name; String main_program_name;
for (; auxvp->a_type != AT_NULL; ++auxvp) { for (; auxvp->a_type != AT_NULL; ++auxvp) {
@ -288,62 +155,7 @@ static FlatPtr loader_main(auxv_t* auxvp)
_exit(1); _exit(1);
} }
map_library(main_program_name, main_program_fd); ELF::DynamicLinker::linker_main(move(main_program_name), main_program_fd, argc, argv, envp);
map_dependencies(main_program_name); ASSERT_NOT_REACHED();
VERBOSE("loaded all dependencies");
for ([[maybe_unused]] auto& lib : g_loaders) {
VERBOSE("%s - tls size: %zu, tls offset: %zu\n", lib.key.characters(), lib.value->tls_size(), lib.value->tls_offset());
}
allocate_tls();
load_elf(main_program_name);
auto main_program_lib = g_loaders.get(main_program_name).value();
FlatPtr entry_point = reinterpret_cast<FlatPtr>(main_program_lib->image().entry().as_ptr());
if (main_program_lib->is_dynamic())
entry_point += reinterpret_cast<FlatPtr>(main_program_lib->text_segment_load_address().as_ptr());
VERBOSE("entry point: %p\n", (void*)entry_point);
// This will unmap the temporary memory maps we had for loading the libraries
clear_temporary_objects_mappings();
return entry_point;
}
extern "C" {
// The compiler expects a previous declaration
void _start(int, char**, char**);
void _start(int argc, char** argv, char** envp)
{
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 ([[maybe_unused]] auto& obj : g_loaded_objects) {
VERBOSE("%s: %p\n", obj.key.characters(), obj.value->base_address().as_ptr());
}
MainFunction main_function = (MainFunction)(entry);
VERBOSE("jumping to main program entry point: %p\n", main_function);
int rc = main_function(argc, argv, envp);
VERBOSE("rc: %d\n", rc);
if (g_libc_exit != nullptr) {
g_libc_exit(rc);
} else {
_exit(rc);
}
} }
} }