Serenity Operating System
at portability 128 lines 4.3 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <assert.h> 28#include <dlfcn.h> 29#include <fcntl.h> 30#include <mman.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <sys/stat.h> 34 35#include <AK/FileSystemPath.h> 36#include <AK/HashMap.h> 37#include <AK/RefPtr.h> 38#include <AK/ScopeGuard.h> 39#include <AK/String.h> 40#include <AK/StringBuilder.h> 41#include <LibELF/ELFDynamicLoader.h> 42 43// NOTE: The string here should never include a trailing newline (according to POSIX) 44String g_dlerror_msg; 45 46HashMap<String, RefPtr<ELFDynamicLoader>> g_elf_objects; 47 48extern "C" { 49 50int dlclose(void*) 51{ 52 g_dlerror_msg = "dlclose not implemented!"; 53 return -1; 54} 55 56char* dlerror() 57{ 58 return const_cast<char*>(g_dlerror_msg.characters()); 59} 60 61void* dlopen(const char* filename, int flags) 62{ 63 // FIXME: Create a global mutex/semaphore/lock for dlopen/dlclose/dlsym and (?) dlerror 64 // FIXME: refcount? 65 66 if (!filename) { 67 // FIXME: Return the handle for "the main executable" 68 // The Serenity Kernel will keep a mapping of the main elf binary resident in memory, 69 // But a future dynamic loader might have a different idea/way of letting us access this information 70 ASSERT_NOT_REACHED(); 71 } 72 73 FileSystemPath file_path(filename); 74 75 auto existing_elf_object = g_elf_objects.get(file_path.basename()); 76 if (existing_elf_object.has_value()) { 77 return const_cast<ELFDynamicLoader*>(existing_elf_object.value()); 78 } 79 80 int fd = open(filename, O_RDONLY); 81 if (!fd) { 82 g_dlerror_msg = String::format("Unable to open file %s", filename); 83 return nullptr; 84 } 85 86 ScopeGuard close_fd_guard([fd]() { close(fd); }); 87 88 struct stat file_stats{}; 89 90 int ret = fstat(fd, &file_stats); 91 if (ret < 0) { 92 g_dlerror_msg = String::format("Unable to stat file %s", filename); 93 return nullptr; 94 } 95 96 auto loader = ELFDynamicLoader::construct(filename, fd, file_stats.st_size); 97 98 if (!loader->is_valid()) { 99 g_dlerror_msg = String::format("%s is not a valid ELF dynamic shared object!", filename); 100 return nullptr; 101 } 102 103 if (!loader->load_from_image(flags)) { 104 g_dlerror_msg = String::format("Failed to load ELF object %s", filename); 105 return nullptr; 106 } 107 108 g_elf_objects.set(file_path.basename(), move(loader)); 109 g_dlerror_msg = "Successfully loaded ELF object."; 110 111 // we have one refcount already 112 return const_cast<ELFDynamicLoader*>(g_elf_objects.get(file_path.basename()).value()); 113} 114 115void* dlsym(void* handle, const char* symbol_name) 116{ 117 // FIXME: When called with a NULL handle we're supposed to search every dso in the process... that'll get expensive 118 ASSERT(handle); 119 auto* dso = reinterpret_cast<ELFDynamicLoader*>(handle); 120 void* symbol = dso->symbol_for_name(symbol_name); 121 if (!symbol) { 122 g_dlerror_msg = "Symbol not found"; 123 return nullptr; 124 } 125 return symbol; 126} 127 128} // extern "C"