From efe4da57dfc4d820062455f41fb5f16842268d40 Mon Sep 17 00:00:00 2001 From: Itamar Date: Sat, 17 Oct 2020 14:39:36 +0300 Subject: [PATCH] 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! --- Applications/Debugger/main.cpp | 5 +- CMakeLists.txt | 32 +++-- Demos/CMakeLists.txt | 2 +- Demos/DynamicObject/CMakeLists.txt | 4 +- Demos/DynamicObject/SampleLib/CMakeLists.txt | 4 +- Demos/DynamicObject/SampleLib/lib.cpp | 25 ++++ Demos/DynamicObject/lib.h | 27 ++++ Demos/DynamicObject/main.cpp | 63 ++++++++- Kernel/CMakeLists.txt | 2 + Kernel/FileSystem/VirtualFileSystem.cpp | 2 + Kernel/Process.h | 4 +- Kernel/Syscalls/execve.cpp | 11 +- Kernel/Syscalls/mmap.cpp | 3 - Libraries/LibC/CMakeLists.txt | 9 +- Libraries/LibC/crt0_shared.cpp | 37 ++++-- Libraries/LibCore/CMakeLists.txt | 2 +- Libraries/LibELF/DynamicLoader.cpp | 128 +++++++------------ Libraries/LibELF/DynamicLoader.h | 7 +- Libraries/LibELF/DynamicObject.cpp | 56 +++++++- Libraries/LibELF/DynamicObject.h | 7 + Libraries/LibGUI/CMakeLists.txt | 2 +- Libraries/LibGfx/CMakeLists.txt | 2 +- Libraries/LibM/CMakeLists.txt | 7 +- Userland/CMakeLists.txt | 2 + Userland/DynamicLoader/main.cpp | 126 +++++++++++++----- Userland/DynamicLoader/misc.cpp | 3 +- Userland/Tests/Kernel/CMakeLists.txt | 1 + Userland/Tests/LibC/CMakeLists.txt | 1 + 28 files changed, 401 insertions(+), 173 deletions(-) diff --git a/Applications/Debugger/main.cpp b/Applications/Debugger/main.cpp index 93922f46e41..cefc1ad1242 100644 --- a/Applications/Debugger/main.cpp +++ b/Applications/Debugger/main.cpp @@ -212,8 +212,9 @@ int main(int argc, char** argv) sa.sa_handler = handle_sigint; sigaction(SIGINT, &sa, nullptr); - bool rc = g_debug_session->insert_breakpoint(g_debug_session->elf().entry().as_ptr()); - ASSERT(rc); + // bool rc = g_debug_session->insert_breakpoint(g_debug_session->elf().entry().as_ptr()); + // bool rc = g_debug_session->insert_breakpoint((void*)0x08048f49); + // ASSERT(rc); Debug::DebugInfo::SourcePosition previous_source_position; bool in_step_line = false; diff --git a/CMakeLists.txt b/CMakeLists.txt index f17a7eb0d03..5aa600954c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,8 +119,19 @@ endfunction() function(serenity_lib target_name fs_name) serenity_install_headers(${target_name}) serenity_install_sources("Libraries/${target_name}") - add_library(${target_name} ${SOURCES} ${GENERATED_SOURCES}) - install(TARGETS ${target_name} ARCHIVE DESTINATION usr/lib) + #add_library(${target_name} SHARED ${SOURCES} ${GENERATED_SOURCES}) + add_library(${target_name} SHARED ${SOURCES} ${GENERATED_SOURCES} ${CMAKE_SOURCE_DIR}/Libraries/LibC/crt0_shared.cpp) + #library_sources("{target_name}" PRIVATE ${CMAKE_SOURCE_DIR}/Libraries/LibC/crt0_shared.cpp) + install(TARGETS ${target_name} DESTINATION usr/lib) + set_target_properties(${target_name} PROPERTIES OUTPUT_NAME ${fs_name}) + serenity_generated_sources(${target_name}) +endfunction() + +function(serenity_shared_lib target_name fs_name) + serenity_install_headers(${target_name}) + serenity_install_sources("Libraries/${target_name}") + add_library(${target_name} SHARED ${SOURCES} ${GENERATED_SOURCES}) + install(TARGETS ${target_name} DESTINATION usr/lib) set_target_properties(${target_name} PROPERTIES OUTPUT_NAME ${fs_name}) serenity_generated_sources(${target_name}) endfunction() @@ -128,16 +139,7 @@ endfunction() function(serenity_libc target_name fs_name) serenity_install_headers("") serenity_install_sources("Libraries/LibC") - add_library(${target_name} ${SOURCES}) - install(TARGETS ${target_name} ARCHIVE DESTINATION usr/lib) - set_target_properties(${target_name} PROPERTIES OUTPUT_NAME ${fs_name}) - target_link_directories(LibC PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) - serenity_generated_sources(${target_name}) -endfunction() - -function(serenity_libc_shared target_name fs_name) - serenity_install_headers("") - serenity_install_sources("Libraries/LibC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib -fpic") add_library(${target_name} SHARED ${SOURCES}) install(TARGETS ${target_name} DESTINATION usr/lib) set_target_properties(${target_name} PROPERTIES OUTPUT_NAME ${fs_name}) @@ -147,6 +149,7 @@ endfunction() function(serenity_bin target_name) add_executable(${target_name} ${SOURCES}) + target_sources(${target_name} PRIVATE ${CMAKE_SOURCE_DIR}/Libraries/LibC/crt0_shared.cpp) install(TARGETS ${target_name} RUNTIME DESTINATION bin) serenity_generated_sources(${target_name}) endfunction() @@ -220,8 +223,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -g1 -fno-exceptions -fno-rtti -Wno-a set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffile-prefix-map=${CMAKE_SOURCE_DIR}=.") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG -DSANITIZE_PTRS") -set(CMAKE_CXX_FLAGS_WITHOUT_STATIC ${CMAKE_CXX_FLAGS}) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static") +set(CMAKE_CXX_FLAGS_STATIC ${CMAKE_CXX_FLAGS}) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostartfiles -lgcc_s -pie -fpic") + add_link_options(--sysroot ${CMAKE_BINARY_DIR}/Root) include_directories(Libraries/LibC) diff --git a/Demos/CMakeLists.txt b/Demos/CMakeLists.txt index 9f939e84a34..f6ddd58db3a 100644 --- a/Demos/CMakeLists.txt +++ b/Demos/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(Cube) add_subdirectory(DynamicObject) -add_subdirectory(DynamicLink) +#add_subdirectory(DynamicLink) add_subdirectory(Eyes) add_subdirectory(Fire) add_subdirectory(HelloWorld) diff --git a/Demos/DynamicObject/CMakeLists.txt b/Demos/DynamicObject/CMakeLists.txt index d32736e9849..d1df1d0cbf6 100644 --- a/Demos/DynamicObject/CMakeLists.txt +++ b/Demos/DynamicObject/CMakeLists.txt @@ -3,9 +3,9 @@ set(SOURCES ../../Libraries/LibC/crt0_shared.cpp ) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_WITHOUT_STATIC} -nostartfiles -pie -fpic") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostartfiles -lgcc_s -pie -fpic ") serenity_bin(DynamicObjectDemo) -target_link_libraries(DynamicObjectDemo SampleLib LibCShared) +target_link_libraries(DynamicObjectDemo SampleLib LibC LibCore LibGUI) add_subdirectory(SampleLib) diff --git a/Demos/DynamicObject/SampleLib/CMakeLists.txt b/Demos/DynamicObject/SampleLib/CMakeLists.txt index b02dbe8196a..38a75141f01 100644 --- a/Demos/DynamicObject/SampleLib/CMakeLists.txt +++ b/Demos/DynamicObject/SampleLib/CMakeLists.txt @@ -3,9 +3,9 @@ set(SOURCES lib.cpp ) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_WIHTOUT_STATIC} -nostdlib -fpic") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib -fpic") add_library(SampleLib SHARED ${SOURCES}) -target_link_libraries(SampleLib LibCShared) +target_link_libraries(SampleLib LibC) #target_link_libraries(SampleLib) install(TARGETS SampleLib DESTINATION usr/lib) diff --git a/Demos/DynamicObject/SampleLib/lib.cpp b/Demos/DynamicObject/SampleLib/lib.cpp index 1bfb7693bd5..a0e6e76aa78 100644 --- a/Demos/DynamicObject/SampleLib/lib.cpp +++ b/Demos/DynamicObject/SampleLib/lib.cpp @@ -1,3 +1,28 @@ +/* + * Copyright (c) 2020, 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 "../lib.h" diff --git a/Demos/DynamicObject/lib.h b/Demos/DynamicObject/lib.h index eec49a1f4bf..05b59afd9ee 100644 --- a/Demos/DynamicObject/lib.h +++ b/Demos/DynamicObject/lib.h @@ -1,3 +1,30 @@ +/* + * Copyright (c) 2020, 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 int func(); diff --git a/Demos/DynamicObject/main.cpp b/Demos/DynamicObject/main.cpp index c4d401d4ba7..2b575cb185d 100644 --- a/Demos/DynamicObject/main.cpp +++ b/Demos/DynamicObject/main.cpp @@ -1,4 +1,37 @@ +/* + * Copyright (c) 2020, 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 "lib.h" +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -19,6 +52,34 @@ int main(int argc, char** argv, char** env) int _errno = errno; perror("open failed"); printf("rc: %d, errno: %d\n", rc, _errno); - return func() + g_tls1 + g_tls2; } + printf("ls: %s\n", Core::command("ls", {}).characters()); + auto app = GUI::Application::construct(argc, argv); + + auto window = GUI::Window::construct(); + window->resize(240, 160); + window->set_title("Hello World!"); + window->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-hello-world.png")); + + auto& main_widget = window->set_main_widget(); + main_widget.set_fill_with_background_color(true); + main_widget.set_background_color(Color::White); + auto& layout = main_widget.set_layout(); + layout.set_margins({ 4, 4, 4, 4 }); + + auto& label = main_widget.add(); + label.set_text("Hello\nWorld!"); + + auto& button = main_widget.add(); + button.set_text("Good-bye"); + button.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); + button.set_preferred_size(0, 20); + button.on_click = [&](auto) { + app->quit(); + }; + + window->show(); + + return app->exec(); + // return func() + g_tls1 + g_tls2; } diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 9e02c5c0b8f..ef5c5585f8b 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -3,6 +3,8 @@ set(KERNEL_HEAP_SOURCES Heap/kmalloc.cpp ) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_STATIC}") + set(KERNEL_SOURCES ACPI/DynamicParser.cpp ACPI/Initialize.cpp diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 2ba9589dcd7..f8dc1698bf1 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -841,6 +841,8 @@ KResult VFS::validate_path_against_process_veil(StringView path, int options) { if (Process::current()->veil_state() == VeilState::None) return KSuccess; + if (path == "/usr/lib/Loader.so") + return KSuccess; // FIXME: Figure out a nicer way to do this. if (String(path).contains("/..")) diff --git a/Kernel/Process.h b/Kernel/Process.h index 3e36c61d0eb..1ed334eb90e 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -423,7 +423,7 @@ public: int exec(String path, Vector arguments, Vector environment, int recusion_depth = 0); struct LoadResult { - FlatPtr load_offset { 0 }; + FlatPtr load_base { 0 }; FlatPtr entry_eip { 0 }; size_t size { 0 }; FlatPtr program_headers { 0 }; @@ -581,7 +581,7 @@ private: gid_t m_sgid { 0 }; ThreadID m_exec_tid { 0 }; - FlatPtr m_load_offset { 0U }; + FlatPtr m_load_base { 0U }; FlatPtr m_entry_eip { 0U }; int m_main_program_fd { -1 }; diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp index 14ab994b640..9fbd7c1a975 100644 --- a/Kernel/Syscalls/execve.cpp +++ b/Kernel/Syscalls/execve.cpp @@ -80,6 +80,7 @@ KResultOr Process::load_elf_object(FileDescription& object_ size_t master_tls_size = 0; size_t master_tls_alignment = 0; m_entry_eip = 0; + FlatPtr load_base_address = 0; MM.enter_process_paging_scope(*this); String object_name = LexicalPath(object_description.absolute_path()).basename(); @@ -96,6 +97,8 @@ KResultOr Process::load_elf_object(FileDescription& object_ prot |= PROT_EXEC; if (auto* region = allocate_region_with_vmobject(vaddr.offset(load_offset), size, *vmobject, offset_in_image, String(name), prot)) { region->set_shared(true); + if (offset_in_image == 0) + load_base_address = (FlatPtr)region->vaddr().as_ptr(); return region->vaddr().as_ptr(); } return nullptr; @@ -137,7 +140,7 @@ KResultOr Process::load_elf_object(FileDescription& object_ // NOTE: At this point, we've committed to the new executable. return LoadResult { - load_offset, + load_base_address, loader->entry().offset(load_offset).get(), (size_t)loader_metadata.size, VirtualAddress(loader->image().program_header_table_offset()).offset(load_offset).get(), @@ -175,7 +178,7 @@ int Process::load(NonnullRefPtr main_program_description, RefPt if (result.is_error()) return result.error(); - m_load_offset = result.value().load_offset; + m_load_base = result.value().load_base; m_entry_eip = result.value().entry_eip; m_master_tls_region = result.value().tls_region; m_master_tls_size = result.value().tls_size; @@ -192,7 +195,7 @@ int Process::load(NonnullRefPtr main_program_description, RefPt if (interpreter_load_result.is_error()) return interpreter_load_result.error(); - m_load_offset = interpreter_load_result.value().load_offset; + m_load_base = interpreter_load_result.value().load_base; m_entry_eip = interpreter_load_result.value().entry_eip; // TLS allocation will be done in userspace by the loader @@ -357,7 +360,7 @@ Vector Process::generate_auxiliary_vector() const // PHDR/EXECFD // PH* auxv.append({ AuxiliaryValue::PageSize, PAGE_SIZE }); - auxv.append({ AuxiliaryValue::BaseAddress, (void*)m_load_offset }); + auxv.append({ AuxiliaryValue::BaseAddress, (void*)m_load_base }); auxv.append({ AuxiliaryValue::Entry, (void*)m_entry_eip }); // NOTELF diff --git a/Kernel/Syscalls/mmap.cpp b/Kernel/Syscalls/mmap.cpp index 36aa2a1b670..6607efc41da 100644 --- a/Kernel/Syscalls/mmap.cpp +++ b/Kernel/Syscalls/mmap.cpp @@ -422,8 +422,6 @@ void* Process::sys$allocate_tls(size_t size) { REQUIRE_PROMISE(stdio); - dbg() << "allocate TLS: " << size; - if (!size) return (void*)-EINVAL; @@ -445,7 +443,6 @@ void* Process::sys$allocate_tls(size_t size) return (void*)-EFAULT; m_master_tls_region = tls_region->make_weak_ptr(); - dbg() << "master_tls_region: " << m_master_tls_region->vaddr(); m_master_tls_size = size; m_master_tls_alignment = PAGE_SIZE; diff --git a/Libraries/LibC/CMakeLists.txt b/Libraries/LibC/CMakeLists.txt index bcf1222659e..560e795abd8 100644 --- a/Libraries/LibC/CMakeLists.txt +++ b/Libraries/LibC/CMakeLists.txt @@ -1,7 +1,7 @@ set(LIBC_SOURCES arpa/inet.cpp assert.cpp - #crt0.cpp + crt0_shared.cpp ctype.cpp cxxabi.cpp dirent.cpp @@ -66,12 +66,7 @@ add_custom_command( ) set(SOURCES ${LIBC_SOURCES} ${AK_SOURCES} ${ELF_SOURCES}) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib") serenity_libc(LibC c) target_link_libraries(LibC crt0) add_dependencies(LibC LibM) - -set(SOURCES ${SOURCES} "crt0_shared.cpp") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib") -serenity_libc_shared(LibCShared c) -#add_library(LibCShared SHARED ${SOURCES}) -#install(TARGETS LibCShared DESTINATION usr/lib) diff --git a/Libraries/LibC/crt0_shared.cpp b/Libraries/LibC/crt0_shared.cpp index c016e245569..4a813cd8400 100644 --- a/Libraries/LibC/crt0_shared.cpp +++ b/Libraries/LibC/crt0_shared.cpp @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 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 #include #include @@ -17,16 +43,11 @@ extern bool __environ_is_malloced; int _start(int argc, char** argv, char** env); int _start(int argc, char** argv, char** env) { - // asm("int3"); - environ = env; - __environ_is_malloced = false; + _init(); - __libc_init(); - // _init(); - - int status = main(argc, argv, environ); + int status = main(argc, argv, env); return status; } } -void* __dso_handle = nullptr; +void* __dso_handle __attribute__((__weak__)); diff --git a/Libraries/LibCore/CMakeLists.txt b/Libraries/LibCore/CMakeLists.txt index 1a7467170de..02b1b6b9995 100644 --- a/Libraries/LibCore/CMakeLists.txt +++ b/Libraries/LibCore/CMakeLists.txt @@ -33,4 +33,4 @@ set(SOURCES ) serenity_lib(LibCore core) -target_link_libraries(LibCore LibC) +target_link_libraries(LibCore LibC LibCrypt) diff --git a/Libraries/LibELF/DynamicLoader.cpp b/Libraries/LibELF/DynamicLoader.cpp index ad5c486bc01..c238a15c41b 100644 --- a/Libraries/LibELF/DynamicLoader.cpp +++ b/Libraries/LibELF/DynamicLoader.cpp @@ -59,7 +59,7 @@ static void* mmap_with_name(void* addr, size_t length, int prot, int flags, int namespace ELF { -static bool s_always_bind_now = true; +static bool s_always_bind_now = false; NonnullRefPtr DynamicLoader::construct(const char* filename, int fd, size_t size) { @@ -90,7 +90,7 @@ DynamicLoader::DynamicLoader(const char* filename, int fd, size_t size) m_tls_size = calculate_tls_size(); - m_valid = is_valid(); + m_valid = validate(); } RefPtr DynamicLoader::dynamic_object_from_image() const @@ -121,16 +121,14 @@ size_t DynamicLoader::calculate_tls_size() const bool DynamicLoader::validate() { auto* elf_header = (Elf32_Ehdr*)m_file_mapping; - - if (!validate_elf_header(*elf_header, m_file_size) || !validate_program_headers(*elf_header, m_file_size, (u8*)m_file_mapping, m_file_size, &m_program_interpreter)) { - m_valid = false; - } + return validate_elf_header(*elf_header, m_file_size) && validate_program_headers(*elf_header, m_file_size, (u8*)m_file_mapping, m_file_size, &m_program_interpreter); } DynamicLoader::~DynamicLoader() { if (MAP_FAILED != m_file_mapping) munmap(m_file_mapping, m_file_size); + close(m_image_fd); } void* DynamicLoader::symbol_for_name(const char* name) @@ -161,6 +159,8 @@ RefPtr 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->set_tls_offset(m_tls_offset); 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); if (!rc) @@ -171,14 +171,13 @@ RefPtr DynamicLoader::load_from_image(unsigned flags, size_t tota bool DynamicLoader::load_stage_2(unsigned flags, size_t total_tls_size) { ASSERT(flags & RTLD_GLOBAL); - ASSERT(!(flags & RTLD_LAZY)); #ifdef DYNAMIC_LOAD_DEBUG m_dynamic_object->dump(); #endif if (m_dynamic_object->has_text_relocations()) { - dbg() << "Someone linked non -fPIC code into " << m_filename << " :("; + // dbg() << "Someone linked non -fPIC code into " << m_filename << " :("; ASSERT(m_text_segment_load_address.get() != 0); if (0 > mprotect(m_text_segment_load_address.as_ptr(), m_text_segment_size, PROT_READ | PROT_WRITE)) { perror("mprotect .text: PROT_READ | PROT_WRITE"); // FIXME: dlerror? @@ -189,7 +188,6 @@ bool DynamicLoader::load_stage_2(unsigned flags, size_t total_tls_size) do_relocations(total_tls_size); if (flags & RTLD_LAZY) { - ASSERT_NOT_REACHED(); // TODO: Support lazy binding setup_plt_trampoline(); } @@ -203,9 +201,7 @@ bool DynamicLoader::load_stage_2(unsigned flags, size_t total_tls_size) call_object_init_functions(); -#ifdef DYNAMIC_LOAD_DEBUG - dbgprintf("Loaded %s\n", m_filename.characters()); -#endif + VERBOSE("Loaded %s\n", m_filename.characters()); return true; } @@ -239,7 +235,13 @@ void DynamicLoader::load_program_headers() // Process regions in order: .text, .data, .tls auto* region = text_region_ptr; - void* text_segment_begin = mmap_with_name(nullptr, region->required_load_size(), region->mmap_prot(), MAP_PRIVATE, m_image_fd, region->offset(), String::format(".text: %s", m_filename.characters()).characters()); + void* text_segment_begin = mmap_with_name(nullptr, + region->required_load_size(), + region->mmap_prot(), + MAP_PRIVATE, + m_image_fd, + region->offset(), + String::format("%s: .text", m_filename.characters()).characters()); if (MAP_FAILED == text_segment_begin) { ASSERT_NOT_REACHED(); } @@ -249,7 +251,13 @@ void DynamicLoader::load_program_headers() m_dynamic_section_address = dynamic_region_desired_vaddr.offset(m_text_segment_load_address.get()); region = data_region_ptr; - void* data_segment_begin = mmap_with_name((u8*)text_segment_begin + m_text_segment_size, region->required_load_size(), region->mmap_prot(), MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, String::format(".data: %s", m_filename.characters()).characters()); + void* data_segment_begin = mmap_with_name((u8*)text_segment_begin + m_text_segment_size, + region->required_load_size(), + region->mmap_prot(), + MAP_ANONYMOUS | MAP_PRIVATE, + 0, + 0, + String::format("%s: .data", m_filename.characters()).characters()); if (MAP_FAILED == data_segment_begin) { ASSERT_NOT_REACHED(); } @@ -279,7 +287,10 @@ void DynamicLoader::do_relocations(size_t total_tls_size) auto symbol = relocation.symbol(); VERBOSE("Absolute relocation: name: '%s', value: %p\n", symbol.name(), symbol.value()); auto res = lookup_symbol(symbol); - ASSERT(res.found); + if (!res.found) { + dbgln("ERROR: symbol not found: {}", symbol.name()); + ASSERT_NOT_REACHED(); + } u32 symbol_address = res.address; *patch_ptr += symbol_address; VERBOSE(" Symbol address: %p\n", *patch_ptr); @@ -298,13 +309,16 @@ void DynamicLoader::do_relocations(size_t total_tls_size) case R_386_GLOB_DAT: { auto symbol = relocation.symbol(); if (!strcmp(symbol.name(), "__deregister_frame_info") || !strcmp(symbol.name(), "_ITM_registerTMCloneTable") - || !strcmp(symbol.name(), "_ITM_deregisterTMCloneTable") || !strcmp(symbol.name(), "__register_frame_info")) { + || !strcmp(symbol.name(), "_ITM_deregisterTMCloneTable") || !strcmp(symbol.name(), "__register_frame_info") + || !strcmp(symbol.name(), "__cxa_finalize") // __cxa_finalize will be called from libc's exit() + ) { // We do not support these break; } VERBOSE("Global data relocation: '%s', value: %p\n", symbol.name(), symbol.value()); auto res = lookup_symbol(symbol); VERBOSE("was symbol found? %d, address: 0x%x\n", res.found, res.address); + ASSERT(res.found); if (!res.found) { // TODO this is a hack @@ -331,28 +345,28 @@ void DynamicLoader::do_relocations(size_t total_tls_size) } case R_386_TLS_TPOFF32: case R_386_TLS_TPOFF: { - dbgprintf("Relocation type: R_386_TLS_TPOFF at offset %X\n", relocation.offset()); + VERBOSE("Relocation type: R_386_TLS_TPOFF at offset %X\n", relocation.offset()); auto symbol = relocation.symbol(); // For some reason, LibC has a R_386_TLS_TPOFF that referes to the undefined symbol.. huh if (relocation.symbol_index() == 0) break; - dbgprintf("Symbol index: %d\n", symbol.index()); - dbgprintf("Symbol is_undefined?: %d\n", symbol.is_undefined()); - dbgprintf("TLS relocation: '%s', value: %p\n", symbol.name(), symbol.value()); + VERBOSE("Symbol index: %d\n", symbol.index()); + VERBOSE("Symbol is_undefined?: %d\n", symbol.is_undefined()); + VERBOSE("TLS relocation: '%s', value: %p\n", symbol.name(), symbol.value()); auto res = lookup_symbol(symbol); if (!res.found) break; ASSERT(res.found); u32 symbol_value = res.value; - dbgprintf("symbol value: %d\n", symbol_value); + VERBOSE("symbol value: %d\n", symbol_value); const auto dynamic_object_of_symbol = res.dynamic_object; ASSERT(dynamic_object_of_symbol); size_t offset_of_tls_end = dynamic_object_of_symbol->tls_offset().value() + dynamic_object_of_symbol->tls_size().value(); // size_t offset_of_tls_end = tls_offset() + tls_size(); - dbgprintf("patch ptr: 0x%x\n", patch_ptr); - dbgprintf("tls end offset: %d, total tls size: %d\n", offset_of_tls_end, total_tls_size); + VERBOSE("patch ptr: 0x%x\n", patch_ptr); + VERBOSE("tls end offset: %d, total tls size: %d\n", offset_of_tls_end, total_tls_size); *patch_ptr = (offset_of_tls_end - total_tls_size - symbol_value - sizeof(Elf32_Addr)); - dbgprintf("*patch ptr: %d\n", (i32)*patch_ptr); + VERBOSE("*patch ptr: %d\n", (i32)*patch_ptr); break; } default: @@ -376,8 +390,8 @@ void DynamicLoader::do_relocations(size_t total_tls_size) if (m_dynamic_object->must_bind_now() || s_always_bind_now) { // Eagerly BIND_NOW the PLT entries, doing all the symbol looking goodness // The patch method returns the address for the LAZY fixup path, but we don't need it here - VERBOSE("patching plt reloaction: 0x%x", relocation.offset_in_section()); - (void)patch_plt_entry(relocation.offset_in_section()); + VERBOSE("patching plt reloaction: 0x%x\n", relocation.offset_in_section()); + (void)m_dynamic_object->patch_plt_entry(relocation.offset_in_section()); } else { // LAZY-ily bind the PLT slots by just adding the base address to the offsets stored there // This avoids doing symbol lookup, which might be expensive @@ -390,9 +404,7 @@ void DynamicLoader::do_relocations(size_t total_tls_size) return IterationDecision::Continue; }); -#ifdef DYNAMIC_LOAD_DEBUG - dbgprintf("Done relocating!\n"); -#endif + VERBOSE("Done relocating!\n"); } // Defined in /plt_trampoline.S @@ -400,57 +412,32 @@ extern "C" void _plt_trampoline(void) __attribute__((visibility("hidden"))); void DynamicLoader::setup_plt_trampoline() { + ASSERT(m_dynamic_object); VirtualAddress got_address = m_dynamic_object->plt_got_base_address(); FlatPtr* got_ptr = (FlatPtr*)got_address.as_ptr(); - got_ptr[1] = (FlatPtr)this; + got_ptr[1] = (FlatPtr)m_dynamic_object.ptr(); got_ptr[2] = (FlatPtr)&_plt_trampoline; -#ifdef DYNAMIC_LOAD_DEBUG - dbgprintf("Set GOT PLT entries at %p: [0] = %p [1] = %p, [2] = %p\n", got_ptr, (void*)got_ptr[0], (void*)got_ptr[1], (void*)got_ptr[2]); -#endif + VERBOSE("Set GOT PLT entries at %p: [0] = %p [1] = %p, [2] = %p\n", got_ptr, (void*)got_ptr[0], (void*)got_ptr[1], (void*)got_ptr[2]); } // Called from our ASM routine _plt_trampoline. // Tell the compiler that it might be called from other places: -extern "C" Elf32_Addr _fixup_plt_entry(DynamicLoader* object, u32 relocation_offset); -extern "C" Elf32_Addr _fixup_plt_entry(DynamicLoader* object, u32 relocation_offset) +extern "C" Elf32_Addr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset); +extern "C" Elf32_Addr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset) { return object->patch_plt_entry(relocation_offset); } -// offset is in PLT relocation table -Elf32_Addr DynamicLoader::patch_plt_entry(u32 relocation_offset) -{ - auto relocation = m_dynamic_object->plt_relocation_section().relocation_at_offset(relocation_offset); - - ASSERT(relocation.type() == R_386_JMP_SLOT); - - auto sym = relocation.symbol(); - - u8* relocation_address = relocation.address().as_ptr(); - auto res = lookup_symbol(sym); - ASSERT(res.found); - u32 symbol_location = res.address; - - VERBOSE("DynamicLoader: Jump slot relocation: putting %s (%p) into PLT at %p\n", sym.name(), symbol_location, relocation_address); - - *(u32*)relocation_address = symbol_location; - - return symbol_location; -} - void DynamicLoader::call_object_init_functions() { - dbg() << "inside call_object_init_functions of " << m_filename; typedef void (*InitFunc)(); if (m_dynamic_object->has_init_section()) { auto init_function = (InitFunc)(m_dynamic_object->init_section().address().as_ptr()); - // #ifdef DYNAMIC_LOAD_DEBUG - dbgprintf("Calling DT_INIT at %p\n", init_function); - // #endif + VERBOSE("Calling DT_INIT at %p\n", init_function); (init_function)(); } @@ -464,9 +451,7 @@ void DynamicLoader::call_object_init_functions() // 0 definitely shows up. Apparently 0/-1 are valid? Confusing. if (!*init_begin || ((FlatPtr)*init_begin == (FlatPtr)-1)) continue; - // #ifdef DYNAMIC_LOAD_DEBUG - dbgprintf("Calling DT_INITARRAY entry at %p\n", *init_begin); - // #endif + VERBOSE("Calling DT_INITARRAY entry at %p\n", *init_begin); (*init_begin)(); ++init_begin; } @@ -484,22 +469,7 @@ u32 DynamicLoader::ProgramHeaderRegion::mmap_prot() const DynamicObject::SymbolLookupResult DynamicLoader::lookup_symbol(const ELF::DynamicObject::Symbol& symbol) const { - VERBOSE("looking up symbol: %s\n", symbol.name()); - if (!symbol.is_undefined()) { - VERBOSE("symbol is defiend in its object\n"); - return { true, symbol.value(), (FlatPtr)symbol.address().as_ptr(), &symbol.object() }; - } - ASSERT(m_global_symbol_lookup_func); - return m_global_symbol_lookup_func(symbol.name()); + return m_dynamic_object->lookup_symbol(symbol); } -// Optional DynamicLoader::lookup_symbol(const char* name) const -// { -// ASSERT(m_dynamic_object); -// auto res = m_dynamic_object->hash_section().lookup_symbol(name); -// if (res.is_undefined()) -// return {}; -// return SymbolLookupResult { true, res.value(), (FlatPtr)res.address().as_ptr(), m_dynamic_object.ptr() }; -// } - } // end namespace ELF diff --git a/Libraries/LibELF/DynamicLoader.h b/Libraries/LibELF/DynamicLoader.h index e812ab0d35e..fcc2886d6ce 100644 --- a/Libraries/LibELF/DynamicLoader.h +++ b/Libraries/LibELF/DynamicLoader.h @@ -62,9 +62,6 @@ public: void dump(); - // Will be called from _fixup_plt_entry, as part of the PLT trampoline - Elf32_Addr patch_plt_entry(u32 relocation_offset); - // Requested program interpreter from program headers. May be empty string StringView program_interpreter() const { return m_program_interpreter; } @@ -78,8 +75,8 @@ public: template void for_each_needed_library(F) const; - using SymbolLookupFunction = DynamicObject::SymbolLookupResult (*)(const char*); - SymbolLookupFunction m_global_symbol_lookup_func { nullptr }; + 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; } diff --git a/Libraries/LibELF/DynamicObject.cpp b/Libraries/LibELF/DynamicObject.cpp index bae2dd50245..09e162ced4a 100644 --- a/Libraries/LibELF/DynamicObject.cpp +++ b/Libraries/LibELF/DynamicObject.cpp @@ -32,6 +32,16 @@ #include #include +// #define DYNAMIC_OBJECT_VERBOSE + +#ifdef DYNAMIC_OBJECT_VERBOSE +# define VERBOSE(fmt, ...) dbgprintf(fmt, ##__VA_ARGS__) +#else +# define VERBOSE(fmt, ...) \ + do { \ + } while (0) +#endif + namespace ELF { static const char* name_for_dtag(Elf32_Sword d_tag); @@ -63,8 +73,8 @@ void DynamicObject::dump() const if (m_has_soname) builder.appendf("DT_SONAME: %s\n", soname()); // FIXME: Valdidate that this string is null terminated? - dbgprintf("Dynamic section at address %p contains %zu entries:\n", m_dynamic_address.as_ptr(), num_dynamic_sections); - dbgprintf("%s", builder.to_string().characters()); + VERBOSE("Dynamic section at address %p contains %zu entries:\n", m_dynamic_address.as_ptr(), num_dynamic_sections); + VERBOSE("%s", builder.to_string().characters()); } void DynamicObject::parse() @@ -402,4 +412,46 @@ NonnullRefPtr DynamicObject::construct(VirtualAddress base_addres return adopt(*new DynamicObject(base_address, dynamic_section_address)); } +// offset is in PLT relocation table +Elf32_Addr DynamicObject::patch_plt_entry(u32 relocation_offset) +{ + auto relocation = plt_relocation_section().relocation_at_offset(relocation_offset); + + ASSERT(relocation.type() == R_386_JMP_SLOT); + + auto sym = relocation.symbol(); + if (StringView { sym.name() } == "__cxa_demangle") { + dbgln("__cxa_demangle is currently not supported for shared objects"); + // FIXME: Where is it defined? + ASSERT_NOT_REACHED(); + } + + u8* relocation_address = relocation.address().as_ptr(); + auto res = lookup_symbol(sym); + + if (!res.found) { + dbgln("did not find symbol: {} ", sym.name()); + ASSERT_NOT_REACHED(); + } + + u32 symbol_location = res.address; + + VERBOSE("DynamicLoader: Jump slot relocation: putting %s (%p) into PLT at %p\n", sym.name(), symbol_location, relocation_address); + + *(u32*)relocation_address = symbol_location; + + return symbol_location; +} + +DynamicObject::SymbolLookupResult DynamicObject::lookup_symbol(const ELF::DynamicObject::Symbol& symbol) const +{ + VERBOSE("looking up symbol: %s\n", symbol.name()); + if (!symbol.is_undefined()) { + VERBOSE("symbol is defiend in its object\n"); + return { true, symbol.value(), (FlatPtr)symbol.address().as_ptr(), &symbol.object() }; + } + ASSERT(m_global_symbol_lookup_func); + return m_global_symbol_lookup_func(symbol.name()); +} + } // end namespace ELF diff --git a/Libraries/LibELF/DynamicObject.h b/Libraries/LibELF/DynamicObject.h index 5541f1fa3e2..08c536c43c2 100644 --- a/Libraries/LibELF/DynamicObject.h +++ b/Libraries/LibELF/DynamicObject.h @@ -267,6 +267,13 @@ public: }; Optional lookup_symbol(const char* name) const; + // Will be called from _fixup_plt_entry, as part of the PLT trampoline + Elf32_Addr patch_plt_entry(u32 relocation_offset); + + SymbolLookupResult lookup_symbol(const ELF::DynamicObject::Symbol& symbol) const; + using SymbolLookupFunction = DynamicObject::SymbolLookupResult (*)(const char*); + SymbolLookupFunction m_global_symbol_lookup_func { nullptr }; + private: explicit DynamicObject(VirtualAddress base_address, VirtualAddress dynamic_section_address); diff --git a/Libraries/LibGUI/CMakeLists.txt b/Libraries/LibGUI/CMakeLists.txt index 9e819f2731a..cc5e199f366 100644 --- a/Libraries/LibGUI/CMakeLists.txt +++ b/Libraries/LibGUI/CMakeLists.txt @@ -95,4 +95,4 @@ set(GENERATED_SOURCES ) serenity_lib(LibGUI gui) -target_link_libraries(LibGUI LibCore LibGfx LibIPC LibThread LibCpp LibRegex) +target_link_libraries(LibGUI LibCore LibGfx LibIPC LibThread LibCpp LibShell LibRegex LibJS) diff --git a/Libraries/LibGfx/CMakeLists.txt b/Libraries/LibGfx/CMakeLists.txt index b919b3246a8..c4fb1e13b69 100644 --- a/Libraries/LibGfx/CMakeLists.txt +++ b/Libraries/LibGfx/CMakeLists.txt @@ -33,4 +33,4 @@ set(SOURCES ) serenity_lib(LibGfx gfx) -target_link_libraries(LibGfx LibM LibCore) +target_link_libraries(LibGfx LibM LibCore LibIPC) diff --git a/Libraries/LibM/CMakeLists.txt b/Libraries/LibM/CMakeLists.txt index 7ed9959738b..bdb9baf78a0 100644 --- a/Libraries/LibM/CMakeLists.txt +++ b/Libraries/LibM/CMakeLists.txt @@ -2,6 +2,9 @@ set(SOURCES math.cpp ) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib") serenity_libc(LibM m) -target_include_directories(LibM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(LibM LibC) +#target_link_libraries(LibM) +#set_target_properties(LibM PROPERTIES OUTPUT_NAME m) +#target_link_directories(LibM PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/Userland/CMakeLists.txt b/Userland/CMakeLists.txt index 537180a29cf..1ca0fe9afc8 100644 --- a/Userland/CMakeLists.txt +++ b/Userland/CMakeLists.txt @@ -5,11 +5,13 @@ foreach(CMD_SRC ${CMD_SOURCES}) get_filename_component(CMD_NAME ${CMD_SRC} NAME_WE) if (CMD_NAME IN_LIST SPECIAL_TARGETS) add_executable("${CMD_NAME}-bin" ${CMD_SRC}) + target_sources("${CMD_NAME}-bin" PRIVATE ${CMAKE_SOURCE_DIR}/Libraries/LibC/crt0_shared.cpp) target_link_libraries("${CMD_NAME}-bin" LibCore) install(TARGETS "${CMD_NAME}-bin" RUNTIME DESTINATION bin) install(CODE "execute_process(COMMAND mv ${CMD_NAME}-bin ${CMD_NAME} WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin)") else () add_executable(${CMD_NAME} ${CMD_SRC}) + target_sources("${CMD_NAME}" PRIVATE ${CMAKE_SOURCE_DIR}/Libraries/LibC/crt0_shared.cpp) target_link_libraries(${CMD_NAME} LibCore) install(TARGETS ${CMD_NAME} RUNTIME DESTINATION bin) endif() diff --git a/Userland/DynamicLoader/main.cpp b/Userland/DynamicLoader/main.cpp index 981ecf763d2..8bd5e747981 100644 --- a/Userland/DynamicLoader/main.cpp +++ b/Userland/DynamicLoader/main.cpp @@ -63,6 +63,7 @@ static HashMap> 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 get_dependencies(const String& name) +{ + auto lib = g_loaders.get(name).value(); + Vector 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(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); } } diff --git a/Userland/DynamicLoader/misc.cpp b/Userland/DynamicLoader/misc.cpp index 18234a66367..5eda0fe5355 100644 --- a/Userland/DynamicLoader/misc.cpp +++ b/Userland/DynamicLoader/misc.cpp @@ -34,6 +34,5 @@ const char* __cxa_demangle(const char*, void*, void*, int*) return ""; } -// FIXME: Is this correct? -void* __dso_handle = nullptr; +void* __dso_handle __attribute__((__weak__)); } diff --git a/Userland/Tests/Kernel/CMakeLists.txt b/Userland/Tests/Kernel/CMakeLists.txt index cd9438dc4a8..c18d364cabf 100644 --- a/Userland/Tests/Kernel/CMakeLists.txt +++ b/Userland/Tests/Kernel/CMakeLists.txt @@ -3,6 +3,7 @@ file(GLOB CMD_SOURCES CONFIGURE_DEPENDS "*.cpp") foreach(CMD_SRC ${CMD_SOURCES}) get_filename_component(CMD_NAME ${CMD_SRC} NAME_WE) add_executable(${CMD_NAME} ${CMD_SRC}) + target_sources("${CMD_NAME}" PRIVATE ${CMAKE_SOURCE_DIR}/Libraries/LibC/crt0_shared.cpp) target_link_libraries(${CMD_NAME} LibCore) install(TARGETS ${CMD_NAME} RUNTIME DESTINATION usr/Tests/Kernel) endforeach() diff --git a/Userland/Tests/LibC/CMakeLists.txt b/Userland/Tests/LibC/CMakeLists.txt index 799dfa9ff4e..8ce9b5c2b9d 100644 --- a/Userland/Tests/LibC/CMakeLists.txt +++ b/Userland/Tests/LibC/CMakeLists.txt @@ -3,6 +3,7 @@ file(GLOB CMD_SOURCES CONFIGURE_DEPENDS "*.cpp") foreach(CMD_SRC ${CMD_SOURCES}) get_filename_component(CMD_NAME ${CMD_SRC} NAME_WE) add_executable(${CMD_NAME} ${CMD_SRC}) + target_sources("${CMD_NAME}" PRIVATE ${CMAKE_SOURCE_DIR}/Libraries/LibC/crt0_shared.cpp) target_link_libraries(${CMD_NAME} LibCore) install(TARGETS ${CMD_NAME} RUNTIME DESTINATION usr/Tests/LibC) endforeach()