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 }