1 /** 2 * Written in the D programming language. 3 * This module provides Win32-specific support for sections. 4 * 5 * Copyright: Copyright Digital Mars 2008 - 2012. 6 * License: Distributed under the 7 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 8 * (See accompanying file LICENSE) 9 * Authors: Walter Bright, Sean Kelly, Martin Nowak 10 * Source: $(DRUNTIMESRC rt/_sections_win32.d) 11 */ 12 13 module rt.sections_win32; 14 15 version (CRuntime_DigitalMars): 16 17 // debug = PRINTF; 18 debug(PRINTF) import core.stdc.stdio; 19 import rt.minfo; 20 import core.stdc.stdlib : malloc, free; 21 import core.sys.windows.winbase : FreeLibrary, GetProcAddress, LoadLibraryA, LoadLibraryW; 22 import core.sys.windows.winnt : WCHAR; 23 24 struct SectionGroup 25 { 26 static int opApply(scope int delegate(ref SectionGroup) dg) 27 { 28 return dg(_sections); 29 } 30 31 static int opApplyReverse(scope int delegate(ref SectionGroup) dg) 32 { 33 return dg(_sections); 34 } 35 36 @property immutable(ModuleInfo*)[] modules() const nothrow @nogc 37 { 38 return _moduleGroup.modules; 39 } 40 41 @property ref inout(ModuleGroup) moduleGroup() inout return nothrow @nogc 42 { 43 return _moduleGroup; 44 } 45 46 @property inout(void[])[] gcRanges() inout nothrow @nogc 47 { 48 return _gcRanges[]; 49 } 50 51 private: 52 ModuleGroup _moduleGroup; 53 void[][] _gcRanges; 54 } 55 56 shared(bool) conservative; 57 58 /**** 59 * Gets called on program startup just before GC is initialized. 60 */ 61 void initSections() nothrow @nogc 62 { 63 _sections._moduleGroup = ModuleGroup(getModuleInfos()); 64 65 import rt.sections; 66 conservative = !scanDataSegPrecisely(); 67 68 if (conservative) 69 { 70 _sections._gcRanges = (cast(void[]*) malloc(2 * (void[]).sizeof))[0..2]; 71 72 auto databeg = cast(void*)&_xi_a; 73 auto dataend = cast(void*)_moduleinfo_array.ptr; 74 _sections._gcRanges[0] = databeg[0 .. dataend - databeg]; 75 76 // skip module info and CONST segment 77 auto bssbeg = cast(void*)&_edata; 78 auto bssend = cast(void*)&_end; 79 _sections._gcRanges[1] = bssbeg[0 .. bssend - bssbeg]; 80 } 81 else 82 { 83 size_t count = &_DPend - &_DPbegin; 84 auto ranges = cast(void[]*) malloc(count * (void[]).sizeof); 85 size_t r = 0; 86 void* prev = null; 87 for (size_t i = 0; i < count; i++) 88 { 89 void* addr = (&_DPbegin)[i]; 90 if (prev + (void*).sizeof == addr) 91 ranges[r-1] = ranges[r-1].ptr[0 .. ranges[r-1].length + (void*).sizeof]; 92 else 93 ranges[r++] = (cast(void**)addr)[0..1]; 94 prev = addr; 95 } 96 _sections._gcRanges = ranges[0..r]; 97 } 98 } 99 100 /*** 101 * Gets called on program shutdown just after GC is terminated. 102 */ 103 void finiSections() nothrow @nogc 104 { 105 free(_sections._gcRanges.ptr); 106 } 107 108 /*** 109 * Called once per thread; returns array of thread local storage ranges 110 */ 111 void[] initTLSRanges() nothrow @nogc 112 { 113 auto pbeg = cast(void*)&_tlsstart; 114 auto pend = cast(void*)&_tlsend; 115 return pbeg[0 .. pend - pbeg]; 116 } 117 118 void finiTLSRanges(void[] rng) nothrow @nogc 119 { 120 } 121 122 void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow 123 { 124 if (conservative) 125 { 126 dg(rng.ptr, rng.ptr + rng.length); 127 } 128 else 129 { 130 for (auto p = &_TPbegin; p < &_TPend; ) 131 { 132 uint beg = *p++; 133 uint end = beg + cast(uint)((void*).sizeof); 134 while (p < &_TPend && *p == end) 135 { 136 end += (void*).sizeof; 137 p++; 138 } 139 dg(rng.ptr + beg, rng.ptr + end); 140 } 141 } 142 } 143 144 private: 145 146 /////////////////////////////////////////////////////////////////////////////// 147 // Compiler to runtime interface. 148 /////////////////////////////////////////////////////////////////////////////// 149 150 __gshared SectionGroup _sections; 151 152 // Windows: this gets initialized by minit.asm 153 extern(C) __gshared immutable(ModuleInfo*)[] _moduleinfo_array; 154 extern(C) void _minit() nothrow @nogc; 155 156 immutable(ModuleInfo*)[] getModuleInfos() nothrow @nogc 157 out (result) 158 { 159 foreach (m; result) 160 assert(m !is null); 161 } 162 do 163 { 164 // _minit directly alters the global _moduleinfo_array 165 _minit(); 166 return _moduleinfo_array; 167 } 168 169 extern(C) 170 { 171 extern __gshared 172 { 173 int _xi_a; // &_xi_a just happens to be start of data segment 174 int _edata; // &_edata is start of BSS segment 175 int _end; // &_end is past end of BSS 176 177 void* _DPbegin; // first entry in the array of pointers addresses 178 void* _DPend; // &_DPend points after last entry of array 179 uint _TPbegin; // first entry in the array of TLS offsets of pointers 180 uint _TPend; // &_DPend points after last entry of array 181 } 182 183 extern 184 { 185 int _tlsstart; 186 int _tlsend; 187 } 188 } 189 190 /////////////////////////////////////////////////////////////////////////////// 191 // dynamic loading 192 /////////////////////////////////////////////////////////////////////////////// 193 194 /*********************************** 195 * These are a temporary means of providing a GC hook for DLL use. They may be 196 * replaced with some other similar functionality later. 197 */ 198 extern (C) 199 { 200 void* gc_getProxy(); 201 void gc_setProxy(void* p); 202 void gc_clrProxy(); 203 204 alias void function(void*) gcSetFn; 205 alias void function() gcClrFn; 206 } 207 208 /******************************************* 209 * Loads a DLL written in D with the name 'name'. 210 * Returns: 211 * opaque handle to the DLL if successfully loaded 212 * null if failure 213 */ 214 extern (C) void* rt_loadLibrary(const char* name) 215 { 216 return initLibrary(.LoadLibraryA(name)); 217 } 218 219 extern (C) void* rt_loadLibraryW(const WCHAR* name) 220 { 221 return initLibrary(.LoadLibraryW(name)); 222 } 223 224 void* initLibrary(void* mod) 225 { 226 // BUG: LoadLibrary() call calls rt_init(), which fails if proxy is not set! 227 // (What? LoadLibrary() is a Windows API call, it shouldn't call rt_init().) 228 if (mod is null) 229 return mod; 230 gcSetFn gcSet = cast(gcSetFn) GetProcAddress(mod, "gc_setProxy"); 231 if (gcSet !is null) 232 { // BUG: Set proxy, but too late 233 gcSet(gc_getProxy()); 234 } 235 return mod; 236 } 237 238 /************************************* 239 * Unloads DLL that was previously loaded by rt_loadLibrary(). 240 * Input: 241 * ptr the handle returned by rt_loadLibrary() 242 * Returns: 243 * 1 succeeded 244 * 0 some failure happened 245 */ 246 extern (C) int rt_unloadLibrary(void* ptr) 247 { 248 gcClrFn gcClr = cast(gcClrFn) GetProcAddress(ptr, "gc_clrProxy"); 249 if (gcClr !is null) 250 gcClr(); 251 return FreeLibrary(ptr) != 0; 252 }