1# 2# 3# Nim's Runtime Library 4# (c) Copyright 2012 Andreas Rumpf 5# 6# See the file "copying.txt", included in this 7# distribution, for details about the copyright. 8# 9 10# This file implements the ability to call native procs from libraries. 11# It is not possible to do this in a platform independent way, unfortunately. 12# However, the interface has been designed to take platform differences into 13# account and been ported to all major platforms. 14 15{.push stack_trace: off.} 16 17const 18 NilLibHandle: LibHandle = nil 19 20proc nimLoadLibraryError(path: string) = 21 # carefully written to avoid memory allocation: 22 const prefix = "could not load: " 23 cstderr.rawWrite(prefix) 24 cstderr.rawWrite(path) 25 when not defined(nimDebugDlOpen) and not defined(windows): 26 cstderr.rawWrite("\n(compile with -d:nimDebugDlOpen for more information)") 27 when defined(windows): 28 const badExe = "\n(bad format; library may be wrong architecture)" 29 let loadError = GetLastError() 30 if loadError == ERROR_BAD_EXE_FORMAT: 31 cstderr.rawWrite(badExe) 32 when defined(guiapp): 33 # Because console output is not shown in GUI apps, display the error as a 34 # message box instead: 35 var 36 msg: array[1000, char] 37 msgLeft = msg.len - 1 # leave (at least) one for nullchar 38 msgIdx = 0 39 copyMem(msg[msgIdx].addr, prefix.cstring, prefix.len) 40 msgLeft -= prefix.len 41 msgIdx += prefix.len 42 let pathLen = min(path.len, msgLeft) 43 copyMem(msg[msgIdx].addr, path.cstring, pathLen) 44 msgLeft -= pathLen 45 msgIdx += pathLen 46 if loadError == ERROR_BAD_EXE_FORMAT and msgLeft >= badExe.len: 47 copyMem(msg[msgIdx].addr, badExe.cstring, badExe.len) 48 discard MessageBoxA(nil, msg[0].addr, nil, 0) 49 cstderr.rawWrite("\n") 50 quit(1) 51 52proc procAddrError(name: cstring) {.compilerproc, nonReloadable, hcrInline.} = 53 # carefully written to avoid memory allocation: 54 cstderr.rawWrite("could not import: ") 55 cstderr.rawWrite(name) 56 cstderr.rawWrite("\n") 57 quit(1) 58 59# this code was inspired from Lua's source code: 60# Lua - An Extensible Extension Language 61# Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil 62# http://www.lua.org 63# mailto:info@lua.org 64 65when defined(posix): 66 # 67 # ========================================================================= 68 # This is an implementation based on the dlfcn interface. 69 # The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, 70 # NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least 71 # as an emulation layer on top of native functions. 72 # ========================================================================= 73 # 74 75 # c stuff: 76 when defined(linux) or defined(macosx): 77 const RTLD_NOW = cint(2) 78 else: 79 var 80 RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: cint 81 82 proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".} 83 proc dlopen(path: cstring, mode: cint): LibHandle {. 84 importc, header: "<dlfcn.h>".} 85 proc dlsym(lib: LibHandle, name: cstring): ProcAddr {. 86 importc, header: "<dlfcn.h>".} 87 88 proc dlerror(): cstring {.importc, header: "<dlfcn.h>".} 89 90 proc nimUnloadLibrary(lib: LibHandle) = 91 dlclose(lib) 92 93 proc nimLoadLibrary(path: string): LibHandle = 94 let flags = 95 when defined(globalSymbols): RTLD_NOW or RTLD_GLOBAL 96 else: RTLD_NOW 97 result = dlopen(path, flags) 98 when defined(nimDebugDlOpen): 99 let error = dlerror() 100 if error != nil: 101 cstderr.rawWrite(error) 102 cstderr.rawWrite("\n") 103 104 proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = 105 result = dlsym(lib, name) 106 if result == nil: procAddrError(name) 107 108elif defined(windows) or defined(dos): 109 # 110 # ======================================================================= 111 # Native Windows Implementation 112 # ======================================================================= 113 # 114 when defined(cpp): 115 type 116 THINSTANCE {.importc: "HINSTANCE".} = object 117 x: pointer 118 proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {. 119 importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.} 120 else: 121 type 122 THINSTANCE {.importc: "HINSTANCE".} = pointer 123 proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {. 124 importc: "GetProcAddress", header: "<windows.h>", stdcall.} 125 126 proc freeLibrary(lib: THINSTANCE) {. 127 importc: "FreeLibrary", header: "<windows.h>", stdcall.} 128 proc winLoadLibrary(path: cstring): THINSTANCE {. 129 importc: "LoadLibraryA", header: "<windows.h>", stdcall.} 130 131 proc nimUnloadLibrary(lib: LibHandle) = 132 freeLibrary(cast[THINSTANCE](lib)) 133 134 proc nimLoadLibrary(path: string): LibHandle = 135 result = cast[LibHandle](winLoadLibrary(path)) 136 137 proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = 138 result = getProcAddress(cast[THINSTANCE](lib), name) 139 if result != nil: return 140 const decoratedLength = 250 141 var decorated: array[decoratedLength, char] 142 decorated[0] = '_' 143 var m = 1 144 while m < (decoratedLength - 5): 145 if name[m - 1] == '\x00': break 146 decorated[m] = name[m - 1] 147 inc(m) 148 decorated[m] = '@' 149 for i in countup(0, 50): 150 var k = i * 4 151 if k div 100 == 0: 152 if k div 10 == 0: 153 m = m + 1 154 else: 155 m = m + 2 156 else: 157 m = m + 3 158 decorated[m + 1] = '\x00' 159 while true: 160 decorated[m] = chr(ord('0') + (k %% 10)) 161 dec(m) 162 k = k div 10 163 if k == 0: break 164 result = getProcAddress(cast[THINSTANCE](lib), addr decorated) 165 if result != nil: return 166 procAddrError(name) 167 168elif defined(genode): 169 170 proc nimUnloadLibrary(lib: LibHandle) = 171 raiseAssert("nimUnloadLibrary not implemented") 172 173 proc nimLoadLibrary(path: string): LibHandle = 174 raiseAssert("nimLoadLibrary not implemented") 175 176 proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = 177 raiseAssert("nimGetProcAddr not implemented") 178 179elif defined(nintendoswitch) or defined(freertos): 180 proc nimUnloadLibrary(lib: LibHandle) = 181 cstderr.rawWrite("nimUnLoadLibrary not implemented") 182 cstderr.rawWrite("\n") 183 quit(1) 184 185 proc nimLoadLibrary(path: string): LibHandle = 186 cstderr.rawWrite("nimLoadLibrary not implemented") 187 cstderr.rawWrite("\n") 188 quit(1) 189 190 191 proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = 192 cstderr.rawWrite("nimGetProAddr not implemented") 193 cstderr.rawWrite(name) 194 cstderr.rawWrite("\n") 195 quit(1) 196 197else: 198 {.error: "no implementation for dyncalls".} 199 200{.pop.} 201