Browse Source

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
Andrew Kaster 5 years ago
parent
commit
b6590b7f83

+ 1 - 1
.gitignore

@@ -8,7 +8,7 @@
 *.o
 *.o
 *.ao
 *.ao
 *.a
 *.a
-
+*.so
 *.d
 *.d
 
 
 *.swp
 *.swp

+ 6 - 0
Demos/DynamicLink/LinkDemo/Makefile

@@ -0,0 +1,6 @@
+OBJS = \
+    main.o
+
+PROGRAM = LinkDemo
+
+include ../../../Makefile.common

+ 72 - 0
Demos/DynamicLink/LinkDemo/main.cpp

@@ -0,0 +1,72 @@
+#include <AK/String.h>
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+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;
+}

+ 72 - 0
Demos/DynamicLink/LinkLib/DynamicLib.cpp

@@ -0,0 +1,72 @@
+#include <AK/kstdio.h>
+#include <AK/String.h>
+#include <assert.h>
+#include <stdio.h>
+
+// 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();
+}
+}

+ 20 - 0
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

+ 3 - 0
Demos/DynamicLink/Makefile

@@ -0,0 +1,3 @@
+SUBDIRS := $(wildcard */.)
+
+include ../../Makefile.subdir

+ 5 - 0
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/HelloWorld2/HelloWorld2 mnt/bin/HelloWorld2
 cp ../Demos/WidgetGallery/WidgetGallery mnt/bin/WidgetGallery
 cp ../Demos/WidgetGallery/WidgetGallery mnt/bin/WidgetGallery
 cp ../Demos/Fire/Fire mnt/bin/Fire
 cp ../Demos/Fire/Fire mnt/bin/Fire
+cp ../Demos/DynamicLink/LinkDemo/LinkDemo mnt/bin/LinkDemo
 cp ../DevTools/HackStudio/HackStudio mnt/bin/HackStudio
 cp ../DevTools/HackStudio/HackStudio mnt/bin/HackStudio
 cp ../DevTools/VisualBuilder/VisualBuilder mnt/bin/VisualBuilder
 cp ../DevTools/VisualBuilder/VisualBuilder mnt/bin/VisualBuilder
 cp ../DevTools/Inspector/Inspector mnt/bin/Inspector
 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/
 cp ../MenuApplets/Clock/Clock.MenuApplet mnt/bin/
 echo "done"
 echo "done"
 
 
+printf "installing dynamic libraries... "
+cp ../Demos/DynamicLink/LinkLib/libDynamicLib.so mnt/usr/lib
+echo "done"
+
 printf "installing shortcuts... "
 printf "installing shortcuts... "
 ln -s FileManager mnt/bin/fm
 ln -s FileManager mnt/bin/fm
 ln -s HelloWorld mnt/bin/hw
 ln -s HelloWorld mnt/bin/hw