rename the *_load_time examples, start GUIDE.txt, write the xlist base layer example
							parent
							
								
									a3befc6dcd
								
							
						
					
					
						commit
						40183c2eed
					
				|  | @ -0,0 +1,21 @@ | |||
| The main goal of this investigation is to organize shared data and code across  | ||||
| multiple binary files. This is especially important for something like a base | ||||
| layer that will be used in a program that supports hot-reloading or plugins. | ||||
| 
 | ||||
| Each isolated example in this repository explores a way to set up the base | ||||
| layer, plugin, and main program. | ||||
| 
 | ||||
| The examples: | ||||
| 
 | ||||
| *_concrete - Concrete examples for each operating system I have investigated | ||||
|              showing how to setup and use various types of dynamic linking. In | ||||
|              these the "base" layer goes through load-time linking, the | ||||
|              "plugin" layer goes through run-time linking, and the "main" layer | ||||
|               acts as the executable that must bind it all together. | ||||
| 
 | ||||
| xlist - My prefered solution to the problem posed in the investigation which | ||||
|         relies only on run-time linking. It uses an xlist to manage the | ||||
|         maintenance burden of run-time linking, and a basic outline of the | ||||
|         abstracted form of each layer. | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,72 @@ | |||
| // base symbols shared
 | ||||
| 
 | ||||
| #if defined(BASE_IMPLEMENTOR) | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| int x = 0; | ||||
| 
 | ||||
| void | ||||
| base_func(void){ | ||||
|   printf("x = %d\n", x); | ||||
|   x += 1; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| // dynamic function linkage protocol
 | ||||
| 
 | ||||
| #if defined(BASE_IMPLEMENTOR) | ||||
| 
 | ||||
| EXPORT_SYMBOL BASE_Funcs* | ||||
| base_export_functions(void){ | ||||
|   static BASE_Funcs funcs = {0}; | ||||
|   if (funcs.base_func == 0){ | ||||
| #define X(N,R,P) funcs.N = N; | ||||
| #include "base.xlist.h" | ||||
| #undef X | ||||
|   } | ||||
|   return(&funcs); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| #if !defined(BASE_IMPLEMENTOR) | ||||
| 
 | ||||
| #if OS_WINDOWS | ||||
| # include <Windows.h> | ||||
| #elif OS_LINUX | ||||
| # include <dlfcn.h> | ||||
| #endif | ||||
| 
 | ||||
| BEFORE_MAIN(base_dynamic_user_init){ | ||||
|   BASE_Funcs *funcs = 0; | ||||
|    | ||||
| #if OS_WINDOWS | ||||
|   HMODULE module = LoadLibraryA("base.dll"); | ||||
|   if (module != 0){ | ||||
|     BASE_ExportFuncs *base_export_functions = (BASE_ExportFuncs*)GetProcAddress(module, "base_export_functions"); | ||||
|     if (base_export_functions != 0){ | ||||
|       funcs = base_export_functions(); | ||||
|     } | ||||
|   } | ||||
| #elif OS_LINUX | ||||
|   void *module = dlopen("./base.so", RTLD_NOW); | ||||
|   if (module != 0){ | ||||
|     BASE_ExportFuncs *base_export_functions = (BASE_ExportFuncs*)dlsym(module, "base_export_functions"); | ||||
|     if (base_export_functions != 0){ | ||||
|       funcs = base_export_functions(); | ||||
|     } | ||||
|   } | ||||
| #else | ||||
| # error base_import_functions not completed for this OS | ||||
| #endif | ||||
|    | ||||
| #define X(N,R,P) N = funcs->N; | ||||
| #include "base.xlist.h" | ||||
| #undef X | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,79 @@ | |||
| // baby context cracking
 | ||||
| 
 | ||||
| #if defined(_WIN32) | ||||
| # define OS_WINDOWS 1 | ||||
| #elif defined(__gnu_linux__) | ||||
| # define OS_LINUX 1 | ||||
| #else | ||||
| # error this configuration of compiler & OS is not supported | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(OS_WINDOWS) | ||||
| # define OS_WINDOWS 0 | ||||
| #endif | ||||
| #if !defined(OS_LINUX) | ||||
| # define OS_LINUX 0 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| // linkage keyword abstraction
 | ||||
| 
 | ||||
| #if OS_WINDOWS | ||||
| # define EXPORT_SYMBOL __declspec(dllexport) | ||||
| #elif OS_LINUX | ||||
| # define EXPORT_SYMBOL __attribute__ ((visibility ("default"))) | ||||
| #else | ||||
| # error keyword abstractions missing for this OS | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| #if OS_WINDOWS | ||||
| 
 | ||||
| # pragma section(".CRT$XCU", read) | ||||
| 
 | ||||
| # define BEFORE_MAIN(n) extern void n(void);                   \ | ||||
| __declspec(allocate(".CRT$XCU")) void (*n##__)(void) = n;     \ | ||||
| __pragma(comment(linker, "/include:" #n)) extern void n(void) | ||||
| 
 | ||||
| #elif OS_LINUX | ||||
| 
 | ||||
| # define BEFORE_MAIN(n) \ | ||||
| __attribute__((constructor)) static void n(void) | ||||
| 
 | ||||
| #else | ||||
| # error BEFORE_MAIN missing for this OS | ||||
| #endif | ||||
| 
 | ||||
| // base layer types
 | ||||
| 
 | ||||
| typedef void BASE_Library; | ||||
| 
 | ||||
| 
 | ||||
| // base symbols shared
 | ||||
| 
 | ||||
| #if defined(BASE_IMPLEMENTOR) | ||||
| 
 | ||||
| void base_func(void); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| // dynamic function linkage protocol
 | ||||
| 
 | ||||
| typedef struct BASE_Funcs{ | ||||
| #define X(N,R,P) R (*N) P; | ||||
| #include "base.xlist.h" | ||||
| #undef X | ||||
| } BASE_Funcs; | ||||
| 
 | ||||
| typedef BASE_Funcs* BASE_ExportFuncs(void); | ||||
| 
 | ||||
| #if defined(BASE_IMPLEMENTOR) | ||||
| EXPORT_SYMBOL BASE_Funcs* base_export_functions(void); | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(BASE_IMPLEMENTOR) | ||||
| #define X(N,R,P) R (*N) P = 0; | ||||
| #include "base.xlist.h" | ||||
| #undef X | ||||
| #endif | ||||
|  | @ -0,0 +1,3 @@ | |||
| #define BASE_IMPLEMENTOR 1 | ||||
| #include "base.h" | ||||
| #include "base.c" | ||||
|  | @ -0,0 +1 @@ | |||
| X(base_func, void, (void)) | ||||
|  | @ -0,0 +1,17 @@ | |||
| @echo off | ||||
| 
 | ||||
| REM: Path setup | ||||
| 
 | ||||
| SET src=%cd% | ||||
| cd .. | ||||
| if not exist "build\" mkdir build | ||||
| cd build | ||||
| 
 | ||||
| REM: Build the base layer | ||||
| cl /nologo /Zi /LD %src%\base.target.c /Febase.dll | ||||
| 
 | ||||
| REM: Build the main layer | ||||
| cl /nologo /Zi %src%\main.c | ||||
| 
 | ||||
| REM: Build the plugin layer | ||||
| cl /nologo /Zi /LD %src%\plugin.c /Feplugin.dll | ||||
|  | @ -0,0 +1,16 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| # Path setup | ||||
| src=$PWD | ||||
| cd .. | ||||
| mkdir -p build | ||||
| cd build | ||||
| 
 | ||||
| # Build the base layer as base.so | ||||
| gcc -fvisibility=hidden -fPIC -shared $src/base.target.c -o base.so | ||||
| 
 | ||||
| # Build the main layer | ||||
| gcc -fvisibility=hidden $src/main.c -o main | ||||
| 
 | ||||
| # Build the plugin layer | ||||
| gcc -fvisibility=hidden -fPIC -shared $src/plugin.c -o plugin.so | ||||
|  | @ -0,0 +1,38 @@ | |||
| #include "base.h" | ||||
| 
 | ||||
| #include "base.c" | ||||
| 
 | ||||
| 
 | ||||
| // setup plugin_func as a function pointer so that it can be linked at run time
 | ||||
| typedef void PLUGIN_Func(void); | ||||
| PLUGIN_Func *plugin_func = 0; | ||||
| 
 | ||||
| 
 | ||||
| int main(){ | ||||
|   // base layer initialization is automatic and runs before main - base functions begin working right away
 | ||||
|   base_func(); | ||||
|    | ||||
|    | ||||
|   // to call a function with run-time linking, we must manually load and link it
 | ||||
| #if OS_WINDOWS | ||||
|   HMODULE module = LoadLibraryA("plugin.dll"); | ||||
|   if (module != 0){ | ||||
|     plugin_func = (PLUGIN_Func*)GetProcAddress(module, "plugin_func"); | ||||
|   } | ||||
| #elif OS_LINUX | ||||
|   void *module = dlopen("./plugin.so", RTLD_NOW); | ||||
|   if (module != 0){ | ||||
|     plugin_func = (PLUGIN_Func*)dlsym(module, "plugin_func"); | ||||
|   } | ||||
| #endif | ||||
|    | ||||
|    | ||||
|   // calls to plugin_func only work after the "plugin" loaded successfully
 | ||||
|   if (plugin_func != 0){ | ||||
|     plugin_func(); | ||||
|   } | ||||
|    | ||||
|    | ||||
|   // demonstration: the data structures contained in the 'base' are not duplicated in each binary
 | ||||
|   base_func(); | ||||
| } | ||||
|  | @ -0,0 +1,15 @@ | |||
| #include "base.h" | ||||
| 
 | ||||
| #include "base.c" | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| EXPORT_SYMBOL void | ||||
| plugin_func(void){ | ||||
|   printf("provided by plugin: {\n"); | ||||
|   printf(" "); | ||||
|   base_func(); | ||||
|   printf(" "); | ||||
|   base_func(); | ||||
|   printf("}\n"); | ||||
| } | ||||
| 
 | ||||
		Loading…
	
		Reference in New Issue