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