]> git.ipfire.org Git - thirdparty/gcc.git/blame - libphobos/libdruntime/rt/sections_win64.d
libphobos: Merge phobos and druntime with upstream.
[thirdparty/gcc.git] / libphobos / libdruntime / rt / sections_win64.d
CommitLineData
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
13module rt.sections_win64;
14
15version (CRuntime_Microsoft):
16
17// debug = PRINTF;
18debug(PRINTF) import core.stdc.stdio;
19import core.stdc.stdlib : malloc, free;
20import rt.deh, rt.minfo;
21
22struct 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)
22163f0d 45 @property immutable(FuncTable)[] ehTables() const nothrow @nogc
03385ed3 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
57private:
58 ModuleGroup _moduleGroup;
59 void[][] _gcRanges;
60}
61
62shared(bool) conservative;
63
64void 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
105void finiSections() nothrow @nogc
106{
107 .free(cast(void*)_sections.modules.ptr);
108 .free(_sections._gcRanges.ptr);
109}
110
111void[] 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
154void finiTLSRanges(void[] rng) nothrow @nogc
155{
156}
157
158void 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
180private:
181__gshared SectionGroup _sections;
182
183extern(C)
184{
185 extern __gshared void* _minfo_beg;
186 extern __gshared void* _minfo_end;
187}
188
189immutable(ModuleInfo*)[] getModuleInfos() nothrow @nogc
190out (result)
191{
192 foreach (m; result)
193 assert(m !is null);
194}
195body
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
221extern(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
245enum IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ
246
247struct 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
254struct 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
265struct IMAGE_NT_HEADERS
266{
267 uint Signature;
268 IMAGE_FILE_HEADER FileHeader;
269 // optional header follows
270}
271
272struct 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
289bool 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
296void[] 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}