From b6590b7f83ebfe8937a32f0cfef9e002aadb70de Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Tue, 31 Dec 2019 16:43:11 -0500 Subject: [PATCH] Demos: Add a dynamic linking demo to show off dlfcn methods The LinkDemo program calls dlopen/dlsym/dlclose to try and load a dyanmic library from /usr/lib. It read a global variable and calls a global function (extern "C" of course :) ). There a few hacks left in the LinkLib dynamic library, however. In order to get the linker to stop complaining, we have to use -nostartfiles -ffreestanding otherwise it will link crt0.o to our shared object, which is definitely not right as the _init function for a main program (that calls main) is not suitable for our lib --- .gitignore | 2 +- Demos/DynamicLink/LinkDemo/Makefile | 6 ++ Demos/DynamicLink/LinkDemo/main.cpp | 72 ++++++++++++++++++++++++ Demos/DynamicLink/LinkLib/DynamicLib.cpp | 72 ++++++++++++++++++++++++ Demos/DynamicLink/LinkLib/Makefile | 20 +++++++ Demos/DynamicLink/Makefile | 3 + Kernel/build-root-filesystem.sh | 5 ++ 7 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 Demos/DynamicLink/LinkDemo/Makefile create mode 100644 Demos/DynamicLink/LinkDemo/main.cpp create mode 100644 Demos/DynamicLink/LinkLib/DynamicLib.cpp create mode 100644 Demos/DynamicLink/LinkLib/Makefile create mode 100644 Demos/DynamicLink/Makefile diff --git a/.gitignore b/.gitignore index 8490cd252fe..4ff7aa74e6e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ *.o *.ao *.a - +*.so *.d *.swp diff --git a/Demos/DynamicLink/LinkDemo/Makefile b/Demos/DynamicLink/LinkDemo/Makefile new file mode 100644 index 00000000000..def5edea1f1 --- /dev/null +++ b/Demos/DynamicLink/LinkDemo/Makefile @@ -0,0 +1,6 @@ +OBJS = \ + main.o + +PROGRAM = LinkDemo + +include ../../../Makefile.common diff --git a/Demos/DynamicLink/LinkDemo/main.cpp b/Demos/DynamicLink/LinkDemo/main.cpp new file mode 100644 index 00000000000..a186e63eda5 --- /dev/null +++ b/Demos/DynamicLink/LinkDemo/main.cpp @@ -0,0 +1,72 @@ +#include + +#include +#include + +int main() +{ + void* handle = dlopen("/usr/lib/libDynamicLib.so", RTLD_LAZY | RTLD_GLOBAL); + + if (!handle) { + printf("Failed to dlopen! %s\n", dlerror()); + return 1; + } + + // Test getting an external variable from the library and read it out + int* ptr_global = (int*)dlsym(handle, "global_lib_variable"); + + if (!ptr_global) { + printf("Failed to dlsym for \"global_lib_variable\"! %s\n", dlerror()); + return 2; + } + + printf("Found global lib variable address: %p\n", ptr_global); + + printf("Global lib variable is %d\n", *ptr_global); + + // Test getting a method from the library and calling it + void (*lib_func)(void) = (void (*)(void))dlsym(handle, "global_lib_function"); + + printf("Found global lib function address: %p\n", lib_func); + + if (!lib_func) { + printf("Failed to dlsym for \"global_lib_function\"! %s\n", dlerror()); + return 2; + } + + lib_func(); + + printf("I think I called my lib function!\n"); + + // Test getting a method that takes and returns arugments now + const char* (*other_func)(int) = (const char* (*)(int))dlsym(handle, "other_lib_function"); + + printf("Found other lib function address %p\n", other_func); + + if (!other_func) { + printf("Failed to dlsym for \"other_lib_function\"! %s\n", dlerror()); + return 2; + } + + // Call it twice with different arguments + String formatted_result = other_func(10); + + printf("(%d + %d = %d) %s\n", *ptr_global, 10, *ptr_global + 10, formatted_result.characters()); + + *ptr_global = 17; + + formatted_result = other_func(5); + + printf("(%d + %d = %d) %s\n", *ptr_global, 5, *ptr_global + 5, formatted_result.characters()); + + int ret = dlclose(handle); + + if (ret < 0) { + printf("Failed to dlclose! %s\n", dlerror()); + return 3; + } + + printf("Bye for now!\n"); + + return 0; +} \ No newline at end of file diff --git a/Demos/DynamicLink/LinkLib/DynamicLib.cpp b/Demos/DynamicLink/LinkLib/DynamicLib.cpp new file mode 100644 index 00000000000..106eeb73a4a --- /dev/null +++ b/Demos/DynamicLink/LinkLib/DynamicLib.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +// FIXME: See Makefile. We need -ffreestanding and -nostartfiles to +// Get GCC to stop linking crt0.o w/our .so. +// So, we need __dso_handle. ... Yikes +extern void* __dso_handle __attribute__((__section__(".sdata"))); +extern void* __dso_handle __attribute__((__visibility__("hidden"))); +void* __dso_handle = (void*)1234; // FIXME: Is the dynamic linker supposed to set this value? + +// FIXME: Things defined in crt0 >:( +__thread int errno; +char* __static_environ[] = { nullptr }; // We don't get the environment without some libc workarounds.. +char** environ = __static_environ; +bool __environ_is_malloced = false; +extern unsigned __stack_chk_guard; +unsigned __stack_chk_guard = (unsigned)0xc0000c13; + +[[noreturn]] void __stack_chk_fail() +{ + ASSERT_NOT_REACHED(); +} + +// FIXME: Because we need to call printf, and we don't have access to the stout file descriptor +// from the main executable, we need to create our own copy in __stdio_init :/ +// Same deal for malloc init. We're essentially manually calling __libc_init here. +extern "C" void __stdio_init(); +extern "C" void __malloc_init(); + +class Global { +public: + Global(int i) + : m_i(i) + { + __malloc_init(); + __stdio_init(); + } + + int get_i() const { return m_i; } + +private: + int m_i = 0; +}; + +// This object exists to call __stdio_init and __malloc_init. Also to show that global vars work +Global g_glob { 5 }; + +extern "C" { +int global_lib_variable = 1234; + +void global_lib_function() +{ + printf("Hello from Dynamic Lib! g_glob::m_i == %d\n", g_glob.get_i()); +} + +const char* other_lib_function(int my_argument) +{ + dbgprintf("Hello from Dynamic Lib, now from the debug port! g_glob::m_i == %d\n", g_glob.get_i()); + + int sum = my_argument + global_lib_variable; + + // FIXME: We can't just return AK::String::format across the lib boundary here. + // It will use malloc from our DSO's copy of LibC, and then probably be free'd into + // the malloc of the main program which would be what they call 'very crash'. + // Feels very Windows :) + static String s_string; + s_string = String::format("Here's your string! Sum of argument and global_lib_variable: %d", sum); + return s_string.characters(); +} +} diff --git a/Demos/DynamicLink/LinkLib/Makefile b/Demos/DynamicLink/LinkLib/Makefile new file mode 100644 index 00000000000..f8db5328445 --- /dev/null +++ b/Demos/DynamicLink/LinkLib/Makefile @@ -0,0 +1,20 @@ + +include ../../../Makefile.common + +DYNLIBRARY = libDynamicLib.so + +.PHONY: clean all + +all: $(DYNLIBRARY) + +DynamicLib.o: DynamicLib.cpp + $(CXX) -DDEBUG -fPIC -isystem../../../ -o $@ -c $< + +# FIXME: Why do I need -nostartfiles and -nofreestanding? +# GCC isn't smart enough to not link crt0 against this dynamic lib +# which is clearly wrong. Isn't it? We don't want _start... +$(DYNLIBRARY): DynamicLib.o + $(CXX) -shared -nostartfiles -ffreestanding -o $(DYNLIBRARY) $< + +clean: + rm -f *.o *.d *.so diff --git a/Demos/DynamicLink/Makefile b/Demos/DynamicLink/Makefile new file mode 100644 index 00000000000..d10b5ae814d --- /dev/null +++ b/Demos/DynamicLink/Makefile @@ -0,0 +1,3 @@ +SUBDIRS := $(wildcard */.) + +include ../../Makefile.subdir diff --git a/Kernel/build-root-filesystem.sh b/Kernel/build-root-filesystem.sh index 428bae1d1da..9e3c83f127d 100755 --- a/Kernel/build-root-filesystem.sh +++ b/Kernel/build-root-filesystem.sh @@ -110,6 +110,7 @@ cp ../Demos/HelloWorld/HelloWorld mnt/bin/HelloWorld cp ../Demos/HelloWorld2/HelloWorld2 mnt/bin/HelloWorld2 cp ../Demos/WidgetGallery/WidgetGallery mnt/bin/WidgetGallery cp ../Demos/Fire/Fire mnt/bin/Fire +cp ../Demos/DynamicLink/LinkDemo/LinkDemo mnt/bin/LinkDemo cp ../DevTools/HackStudio/HackStudio mnt/bin/HackStudio cp ../DevTools/VisualBuilder/VisualBuilder mnt/bin/VisualBuilder cp ../DevTools/Inspector/Inspector mnt/bin/Inspector @@ -129,6 +130,10 @@ cp ../MenuApplets/CPUGraph/CPUGraph.MenuApplet mnt/bin/ cp ../MenuApplets/Clock/Clock.MenuApplet mnt/bin/ echo "done" +printf "installing dynamic libraries... " +cp ../Demos/DynamicLink/LinkLib/libDynamicLib.so mnt/usr/lib +echo "done" + printf "installing shortcuts... " ln -s FileManager mnt/bin/fm ln -s HelloWorld mnt/bin/hw