diff options
author | Andreas Kling <kling@serenityos.org> | 2021-01-12 12:17:30 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-01-12 12:17:46 +0100 |
commit | 13d7c09125f8eec703d0a43a9a87fc8aa08f7319 (patch) | |
tree | 70fd643c429cea5c1f9362c2674511d17a53f3b5 /Libraries/LibELF | |
parent | dc28c07fa526841e05e16161c74a6c23984f1dd5 (diff) | |
download | serenity-13d7c09125f8eec703d0a43a9a87fc8aa08f7319.zip |
Libraries: Move to Userland/Libraries/
Diffstat (limited to 'Libraries/LibELF')
-rw-r--r-- | Libraries/LibELF/Arch/i386/plt_trampoline.S | 58 | ||||
-rw-r--r-- | Libraries/LibELF/AuxiliaryVector.h | 123 | ||||
-rw-r--r-- | Libraries/LibELF/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Libraries/LibELF/CoreDump.h | 87 | ||||
-rw-r--r-- | Libraries/LibELF/DynamicLinker.cpp | 287 | ||||
-rw-r--r-- | Libraries/LibELF/DynamicLinker.h | 45 | ||||
-rw-r--r-- | Libraries/LibELF/DynamicLoader.cpp | 530 | ||||
-rw-r--r-- | Libraries/LibELF/DynamicLoader.h | 164 | ||||
-rw-r--r-- | Libraries/LibELF/DynamicObject.cpp | 527 | ||||
-rw-r--r-- | Libraries/LibELF/DynamicObject.h | 414 | ||||
-rw-r--r-- | Libraries/LibELF/Image.cpp | 419 | ||||
-rw-r--r-- | Libraries/LibELF/Image.h | 299 | ||||
-rw-r--r-- | Libraries/LibELF/Validation.cpp | 267 | ||||
-rw-r--r-- | Libraries/LibELF/Validation.h | 36 | ||||
-rw-r--r-- | Libraries/LibELF/exec_elf.h | 792 |
15 files changed, 0 insertions, 4049 deletions
diff --git a/Libraries/LibELF/Arch/i386/plt_trampoline.S b/Libraries/LibELF/Arch/i386/plt_trampoline.S deleted file mode 100644 index 6eb5e96a5f..0000000000 --- a/Libraries/LibELF/Arch/i386/plt_trampoline.S +++ /dev/null @@ -1,58 +0,0 @@ -/*- - * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Christos Zoulas and by Charles M. Hannum. - * - * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. - */ - -/** - * This asm method is copied from NetBSD. We changed the internal method that - * gets called and the name, but it's still essentially the same as - * _rtld_bind_start from libexec/ld.elf_so/arch/i386/rtld_start.S - */ - -.align 4 - .globl _plt_trampoline - .hidden _plt_trampoline - .type _plt_trampoline,@function -_plt_trampoline: # (obj, reloff) - pushf # save registers - pushl %eax - pushl %ecx - pushl %edx - - pushl 20(%esp) # Copy of reloff - pushl 20(%esp) # Copy of obj - call _fixup_plt_entry # Call the binder - addl $8,%esp # pop binder args - movl %eax,20(%esp) # Store function to be called in obj - - popl %edx - popl %ecx - popl %eax - popf - - leal 4(%esp),%esp # Discard reloff, do not change eflags - ret diff --git a/Libraries/LibELF/AuxiliaryVector.h b/Libraries/LibELF/AuxiliaryVector.h deleted file mode 100644 index 24a5f0924c..0000000000 --- a/Libraries/LibELF/AuxiliaryVector.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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 - -#include <AK/String.h> -#include <AK/Types.h> - -/* Auxiliary Vector types, from Intel386 ABI ver 1.0 section 2.3.3 */ -typedef struct -{ - long a_type; /* Note: Extended to long from int, for ease of comaptibility w/64 bit */ - union { - long a_val; - void* a_ptr; - void (*a_fnc)(); /* In spec, not used */ - } a_un; -} auxv_t; - -// clang-format off -#define AT_NULL 0 /* No length, last entry's a_type has this value */ -#define AT_IGNORE 1 /* Entry has no meaning, a_un undefined */ -#define AT_EXECFD 2 /* a_val contains a file descriptor of the main program image */ -#define AT_PHDR 3 /* a_ptr contains pointer to program header table of main program image */ -#define AT_PHENT 4 /* a_val holds size of program header table entries */ -#define AT_PHNUM 5 /* a_val holds number of program header table entries */ -#define AT_PAGESZ 6 /* a_val gives system page size in bytes */ -#define AT_BASE 7 /* a_ptr holds base address that Loader was loaded into memory */ -#define AT_FLAGS 8 /* a_val holds 1 bit flags. Undefined flags are 0 */ -#define AT_ENTRY 9 /* a_ptr holds entry point of the main program */ -#define AT_NOTELF 10 /* a_val non-zero if the program is not ELF */ -#define AT_UID 11 /* a_val holds real user id of process */ -#define AT_EUID 12 /* a_val holds effective user id of process */ -#define AT_GID 13 /* a_val holds real group id of process */ -#define AT_EGID 14 /* a_val holds effective group id of process */ -#define AT_PLATFORM 15 /* a_val points to a string containing platform name */ -#define AT_HWCAP 16 /* a_val contains bitmask of CPU features. Equivalent to CPUID 1.EDX*/ -#define AT_CLKTCK 17 /* a_val contains frequence at which times() increments. (Re: Spec. What is times()?) */ -#define AT_SECURE 23 /* a_val holds 1 if program in secure mode (e.g. suid). Otherwise 0 */ -#define AT_BASE_PLATFORM 24 /* a_ptr points to a string identifying base platform name, which might be different from platform (e.g x86_64 when in i386 compat) */ -#define AT_RANDOM 25 /* a_ptr points to 16 securely generated random bytes */ -#define AT_HWCAP2 26 /* a_val holds extended hw feature mask. Currently 0 */ -#define AT_EXECFN 31 /* a_ptr points to file name of executed program */ -#define AT_EXE_BASE 32 /* a_ptr holds base address where main program was loaded into memory */ -#define AT_EXE_SIZE 33 /* a_val holds the size of the main program in memory */ -// clang-format on - -namespace ELF { - -struct AuxiliaryValue { - enum Type { - Null = AT_NULL, - Ignore = AT_IGNORE, - ExecFileDescriptor = AT_EXECFD, - Phdr = AT_PHDR, - Phent = AT_PHENT, - Phnum = AT_PHNUM, - PageSize = AT_PAGESZ, - BaseAddress = AT_BASE, - Flags = AT_FLAGS, - Entry = AT_ENTRY, - NotELF = AT_NOTELF, - Uid = AT_UID, - EUid = AT_EUID, - Gid = AT_GID, - EGid = AT_EGID, - Platform = AT_PLATFORM, - HwCap = AT_HWCAP, - ClockTick = AT_CLKTCK, - Secure = AT_SECURE, - BasePlatform = AT_BASE_PLATFORM, - Random = AT_RANDOM, - HwCap2 = AT_HWCAP2, - ExecFilename = AT_EXECFN, - ExeBaseAddress = AT_EXE_BASE, - ExeSize = AT_EXE_SIZE - }; - - AuxiliaryValue(Type type, long val) - { - auxv.a_type = type; - auxv.a_un.a_val = val; - } - AuxiliaryValue(Type type, void* ptr) - { - auxv.a_type = type; - auxv.a_un.a_ptr = (void*)ptr; - } - AuxiliaryValue(Type type, String string) - { - auxv.a_type = type; - auxv.a_un.a_ptr = nullptr; - optional_string = string; - } - - auxv_t auxv {}; - String optional_string; -}; - -} diff --git a/Libraries/LibELF/CMakeLists.txt b/Libraries/LibELF/CMakeLists.txt deleted file mode 100644 index 3c0959e7e9..0000000000 --- a/Libraries/LibELF/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -serenity_install_sources(Libraries/LibELF) diff --git a/Libraries/LibELF/CoreDump.h b/Libraries/LibELF/CoreDump.h deleted file mode 100644 index 4978430306..0000000000 --- a/Libraries/LibELF/CoreDump.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 - -#include <AK/String.h> -#include <AK/Types.h> -#include <LibC/sys/arch/i386/regs.h> - -namespace ELF::Core { - -struct [[gnu::packed]] NotesEntryHeader { - enum Type : u8 { - Null = 0, // Terminates segment - ProcessInfo, - ThreadInfo, - MemoryRegionInfo, - Metadata, - }; - Type type; -}; - -struct [[gnu::packed]] NotesEntry { - NotesEntryHeader header; - char data[]; -}; - -struct [[gnu::packed]] ProcessInfo { - NotesEntryHeader header; - int pid; - u8 termination_signal; - char executable_path[]; // Null terminated -}; - -struct [[gnu::packed]] ThreadInfo { - NotesEntryHeader header; - int tid; - PtraceRegisters regs; -}; - -struct [[gnu::packed]] MemoryRegionInfo { - NotesEntryHeader header; - uint32_t region_start; - uint32_t region_end; - uint16_t program_header_index; - char region_name[]; // Null terminated - - String object_name() const - { - StringView memory_region_name { region_name }; - if (memory_region_name.contains("Loader.so")) - return "Loader.so"; - if (!memory_region_name.contains(":")) - return {}; - return memory_region_name.substring_view(0, memory_region_name.find_first_of(":").value()).to_string(); - } -}; - -struct [[gnu::packed]] Metadata { - NotesEntryHeader header; - char json_data[]; // Null terminated -}; - -} diff --git a/Libraries/LibELF/DynamicLinker.cpp b/Libraries/LibELF/DynamicLinker.cpp deleted file mode 100644 index 3513645d07..0000000000 --- a/Libraries/LibELF/DynamicLinker.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - * 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; - -bool g_allowed_to_check_environment_variables { false }; -bool g_do_breakpoint_trap_before_entry { false }; -} - -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()); -} - -static NonnullRefPtr<DynamicLoader> commit_elf(const String& name) -{ - auto loader = g_loaders.get(name).value(); - for (const auto& needed_name : get_dependencies(name)) { - String library_name = get_library_name(needed_name); - if (g_loaders.contains(library_name)) { - commit_elf(library_name); - } - } - - auto object = loader->load_stage_3(RTLD_GLOBAL | RTLD_LAZY, g_total_tls_size); - ASSERT(object); - if (name == "libc.so") { - initialize_libc(*object); - } - g_loaders.remove(name); - return loader; -} - -static void read_environment_variables() -{ - for (char** env = g_envp; *env; ++env) { - if (StringView { *env } == "_LOADER_BREAKPOINT=1") { - g_do_breakpoint_trap_before_entry = true; - } - } -} - -void ELF::DynamicLinker::linker_main(String&& main_program_name, int main_program_fd, bool is_secure, int argc, char** argv, char** envp) -{ - g_envp = envp; - - g_allowed_to_check_environment_variables = !is_secure; - if (g_allowed_to_check_environment_variables) - read_environment_variables(); - - 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 = commit_elf(main_program_name); - - 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); - if (g_do_breakpoint_trap_before_entry) { - asm("int3"); - } - 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(); -} - -} diff --git a/Libraries/LibELF/DynamicLinker.h b/Libraries/LibELF/DynamicLinker.h deleted file mode 100644 index d476443976..0000000000 --- a/Libraries/LibELF/DynamicLinker.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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, bool is_secure, int argc, char** argv, char** envp); - -private: - DynamicLinker() = delete; - ~DynamicLinker() = delete; -}; - -} diff --git a/Libraries/LibELF/DynamicLoader.cpp b/Libraries/LibELF/DynamicLoader.cpp deleted file mode 100644 index e7c56a370c..0000000000 --- a/Libraries/LibELF/DynamicLoader.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (c) 2019-2020, Andrew Kaster <andrewdkaster@gmail.com> - * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> - * 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/StringBuilder.h> -#include <LibELF/DynamicLoader.h> -#include <LibELF/Validation.h> - -#include <assert.h> -#include <dlfcn.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mman.h> - -#ifndef DYNAMIC_LOAD_DEBUG -# define DYNAMIC_LOAD_DEBUG -#endif - -// #define DYNAMIC_LOAD_VERBOSE - -#ifdef DYNAMIC_LOAD_VERBOSE -# define VERBOSE(fmt, ...) dbgprintf(fmt, ##__VA_ARGS__) -#else -# define VERBOSE(fmt, ...) \ - do { \ - } while (0) -#endif - -#ifndef __serenity__ -static void* mmap_with_name(void* addr, size_t length, int prot, int flags, int fd, off_t offset, const char*) -{ - return mmap(addr, length, prot, flags, fd, offset); -} -#endif - -namespace ELF { - -static bool s_always_bind_now = false; - -NonnullRefPtr<DynamicLoader> DynamicLoader::construct(const char* filename, int fd, size_t size) -{ - return adopt(*new DynamicLoader(filename, fd, size)); -} - -void* DynamicLoader::do_mmap(int fd, size_t size, const String& name) -{ - if (size < sizeof(Elf32_Ehdr)) - return MAP_FAILED; - - String file_mmap_name = String::format("ELF_DYN: %s", name.characters()); - return mmap_with_name(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0, file_mmap_name.characters()); -} - -DynamicLoader::DynamicLoader(const char* filename, int fd, size_t size) - : m_filename(filename) - , m_file_size(size) - , m_image_fd(fd) - , m_file_mapping(do_mmap(m_image_fd, m_file_size, m_filename)) - , m_elf_image((u8*)m_file_mapping, m_file_size) -{ - - if (m_file_mapping == MAP_FAILED) { - m_valid = false; - return; - } - - m_tls_size = calculate_tls_size(); - - m_valid = validate(); -} - -RefPtr<DynamicObject> DynamicLoader::dynamic_object_from_image() const -{ - VirtualAddress dynamic_section_address; - - m_elf_image.for_each_program_header([&dynamic_section_address](auto program_header) { - if (program_header.type() == PT_DYNAMIC) { - dynamic_section_address = VirtualAddress(program_header.raw_data()); - } - return IterationDecision::Continue; - }); - ASSERT(!dynamic_section_address.is_null()); - - return ELF::DynamicObject::construct(VirtualAddress(m_elf_image.base_address()), dynamic_section_address); -} - -size_t DynamicLoader::calculate_tls_size() const -{ - size_t tls_size = 0; - m_elf_image.for_each_program_header([&tls_size](auto program_header) { - if (program_header.type() == PT_TLS) { - tls_size = program_header.size_in_memory(); - } - return IterationDecision::Continue; - }); - return tls_size; -} - -bool DynamicLoader::validate() -{ - auto* elf_header = (Elf32_Ehdr*)m_file_mapping; - 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) -{ - auto symbol = m_dynamic_object->hash_section().lookup_symbol(name); - - if (symbol.is_undefined()) - return nullptr; - - return m_dynamic_object->base_address().offset(symbol.value()).as_ptr(); -} - -RefPtr<DynamicObject> DynamicLoader::load_from_image(unsigned flags, size_t total_tls_size) -{ - - m_valid = m_elf_image.is_valid(); - - if (!m_valid) { - dbgprintf("DynamicLoader::load_from_image failed: image is invalid\n"); - return nullptr; - } - -#ifdef DYNAMIC_LOAD_VERBOSE - // m_image->dump(); -#endif - - load_program_headers(); - - 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); - - auto rc = load_stage_2(flags, total_tls_size); - if (!rc) { - dbgprintf("DynamicLoader::load_from_image failed at load_stage_2\n"); - return nullptr; - } - return m_dynamic_object; -} - -bool DynamicLoader::load_stage_2(unsigned flags, size_t total_tls_size) -{ - ASSERT(flags & RTLD_GLOBAL); - -#ifdef DYNAMIC_LOAD_DEBUG - m_dynamic_object->dump(); -#endif - - if (m_dynamic_object->has_text_relocations()) { - ASSERT(m_text_segment_load_address.get() != 0); - -#ifndef AK_OS_MACOS - // Remap this text region as private. - if (mremap(m_text_segment_load_address.as_ptr(), m_text_segment_size, m_text_segment_size, MAP_PRIVATE) == MAP_FAILED) { - perror("mremap .text: MAP_PRIVATE"); - return false; - } -#endif - - 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? - return false; - } - } - do_main_relocations(total_tls_size); - return true; -} - -void DynamicLoader::do_main_relocations(size_t total_tls_size) -{ - auto do_single_relocation = [&](ELF::DynamicObject::Relocation relocation) { - switch (do_relocation(total_tls_size, relocation)) { - case RelocationResult::Failed: - dbgln("Loader.so: {} unresolved symbol '{}'", m_filename, relocation.symbol().name()); - ASSERT_NOT_REACHED(); - break; - case RelocationResult::ResolveLater: - m_unresolved_relocations.append(relocation); - break; - case RelocationResult::Success: - break; - } - return IterationDecision::Continue; - }; - m_dynamic_object->relocation_section().for_each_relocation(do_single_relocation); - m_dynamic_object->plt_relocation_section().for_each_relocation(do_single_relocation); -} - -RefPtr<DynamicObject> DynamicLoader::load_stage_3(unsigned flags, size_t total_tls_size) -{ - - do_lazy_relocations(total_tls_size); - if (flags & RTLD_LAZY) { - setup_plt_trampoline(); - } - - // Clean up our setting of .text to PROT_READ | PROT_WRITE - if (m_dynamic_object->has_text_relocations()) { - if (0 > mprotect(m_text_segment_load_address.as_ptr(), m_text_segment_size, PROT_READ | PROT_EXEC)) { - perror("mprotect .text: PROT_READ | PROT_EXEC"); // FIXME: dlerror? - return nullptr; - } - } - - call_object_init_functions(); - - VERBOSE("Loaded %s\n", m_filename.characters()); - return m_dynamic_object; -} - -void DynamicLoader::do_lazy_relocations(size_t total_tls_size) -{ - for (const auto& relocation : m_unresolved_relocations) { - if (auto res = do_relocation(total_tls_size, relocation); res != RelocationResult::Success) { - dbgln("Loader.so: {} unresolved symbol '{}'", m_filename, relocation.symbol().name()); - ASSERT_NOT_REACHED(); - } - } -} - -void DynamicLoader::load_program_headers() -{ - Vector<ProgramHeaderRegion> program_headers; - - ProgramHeaderRegion* text_region_ptr = nullptr; - ProgramHeaderRegion* data_region_ptr = nullptr; - ProgramHeaderRegion* tls_region_ptr = nullptr; - VirtualAddress dynamic_region_desired_vaddr; - - m_elf_image.for_each_program_header([&](const Image::ProgramHeader& program_header) { - ProgramHeaderRegion new_region; - new_region.set_program_header(program_header.raw_header()); - program_headers.append(move(new_region)); - auto& region = program_headers.last(); - if (region.is_tls_template()) - tls_region_ptr = ®ion; - else if (region.is_load()) { - if (region.is_executable()) - text_region_ptr = ®ion; - else - data_region_ptr = ®ion; - } else if (region.is_dynamic()) { - dynamic_region_desired_vaddr = region.desired_load_address(); - } - return IterationDecision::Continue; - }); - - ASSERT(text_region_ptr && data_region_ptr); - - // Process regions in order: .text, .data, .tls - auto* region = text_region_ptr; - void* requested_load_address = m_elf_image.is_dynamic() ? nullptr : region->desired_load_address().as_ptr(); - - ASSERT(!region->is_writable()); - - void* text_segment_begin = mmap_with_name( - requested_load_address, - region->required_load_size(), - region->mmap_prot(), - MAP_SHARED, - m_image_fd, - region->offset(), - String::format("%s: .text", m_filename.characters()).characters()); - if (MAP_FAILED == text_segment_begin) { - ASSERT_NOT_REACHED(); - } - ASSERT(requested_load_address == nullptr || requested_load_address == text_segment_begin); - m_text_segment_size = region->required_load_size(); - m_text_segment_load_address = VirtualAddress { (FlatPtr)text_segment_begin }; - - if (m_elf_image.is_dynamic()) - m_dynamic_section_address = dynamic_region_desired_vaddr.offset(m_text_segment_load_address.get()); - else - m_dynamic_section_address = dynamic_region_desired_vaddr; - - 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("%s: .data", m_filename.characters()).characters()); - if (MAP_FAILED == data_segment_begin) { - ASSERT_NOT_REACHED(); - } - VirtualAddress data_segment_actual_addr; - if (m_elf_image.is_dynamic()) { - data_segment_actual_addr = region->desired_load_address().offset((FlatPtr)text_segment_begin); - } else { - data_segment_actual_addr = region->desired_load_address(); - } - memcpy(data_segment_actual_addr.as_ptr(), (u8*)m_file_mapping + region->offset(), region->size_in_image()); - // FIXME: Initialize the values in the TLS section. Currently, it is zeroed. -} - -DynamicLoader::RelocationResult DynamicLoader::do_relocation(size_t total_tls_size, ELF::DynamicObject::Relocation relocation) -{ - VERBOSE("Relocation symbol: %s, type: %d\n", relocation.symbol().name(), relocation.type()); - FlatPtr* patch_ptr = nullptr; - if (is_dynamic()) - patch_ptr = (FlatPtr*)(m_dynamic_object->base_address().as_ptr() + relocation.offset()); - else - patch_ptr = (FlatPtr*)(FlatPtr)relocation.offset(); - - // VERBOSE("dynamic object name: %s\n", dynamic_object.object_name()); - VERBOSE("dynamic object base address: %p\n", m_dynamic_object->base_address()); - VERBOSE("relocation offset: 0x%x\n", relocation.offset()); - VERBOSE("patch_ptr: %p\n", patch_ptr); - switch (relocation.type()) { - case R_386_NONE: - // Apparently most loaders will just skip these? - // Seems if the 'link editor' generates one something is funky with your code - VERBOSE("None relocation. No symbol, no nothing.\n"); - break; - case R_386_32: { - auto symbol = relocation.symbol(); - VERBOSE("Absolute relocation: name: '%s', value: %p\n", symbol.name(), symbol.value()); - auto res = lookup_symbol(symbol); - if (!res.found) { - if (symbol.bind() == STB_WEAK) { - return RelocationResult::ResolveLater; - } - 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); - break; - } - case R_386_PC32: { - auto symbol = relocation.symbol(); - VERBOSE("PC-relative relocation: '%s', value: %p\n", symbol.name(), symbol.value()); - auto res = lookup_symbol(symbol); - ASSERT(res.found); - u32 relative_offset = (res.address - (FlatPtr)(m_dynamic_object->base_address().as_ptr() + relocation.offset())); - *patch_ptr += relative_offset; - VERBOSE(" Symbol address: %p\n", *patch_ptr); - break; - } - case R_386_GLOB_DAT: { - auto symbol = relocation.symbol(); - VERBOSE("Global data relocation: '%s', value: %p\n", symbol.name(), symbol.value()); - auto res = lookup_symbol(symbol); - if (!res.found) { - // We do not support these - // TODO: Can we tell gcc not to generate the piece of code that uses these? - // (--disable-tm-clone-registry flag in gcc conifugraion?) - if (!strcmp(symbol.name(), "__deregister_frame_info") || !strcmp(symbol.name(), "_ITM_registerTMCloneTable") - || !strcmp(symbol.name(), "_ITM_deregisterTMCloneTable") || !strcmp(symbol.name(), "__register_frame_info")) { - break; - } - - if (symbol.bind() == STB_WEAK) { - return RelocationResult::ResolveLater; - } - - // Symbol not found - return RelocationResult::Failed; - } - VERBOSE("was symbol found? %d, address: 0x%x\n", res.found, res.address); - VERBOSE("object: %s\n", m_filename.characters()); - - u32 symbol_location = res.address; - ASSERT(symbol_location != (FlatPtr)m_dynamic_object->base_address().as_ptr()); - *patch_ptr = symbol_location; - VERBOSE(" Symbol address: %p\n", *patch_ptr); - break; - } - case R_386_RELATIVE: { - // FIXME: According to the spec, R_386_relative ones must be done first. - // We could explicitly do them first using m_number_of_relocatoins from DT_RELCOUNT - // However, our compiler is nice enough to put them at the front of the relocations for us :) - VERBOSE("Load address relocation at offset %X\n", relocation.offset()); - VERBOSE(" patch ptr == %p, adding load base address (%p) to it and storing %p\n", *patch_ptr, m_dynamic_object->base_address().as_ptr(), *patch_ptr + m_dynamic_object->base_address().as_ptr()); - *patch_ptr += (FlatPtr)m_dynamic_object->base_address().as_ptr(); // + addend for RelA (addend for Rel is stored at addr) - break; - } - case R_386_TLS_TPOFF32: - case R_386_TLS_TPOFF: { - 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 refers to the undefined symbol.. huh - if (relocation.symbol_index() == 0) - break; - 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; - 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(); - 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)); - VERBOSE("*patch ptr: %d\n", (i32)*patch_ptr); - break; - } - case R_386_JMP_SLOT: { - // FIXME: Or BIND_NOW flag passed in? - 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\n", relocation.offset_in_section()); - [[maybe_unused]] auto rc = m_dynamic_object->patch_plt_entry(relocation.offset_in_section()); - } else { - u8* relocation_address = relocation.address().as_ptr(); - - if (m_elf_image.is_dynamic()) - *(u32*)relocation_address += (FlatPtr)m_dynamic_object->base_address().as_ptr(); - } - break; - } - default: - // Raise the alarm! Someone needs to implement this relocation type - VERBOSE("Found a new exciting relocation type %d\n", relocation.type()); - // printf("DynamicLoader: Found unknown relocation type %d\n", relocation.type()); - ASSERT_NOT_REACHED(); - break; - } - return RelocationResult::Success; -} - -// Defined in <arch>/plt_trampoline.S -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)m_dynamic_object.ptr(); - got_ptr[2] = (FlatPtr)&_plt_trampoline; - - 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(DynamicObject* object, u32 relocation_offset); -extern "C" Elf32_Addr _fixup_plt_entry(DynamicObject* object, u32 relocation_offset) -{ - return object->patch_plt_entry(relocation_offset); -} - -void DynamicLoader::call_object_init_functions() -{ - typedef void (*InitFunc)(); - - if (m_dynamic_object->has_init_section()) { - auto init_function = (InitFunc)(m_dynamic_object->init_section().address().as_ptr()); - - VERBOSE("Calling DT_INIT at %p\n", init_function); - (init_function)(); - } - - if (m_dynamic_object->has_init_array_section()) { - auto init_array_section = m_dynamic_object->init_array_section(); - - InitFunc* init_begin = (InitFunc*)(init_array_section.address().as_ptr()); - InitFunc* init_end = init_begin + init_array_section.entry_count(); - while (init_begin != init_end) { - // Android sources claim that these can be -1, to be ignored. - // 0 definitely shows up. Apparently 0/-1 are valid? Confusing. - if (!*init_begin || ((FlatPtr)*init_begin == (FlatPtr)-1)) - continue; - VERBOSE("Calling DT_INITARRAY entry at %p\n", *init_begin); - (*init_begin)(); - ++init_begin; - } - } -} - -u32 DynamicLoader::ProgramHeaderRegion::mmap_prot() const -{ - int prot = 0; - prot |= is_executable() ? PROT_EXEC : 0; - prot |= is_readable() ? PROT_READ : 0; - prot |= is_writable() ? PROT_WRITE : 0; - return prot; -} - -DynamicObject::SymbolLookupResult DynamicLoader::lookup_symbol(const ELF::DynamicObject::Symbol& symbol) const -{ - return m_dynamic_object->lookup_symbol(symbol); -} - -} // end namespace ELF diff --git a/Libraries/LibELF/DynamicLoader.h b/Libraries/LibELF/DynamicLoader.h deleted file mode 100644 index 6c9f984296..0000000000 --- a/Libraries/LibELF/DynamicLoader.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2019-2020, Andrew Kaster <andrewdkaster@gmail.com> - * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> - * 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/Assertions.h> -#include <AK/OwnPtr.h> -#include <AK/RefCounted.h> -#include <AK/String.h> -#include <LibELF/DynamicObject.h> -#include <LibELF/Image.h> -#include <LibELF/exec_elf.h> -#include <sys/mman.h> - -namespace ELF { - -#define ALIGN_ROUND_UP(x, align) ((((size_t)(x)) + align - 1) & (~(align - 1))) - -class DynamicLoader : public RefCounted<DynamicLoader> { -public: - static NonnullRefPtr<DynamicLoader> construct(const char* filename, int fd, size_t file_size); - - ~DynamicLoader(); - - bool is_valid() const { return m_valid; } - - // Load a full ELF image from file into the current process and create an DynamicObject - // from the SHT_DYNAMIC in the file. - RefPtr<DynamicObject> load_from_image(unsigned flags, size_t total_tls_size); - - // Stage 2 of loading: dynamic object loading and primary relocations - bool load_stage_2(unsigned flags, size_t total_tls_size); - - // Stage 3 of loading: lazy relocations and initializers - RefPtr<DynamicObject> load_stage_3(unsigned flags, size_t total_tls_size); - // Intended for use by dlsym or other internal methods - void* symbol_for_name(const char*); - - void dump(); - - // Requested program interpreter from program headers. May be empty string - StringView program_interpreter() const { return m_program_interpreter; } - - VirtualAddress text_segment_load_addresss() const { return m_text_segment_load_address; } - - void set_tls_offset(size_t offset) { m_tls_offset = offset; }; - size_t tls_size() const { return m_tls_size; } - size_t tls_offset() const { return m_tls_offset; } - const ELF::Image& image() const { return m_elf_image; } - - template<typename F> - void for_each_needed_library(F) const; - - VirtualAddress text_segment_load_address() const { return m_text_segment_load_address; } - bool is_dynamic() const { return m_elf_image.is_dynamic(); } - -private: - class ProgramHeaderRegion { - public: - void set_program_header(const Elf32_Phdr& header) { m_program_header = header; } - - // Information from ELF Program header - u32 type() const { return m_program_header.p_type; } - u32 flags() const { return m_program_header.p_flags; } - u32 offset() const { return m_program_header.p_offset; } - VirtualAddress desired_load_address() const { return VirtualAddress(m_program_header.p_vaddr); } - u32 size_in_memory() const { return m_program_header.p_memsz; } - u32 size_in_image() const { return m_program_header.p_filesz; } - u32 alignment() const { return m_program_header.p_align; } - u32 mmap_prot() const; - bool is_readable() const { return flags() & PF_R; } - bool is_writable() const { return flags() & PF_W; } - bool is_executable() const { return flags() & PF_X; } - bool is_tls_template() const { return type() == PT_TLS; } - bool is_load() const { return type() == PT_LOAD; } - bool is_dynamic() const { return type() == PT_DYNAMIC; } - - u32 required_load_size() { return ALIGN_ROUND_UP(m_program_header.p_memsz, m_program_header.p_align); } - - private: - Elf32_Phdr m_program_header; // Explicitly a copy of the PHDR in the image - }; - - static void* do_mmap(int fd, size_t size, const String& name); - RefPtr<DynamicObject> dynamic_object_from_image() const; - - explicit DynamicLoader(const char* filename, int fd, size_t file_size); - - // Stage 1 - void load_program_headers(); - - // Stage 2 - void do_main_relocations(size_t total_tls_size); - - // Stage 3 - void do_lazy_relocations(size_t total_tls_size); - void setup_plt_trampoline(); - void call_object_init_functions(); - - bool validate(); - - enum class RelocationResult : uint8_t { - Failed = 0, - Success = 1, - ResolveLater = 2, - }; - RelocationResult do_relocation(size_t total_tls_size, DynamicObject::Relocation relocation); - size_t calculate_tls_size() const; - - DynamicObject::SymbolLookupResult lookup_symbol(const ELF::DynamicObject::Symbol& symbol) const; - - String m_filename; - String m_program_interpreter; - size_t m_file_size { 0 }; - int m_image_fd { -1 }; - void* m_file_mapping { MAP_FAILED }; - ELF::Image m_elf_image; - bool m_valid { true }; - - RefPtr<DynamicObject> m_dynamic_object; - - VirtualAddress m_text_segment_load_address; - size_t m_text_segment_size { 0 }; - - VirtualAddress m_tls_segment_address; - VirtualAddress m_dynamic_section_address; - - size_t m_tls_offset { 0 }; - size_t m_tls_size { 0 }; - - Vector<DynamicObject::Relocation> m_unresolved_relocations; -}; - -template<typename F> -void DynamicLoader::for_each_needed_library(F func) const -{ - dynamic_object_from_image()->for_each_needed_library(move(func)); -} - -} // end namespace ELF diff --git a/Libraries/LibELF/DynamicObject.cpp b/Libraries/LibELF/DynamicObject.cpp deleted file mode 100644 index 39b06beba2..0000000000 --- a/Libraries/LibELF/DynamicObject.cpp +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (c) 2019-2020, Andrew Kaster <andrewdkaster@gmail.com> - * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> - * 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/String.h> -#include <AK/StringBuilder.h> -#include <LibELF/DynamicLinker.h> -#include <LibELF/DynamicObject.h> -#include <LibELF/exec_elf.h> -#include <stdio.h> -#include <string.h> - -// #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); - -DynamicObject::DynamicObject(VirtualAddress base_address, VirtualAddress dynamic_section_addresss) - : m_base_address(base_address) - , m_dynamic_address(dynamic_section_addresss) -{ - Elf32_Ehdr* header = (Elf32_Ehdr*)base_address.as_ptr(); - Elf32_Phdr* pheader = (Elf32_Phdr*)(base_address.as_ptr() + header->e_phoff); - m_elf_base_address = VirtualAddress(pheader->p_vaddr - pheader->p_offset); - if (header->e_type == ET_DYN) - m_is_elf_dynamic = true; - else - m_is_elf_dynamic = false; - - parse(); -} - -DynamicObject::~DynamicObject() -{ -} - -void DynamicObject::dump() const -{ - StringBuilder builder; - builder.append("\nd_tag tag_name value\n"); - size_t num_dynamic_sections = 0; - - for_each_dynamic_entry([&](const DynamicObject::DynamicEntry& entry) { - String name_field = String::format("(%s)", name_for_dtag(entry.tag())); - builder.appendf("0x%08X %-17s0x%X\n", entry.tag(), name_field.characters(), entry.val()); - num_dynamic_sections++; - return IterationDecision::Continue; - }); - - if (m_has_soname) - builder.appendf("DT_SONAME: %s\n", soname()); // FIXME: Valdidate that this string is null terminated? - - 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() -{ - for_each_dynamic_entry([&](const DynamicEntry& entry) { - switch (entry.tag()) { - case DT_INIT: - m_init_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_FINI: - m_fini_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_INIT_ARRAY: - m_init_array_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_INIT_ARRAYSZ: - m_init_array_size = entry.val(); - break; - case DT_FINI_ARRAY: - m_fini_array_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_FINI_ARRAYSZ: - m_fini_array_size = entry.val(); - break; - case DT_HASH: - // Use SYSV hash only if GNU hash is not available - if (m_hash_type == HashType::SYSV) { - m_hash_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - } - break; - case DT_GNU_HASH: - m_hash_type = HashType::GNU; - m_hash_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_SYMTAB: - m_symbol_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_STRTAB: - m_string_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_STRSZ: - m_size_of_string_table = entry.val(); - break; - case DT_SYMENT: - m_size_of_symbol_table_entry = entry.val(); - break; - case DT_PLTGOT: - m_procedure_linkage_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_PLTRELSZ: - m_size_of_plt_relocation_entry_list = entry.val(); - break; - case DT_PLTREL: - m_procedure_linkage_table_relocation_type = entry.val(); - ASSERT(m_procedure_linkage_table_relocation_type & (DT_REL | DT_RELA)); - break; - case DT_JMPREL: - m_plt_relocation_offset_location = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_RELA: - case DT_REL: - m_relocation_table_offset = entry.ptr() - (FlatPtr)m_elf_base_address.as_ptr(); - break; - case DT_RELASZ: - case DT_RELSZ: - m_size_of_relocation_table = entry.val(); - break; - case DT_RELAENT: - case DT_RELENT: - m_size_of_relocation_entry = entry.val(); - break; - case DT_RELACOUNT: - case DT_RELCOUNT: - m_number_of_relocations = entry.val(); - break; - case DT_FLAGS: - m_dt_flags = entry.val(); - break; - case DT_TEXTREL: - m_dt_flags |= DF_TEXTREL; // This tag seems to exist for legacy reasons only? - break; - case DT_SONAME: - m_soname_index = entry.val(); - m_has_soname = true; - break; - case DT_DEBUG: - break; - case DT_FLAGS_1: - break; - case DT_NEEDED: - // We handle these in for_each_needed_library - break; - default: - dbgprintf("DynamicObject: DYNAMIC tag handling not implemented for DT_%s\n", name_for_dtag(entry.tag())); - printf("DynamicObject: DYNAMIC tag handling not implemented for DT_%s\n", name_for_dtag(entry.tag())); - ASSERT_NOT_REACHED(); // FIXME: Maybe just break out here and return false? - break; - } - return IterationDecision::Continue; - }); - - if (!m_size_of_relocation_entry) { - // TODO: FIXME, this shouldn't be hardcoded - // The reason we need this here is that for some reason, when there only PLT relocations, the compiler - // doesn't insert a 'PLTRELSZ' entry to the dynamic section - m_size_of_relocation_entry = sizeof(Elf32_Rel); - } - - auto hash_section_address = hash_section().address().as_ptr(); - // TODO: consider base address - it might not be zero - auto num_hash_chains = ((u32*)hash_section_address)[1]; - m_symbol_count = num_hash_chains; -} - -const DynamicObject::Relocation DynamicObject::RelocationSection::relocation(unsigned index) const -{ - ASSERT(index < entry_count()); - unsigned offset_in_section = index * entry_size(); - auto relocation_address = (Elf32_Rel*)address().offset(offset_in_section).as_ptr(); - return Relocation(m_dynamic, *relocation_address, offset_in_section); -} - -const DynamicObject::Relocation DynamicObject::RelocationSection::relocation_at_offset(unsigned offset) const -{ - ASSERT(offset <= (m_section_size_bytes - m_entry_size)); - auto relocation_address = (Elf32_Rel*)address().offset(offset).as_ptr(); - return Relocation(m_dynamic, *relocation_address, offset); -} - -const DynamicObject::Symbol DynamicObject::symbol(unsigned index) const -{ - auto symbol_section = Section(*this, m_symbol_table_offset, (m_symbol_count * m_size_of_symbol_table_entry), m_size_of_symbol_table_entry, "DT_SYMTAB"); - auto symbol_entry = (Elf32_Sym*)symbol_section.address().offset(index * symbol_section.entry_size()).as_ptr(); - return Symbol(*this, index, *symbol_entry); -} - -const DynamicObject::Section DynamicObject::init_section() const -{ - return Section(*this, m_init_offset, sizeof(void (*)()), sizeof(void (*)()), "DT_INIT"); -} - -const DynamicObject::Section DynamicObject::fini_section() const -{ - return Section(*this, m_fini_offset, sizeof(void (*)()), sizeof(void (*)()), "DT_FINI"); -} - -const DynamicObject::Section DynamicObject::init_array_section() const -{ - return Section(*this, m_init_array_offset, m_init_array_size, sizeof(void (*)()), "DT_INIT_ARRAY"); -} - -const DynamicObject::Section DynamicObject::fini_array_section() const -{ - return Section(*this, m_fini_array_offset, m_fini_array_size, sizeof(void (*)()), "DT_FINI_ARRAY"); -} - -const DynamicObject::HashSection DynamicObject::hash_section() const -{ - const char* section_name = m_hash_type == HashType::SYSV ? "DT_HASH" : "DT_GNU_HASH"; - return HashSection(Section(*this, m_hash_table_offset, 0, 0, section_name), m_hash_type); -} - -const DynamicObject::RelocationSection DynamicObject::relocation_section() const -{ - return RelocationSection(Section(*this, m_relocation_table_offset, m_size_of_relocation_table, m_size_of_relocation_entry, "DT_REL")); -} - -const DynamicObject::RelocationSection DynamicObject::plt_relocation_section() const -{ - return RelocationSection(Section(*this, m_plt_relocation_offset_location, m_size_of_plt_relocation_entry_list, m_size_of_relocation_entry, "DT_JMPREL")); -} - -u32 DynamicObject::HashSection::calculate_elf_hash(const char* name) const -{ - // SYSV ELF hash algorithm - // Note that the GNU HASH algorithm has less collisions - - uint32_t hash = 0; - - while (*name != '\0') { - hash = hash << 4; - hash += *name; - name++; - - const uint32_t top_nibble_of_hash = hash & 0xF0000000U; - hash ^= top_nibble_of_hash >> 24; - hash &= ~top_nibble_of_hash; - } - - return hash; -} - -u32 DynamicObject::HashSection::calculate_gnu_hash(const char* name) const -{ - // GNU ELF hash algorithm - u32 hash = 5381; - - for (; *name != '\0'; ++name) { - hash = hash * 33 + *name; - } - - return hash; -} - -const DynamicObject::Symbol DynamicObject::HashSection::lookup_symbol(const char* name) const -{ - return (this->*(m_lookup_function))(name); -} - -const DynamicObject::Symbol DynamicObject::HashSection::lookup_elf_symbol(const char* name) const -{ - u32 hash_value = calculate_elf_hash(name); - - u32* hash_table_begin = (u32*)address().as_ptr(); - - size_t num_buckets = hash_table_begin[0]; - - // This is here for completeness, but, since we're using the fact that every chain - // will end at chain 0 (which means 'not found'), we don't need to check num_chains. - // Interestingly, num_chains is required to be num_symbols - - // size_t num_chains = hash_table_begin[1]; - - u32* buckets = &hash_table_begin[2]; - u32* chains = &buckets[num_buckets]; - - for (u32 i = buckets[hash_value % num_buckets]; i; i = chains[i]) { - auto symbol = m_dynamic.symbol(i); - if (strcmp(name, symbol.name()) == 0) { - VERBOSE("Returning SYSV dynamic symbol with index %u for %s: %p\n", i, symbol.name(), symbol.address().as_ptr()); - return symbol; - } - } - return Symbol::create_undefined(m_dynamic); -} - -const DynamicObject::Symbol DynamicObject::HashSection::lookup_gnu_symbol(const char* name) const -{ - // Algorithm reference: https://ent-voy.blogspot.com/2011/02/ - // TODO: Handle 64bit bloomwords for ELF_CLASS64 - using BloomWord = u32; - constexpr size_t bloom_word_size = sizeof(BloomWord) * 8; - - const u32* hash_table_begin = (u32*)address().as_ptr(); - - const size_t num_buckets = hash_table_begin[0]; - const size_t num_omitted_symbols = hash_table_begin[1]; - const u32 num_maskwords = hash_table_begin[2]; - // This works because num_maskwords is required to be a power of 2 - const u32 num_maskwords_bitmask = num_maskwords - 1; - const u32 shift2 = hash_table_begin[3]; - - const BloomWord* bloom_words = &hash_table_begin[4]; - const u32* const buckets = &bloom_words[num_maskwords]; - const u32* const chains = &buckets[num_buckets]; - - BloomWord hash1 = calculate_gnu_hash(name); - BloomWord hash2 = hash1 >> shift2; - const BloomWord bitmask = (1 << (hash1 % bloom_word_size)) | (1 << (hash2 % bloom_word_size)); - - if ((bloom_words[(hash1 / bloom_word_size) & num_maskwords_bitmask] & bitmask) != bitmask) { - return Symbol::create_undefined(m_dynamic); - } - - size_t current_sym = buckets[hash1 % num_buckets]; - if (current_sym == 0) { - return Symbol::create_undefined(m_dynamic); - } - const u32* current_chain = &chains[current_sym - num_omitted_symbols]; - - for (hash1 &= ~1;; ++current_sym) { - hash2 = *(current_chain++); - const auto symbol = m_dynamic.symbol(current_sym); - if ((hash1 == (hash2 & ~1)) && strcmp(name, symbol.name()) == 0) { - VERBOSE("Returning GNU dynamic symbol with index %zu for %s: %p\n", current_sym, symbol.name(), symbol.address().as_ptr()); - return symbol; - } - if (hash2 & 1) { - break; - } - } - - return Symbol::create_undefined(m_dynamic); -} - -const char* DynamicObject::symbol_string_table_string(Elf32_Word index) const -{ - return (const char*)base_address().offset(m_string_table_offset + index).as_ptr(); -} - -DynamicObject::InitializationFunction DynamicObject::init_section_function() const -{ - ASSERT(has_init_section()); - return (InitializationFunction)init_section().address().as_ptr(); -} - -static const char* name_for_dtag(Elf32_Sword d_tag) -{ - switch (d_tag) { - case DT_NULL: - return "NULL"; /* marks end of _DYNAMIC array */ - case DT_NEEDED: - return "NEEDED"; /* string table offset of needed lib */ - case DT_PLTRELSZ: - return "PLTRELSZ"; /* size of relocation entries in PLT */ - case DT_PLTGOT: - return "PLTGOT"; /* address PLT/GOT */ - case DT_HASH: - return "HASH"; /* address of symbol hash table */ - case DT_STRTAB: - return "STRTAB"; /* address of string table */ - case DT_SYMTAB: - return "SYMTAB"; /* address of symbol table */ - case DT_RELA: - return "RELA"; /* address of relocation table */ - case DT_RELASZ: - return "RELASZ"; /* size of relocation table */ - case DT_RELAENT: - return "RELAENT"; /* size of relocation entry */ - case DT_STRSZ: - return "STRSZ"; /* size of string table */ - case DT_SYMENT: - return "SYMENT"; /* size of symbol table entry */ - case DT_INIT: - return "INIT"; /* address of initialization func. */ - case DT_FINI: - return "FINI"; /* address of termination function */ - case DT_SONAME: - return "SONAME"; /* string table offset of shared obj */ - case DT_RPATH: - return "RPATH"; /* string table offset of library search path */ - case DT_SYMBOLIC: - return "SYMBOLIC"; /* start sym search in shared obj. */ - case DT_REL: - return "REL"; /* address of rel. tbl. w addends */ - case DT_RELSZ: - return "RELSZ"; /* size of DT_REL relocation table */ - case DT_RELENT: - return "RELENT"; /* size of DT_REL relocation entry */ - case DT_PLTREL: - return "PLTREL"; /* PLT referenced relocation entry */ - case DT_DEBUG: - return "DEBUG"; /* bugger */ - case DT_TEXTREL: - return "TEXTREL"; /* Allow rel. mod. to unwritable seg */ - case DT_JMPREL: - return "JMPREL"; /* add. of PLT's relocation entries */ - case DT_BIND_NOW: - return "BIND_NOW"; /* Bind now regardless of env setting */ - case DT_INIT_ARRAY: - return "INIT_ARRAY"; /* address of array of init func */ - case DT_FINI_ARRAY: - return "FINI_ARRAY"; /* address of array of term func */ - case DT_INIT_ARRAYSZ: - return "INIT_ARRAYSZ"; /* size of array of init func */ - case DT_FINI_ARRAYSZ: - return "FINI_ARRAYSZ"; /* size of array of term func */ - case DT_RUNPATH: - return "RUNPATH"; /* strtab offset of lib search path */ - case DT_FLAGS: - return "FLAGS"; /* Set of DF_* flags */ - case DT_ENCODING: - return "ENCODING"; /* further DT_* follow encoding rules */ - case DT_PREINIT_ARRAY: - return "PREINIT_ARRAY"; /* address of array of preinit func */ - case DT_PREINIT_ARRAYSZ: - return "PREINIT_ARRAYSZ"; /* size of array of preinit func */ - case DT_LOOS: - return "LOOS"; /* reserved range for OS */ - case DT_HIOS: - return "HIOS"; /* specific dynamic array tags */ - case DT_LOPROC: - return "LOPROC"; /* reserved range for processor */ - case DT_HIPROC: - return "HIPROC"; /* specific dynamic array tags */ - case DT_GNU_HASH: - return "GNU_HASH"; /* address of GNU hash table */ - case DT_RELACOUNT: - return "RELACOUNT"; /* if present, number of RELATIVE */ - case DT_RELCOUNT: - return "RELCOUNT"; /* relocs, which must come first */ - case DT_FLAGS_1: - return "FLAGS_1"; - default: - return "??"; - } -} - -DynamicObject::SymbolLookupResult DynamicObject::lookup_symbol(const char* name) const -{ - auto res = hash_section().lookup_symbol(name); - if (res.is_undefined()) - return {}; - return SymbolLookupResult { true, res.value(), (FlatPtr)res.address().as_ptr(), res.bind(), this }; -} - -NonnullRefPtr<DynamicObject> DynamicObject::construct(VirtualAddress base_address, VirtualAddress dynamic_section_address) -{ - 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(); - - 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(), (void*)symbol_location, (void*)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() || symbol.bind() == STB_WEAK) - return DynamicLinker::lookup_global_symbol(symbol.name()); - - if (!symbol.is_undefined()) { - VERBOSE("symbol is defined in its object\n"); - return { true, symbol.value(), (FlatPtr)symbol.address().as_ptr(), symbol.bind(), &symbol.object() }; - } - return DynamicLinker::lookup_global_symbol(symbol.name()); -} - -} // end namespace ELF diff --git a/Libraries/LibELF/DynamicObject.h b/Libraries/LibELF/DynamicObject.h deleted file mode 100644 index 7b03c43c6d..0000000000 --- a/Libraries/LibELF/DynamicObject.h +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright (c) 2019-2020, Andrew Kaster <andrewdkaster@gmail.com> - * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> - * 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/Assertions.h> -#include <AK/RefCounted.h> -#include <Kernel/VirtualAddress.h> -#include <LibELF/exec_elf.h> - -namespace ELF { - -class DynamicObject : public RefCounted<DynamicObject> { -public: - static NonnullRefPtr<DynamicObject> construct(VirtualAddress base_address, VirtualAddress dynamic_section_address); - - ~DynamicObject(); - void dump() const; - - class DynamicEntry; - class Section; - class RelocationSection; - class Symbol; - class Relocation; - class HashSection; - - class DynamicEntry { - public: - DynamicEntry(const Elf32_Dyn& dyn) - : m_dyn(dyn) - { - } - - ~DynamicEntry() { } - - Elf32_Sword tag() const { return m_dyn.d_tag; } - Elf32_Addr ptr() const { return m_dyn.d_un.d_ptr; } - Elf32_Word val() const { return m_dyn.d_un.d_val; } - - private: - const Elf32_Dyn& m_dyn; - }; - - class Symbol { - public: - Symbol(const DynamicObject& dynamic, unsigned index, const Elf32_Sym& sym) - : m_dynamic(dynamic) - , m_sym(sym) - , m_index(index) - { - if (section_index() == 0) - m_is_undefined = true; - } - - Symbol(const Symbol& other) - : m_dynamic(other.m_dynamic) - , m_sym(other.m_sym) - , m_index(other.m_index) - , m_is_undefined(other.m_is_undefined) - { - } - - static Symbol create_undefined(const DynamicObject& dynamic) - { - auto s = Symbol(dynamic, 0, {}); - s.m_is_undefined = true; - return s; - } - - ~Symbol() { } - - const char* name() const { return m_dynamic.symbol_string_table_string(m_sym.st_name); } - unsigned section_index() const { return m_sym.st_shndx; } - unsigned value() const { return m_sym.st_value; } - unsigned size() const { return m_sym.st_size; } - unsigned index() const { return m_index; } - unsigned type() const { return ELF32_ST_TYPE(m_sym.st_info); } - unsigned bind() const { return ELF32_ST_BIND(m_sym.st_info); } - - bool is_undefined() const - { - return m_is_undefined; - } - VirtualAddress address() const - { - if (m_dynamic.elf_is_dynamic()) - return m_dynamic.base_address().offset(value()); - return VirtualAddress { value() }; - } - const DynamicObject& object() const { return m_dynamic; } - - private: - const DynamicObject& m_dynamic; - const Elf32_Sym& m_sym; - const unsigned m_index; - bool m_is_undefined { false }; - }; - - class Section { - public: - Section(const DynamicObject& dynamic, unsigned section_offset, unsigned section_size_bytes, unsigned entry_size, const char* name) - : m_dynamic(dynamic) - , m_section_offset(section_offset) - , m_section_size_bytes(section_size_bytes) - , m_entry_size(entry_size) - , m_name(name) - { - } - ~Section() { } - - const char* name() const { return m_name; } - unsigned offset() const { return m_section_offset; } - unsigned size() const { return m_section_size_bytes; } - unsigned entry_size() const { return m_entry_size; } - unsigned entry_count() const - { - return !entry_size() ? 0 : size() / entry_size(); - } - VirtualAddress address() const - { - return m_dynamic.base_address().offset(m_section_offset); - } - - protected: - friend class RelocationSection; - friend class HashSection; - const DynamicObject& m_dynamic; - unsigned m_section_offset; - unsigned m_section_size_bytes; - unsigned m_entry_size; - const char* m_name { nullptr }; - }; - - class RelocationSection : public Section { - public: - RelocationSection(const Section& section) - : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name) - { - } - unsigned relocation_count() const { return entry_count(); } - const Relocation relocation(unsigned index) const; - const Relocation relocation_at_offset(unsigned offset) const; - template<typename F> - void for_each_relocation(F) const; - }; - - class Relocation { - public: - Relocation(const DynamicObject& dynamic, const Elf32_Rel& rel, unsigned offset_in_section) - : m_dynamic(dynamic) - , m_rel(rel) - , m_offset_in_section(offset_in_section) - { - } - - ~Relocation() { } - - unsigned offset_in_section() const { return m_offset_in_section; } - unsigned offset() const { return m_rel.r_offset; } - unsigned type() const { return ELF32_R_TYPE(m_rel.r_info); } - unsigned symbol_index() const { return ELF32_R_SYM(m_rel.r_info); } - const Symbol symbol() const { return m_dynamic.symbol(symbol_index()); } - VirtualAddress address() const - { - if (m_dynamic.elf_is_dynamic()) - return m_dynamic.base_address().offset(offset()); - return VirtualAddress { offset() }; - } - - private: - const DynamicObject& m_dynamic; - const Elf32_Rel& m_rel; - const unsigned m_offset_in_section; - }; - - enum class HashType { - SYSV, - GNU - }; - - class HashSection : public Section { - public: - HashSection(const Section& section, HashType hash_type) - : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name) - { - switch (hash_type) { - case HashType::SYSV: - m_lookup_function = &HashSection::lookup_elf_symbol; - break; - case HashType::GNU: - m_lookup_function = &HashSection::lookup_gnu_symbol; - break; - default: - ASSERT_NOT_REACHED(); - break; - } - } - - const Symbol lookup_symbol(const char*) const; - - private: - u32 calculate_elf_hash(const char* name) const; - u32 calculate_gnu_hash(const char* name) const; - - const DynamicObject::Symbol lookup_elf_symbol(const char* name) const; - const DynamicObject::Symbol lookup_gnu_symbol(const char* name) const; - - typedef const DynamicObject::Symbol (HashSection::*LookupFunction)(const char*) const; - LookupFunction m_lookup_function; - }; - - unsigned symbol_count() const { return m_symbol_count; } - - const Symbol symbol(unsigned) const; - - typedef void (*InitializationFunction)(); - - bool has_init_section() const { return m_init_offset != 0; } - bool has_init_array_section() const { return m_init_array_offset != 0; } - const Section init_section() const; - InitializationFunction init_section_function() const; - const Section fini_section() const; - const Section init_array_section() const; - const Section fini_array_section() const; - - const HashSection hash_section() const; - - const RelocationSection relocation_section() const; - const RelocationSection plt_relocation_section() const; - - bool should_process_origin() const { return m_dt_flags & DF_ORIGIN; } - bool requires_symbolic_symbol_resolution() const { return m_dt_flags & DF_SYMBOLIC; } - // Text relocations meaning: we need to edit the .text section which is normally mapped PROT_READ - bool has_text_relocations() const { return m_dt_flags & DF_TEXTREL; } - bool must_bind_now() const { return m_dt_flags & DF_BIND_NOW; } - bool has_static_thread_local_storage() const { return m_dt_flags & DF_STATIC_TLS; } - - VirtualAddress plt_got_base_address() const { return m_base_address.offset(m_procedure_linkage_table_offset); } - VirtualAddress base_address() const { return m_base_address; } - - const char* soname() const { return m_has_soname ? symbol_string_table_string(m_soname_index) : nullptr; } - - Optional<FlatPtr> tls_offset() const { return m_tls_offset; } - Optional<FlatPtr> tls_size() const { return m_tls_size; } - void set_tls_offset(FlatPtr offset) { m_tls_offset = offset; } - void set_tls_size(FlatPtr size) { m_tls_size = size; } - - template<typename F> - void for_each_needed_library(F) const; - - template<typename F> - void for_each_initialization_array_function(F f) const; - - struct SymbolLookupResult { - bool found { false }; - FlatPtr value { 0 }; - FlatPtr address { 0 }; - unsigned bind { STB_LOCAL }; - const ELF::DynamicObject* dynamic_object { nullptr }; // The object in which the symbol is defined - }; - SymbolLookupResult 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 }; - - bool elf_is_dynamic() const { return m_is_elf_dynamic; } - -private: - explicit DynamicObject(VirtualAddress base_address, VirtualAddress dynamic_section_address); - - const char* symbol_string_table_string(Elf32_Word) const; - void parse(); - - template<typename F> - void for_each_symbol(F) const; - - template<typename F> - void for_each_dynamic_entry(F) const; - - VirtualAddress m_base_address; - VirtualAddress m_dynamic_address; - VirtualAddress m_elf_base_address; - - unsigned m_symbol_count { 0 }; - - // Begin Section information collected from DT_* entries - FlatPtr m_init_offset { 0 }; - FlatPtr m_fini_offset { 0 }; - - FlatPtr m_init_array_offset { 0 }; - size_t m_init_array_size { 0 }; - FlatPtr m_fini_array_offset { 0 }; - size_t m_fini_array_size { 0 }; - - FlatPtr m_hash_table_offset { 0 }; - HashType m_hash_type { HashType::SYSV }; - - FlatPtr m_string_table_offset { 0 }; - size_t m_size_of_string_table { 0 }; - FlatPtr m_symbol_table_offset { 0 }; - size_t m_size_of_symbol_table_entry { 0 }; - - Elf32_Sword m_procedure_linkage_table_relocation_type { -1 }; - FlatPtr m_plt_relocation_offset_location { 0 }; // offset of PLT relocations, at end of relocations - size_t m_size_of_plt_relocation_entry_list { 0 }; - FlatPtr m_procedure_linkage_table_offset { 0 }; - - // NOTE: We'll only ever either RELA or REL entries, not both (thank god) - // NOTE: The x86 ABI will only ever genrerate REL entries. - size_t m_number_of_relocations { 0 }; - size_t m_size_of_relocation_entry { 0 }; - size_t m_size_of_relocation_table { 0 }; - FlatPtr m_relocation_table_offset { 0 }; - bool m_is_elf_dynamic { false }; - - // DT_FLAGS - Elf32_Word m_dt_flags { 0 }; - - bool m_has_soname { false }; - Elf32_Word m_soname_index { 0 }; // Index into dynstr table for SONAME - - Optional<FlatPtr> m_tls_offset; - Optional<FlatPtr> m_tls_size; - // End Section information from DT_* entries -}; - -template<typename F> -inline void DynamicObject::RelocationSection::for_each_relocation(F func) const -{ - for (unsigned i = 0; i < relocation_count(); ++i) { - const auto reloc = relocation(i); - if (reloc.type() == 0) - continue; - if (func(reloc) == IterationDecision::Break) - break; - } -} - -template<typename F> -inline void DynamicObject::for_each_symbol(F func) const -{ - for (unsigned i = 0; i < symbol_count(); ++i) { - if (func(symbol(i)) == IterationDecision::Break) - break; - } -} - -template<typename F> -inline void DynamicObject::for_each_dynamic_entry(F func) const -{ - auto* dyns = reinterpret_cast<const Elf32_Dyn*>(m_dynamic_address.as_ptr()); - for (unsigned i = 0;; ++i) { - auto&& dyn = DynamicEntry(dyns[i]); - if (dyn.tag() == DT_NULL) - break; - if (func(dyn) == IterationDecision::Break) - break; - } -} -template<typename F> -inline void DynamicObject::for_each_needed_library(F func) const -{ - for_each_dynamic_entry([func, this](auto entry) { - if (entry.tag() != DT_NEEDED) - return IterationDecision::Continue; - Elf32_Word offset = entry.val(); - const char* name = (const char*)(m_base_address.offset(m_string_table_offset).offset(offset)).as_ptr(); - if (func(StringView(name)) == IterationDecision::Break) - return IterationDecision::Break; - return IterationDecision::Continue; - }); -} - -template<typename F> -void DynamicObject::for_each_initialization_array_function(F f) const -{ - if (!has_init_array_section()) - return; - FlatPtr init_array = (FlatPtr)init_array_section().address().as_ptr(); - for (size_t i = 0; i < (m_init_array_size / sizeof(void*)); ++i) { - InitializationFunction current = ((InitializationFunction*)(init_array))[i]; - f(current); - } -} - -} // end namespace ELF diff --git a/Libraries/LibELF/Image.cpp b/Libraries/LibELF/Image.cpp deleted file mode 100644 index 27bf519353..0000000000 --- a/Libraries/LibELF/Image.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> - * 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/Demangle.h> -#include <AK/Memory.h> -#include <AK/QuickSort.h> -#include <AK/StringBuilder.h> -#include <AK/StringView.h> -#include <LibELF/Image.h> -#include <LibELF/Validation.h> - -//#define ELF_IMAGE_DEBUG - -namespace ELF { - -Image::Image(ReadonlyBytes bytes, bool verbose_logging) - : m_buffer(bytes.data()) - , m_size(bytes.size()) - , m_verbose_logging(verbose_logging) -{ - parse(); -} - -Image::Image(const u8* buffer, size_t size, bool verbose_logging) - : Image(ReadonlyBytes { buffer, size }, verbose_logging) -{ -} - -Image::~Image() -{ -} - -#ifdef ELF_IMAGE_DEBUG -static const char* object_file_type_to_string(Elf32_Half type) -{ - switch (type) { - case ET_NONE: - return "None"; - case ET_REL: - return "Relocatable"; - case ET_EXEC: - return "Executable"; - case ET_DYN: - return "Shared object"; - case ET_CORE: - return "Core"; - default: - return "(?)"; - } -} -#endif - -StringView Image::section_index_to_string(unsigned index) const -{ - ASSERT(m_valid); - if (index == SHN_UNDEF) - return "Undefined"; - if (index >= SHN_LORESERVE) - return "Reserved"; - return section(index).name(); -} - -unsigned Image::symbol_count() const -{ - ASSERT(m_valid); - if (!section_count()) - return 0; - return section(m_symbol_table_section_index).entry_count(); -} - -void Image::dump() const -{ -#ifdef ELF_IMAGE_DEBUG - dbgln("ELF::Image({:p}) {{", this); - dbgln(" is_valid: {}", is_valid()); - - if (!is_valid()) { - dbgln("}}"); - return; - } - - dbgln(" type: {}", object_file_type_to_string(header().e_type)); - dbgln(" machine: {}", header().e_machine); - dbgln(" entry: {:x}", header().e_entry); - dbgln(" shoff: {}", header().e_shoff); - dbgln(" shnum: {}", header().e_shnum); - dbgln(" phoff: {}", header().e_phoff); - dbgln(" phnum: {}", header().e_phnum); - dbgln(" shstrndx: {}", header().e_shstrndx); - - for_each_program_header([&](const ProgramHeader& program_header) { - dbgln(" Program Header {}: {{", program_header.index()); - dbgln(" type: {:x}", program_header.type()); - dbgln(" offset: {:x}", program_header.offset()); - dbgln(" flags: {:x}", program_header.flags()); - dbgln(" }}"); - return IterationDecision::Continue; - }); - - for (unsigned i = 0; i < header().e_shnum; ++i) { - auto& section = this->section(i); - dbgln(" Section {}: {{", i); - dbgln(" name: {}", section.name()); - dbgln(" type: {:x}", section.type()); - dbgln(" offset: {:x}", section.offset()); - dbgln(" size: {}", section.size()); - dbgln(" "); - dbgln(" }}"); - } - - dbgln("Symbol count: {} (table is {})", symbol_count(), m_symbol_table_section_index); - for (unsigned i = 1; i < symbol_count(); ++i) { - auto& sym = symbol(i); - dbgln("Symbol @{}:", i); - dbgln(" Name: {}", sym.name()); - dbgln(" In section: {}", section_index_to_string(sym.section_index())); - dbgln(" Value: {}", sym.value()); - dbgln(" Size: {}", sym.size()); - } - - dbgln("}}"); -#endif -} - -unsigned Image::section_count() const -{ - ASSERT(m_valid); - return header().e_shnum; -} - -unsigned Image::program_header_count() const -{ - ASSERT(m_valid); - return header().e_phnum; -} - -bool Image::parse() -{ - if (m_size < sizeof(Elf32_Ehdr) || !validate_elf_header(header(), m_size, m_verbose_logging)) { - if (m_verbose_logging) - dbgln("ELF::Image::parse(): ELF Header not valid"); - return m_valid = false; - } - - if (!validate_program_headers(header(), m_size, m_buffer, m_size, nullptr, m_verbose_logging)) { - if (m_verbose_logging) - dbgln("ELF::Image::parse(): ELF Program Headers not valid"); - return m_valid = false; - } - - m_valid = true; - - // First locate the string tables. - for (unsigned i = 0; i < section_count(); ++i) { - auto& sh = section_header(i); - if (sh.sh_type == SHT_SYMTAB) { - if (m_symbol_table_section_index && m_symbol_table_section_index != i) - return m_valid = false; - m_symbol_table_section_index = i; - } - if (sh.sh_type == SHT_STRTAB && i != header().e_shstrndx) { - if (section_header_table_string(sh.sh_name) == ELF_STRTAB) - m_string_table_section_index = i; - } - } - - // Then create a name-to-index map. - for (unsigned i = 0; i < section_count(); ++i) { - auto& section = this->section(i); - m_sections.set(section.name(), move(i)); - } - - return m_valid; -} - -StringView Image::table_string(unsigned table_index, unsigned offset) const -{ - ASSERT(m_valid); - auto& sh = section_header(table_index); - if (sh.sh_type != SHT_STRTAB) - return nullptr; - size_t computed_offset = sh.sh_offset + offset; - if (computed_offset >= m_size) { - if (m_verbose_logging) - dbgln("SHENANIGANS! Image::table_string() computed offset outside image."); - return {}; - } - size_t max_length = m_size - computed_offset; - size_t length = strnlen(raw_data(sh.sh_offset + offset), max_length); - return { raw_data(sh.sh_offset + offset), length }; -} - -StringView Image::section_header_table_string(unsigned offset) const -{ - ASSERT(m_valid); - return table_string(header().e_shstrndx, offset); -} - -StringView Image::table_string(unsigned offset) const -{ - ASSERT(m_valid); - return table_string(m_string_table_section_index, offset); -} - -const char* Image::raw_data(unsigned offset) const -{ - ASSERT(offset < m_size); // Callers must check indices into raw_data()'s result are also in bounds. - return reinterpret_cast<const char*>(m_buffer) + offset; -} - -const Elf32_Ehdr& Image::header() const -{ - ASSERT(m_size >= sizeof(Elf32_Ehdr)); - return *reinterpret_cast<const Elf32_Ehdr*>(raw_data(0)); -} - -const Elf32_Phdr& Image::program_header_internal(unsigned index) const -{ - ASSERT(m_valid); - ASSERT(index < header().e_phnum); - return *reinterpret_cast<const Elf32_Phdr*>(raw_data(header().e_phoff + (index * sizeof(Elf32_Phdr)))); -} - -const Elf32_Shdr& Image::section_header(unsigned index) const -{ - ASSERT(m_valid); - ASSERT(index < header().e_shnum); - return *reinterpret_cast<const Elf32_Shdr*>(raw_data(header().e_shoff + (index * header().e_shentsize))); -} - -const Image::Symbol Image::symbol(unsigned index) const -{ - ASSERT(m_valid); - ASSERT(index < symbol_count()); - auto* raw_syms = reinterpret_cast<const Elf32_Sym*>(raw_data(section(m_symbol_table_section_index).offset())); - return Symbol(*this, index, raw_syms[index]); -} - -const Image::Section Image::section(unsigned index) const -{ - ASSERT(m_valid); - ASSERT(index < section_count()); - return Section(*this, index); -} - -const Image::ProgramHeader Image::program_header(unsigned index) const -{ - ASSERT(m_valid); - ASSERT(index < program_header_count()); - return ProgramHeader(*this, index); -} - -FlatPtr Image::program_header_table_offset() const -{ - return header().e_phoff; -} - -const Image::Relocation Image::RelocationSection::relocation(unsigned index) const -{ - ASSERT(index < relocation_count()); - auto* rels = reinterpret_cast<const Elf32_Rel*>(m_image.raw_data(offset())); - return Relocation(m_image, rels[index]); -} - -const Image::RelocationSection Image::Section::relocations() const -{ - StringBuilder builder; - builder.append(".rel"); - builder.append(name()); - - auto relocation_section = m_image.lookup_section(builder.to_string()); - if (relocation_section.type() != SHT_REL) - return static_cast<const RelocationSection>(m_image.section(0)); - -#ifdef ELF_IMAGE_DEBUG - dbgln("Found relocations for {} in {}", name(), relocation_section.name()); -#endif - return static_cast<const RelocationSection>(relocation_section); -} - -const Image::Section Image::lookup_section(const String& name) const -{ - ASSERT(m_valid); - if (auto it = m_sections.find(name); it != m_sections.end()) - return section((*it).value); - return section(0); -} - -StringView Image::Symbol::raw_data() const -{ - auto& section = this->section(); - return { section.raw_data() + (value() - section.address()), size() }; -} - -Optional<Image::Symbol> Image::find_demangled_function(const String& name) const -{ - Optional<Image::Symbol> found; - for_each_symbol([&](const Image::Symbol symbol) { - if (symbol.type() != STT_FUNC) - return IterationDecision::Continue; - if (symbol.is_undefined()) - return IterationDecision::Continue; - auto demangled = demangle(symbol.name()); - auto index_of_paren = demangled.index_of("("); - if (index_of_paren.has_value()) { - demangled = demangled.substring(0, index_of_paren.value()); - } - if (demangled != name) - return IterationDecision::Continue; - found = symbol; - return IterationDecision::Break; - }); - return found; -} - -Optional<Image::Symbol> Image::find_symbol(u32 address, u32* out_offset) const -{ - auto symbol_count = this->symbol_count(); - if (!symbol_count) - return {}; - - SortedSymbol* sorted_symbols = nullptr; - if (m_sorted_symbols.is_empty()) { - m_sorted_symbols.ensure_capacity(symbol_count); - for_each_symbol([this](auto& symbol) { - m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol }); - return IterationDecision::Continue; - }); - quick_sort(m_sorted_symbols, [](auto& a, auto& b) { - return a.address < b.address; - }); - } - sorted_symbols = m_sorted_symbols.data(); - - for (size_t i = 0; i < symbol_count; ++i) { - if (sorted_symbols[i].address > address) { - if (i == 0) - return {}; - auto& symbol = sorted_symbols[i - 1]; - if (out_offset) - *out_offset = address - symbol.address; - return symbol.symbol; - } - } - return {}; -} - -String Image::symbolicate(u32 address, u32* out_offset) const -{ - auto symbol_count = this->symbol_count(); - if (!symbol_count) { - if (out_offset) - *out_offset = 0; - return "??"; - } - SortedSymbol* sorted_symbols = nullptr; - - if (m_sorted_symbols.is_empty()) { - m_sorted_symbols.ensure_capacity(symbol_count); - for_each_symbol([this](auto& symbol) { - m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol }); - return IterationDecision::Continue; - }); - quick_sort(m_sorted_symbols, [](auto& a, auto& b) { - return a.address < b.address; - }); - } - sorted_symbols = m_sorted_symbols.data(); - - for (size_t i = 0; i < symbol_count; ++i) { - if (sorted_symbols[i].address > address) { - if (i == 0) { - if (out_offset) - *out_offset = 0; - return "!!"; - } - auto& symbol = sorted_symbols[i - 1]; - - auto& demangled_name = symbol.demangled_name; - if (demangled_name.is_null()) { - demangled_name = demangle(symbol.name); - } - - if (out_offset) { - *out_offset = address - symbol.address; - return demangled_name; - } - return String::format("%s +0x%x", demangled_name.characters(), address - symbol.address); - } - } - if (out_offset) - *out_offset = 0; - return "??"; -} - -} // end namespace ELF diff --git a/Libraries/LibELF/Image.h b/Libraries/LibELF/Image.h deleted file mode 100644 index 3250cf4deb..0000000000 --- a/Libraries/LibELF/Image.h +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * 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/ByteBuffer.h> -#include <AK/HashMap.h> -#include <AK/OwnPtr.h> -#include <AK/String.h> -#include <Kernel/VirtualAddress.h> -#include <LibELF/exec_elf.h> - -namespace ELF { - -class Image { -public: - explicit Image(ReadonlyBytes, bool verbose_logging = true); - explicit Image(const u8*, size_t, bool verbose_logging = true); - - ~Image(); - void dump() const; - bool is_valid() const { return m_valid; } - bool parse(); - - bool is_within_image(const void* address, size_t size) const - { - if (address < m_buffer) - return false; - if (((const u8*)address + size) > m_buffer + m_size) - return false; - return true; - } - - class Section; - class RelocationSection; - class Symbol; - class Relocation; - - class Symbol { - public: - Symbol(const Image& image, unsigned index, const Elf32_Sym& sym) - : m_image(image) - , m_sym(sym) - , m_index(index) - { - } - - ~Symbol() { } - - StringView name() const { return m_image.table_string(m_sym.st_name); } - unsigned section_index() const { return m_sym.st_shndx; } - unsigned value() const { return m_sym.st_value; } - unsigned size() const { return m_sym.st_size; } - unsigned index() const { return m_index; } - unsigned type() const { return ELF32_ST_TYPE(m_sym.st_info); } - unsigned bind() const { return ELF32_ST_BIND(m_sym.st_info); } - const Section section() const { return m_image.section(section_index()); } - bool is_undefined() const { return section_index() == 0; } - StringView raw_data() const; - - private: - const Image& m_image; - const Elf32_Sym& m_sym; - const unsigned m_index; - }; - - class ProgramHeader { - public: - ProgramHeader(const Image& image, unsigned program_header_index) - : m_image(image) - , m_program_header(image.program_header_internal(program_header_index)) - , m_program_header_index(program_header_index) - { - } - ~ProgramHeader() { } - - unsigned index() const { return m_program_header_index; } - u32 type() const { return m_program_header.p_type; } - u32 flags() const { return m_program_header.p_flags; } - u32 offset() const { return m_program_header.p_offset; } - VirtualAddress vaddr() const { return VirtualAddress(m_program_header.p_vaddr); } - u32 size_in_memory() const { return m_program_header.p_memsz; } - u32 size_in_image() const { return m_program_header.p_filesz; } - u32 alignment() const { return m_program_header.p_align; } - bool is_readable() const { return flags() & PF_R; } - bool is_writable() const { return flags() & PF_W; } - bool is_executable() const { return flags() & PF_X; } - const char* raw_data() const { return m_image.raw_data(m_program_header.p_offset); } - Elf32_Phdr raw_header() const { return m_program_header; } - - private: - const Image& m_image; - const Elf32_Phdr& m_program_header; - unsigned m_program_header_index { 0 }; - }; - - class Section { - public: - Section(const Image& image, unsigned sectionIndex) - : m_image(image) - , m_section_header(image.section_header(sectionIndex)) - , m_section_index(sectionIndex) - { - } - ~Section() { } - - StringView name() const { return m_image.section_header_table_string(m_section_header.sh_name); } - unsigned type() const { return m_section_header.sh_type; } - unsigned offset() const { return m_section_header.sh_offset; } - unsigned size() const { return m_section_header.sh_size; } - unsigned entry_size() const { return m_section_header.sh_entsize; } - unsigned entry_count() const { return !entry_size() ? 0 : size() / entry_size(); } - u32 address() const { return m_section_header.sh_addr; } - const char* raw_data() const { return m_image.raw_data(m_section_header.sh_offset); } - ReadonlyBytes bytes() const { return { raw_data(), size() }; } - bool is_undefined() const { return m_section_index == SHN_UNDEF; } - const RelocationSection relocations() const; - u32 flags() const { return m_section_header.sh_flags; } - bool is_writable() const { return flags() & SHF_WRITE; } - bool is_executable() const { return flags() & PF_X; } - - protected: - friend class RelocationSection; - const Image& m_image; - const Elf32_Shdr& m_section_header; - unsigned m_section_index; - }; - - class RelocationSection : public Section { - public: - RelocationSection(const Section& section) - : Section(section.m_image, section.m_section_index) - { - } - unsigned relocation_count() const { return entry_count(); } - const Relocation relocation(unsigned index) const; - template<typename F> - void for_each_relocation(F) const; - }; - - class Relocation { - public: - Relocation(const Image& image, const Elf32_Rel& rel) - : m_image(image) - , m_rel(rel) - { - } - - ~Relocation() { } - - unsigned offset() const { return m_rel.r_offset; } - unsigned type() const { return ELF32_R_TYPE(m_rel.r_info); } - unsigned symbol_index() const { return ELF32_R_SYM(m_rel.r_info); } - const Symbol symbol() const { return m_image.symbol(symbol_index()); } - - private: - const Image& m_image; - const Elf32_Rel& m_rel; - }; - - unsigned symbol_count() const; - unsigned section_count() const; - unsigned program_header_count() const; - - const Symbol symbol(unsigned) const; - const Section section(unsigned) const; - const ProgramHeader program_header(unsigned const) const; - FlatPtr program_header_table_offset() const; - - template<typename F> - void for_each_section(F) const; - template<typename F> - void for_each_section_of_type(unsigned, F) const; - template<typename F> - void for_each_symbol(F) const; - template<typename F> - void for_each_program_header(F) const; - - // NOTE: Returns section(0) if section with name is not found. - // FIXME: I don't love this API. - const Section lookup_section(const String& name) const; - - bool is_executable() const { return header().e_type == ET_EXEC; } - bool is_relocatable() const { return header().e_type == ET_REL; } - bool is_dynamic() const { return header().e_type == ET_DYN; } - - VirtualAddress entry() const { return VirtualAddress(header().e_entry); } - FlatPtr base_address() const { return (FlatPtr)m_buffer; } - size_t size() const { return m_size; } - - Optional<Symbol> find_demangled_function(const String& name) const; - - bool has_symbols() const { return symbol_count(); } - String symbolicate(u32 address, u32* offset = nullptr) const; - Optional<Image::Symbol> find_symbol(u32 address, u32* offset = nullptr) const; - -private: - const char* raw_data(unsigned offset) const; - const Elf32_Ehdr& header() const; - const Elf32_Shdr& section_header(unsigned) const; - const Elf32_Phdr& program_header_internal(unsigned) const; - StringView table_string(unsigned offset) const; - StringView section_header_table_string(unsigned offset) const; - StringView section_index_to_string(unsigned index) const; - StringView table_string(unsigned table_index, unsigned offset) const; - - const u8* m_buffer { nullptr }; - size_t m_size { 0 }; - bool m_verbose_logging { true }; - HashMap<String, unsigned> m_sections; - bool m_valid { false }; - unsigned m_symbol_table_section_index { 0 }; - unsigned m_string_table_section_index { 0 }; - - struct SortedSymbol { - u32 address; - StringView name; - String demangled_name; - Optional<Image::Symbol> symbol; - }; - - mutable Vector<SortedSymbol> m_sorted_symbols; -}; - -template<typename F> -inline void Image::for_each_section(F func) const -{ - auto section_count = this->section_count(); - for (unsigned i = 0; i < section_count; ++i) - func(section(i)); -} - -template<typename F> -inline void Image::for_each_section_of_type(unsigned type, F func) const -{ - auto section_count = this->section_count(); - for (unsigned i = 0; i < section_count; ++i) { - auto& section = this->section(i); - if (section.type() == type) { - if (func(section) == IterationDecision::Break) - break; - } - } -} - -template<typename F> -inline void Image::RelocationSection::for_each_relocation(F func) const -{ - auto relocation_count = this->relocation_count(); - for (unsigned i = 0; i < relocation_count; ++i) { - if (func(relocation(i)) == IterationDecision::Break) - break; - } -} - -template<typename F> -inline void Image::for_each_symbol(F func) const -{ - auto symbol_count = this->symbol_count(); - for (unsigned i = 0; i < symbol_count; ++i) { - if (func(symbol(i)) == IterationDecision::Break) - break; - } -} - -template<typename F> -inline void Image::for_each_program_header(F func) const -{ - auto program_header_count = this->program_header_count(); - for (unsigned i = 0; i < program_header_count; ++i) { - if (func(program_header(i)) == IterationDecision::Break) - return; - } -} - -} // end namespace ELF diff --git a/Libraries/LibELF/Validation.cpp b/Libraries/LibELF/Validation.cpp deleted file mode 100644 index 1700a48b1e..0000000000 --- a/Libraries/LibELF/Validation.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2020, Andrew Kaster <andrewdkaster@gmail.com> - * 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/Assertions.h> -#include <AK/String.h> -#include <LibELF/Validation.h> -#include <LibELF/exec_elf.h> - -namespace ELF { - -bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool verbose) -{ - if (!IS_ELF(elf_header)) { - if (verbose) - dbgln("File is not an ELF file."); - return false; - } - - if (ELFCLASS32 != elf_header.e_ident[EI_CLASS]) { - if (verbose) - dbgln("File is not a 32 bit ELF file."); - return false; - } - - if (ELFDATA2LSB != elf_header.e_ident[EI_DATA]) { - if (verbose) - dbgln("File is not a little endian ELF file."); - return false; - } - - if (EV_CURRENT != elf_header.e_ident[EI_VERSION]) { - if (verbose) - dbgln("File has unrecognized ELF version ({}), expected ({})!", elf_header.e_ident[EI_VERSION], EV_CURRENT); - return false; - } - - if (ELFOSABI_SYSV != elf_header.e_ident[EI_OSABI]) { - if (verbose) - dbgln("File has unknown OS ABI ({}), expected SYSV(0)!", elf_header.e_ident[EI_OSABI]); - return false; - } - - if (0 != elf_header.e_ident[EI_ABIVERSION]) { - if (verbose) - dbgln("File has unknown SYSV ABI version ({})!", elf_header.e_ident[EI_ABIVERSION]); - return false; - } - - if (EM_386 != elf_header.e_machine) { - if (verbose) - dbgln("File has unknown machine ({}), expected i386 (3)!", elf_header.e_machine); - return false; - } - - if (ET_EXEC != elf_header.e_type && ET_DYN != elf_header.e_type && ET_REL != elf_header.e_type && ET_CORE != elf_header.e_type) { - if (verbose) - dbgln("File has unloadable ELF type ({}), expected REL (1), EXEC (2), DYN (3) or CORE(4)!", elf_header.e_type); - return false; - } - - if (EV_CURRENT != elf_header.e_version) { - if (verbose) - dbgln("File has unrecognized ELF version ({}), expected ({})!", elf_header.e_version, EV_CURRENT); - return false; - } - - if (sizeof(Elf32_Ehdr) != elf_header.e_ehsize) { - if (verbose) - dbgln("File has incorrect ELF header size..? ({}), expected ({})!", elf_header.e_ehsize, sizeof(Elf32_Ehdr)); - return false; - } - - if (elf_header.e_phoff < elf_header.e_ehsize || (elf_header.e_shnum != SHN_UNDEF && elf_header.e_shoff < elf_header.e_ehsize)) { - if (verbose) { - dbgln("SHENANIGANS! program header offset ({}) or section header offset ({}) overlap with ELF header!", - elf_header.e_phoff, elf_header.e_shoff); - } - return false; - } - - if (elf_header.e_phoff > file_size || elf_header.e_shoff > file_size) { - if (verbose) { - dbgln("SHENANIGANS! program header offset ({}) or section header offset ({}) are past the end of the file!", - elf_header.e_phoff, elf_header.e_shoff); - } - return false; - } - - if (elf_header.e_phnum == 0 && elf_header.e_phoff != 0) { - if (verbose) - dbgln("SHENANIGANS! File has no program headers, but it does have a program header offset ({})!", elf_header.e_phoff); - return false; - } - - if (elf_header.e_phnum != 0 && elf_header.e_phoff != elf_header.e_ehsize) { - if (verbose) { - dbgln("File does not have program headers directly after the ELF header? program header offset ({}), expected ({}).", - elf_header.e_phoff, elf_header.e_ehsize); - } - return false; - } - - if (0 != elf_header.e_flags) { - if (verbose) - dbgln("File has incorrect ELF header flags...? ({}), expected ({}).", elf_header.e_flags, 0); - return false; - } - - if (0 != elf_header.e_phnum && sizeof(Elf32_Phdr) != elf_header.e_phentsize) { - if (verbose) - dbgln("File has incorrect program header size..? ({}), expected ({}).", elf_header.e_phentsize, sizeof(Elf32_Phdr)); - return false; - } - - if (sizeof(Elf32_Shdr) != elf_header.e_shentsize) { - if (verbose) - dbgln("File has incorrect section header size..? ({}), expected ({}).", elf_header.e_shentsize, sizeof(Elf32_Shdr)); - return false; - } - - size_t end_of_last_program_header = elf_header.e_phoff + (elf_header.e_phnum * elf_header.e_phentsize); - if (end_of_last_program_header > file_size) { - if (verbose) - dbgln("SHENANIGANS! End of last program header ({}) is past the end of the file!", end_of_last_program_header); - return false; - } - - if (elf_header.e_shoff != SHN_UNDEF && elf_header.e_shoff < end_of_last_program_header) { - if (verbose) { - dbgln("SHENANIGANS! Section header table begins at file offset {}, which is within program headers [ {} - {} ]!", - elf_header.e_shoff, elf_header.e_phoff, end_of_last_program_header); - } - return false; - } - - size_t end_of_last_section_header = elf_header.e_shoff + (elf_header.e_shnum * elf_header.e_shentsize); - if (end_of_last_section_header > file_size) { - if (verbose) - dbgln("SHENANIGANS! End of last section header ({}) is past the end of the file!", end_of_last_section_header); - return false; - } - - if (elf_header.e_shstrndx != SHN_UNDEF && elf_header.e_shstrndx >= elf_header.e_shnum) { - if (verbose) - dbgln("SHENANIGANS! Section header string table index ({}) is not a valid index given we have {} section headers!", elf_header.e_shstrndx, elf_header.e_shnum); - return false; - } - - return true; -} - -bool validate_program_headers(const Elf32_Ehdr& elf_header, size_t file_size, const u8* buffer, size_t buffer_size, String* interpreter_path, bool verbose) -{ - // Can we actually parse all the program headers in the given buffer? - size_t end_of_last_program_header = elf_header.e_phoff + (elf_header.e_phnum * elf_header.e_phentsize); - if (end_of_last_program_header > buffer_size) { - if (verbose) - dbgln("Unable to parse program headers from buffer, buffer too small! Buffer size: {}, End of program headers {}", - buffer_size, end_of_last_program_header); - return false; - } - - if (file_size < buffer_size) { - dbgln("We somehow read more from a file than was in the file in the first place!"); - ASSERT_NOT_REACHED(); - } - - size_t num_program_headers = elf_header.e_phnum; - auto program_header_begin = (const Elf32_Phdr*)&(buffer[elf_header.e_phoff]); - - for (size_t header_index = 0; header_index < num_program_headers; ++header_index) { - auto& program_header = program_header_begin[header_index]; - - if (program_header.p_filesz > program_header.p_memsz) { - if (verbose) - dbgln("Program header ({}) has p_filesz ({}) larger than p_memsz ({})", header_index, program_header.p_filesz, program_header.p_memsz); - return false; - } - - if (program_header.p_memsz <= 0 && (program_header.p_type == PT_TLS || program_header.p_type == PT_LOAD)) { - if (verbose) - dbgln("Program header ({}) has invalid size in memory ({})", header_index, program_header.p_memsz); - return false; - } - - if (program_header.p_type == PT_LOAD && program_header.p_align != PAGE_SIZE) { - if (elf_header.e_type != ET_CORE) { - if (verbose) - dbgln("Program header ({}) with p_type PT_LOAD has p_align ({}) not equal to page size ({})", header_index, program_header.p_align, PAGE_SIZE); - return false; - } - } - - switch (program_header.p_type) { - case PT_INTERP: - // We checked above that file_size was >= buffer size. We only care about buffer size anyway, we're trying to read this! - if (program_header.p_offset + program_header.p_filesz > buffer_size) { - if (verbose) - dbgln("Found PT_INTERP header ({}), but the .interp section was not within the buffer :(", header_index); - return false; - } - if (interpreter_path) - *interpreter_path = String((const char*)&buffer[program_header.p_offset], program_header.p_filesz - 1); - break; - case PT_LOAD: - case PT_DYNAMIC: - case PT_NOTE: - case PT_PHDR: - case PT_TLS: - if (program_header.p_offset + program_header.p_filesz > file_size) { - if (verbose) - dbgln("SHENANIGANS! Program header {} segment leaks beyond end of file!", header_index); - return false; - } - if ((program_header.p_flags & PF_X) && (program_header.p_flags & PF_W)) { - if (verbose) - dbgln("SHENANIGANS! Program header {} segment is marked write and execute", header_index); - return false; - } - break; - case PT_GNU_STACK: - if (program_header.p_flags & PF_X) { - if (verbose) - dbgln("Possible shenanigans! Validating an ELF with executable stack."); - } - break; - case PT_GNU_RELRO: - if ((program_header.p_flags & PF_X) && (program_header.p_flags & PF_W)) { - if (verbose) - dbgln("SHENANIGANS! Program header {} segment is marked write and execute", header_index); - return false; - } - break; - default: - // Not handling other program header types in other code so... let's not surprise them - if (verbose) - dbgln("Found program header ({}) of unrecognized type {}!", header_index, program_header.p_type); - return false; - } - } - return true; -} - -} // end namespace ELF diff --git a/Libraries/LibELF/Validation.h b/Libraries/LibELF/Validation.h deleted file mode 100644 index fe49c80b82..0000000000 --- a/Libraries/LibELF/Validation.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2020, Andrew Kaster <andrewdkaster@gmail.com> - * 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 <LibELF/exec_elf.h> - -namespace ELF { - -bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool verbose = true); -bool validate_program_headers(const Elf32_Ehdr& elf_header, size_t file_size, const u8* buffer, size_t buffer_size, String* interpreter_path, bool verbose = true); - -} // end namespace ELF diff --git a/Libraries/LibELF/exec_elf.h b/Libraries/LibELF/exec_elf.h deleted file mode 100644 index 45a0e9401f..0000000000 --- a/Libraries/LibELF/exec_elf.h +++ /dev/null @@ -1,792 +0,0 @@ -/* $OpenBSD: exec_elf.h,v 1.83 2019/01/22 23:23:18 jsg Exp $ */ -/* - * Copyright (c) 1995, 1996 Erik Theisen. 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. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - */ - -/* - * This is the ELF ABI header file - * formerly known as "elf_abi.h". - */ - -#ifndef _SYS_EXEC_ELF_H_ -#define _SYS_EXEC_ELF_H_ - -#include <AK/Types.h> - -typedef uint8_t Elf_Byte; - -typedef uint32_t Elf32_Addr; /* Unsigned program address */ -typedef uint32_t Elf32_Off; /* Unsigned file offset */ -typedef int32_t Elf32_Sword; /* Signed large integer */ -typedef uint32_t Elf32_Word; /* Unsigned large integer */ -typedef uint16_t Elf32_Half; /* Unsigned medium integer */ -typedef uint64_t Elf32_Lword; - -typedef uint64_t Elf64_Addr; -typedef uint64_t Elf64_Off; -typedef int32_t Elf64_Shalf; - -#ifdef __alpha__ -typedef int64_t Elf64_Sword; -typedef uint64_t Elf64_Word; -#else -typedef int32_t Elf64_Sword; -typedef uint32_t Elf64_Word; -#endif - -typedef int64_t Elf64_Sxword; -typedef uint64_t Elf64_Xword; -typedef uint64_t Elf64_Lword; - -typedef uint32_t Elf64_Half; -typedef uint16_t Elf64_Quarter; - -/* - * e_ident[] identification indexes - * See http://www.sco.com/developers/gabi/latest/ch4.eheader.html - */ -#define EI_MAG0 0 /* file ID */ -#define EI_MAG1 1 /* file ID */ -#define EI_MAG2 2 /* file ID */ -#define EI_MAG3 3 /* file ID */ -#define EI_CLASS 4 /* file class */ -#define EI_DATA 5 /* data encoding */ -#define EI_VERSION 6 /* ELF header version */ -#define EI_OSABI 7 /* OS/ABI ID */ -#define EI_ABIVERSION 8 /* ABI version */ -#define EI_PAD 9 /* start of pad bytes */ -#define EI_NIDENT 16 /* Gfx::Size of e_ident[] */ - -/* e_ident[] magic number */ -#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ -#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ -#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ -#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ -#define ELFMAG "\177ELF" /* magic */ -#define SELFMAG 4 /* size of magic */ - -/* e_ident[] file class */ -#define ELFCLASSNONE 0 /* invalid */ -#define ELFCLASS32 1 /* 32-bit objs */ -#define ELFCLASS64 2 /* 64-bit objs */ -#define ELFCLASSNUM 3 /* number of classes */ - -/* e_ident[] data encoding */ -#define ELFDATANONE 0 /* invalid */ -#define ELFDATA2LSB 1 /* Little-Endian */ -#define ELFDATA2MSB 2 /* Big-Endian */ -#define ELFDATANUM 3 /* number of data encode defines */ - -/* e_ident[] Operating System/ABI */ -#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ -#define ELFOSABI_HPUX 1 /* HP-UX operating system */ -#define ELFOSABI_NETBSD 2 /* NetBSD */ -#define ELFOSABI_LINUX 3 /* GNU/Linux */ -#define ELFOSABI_HURD 4 /* GNU/Hurd */ -#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ -#define ELFOSABI_SOLARIS 6 /* Solaris */ -#define ELFOSABI_MONTEREY 7 /* Monterey */ -#define ELFOSABI_IRIX 8 /* IRIX */ -#define ELFOSABI_FREEBSD 9 /* FreeBSD */ -#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ -#define ELFOSABI_MODESTO 11 /* Novell Modesto */ -#define ELFOSABI_OPENBSD 12 /* OpenBSD */ -#define ELFOSABI_ARM 97 /* ARM */ -#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ - -/* e_ident */ -#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && (ehdr).e_ident[EI_MAG1] == ELFMAG1 && (ehdr).e_ident[EI_MAG2] == ELFMAG2 && (ehdr).e_ident[EI_MAG3] == ELFMAG3) - -/* ELF Header */ -typedef struct elfhdr { - unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ - Elf32_Half e_type; /* object file type */ - Elf32_Half e_machine; /* machine */ - Elf32_Word e_version; /* object file version */ - Elf32_Addr e_entry; /* virtual entry point */ - Elf32_Off e_phoff; /* program header table offset */ - Elf32_Off e_shoff; /* section header table offset */ - Elf32_Word e_flags; /* processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size */ - Elf32_Half e_phentsize; /* program header entry size */ - Elf32_Half e_phnum; /* number of program header entries */ - Elf32_Half e_shentsize; /* section header entry size */ - Elf32_Half e_shnum; /* number of section header entries */ - Elf32_Half e_shstrndx; /* section header table's "section - header string table" entry offset */ -} Elf32_Ehdr; - -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* Id bytes */ - Elf64_Quarter e_type; /* file type */ - Elf64_Quarter e_machine; /* machine type */ - Elf64_Half e_version; /* version number */ - Elf64_Addr e_entry; /* entry point */ - Elf64_Off e_phoff; /* Program hdr offset */ - Elf64_Off e_shoff; /* Section hdr offset */ - Elf64_Half e_flags; /* Processor flags */ - Elf64_Quarter e_ehsize; /* sizeof ehdr */ - Elf64_Quarter e_phentsize; /* Program header entry size */ - Elf64_Quarter e_phnum; /* Number of program headers */ - Elf64_Quarter e_shentsize; /* Section header entry size */ - Elf64_Quarter e_shnum; /* Number of section headers */ - Elf64_Quarter e_shstrndx; /* String table index */ -} Elf64_Ehdr; - -/* e_type */ -#define ET_NONE 0 /* No file type */ -#define ET_REL 1 /* relocatable file */ -#define ET_EXEC 2 /* executable file */ -#define ET_DYN 3 /* shared object file */ -#define ET_CORE 4 /* core file */ -#define ET_NUM 5 /* number of types */ -#define ET_LOPROC 0xff00 /* reserved range for processor */ -#define ET_HIPROC 0xffff /* specific e_type */ - -/* e_machine */ -#define EM_NONE 0 /* No Machine */ -#define EM_M32 1 /* AT&T WE 32100 */ -#define EM_SPARC 2 /* SPARC */ -#define EM_386 3 /* Intel 80386 */ -#define EM_68K 4 /* Motorola 68000 */ -#define EM_88K 5 /* Motorola 88000 */ -#define EM_486 6 /* Intel 80486 - unused? */ -#define EM_860 7 /* Intel 80860 */ -#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ -/* - * Don't know if EM_MIPS_RS4_BE, - * EM_SPARC64, EM_PARISC, - * or EM_PPC are ABI compliant - */ -#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ -#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */ -#define EM_PARISC 15 /* HPPA */ -#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ -#define EM_PPC 20 /* PowerPC */ -#define EM_PPC64 21 /* PowerPC 64 */ -#define EM_ARM 40 /* Advanced RISC Machines ARM */ -#define EM_ALPHA 41 /* DEC ALPHA */ -#define EM_SH 42 /* Hitachi/Renesas Super-H */ -#define EM_SPARCV9 43 /* SPARC version 9 */ -#define EM_IA_64 50 /* Intel IA-64 Processor */ -#define EM_AMD64 62 /* AMD64 architecture */ -#define EM_X86_64 EM_AMD64 -#define EM_VAX 75 /* DEC VAX */ -#define EM_AARCH64 183 /* ARM 64-bit architecture (AArch64) */ - -/* Non-standard */ -#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ -#define EM__LAST__ (EM_ALPHA_EXP + 1) - -#define EM_NUM 22 /* number of machine types */ - -/* Version */ -#define EV_NONE 0 /* Invalid */ -#define EV_CURRENT 1 /* Current */ -#define EV_NUM 2 /* number of versions */ - -/* Magic for e_phnum: get real value from sh_info of first section header */ -#define PN_XNUM 0xffff - -/* Section Header */ -typedef struct { - Elf32_Word sh_name; /* name - index into section header - string table section */ - Elf32_Word sh_type; /* type */ - Elf32_Word sh_flags; /* flags */ - Elf32_Addr sh_addr; /* address */ - Elf32_Off sh_offset; /* file offset */ - Elf32_Word sh_size; /* section size */ - Elf32_Word sh_link; /* section header table index link */ - Elf32_Word sh_info; /* extra information */ - Elf32_Word sh_addralign; /* address alignment */ - Elf32_Word sh_entsize; /* section entry size */ -} Elf32_Shdr; - -typedef struct { - Elf64_Half sh_name; /* section name */ - Elf64_Half sh_type; /* section type */ - Elf64_Xword sh_flags; /* section flags */ - Elf64_Addr sh_addr; /* virtual address */ - Elf64_Off sh_offset; /* file offset */ - Elf64_Xword sh_size; /* section size */ - Elf64_Half sh_link; /* link to another */ - Elf64_Half sh_info; /* misc info */ - Elf64_Xword sh_addralign; /* memory alignment */ - Elf64_Xword sh_entsize; /* table entry size */ -} Elf64_Shdr; - -/* Special Section Indexes */ -#define SHN_UNDEF 0 /* undefined */ -#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ -#define SHN_LOPROC 0xff00 /* reserved range for processor */ -#define SHN_HIPROC 0xff1f /* specific section indexes */ -#define SHN_ABS 0xfff1 /* absolute value */ -#define SHN_COMMON 0xfff2 /* common symbol */ -#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */ -#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ - -/* sh_type */ -#define SHT_NULL 0 /* inactive */ -#define SHT_PROGBITS 1 /* program defined information */ -#define SHT_SYMTAB 2 /* symbol table section */ -#define SHT_STRTAB 3 /* string table section */ -#define SHT_RELA 4 /* relocation section with addends*/ -#define SHT_HASH 5 /* symbol hash table section */ -#define SHT_DYNAMIC 6 /* dynamic section */ -#define SHT_NOTE 7 /* note section */ -#define SHT_NOBITS 8 /* no space section */ -#define SHT_REL 9 /* relation section without addends */ -#define SHT_SHLIB 10 /* reserved - purpose unknown */ -#define SHT_DYNSYM 11 /* dynamic symbol table section */ -#define SHT_NUM 12 /* number of section types */ -#define SHT_INIT_ARRAY 14 /* pointers to init functions */ -#define SHT_FINI_ARRAY 15 /* pointers to termination functions */ -#define SHT_PREINIT_ARRAY 16 /* ptrs to funcs called before init */ -#define SHT_GROUP 17 /* defines a section group */ -#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */ -#define SHT_LOOS 0x60000000 /* reserved range for OS specific */ -#define SHT_SUNW_dof 0x6ffffff4 /* used by dtrace */ -#define SHT_GNU_LIBLIST 0x6ffffff7 /* libraries to be prelinked */ -#define SHT_SUNW_move 0x6ffffffa /* inf for partially init'ed symbols */ -#define SHT_SUNW_syminfo 0x6ffffffc /* ad symbol information */ -#define SHT_SUNW_verdef 0x6ffffffd /* symbol versioning inf */ -#define SHT_SUNW_verneed 0x6ffffffe /* symbol versioning req */ -#define SHT_SUNW_versym 0x6fffffff /* symbol versioning table */ -#define SHT_HIOS 0x6fffffff /* section header types */ -#define SHT_LOPROC 0x70000000 /* reserved range for processor */ -#define SHT_HIPROC 0x7fffffff /* specific section header types */ -#define SHT_LOUSER 0x80000000 /* reserved range for application */ -#define SHT_HIUSER 0xffffffff /* specific indexes */ - -#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table section */ - -/* Section names */ -#define ELF_BSS ".bss" /* uninitialized data */ -#define ELF_DATA ".data" /* initialized data */ -#define ELF_CTF ".SUNW_ctf" /* CTF data */ -#define ELF_DEBUG ".debug" /* debug */ -#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ -#define ELF_DYNSTR ".dynstr" /* dynamic string table */ -#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ -#define ELF_FINI ".fini" /* termination code */ -#define ELF_GOT ".got" /* global offset table */ -#define ELF_HASH ".hash" /* symbol hash table */ -#define ELF_INIT ".init" /* initialization code */ -#define ELF_REL_DATA ".rel.data" /* relocation data */ -#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ -#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ -#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */ -#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ -#define ELF_REL_TEXT ".rel.text" /* relocation code */ -#define ELF_RODATA ".rodata" /* read-only data */ -#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ -#define ELF_STRTAB ".strtab" /* string table */ -#define ELF_SYMTAB ".symtab" /* symbol table */ -#define ELF_TEXT ".text" /* code */ -#define ELF_OPENBSDRANDOMDATA ".openbsd.randomdata" /* constant randomdata */ - -/* Section Attribute Flags - sh_flags */ -#define SHF_WRITE 0x1 /* Writable */ -#define SHF_ALLOC 0x2 /* occupies memory */ -#define SHF_EXECINSTR 0x4 /* executable */ -#define SHF_MERGE 0x10 /* may be merged */ -#define SHF_STRINGS 0x20 /* contains strings */ -#define SHF_INFO_LINK 0x40 /* sh_info holds section index */ -#define SHF_LINK_ORDER 0x80 /* ordering requirements */ -#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required */ -#define SHF_GROUP 0x200 /* member of section group */ -#define SHF_TLS 0x400 /* thread local storage */ -#define SHF_COMPRESSED 0x800 /* contains compressed data */ -#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics */ -#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ - /* specific section attributes */ - -/* Symbol Table Entry */ -typedef struct elf32_sym { - Elf32_Word st_name; /* name - index into string table */ - Elf32_Addr st_value; /* symbol value */ - Elf32_Word st_size; /* symbol size */ - unsigned char st_info; /* type and binding */ - unsigned char st_other; /* 0 - no defined meaning */ - Elf32_Half st_shndx; /* section header index */ -} Elf32_Sym; - -typedef struct { - Elf64_Half st_name; /* Symbol name index in str table */ - Elf_Byte st_info; /* type / binding attrs */ - Elf_Byte st_other; /* unused */ - Elf64_Quarter st_shndx; /* section index of symbol */ - Elf64_Xword st_value; /* value of symbol */ - Elf64_Xword st_size; /* size of symbol */ -} Elf64_Sym; - -/* Symbol table index */ -#define STN_UNDEF 0 /* undefined */ - -/* Extract symbol info - st_info */ -#define ELF32_ST_BIND(x) ((x) >> 4) -#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) - -#define ELF64_ST_BIND(x) ((x) >> 4) -#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) - -/* Symbol Binding - ELF32_ST_BIND - st_info */ -#define STB_LOCAL 0 /* Local symbol */ -#define STB_GLOBAL 1 /* Global symbol */ -#define STB_WEAK 2 /* like global - lower precedence */ -#define STB_NUM 3 /* number of symbol bindings */ -#define STB_LOPROC 13 /* reserved range for processor */ -#define STB_HIPROC 15 /* specific symbol bindings */ - -/* Symbol type - ELF32_ST_TYPE - st_info */ -#define STT_NOTYPE 0 /* not specified */ -#define STT_OBJECT 1 /* data object */ -#define STT_FUNC 2 /* function */ -#define STT_SECTION 3 /* section */ -#define STT_FILE 4 /* file */ -#define STT_TLS 6 /* thread local storage */ -#define STT_LOPROC 13 /* reserved range for processor */ -#define STT_HIPROC 15 /* specific symbol types */ - -/* Extract symbol visibility - st_other */ -#define ELF_ST_VISIBILITY(v) ((v)&0x3) -#define ELF32_ST_VISIBILITY ELF_ST_VISIBILITY -#define ELF64_ST_VISIBILITY ELF_ST_VISIBILITY - -#define STV_DEFAULT 0 /* Visibility set by binding type */ -#define STV_INTERNAL 1 /* OS specific version of STV_HIDDEN */ -#define STV_HIDDEN 2 /* can only be seen inside own .so */ -#define STV_PROTECTED 3 /* HIDDEN inside, DEFAULT outside */ - -/* Relocation entry with implicit addend */ -typedef struct { - Elf32_Addr r_offset; /* offset of relocation */ - Elf32_Word r_info; /* symbol table index and type */ -} Elf32_Rel; - -/* Relocation entry with explicit addend */ -typedef struct { - Elf32_Addr r_offset; /* offset of relocation */ - Elf32_Word r_info; /* symbol table index and type */ - Elf32_Sword r_addend; -} Elf32_Rela; - -/* Extract relocation info - r_info */ -#define ELF32_R_SYM(i) ((i) >> 8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) -#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) - -typedef struct { - Elf64_Xword r_offset; /* where to do it */ - Elf64_Xword r_info; /* index & type of relocation */ -} Elf64_Rel; - -typedef struct { - Elf64_Xword r_offset; /* where to do it */ - Elf64_Xword r_info; /* index & type of relocation */ - Elf64_Sxword r_addend; /* adjustment value */ -} Elf64_Rela; - -#define ELF64_R_SYM(info) ((info) >> 32) -#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF) -#define ELF64_R_INFO(s, t) (((s) << 32) + (uint32_t)(t)) - -#if defined(__mips64__) && defined(__MIPSEL__) -/* - * The 64-bit MIPS ELF ABI uses a slightly different relocation format - * than the regular ELF ABI: the r_info field is split into several - * pieces (see gnu/usr.bin/binutils-2.17/include/elf/mips.h for details). - */ -# undef ELF64_R_SYM -# undef ELF64_R_TYPE -# undef ELF64_R_INFO -# define ELF64_R_TYPE(info) ((uint64_t)swap32((info) >> 32)) -# define ELF64_R_SYM(info) ((info)&0xFFFFFFFF) -# define ELF64_R_INFO(s, t) (((uint64_t)swap32(t) << 32) + (uint32_t)(s)) -#endif /* __mips64__ && __MIPSEL__ */ - -/* Program Header */ -typedef struct { - Elf32_Word p_type; /* segment type */ - Elf32_Off p_offset; /* segment offset */ - Elf32_Addr p_vaddr; /* virtual address of segment */ - Elf32_Addr p_paddr; /* physical address - ignored? */ - Elf32_Word p_filesz; /* number of bytes in file for seg. */ - Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ - Elf32_Word p_flags; /* flags */ - Elf32_Word p_align; /* memory alignment */ -} Elf32_Phdr; - -typedef struct { - Elf64_Half p_type; /* entry type */ - Elf64_Half p_flags; /* flags */ - Elf64_Off p_offset; /* offset */ - Elf64_Addr p_vaddr; /* virtual address */ - Elf64_Addr p_paddr; /* physical address */ - Elf64_Xword p_filesz; /* file size */ - Elf64_Xword p_memsz; /* memory size */ - Elf64_Xword p_align; /* memory & file alignment */ -} Elf64_Phdr; - -/* Segment types - p_type */ -#define PT_NULL 0 /* unused */ -#define PT_LOAD 1 /* loadable segment */ -#define PT_DYNAMIC 2 /* dynamic linking section */ -#define PT_INTERP 3 /* the RTLD */ -#define PT_NOTE 4 /* auxiliary information */ -#define PT_SHLIB 5 /* reserved - purpose undefined */ -#define PT_PHDR 6 /* program header */ -#define PT_TLS 7 /* thread local storage */ -#define PT_LOOS 0x60000000 /* reserved range for OS */ -#define PT_HIOS 0x6fffffff /* specific segment types */ -#define PT_LOPROC 0x70000000 /* reserved range for processor */ -#define PT_HIPROC 0x7fffffff /* specific segment types */ - -#define PT_GNU_EH_FRAME 0x6474e550 /* Exception handling info */ -#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ -#define PT_GNU_STACK 0x6474e551 /* Stack permissions info */ - -#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */ -#define PT_OPENBSD_WXNEEDED 0x65a3dbe7 /* program performs W^X violations */ -#define PT_OPENBSD_BOOTDATA 0x65a41be6 /* section for boot arguments */ - -/* Segment flags - p_flags */ -#define PF_X 0x1 /* Executable */ -#define PF_W 0x2 /* Writable */ -#define PF_R 0x4 /* Readable */ -#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ - /* specific segment flags */ - -/* Dynamic structure */ -typedef struct { - Elf32_Sword d_tag; /* controls meaning of d_val */ - union { - Elf32_Word d_val; /* Multiple meanings - see d_tag */ - Elf32_Addr d_ptr; /* program virtual address */ - } d_un; -} Elf32_Dyn; - -typedef struct { - Elf64_Xword d_tag; /* controls meaning of d_val */ - union { - Elf64_Addr d_ptr; - Elf64_Xword d_val; - } d_un; -} Elf64_Dyn; - -/* Dynamic Array Tags - d_tag */ -#define DT_NULL 0 /* marks end of _DYNAMIC array */ -#define DT_NEEDED 1 /* string table offset of needed lib */ -#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ -#define DT_PLTGOT 3 /* address PLT/GOT */ -#define DT_HASH 4 /* address of symbol hash table */ -#define DT_STRTAB 5 /* address of string table */ -#define DT_SYMTAB 6 /* address of symbol table */ -#define DT_RELA 7 /* address of relocation table */ -#define DT_RELASZ 8 /* size of relocation table */ -#define DT_RELAENT 9 /* size of relocation entry */ -#define DT_STRSZ 10 /* size of string table */ -#define DT_SYMENT 11 /* size of symbol table entry */ -#define DT_INIT 12 /* address of initialization func. */ -#define DT_FINI 13 /* address of termination function */ -#define DT_SONAME 14 /* string table offset of shared obj */ -#define DT_RPATH 15 /* string table offset of library \ - search path */ -#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ -#define DT_REL 17 /* address of rel. tbl. w addends */ -#define DT_RELSZ 18 /* size of DT_REL relocation table */ -#define DT_RELENT 19 /* size of DT_REL relocation entry */ -#define DT_PLTREL 20 /* PLT referenced relocation entry */ -#define DT_DEBUG 21 /* bugger */ -#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ -#define DT_JMPREL 23 /* add. of PLT's relocation entries */ -#define DT_BIND_NOW 24 /* Bind now regardless of env setting */ -#define DT_INIT_ARRAY 25 /* address of array of init func */ -#define DT_FINI_ARRAY 26 /* address of array of term func */ -#define DT_INIT_ARRAYSZ 27 /* size of array of init func */ -#define DT_FINI_ARRAYSZ 28 /* size of array of term func */ -#define DT_RUNPATH 29 /* strtab offset of lib search path */ -#define DT_FLAGS 30 /* Set of DF_* flags */ -#define DT_ENCODING 31 /* further DT_* follow encoding rules */ -#define DT_PREINIT_ARRAY 32 /* address of array of preinit func */ -#define DT_PREINIT_ARRAYSZ 33 /* size of array of preinit func */ -#define DT_LOOS 0x6000000d /* reserved range for OS */ -#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */ -#define DT_LOPROC 0x70000000 /* reserved range for processor */ -#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ - -/* some other useful tags */ -#define DT_GNU_HASH 0x6ffffef5 /* address of GNU hash table */ -#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */ -#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */ -#define DT_FLAGS_1 0x6ffffffb - -/* Dynamic Flags - DT_FLAGS .dynamic entry */ -#define DF_ORIGIN 0x00000001 -#define DF_SYMBOLIC 0x00000002 -#define DF_TEXTREL 0x00000004 -#define DF_BIND_NOW 0x00000008 -#define DF_STATIC_TLS 0x00000010 - -/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */ -#define DF_1_NOW 0x00000001 -#define DF_1_GLOBAL 0x00000002 -#define DF_1_GROUP 0x00000004 -#define DF_1_NODELETE 0x00000008 -#define DF_1_LOADFLTR 0x00000010 -#define DF_1_INITFIRST 0x00000020 -#define DF_1_NOOPEN 0x00000040 -#define DF_1_ORIGIN 0x00000080 -#define DF_1_DIRECT 0x00000100 -#define DF_1_TRANS 0x00000200 -#define DF_1_INTERPOSE 0x00000400 -#define DF_1_NODEFLIB 0x00000800 -#define DF_1_NODUMP 0x00001000 -#define DF_1_CONLFAT 0x00002000 - -/* - * Note header - */ -typedef struct { - Elf32_Word n_namesz; - Elf32_Word n_descsz; - Elf32_Word n_type; -} Elf32_Nhdr; - -typedef struct { - Elf64_Half n_namesz; - Elf64_Half n_descsz; - Elf64_Half n_type; -} Elf64_Nhdr; - -/* - * Note Definitions - */ -typedef struct { - Elf32_Word namesz; - Elf32_Word descsz; - Elf32_Word type; -} Elf32_Note; - -typedef struct { - Elf64_Half namesz; - Elf64_Half descsz; - Elf64_Half type; -} Elf64_Note; - -/* Values for n_type. */ -#define NT_PRSTATUS 1 /* Process status. */ -#define NT_FPREGSET 2 /* Floating point registers. */ -#define NT_PRPSINFO 3 /* Process state info. */ - -/* - * OpenBSD-specific core file information. - * - * OpenBSD ELF core files use notes to provide information about - * the process's state. The note name is "OpenBSD" for information - * that is global to the process, and "OpenBSD@nn", where "nn" is the - * thread ID of the thread that the information belongs to (such as - * register state). - * - * We use the following note identifiers: - * - * NT_OPENBSD_PROCINFO - * Note is a "elfcore_procinfo" structure. - * NT_OPENBSD_AUXV - * Note is a a bunch of Auxiliary Vectors, terminated by - * an AT_NULL entry. - * NT_OPENBSD_REGS - * Note is a "reg" structure. - * NT_OPENBSD_FPREGS - * Note is a "fpreg" structure. - * - * Please try to keep the members of the "elfcore_procinfo" structure - * nicely aligned, and if you add elements, add them to the end and - * bump the version. - */ - -#define NT_OPENBSD_PROCINFO 10 -#define NT_OPENBSD_AUXV 11 - -#define NT_OPENBSD_REGS 20 -#define NT_OPENBSD_FPREGS 21 -#define NT_OPENBSD_XFPREGS 22 -#define NT_OPENBSD_WCOOKIE 23 - -struct elfcore_procinfo { - /* Version 1 fields start here. */ - uint32_t cpi_version; /* netbsd_elfcore_procinfo version */ -#define ELFCORE_PROCINFO_VERSION 1 - uint32_t cpi_cpisize; /* sizeof(netbsd_elfcore_procinfo) */ - uint32_t cpi_signo; /* killing signal */ - uint32_t cpi_sigcode; /* signal code */ - uint32_t cpi_sigpend; /* pending signals */ - uint32_t cpi_sigmask; /* blocked signals */ - uint32_t cpi_sigignore; /* ignored signals */ - uint32_t cpi_sigcatch; /* signals being caught by user */ - int32_t cpi_pid; /* process ID */ - int32_t cpi_ppid; /* parent process ID */ - int32_t cpi_pgrp; /* process group ID */ - int32_t cpi_sid; /* session ID */ - uint32_t cpi_ruid; /* real user ID */ - uint32_t cpi_euid; /* effective user ID */ - uint32_t cpi_svuid; /* saved user ID */ - uint32_t cpi_rgid; /* real group ID */ - uint32_t cpi_egid; /* effective group ID */ - uint32_t cpi_svgid; /* saved group ID */ - int8_t cpi_name[32]; /* copy of pr->ps_comm */ -}; - -/* - * XXX - these _KERNEL items aren't part of the ABI! - */ -#if defined(_KERNEL) || defined(_DYN_LOADER) - -# define ELF32_NO_ADDR ((uint32_t)~0) /* Indicates addr. not yet filled in */ - -typedef struct { - Elf32_Sword au_id; /* 32-bit id */ - Elf32_Word au_v; /* 32-bit value */ -} Aux32Info; - -# define ELF64_NO_ADDR ((uint64_t)~0) /* Indicates addr. not yet filled in */ - -typedef struct { - Elf64_Shalf au_id; /* 32-bit id */ - Elf64_Xword au_v; /* 64-bit value */ -} Aux64Info; - -enum AuxID { - AUX_null = 0, - AUX_ignore = 1, - AUX_execfd = 2, - AUX_phdr = 3, /* &phdr[0] */ - AUX_phent = 4, /* sizeof(phdr[0]) */ - AUX_phnum = 5, /* # phdr entries */ - AUX_pagesz = 6, /* PAGESIZE */ - AUX_base = 7, /* ld.so base addr */ - AUX_flags = 8, /* processor flags */ - AUX_entry = 9, /* a.out entry */ - AUX_sun_uid = 2000, /* euid */ - AUX_sun_ruid = 2001, /* ruid */ - AUX_sun_gid = 2002, /* egid */ - AUX_sun_rgid = 2003 /* rgid */ -}; - -struct elf_args { - u_long arg_entry; /* program entry point */ - u_long arg_interp; /* Interpreter load address */ - u_long arg_phaddr; /* program header address */ - u_long arg_phentsize; /* Gfx::Size of program header */ - u_long arg_phnum; /* Number of program headers */ -}; - -#endif - -#if !defined(ELFSIZE) && defined(ARCH_ELFSIZE) -# define ELFSIZE ARCH_ELFSIZE -#endif - -#if defined(ELFSIZE) -# define CONCAT(x, y) __CONCAT(x, y) -# define ELFNAME(x) CONCAT(elf, CONCAT(ELFSIZE, CONCAT(_, x))) -# define ELFDEFNNAME(x) CONCAT(ELF, CONCAT(ELFSIZE, CONCAT(_, x))) -#endif - -#if defined(ELFSIZE) && (ELFSIZE == 32) -# define Elf_Ehdr Elf32_Ehdr -# define Elf_Phdr Elf32_Phdr -# define Elf_Shdr Elf32_Shdr -# define Elf_Sym Elf32_Sym -# define Elf_Rel Elf32_Rel -# define Elf_RelA Elf32_Rela -# define Elf_Dyn Elf32_Dyn -# define Elf_Half Elf32_Half -# define Elf_Word Elf32_Word -# define Elf_Sword Elf32_Sword -# define Elf_Addr Elf32_Addr -# define Elf_Off Elf32_Off -# define Elf_Nhdr Elf32_Nhdr -# define Elf_Note Elf32_Note - -# define ELF_R_SYM ELF32_R_SYM -# define ELF_R_TYPE ELF32_R_TYPE -# define ELF_R_INFO ELF32_R_INFO -# define ELFCLASS ELFCLASS32 - -# define ELF_ST_BIND ELF32_ST_BIND -# define ELF_ST_TYPE ELF32_ST_TYPE -# define ELF_ST_INFO ELF32_ST_INFO - -# define ELF_NO_ADDR ELF32_NO_ADDR -# define AuxInfo Aux32Info -#elif defined(ELFSIZE) && (ELFSIZE == 64) -# define Elf_Ehdr Elf64_Ehdr -# define Elf_Phdr Elf64_Phdr -# define Elf_Shdr Elf64_Shdr -# define Elf_Sym Elf64_Sym -# define Elf_Rel Elf64_Rel -# define Elf_RelA Elf64_Rela -# define Elf_Dyn Elf64_Dyn -# define Elf_Half Elf64_Half -# define Elf_Word Elf64_Word -# define Elf_Sword Elf64_Sword -# define Elf_Addr Elf64_Addr -# define Elf_Off Elf64_Off -# define Elf_Nhdr Elf64_Nhdr -# define Elf_Note Elf64_Note - -# define ELF_R_SYM ELF64_R_SYM -# define ELF_R_TYPE ELF64_R_TYPE -# define ELF_R_INFO ELF64_R_INFO -# define ELFCLASS ELFCLASS64 - -# define ELF_ST_BIND ELF64_ST_BIND -# define ELF_ST_TYPE ELF64_ST_TYPE -# define ELF_ST_INFO ELF64_ST_INFO - -# define ELF_NO_ADDR ELF64_NO_ADDR -# define AuxInfo Aux64Info -#endif - -#define ELF_TARG_VER 1 /* The ver for which this code is intended */ - -/* Relocation types */ -#define R_386_NONE 0 -#define R_386_32 1 /* Symbol + Addend */ -#define R_386_PC32 2 /* Symbol + Addend - Section offset */ -#define R_386_GOT32 3 /* Used by build-time linker to create GOT entry */ -#define R_386_PLT32 4 /* Used by build-time linker to create PLT entry */ -#define R_386_COPY 5 /* https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter4-10454.html#chapter4-84604 */ -#define R_386_GLOB_DAT 6 /* Relation b/w GOT entry and symbol */ -#define R_386_JMP_SLOT 7 /* Fixed up by dynamic loader */ -#define R_386_RELATIVE 8 /* Base address + Addned */ -#define R_386_TLS_TPOFF 14 /* Negative offset into the static TLS storage */ -#define R_386_TLS_TPOFF32 37 - -#endif /* _SYS_EXEC_ELF_H_ */ |