]>
Commit | Line | Data |
---|---|---|
03385ed3 | 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 src/rt/_sections_win64.d) | |
11 | */ | |
12 | ||
13 | module rt.sections_win64; | |
14 | ||
15 | version (CRuntime_Microsoft): | |
16 | ||
17 | // debug = PRINTF; | |
18 | debug(PRINTF) import core.stdc.stdio; | |
19 | import core.stdc.stdlib : malloc, free; | |
20 | import rt.deh, rt.minfo; | |
21 | ||
22 | struct SectionGroup | |
23 | { | |
24 | static int opApply(scope int delegate(ref SectionGroup) dg) | |
25 | { | |
26 | return dg(_sections); | |
27 | } | |
28 | ||
29 | static int opApplyReverse(scope int delegate(ref SectionGroup) dg) | |
30 | { | |
31 | return dg(_sections); | |
32 | } | |
33 | ||
34 | @property immutable(ModuleInfo*)[] modules() const nothrow @nogc | |
35 | { | |
36 | return _moduleGroup.modules; | |
37 | } | |
38 | ||
39 | @property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc | |
40 | { | |
41 | return _moduleGroup; | |
42 | } | |
43 | ||
44 | version (Win64) | |
45 | @property immutable(FuncTable)[] ehTables() const | |
46 | { | |
47 | auto pbeg = cast(immutable(FuncTable)*)&_deh_beg; | |
48 | auto pend = cast(immutable(FuncTable)*)&_deh_end; | |
49 | return pbeg[0 .. pend - pbeg]; | |
50 | } | |
51 | ||
52 | @property inout(void[])[] gcRanges() inout nothrow @nogc | |
53 | { | |
54 | return _gcRanges[]; | |
55 | } | |
56 | ||
57 | private: | |
58 | ModuleGroup _moduleGroup; | |
59 | void[][] _gcRanges; | |
60 | } | |
61 | ||
62 | shared(bool) conservative; | |
63 | ||
64 | void initSections() nothrow @nogc | |
65 | { | |
66 | _sections._moduleGroup = ModuleGroup(getModuleInfos()); | |
67 | ||
68 | // the ".data" image section includes both object file sections ".data" and ".bss" | |
69 | void[] dataSection = findImageSection(".data"); | |
70 | debug(PRINTF) printf("found .data section: [%p,+%llx]\n", dataSection.ptr, | |
71 | cast(ulong)dataSection.length); | |
72 | ||
73 | import rt.sections; | |
74 | conservative = !scanDataSegPrecisely(); | |
75 | ||
76 | if (conservative) | |
77 | { | |
78 | _sections._gcRanges = (cast(void[]*) malloc((void[]).sizeof))[0..1]; | |
79 | _sections._gcRanges[0] = dataSection; | |
80 | } | |
81 | else | |
82 | { | |
83 | size_t count = &_DP_end - &_DP_beg; | |
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 | auto off = (&_DP_beg)[i]; | |
90 | if (off == 0) // skip zero entries added by incremental linking | |
91 | continue; // assumes there is no D-pointer at the very beginning of .data | |
92 | void* addr = dataSection.ptr + off; | |
93 | debug(PRINTF) printf(" scan %p\n", addr); | |
94 | // combine consecutive pointers into single range | |
95 | if (prev + (void*).sizeof == addr) | |
96 | ranges[r-1] = ranges[r-1].ptr[0 .. ranges[r-1].length + (void*).sizeof]; | |
97 | else | |
98 | ranges[r++] = (cast(void**)addr)[0..1]; | |
99 | prev = addr; | |
100 | } | |
101 | _sections._gcRanges = ranges[0..r]; | |
102 | } | |
103 | } | |
104 | ||
105 | void finiSections() nothrow @nogc | |
106 | { | |
107 | .free(cast(void*)_sections.modules.ptr); | |
108 | .free(_sections._gcRanges.ptr); | |
109 | } | |
110 | ||
111 | void[] initTLSRanges() nothrow @nogc | |
112 | { | |
113 | void* pbeg; | |
114 | void* pend; | |
115 | // with VS2017 15.3.1, the linker no longer puts TLS segments into a | |
116 | // separate image section. That way _tls_start and _tls_end no | |
117 | // longer generate offsets into .tls, but DATA. | |
118 | // Use the TEB entry to find the start of TLS instead and read the | |
119 | // length from the TLS directory | |
120 | version (D_InlineAsm_X86) | |
121 | { | |
122 | asm @nogc nothrow | |
123 | { | |
124 | mov EAX, _tls_index; | |
125 | mov ECX, FS:[0x2C]; // _tls_array | |
126 | mov EAX, [ECX+4*EAX]; | |
127 | mov pbeg, EAX; | |
128 | add EAX, [_tls_used+4]; // end | |
129 | sub EAX, [_tls_used+0]; // start | |
130 | mov pend, EAX; | |
131 | } | |
132 | } | |
133 | else version (D_InlineAsm_X86_64) | |
134 | { | |
135 | asm @nogc nothrow | |
136 | { | |
137 | xor RAX, RAX; | |
138 | mov EAX, _tls_index; | |
139 | mov RCX, 0x58; | |
140 | mov RCX, GS:[RCX]; // _tls_array (immediate value causes fixup) | |
141 | mov RAX, [RCX+8*RAX]; | |
142 | mov pbeg, RAX; | |
143 | add RAX, [_tls_used+8]; // end | |
144 | sub RAX, [_tls_used+0]; // start | |
145 | mov pend, RAX; | |
146 | } | |
147 | } | |
148 | else | |
149 | static assert(false, "Architecture not supported."); | |
150 | ||
151 | return pbeg[0 .. pend - pbeg]; | |
152 | } | |
153 | ||
154 | void finiTLSRanges(void[] rng) nothrow @nogc | |
155 | { | |
156 | } | |
157 | ||
158 | void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow | |
159 | { | |
160 | if (conservative) | |
161 | { | |
162 | dg(rng.ptr, rng.ptr + rng.length); | |
163 | } | |
164 | else | |
165 | { | |
166 | for (auto p = &_TP_beg; p < &_TP_end; ) | |
167 | { | |
168 | uint beg = *p++; | |
169 | uint end = beg + cast(uint)((void*).sizeof); | |
170 | while (p < &_TP_end && *p == end) | |
171 | { | |
172 | end += (void*).sizeof; | |
173 | p++; | |
174 | } | |
175 | dg(rng.ptr + beg, rng.ptr + end); | |
176 | } | |
177 | } | |
178 | } | |
179 | ||
180 | private: | |
181 | __gshared SectionGroup _sections; | |
182 | ||
183 | extern(C) | |
184 | { | |
185 | extern __gshared void* _minfo_beg; | |
186 | extern __gshared void* _minfo_end; | |
187 | } | |
188 | ||
189 | immutable(ModuleInfo*)[] getModuleInfos() nothrow @nogc | |
190 | out (result) | |
191 | { | |
192 | foreach (m; result) | |
193 | assert(m !is null); | |
194 | } | |
195 | body | |
196 | { | |
197 | auto m = (cast(immutable(ModuleInfo*)*)&_minfo_beg)[1 .. &_minfo_end - &_minfo_beg]; | |
198 | /* Because of alignment inserted by the linker, various null pointers | |
199 | * are there. We need to filter them out. | |
200 | */ | |
201 | auto p = m.ptr; | |
202 | auto pend = m.ptr + m.length; | |
203 | ||
204 | // count non-null pointers | |
205 | size_t cnt; | |
206 | for (; p < pend; ++p) | |
207 | { | |
208 | if (*p !is null) ++cnt; | |
209 | } | |
210 | ||
211 | auto result = (cast(immutable(ModuleInfo)**).malloc(cnt * size_t.sizeof))[0 .. cnt]; | |
212 | ||
213 | p = m.ptr; | |
214 | cnt = 0; | |
215 | for (; p < pend; ++p) | |
216 | if (*p !is null) result[cnt++] = *p; | |
217 | ||
218 | return cast(immutable)result; | |
219 | } | |
220 | ||
221 | extern(C) | |
222 | { | |
223 | /* Symbols created by the compiler/linker and inserted into the | |
224 | * object file that 'bracket' sections. | |
225 | */ | |
226 | extern __gshared | |
227 | { | |
228 | void* __ImageBase; | |
229 | ||
230 | void* _deh_beg; | |
231 | void* _deh_end; | |
232 | ||
233 | uint _DP_beg; | |
234 | uint _DP_end; | |
235 | uint _TP_beg; | |
236 | uint _TP_end; | |
237 | ||
238 | void*[2] _tls_used; // start, end | |
239 | int _tls_index; | |
240 | } | |
241 | } | |
242 | ||
243 | ///////////////////////////////////////////////////////////////////// | |
244 | ||
245 | enum IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ | |
246 | ||
247 | struct IMAGE_DOS_HEADER // DOS .EXE header | |
248 | { | |
249 | ushort e_magic; // Magic number | |
250 | ushort[29] e_res2; // Reserved ushorts | |
251 | int e_lfanew; // File address of new exe header | |
252 | } | |
253 | ||
254 | struct IMAGE_FILE_HEADER | |
255 | { | |
256 | ushort Machine; | |
257 | ushort NumberOfSections; | |
258 | uint TimeDateStamp; | |
259 | uint PointerToSymbolTable; | |
260 | uint NumberOfSymbols; | |
261 | ushort SizeOfOptionalHeader; | |
262 | ushort Characteristics; | |
263 | } | |
264 | ||
265 | struct IMAGE_NT_HEADERS | |
266 | { | |
267 | uint Signature; | |
268 | IMAGE_FILE_HEADER FileHeader; | |
269 | // optional header follows | |
270 | } | |
271 | ||
272 | struct IMAGE_SECTION_HEADER | |
273 | { | |
274 | char[8] Name; | |
275 | union { | |
276 | uint PhysicalAddress; | |
277 | uint VirtualSize; | |
278 | } | |
279 | uint VirtualAddress; | |
280 | uint SizeOfRawData; | |
281 | uint PointerToRawData; | |
282 | uint PointerToRelocations; | |
283 | uint PointerToLinenumbers; | |
284 | ushort NumberOfRelocations; | |
285 | ushort NumberOfLinenumbers; | |
286 | uint Characteristics; | |
287 | } | |
288 | ||
289 | bool compareSectionName(ref IMAGE_SECTION_HEADER section, string name) nothrow @nogc | |
290 | { | |
291 | if (name[] != section.Name[0 .. name.length]) | |
292 | return false; | |
293 | return name.length == 8 || section.Name[name.length] == 0; | |
294 | } | |
295 | ||
296 | void[] findImageSection(string name) nothrow @nogc | |
297 | { | |
298 | if (name.length > 8) // section name from string table not supported | |
299 | return null; | |
300 | IMAGE_DOS_HEADER* doshdr = cast(IMAGE_DOS_HEADER*) &__ImageBase; | |
301 | if (doshdr.e_magic != IMAGE_DOS_SIGNATURE) | |
302 | return null; | |
303 | ||
304 | auto nthdr = cast(IMAGE_NT_HEADERS*)(cast(void*)doshdr + doshdr.e_lfanew); | |
305 | auto sections = cast(IMAGE_SECTION_HEADER*)(cast(void*)nthdr + IMAGE_NT_HEADERS.sizeof + nthdr.FileHeader.SizeOfOptionalHeader); | |
306 | for (ushort i = 0; i < nthdr.FileHeader.NumberOfSections; i++) | |
307 | if (compareSectionName (sections[i], name)) | |
308 | return (cast(void*)&__ImageBase + sections[i].VirtualAddress)[0 .. sections[i].VirtualSize]; | |
309 | ||
310 | return null; | |
311 | } |