1 module elfhook.library; 2 3 import core.sys.posix.unistd; 4 import core.sys.posix.dlfcn; 5 6 import core.stdc.errno; 7 import core.stdc..string; 8 9 import std.exception; 10 import std..string : toStringz; 11 12 version(Posix): 13 14 immutable int RTLD_LOCAL = 0; 15 immutable int RTLD_LAZY = 1; 16 immutable int RTLD_NOW = 2; 17 immutable int RTLD_GLOBAL = 3; 18 19 /** 20 This is a wrapper of UNIX-specified dynamic loading. 21 See `man 3 dlopen`. 22 */ 23 struct SharedLibrary 24 { 25 void* handle; 26 27 this(in string filename, int flags) 28 { 29 handle = dlopen(filename.toStringz, flags); 30 if (handle is null) 31 { 32 const errorMsg = dlerror(); 33 if (errorMsg !is null) 34 errnoEnforce(false, cast(string) errorMsg[0 .. strlen(errorMsg)]); 35 errnoEnforce(false, "failed to dlopen(3) by unknown reason."); 36 } 37 } 38 39 40 ~this() 41 { 42 if (handle !is null) 43 close(); 44 } 45 46 47 void close() 48 { 49 const ret = dlclose(handle); 50 if (ret != 0) 51 { 52 const errorMsg = dlerror(); 53 if (errorMsg !is null) 54 errnoEnforce(false, cast(string) errorMsg[0 .. strlen(errorMsg)]); 55 errnoEnforce(false, "failed to dlclose(3) by unknown reason."); 56 } 57 } 58 59 60 auto get(in string symbolName) 61 { 62 const symbol = dlsym(handle, symbolName.toStringz); 63 if (symbol is null) 64 { 65 const errorMsg = dlerror(); 66 if (errorMsg !is null) 67 errnoEnforce(false, cast(string) errorMsg[0 .. strlen(errorMsg)]); 68 errnoEnforce(false, "failed to dlsym(3) by unknown reason."); 69 } 70 return symbol; 71 } 72 73 // utility for getting the adress of library loaded. 74 void* getLoadedAddr() 75 { 76 return cast(void*) *cast(const size_t*) handle; 77 } 78 } 79 80 81 unittest 82 { 83 string libm; 84 85 version(linux) 86 { 87 // Using libm.so gots invalid ELF Header. 88 libm = "libm-2.24.so"; 89 } 90 else version(OSX) 91 { 92 libm = "libm.dylib"; 93 } 94 else static assert(false, "Not support your platform."); 95 96 { 97 auto lib = new SharedLibrary(libm, RTLD_NOW); 98 auto ceil = cast(double function(double)) lib.get("ceil"); 99 assert(ceil(0.45) == 1); 100 } 101 102 { 103 auto lib = new SharedLibrary(libm, RTLD_NOW); 104 auto addr = lib.getLoadedAddr(); 105 assert(addr !is null); 106 } 107 }