diff options
-rw-r--r-- | Tests/LibELF/CMakeLists.txt | 16 | ||||
-rw-r--r-- | Tests/LibELF/Dynlib.cpp | 15 | ||||
-rw-r--r-- | Tests/LibELF/TestDlOpen.cpp | 25 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicLinker.cpp | 19 |
4 files changed, 66 insertions, 9 deletions
diff --git a/Tests/LibELF/CMakeLists.txt b/Tests/LibELF/CMakeLists.txt index ab5a9f200a..5e5303be1d 100644 --- a/Tests/LibELF/CMakeLists.txt +++ b/Tests/LibELF/CMakeLists.txt @@ -1,7 +1,21 @@ +macro(add_dlopen_lib NAME FUNCTION) + add_library(${NAME} SHARED Dynlib.cpp) + target_compile_definitions(${NAME} PRIVATE -DFUNCTION=${FUNCTION}) + # LibLine is not special, just an "external" dependency + target_link_libraries(${NAME} LibLine) + # Avoid execution by the test runner + install(TARGETS ${NAME} + DESTINATION usr/Tests/LibELF + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) +endmacro() +add_dlopen_lib(DynlibA dynliba_function) +add_dlopen_lib(DynlibB dynlibb_function) + set(TEST_SOURCES test-elf.cpp + TestDlOpen.cpp ) foreach(source IN LISTS TEST_SOURCES) - serenity_test("${source}" LibELF) + serenity_test("${source}" LibELF LIBS LibDl) endforeach() diff --git a/Tests/LibELF/Dynlib.cpp b/Tests/LibELF/Dynlib.cpp new file mode 100644 index 0000000000..4187378fd1 --- /dev/null +++ b/Tests/LibELF/Dynlib.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021, Rodrigo Tobar <rtobarc@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibLine/Span.h> + +extern "C" { +int FUNCTION(); +int FUNCTION() +{ + return (int)Line::Span(0, 0).beginning(); +} +} diff --git a/Tests/LibELF/TestDlOpen.cpp b/Tests/LibELF/TestDlOpen.cpp new file mode 100644 index 0000000000..92f69a051e --- /dev/null +++ b/Tests/LibELF/TestDlOpen.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021, Rodrigo Tobar <rtobarc@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibDl/dlfcn.h> +#include <LibTest/TestCase.h> + +TEST_CASE(test_dlopen) +{ + auto liba = dlopen("/usr/Tests/LibELF/libDynlibA.so", 0); + EXPECT_NE(liba, nullptr); + auto libb = dlopen("/usr/Tests/LibELF/libDynlibB.so", 0); + EXPECT_NE(libb, nullptr); + + typedef int (*dynlib_func_t)(); + dynlib_func_t func_a = (dynlib_func_t)dlsym(liba, "dynliba_function"); + EXPECT_NE(func_a, nullptr); + EXPECT_EQ(0, func_a()); + + dynlib_func_t func_b = (dynlib_func_t)dlsym(libb, "dynlibb_function"); + EXPECT_NE(func_b, nullptr); + EXPECT_EQ(0, func_b()); +} diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp index 4e017bd744..eb05122ad6 100644 --- a/Userland/Libraries/LibELF/DynamicLinker.cpp +++ b/Userland/Libraries/LibELF/DynamicLinker.cpp @@ -257,38 +257,41 @@ static void initialize_libc(DynamicObject& libc) } template<typename Callback> -static void for_each_unfinished_dependency_of(const String& name, HashTable<String>& seen_names, Callback callback) +static void for_each_unfinished_dependency_of(const String& name, HashTable<String>& seen_names, bool first, bool skip_global_objects, Callback callback) { if (!s_loaders.contains(name)) return; + if (!first && skip_global_objects && s_global_objects.contains(name)) + return; + if (seen_names.contains(name)) return; seen_names.set(name); for (const auto& needed_name : get_dependencies(name)) - for_each_unfinished_dependency_of(get_library_name(needed_name), seen_names, callback); + for_each_unfinished_dependency_of(get_library_name(needed_name), seen_names, false, skip_global_objects, callback); callback(*s_loaders.get(name).value()); } -static NonnullRefPtrVector<DynamicLoader> collect_loaders_for_library(const String& name) +static NonnullRefPtrVector<DynamicLoader> collect_loaders_for_library(const String& name, bool skip_global_objects) { HashTable<String> seen_names; NonnullRefPtrVector<DynamicLoader> loaders; - for_each_unfinished_dependency_of(name, seen_names, [&](auto& loader) { + for_each_unfinished_dependency_of(name, seen_names, true, skip_global_objects, [&](auto& loader) { loaders.append(loader); }); return loaders; } -static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> load_main_library(const String& name, int flags) +static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> load_main_library(const String& name, int flags, bool skip_global_objects) { auto main_library_loader = *s_loaders.get(name); auto main_library_object = main_library_loader->map(); s_global_objects.set(name, *main_library_object); - auto loaders = collect_loaders_for_library(name); + auto loaders = collect_loaders_for_library(name, skip_global_objects); for (auto& loader : loaders) { auto dynamic_object = loader.map(); @@ -411,7 +414,7 @@ static Result<void*, DlErrorMessage> __dlopen(const char* filename, int flags) return result2.error(); } - auto result = load_main_library(library_name, flags); + auto result = load_main_library(library_name, flags, true); if (result.is_error()) return result.error(); @@ -535,7 +538,7 @@ void ELF::DynamicLinker::linker_main(String&& main_program_name, int main_progra auto entry_point_function = [&main_program_name] { auto library_name = get_library_name(main_program_name); - auto result = load_main_library(library_name, RTLD_GLOBAL | RTLD_LAZY); + auto result = load_main_library(library_name, RTLD_GLOBAL | RTLD_LAZY, false); if (result.is_error()) { warnln("{}", result.error().text); _exit(1); |