1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | // |
5 | // ZapHeaders.cpp |
6 | // |
7 | |
8 | // |
9 | // Zapping of headers (IMAGE_COR20_HEADER, CORCOMPILE_HEADER, etc.) |
10 | // |
11 | // ====================================================================================== |
12 | |
13 | #include "common.h" |
14 | |
15 | #include "zapheaders.h" |
16 | |
17 | #include "zapcode.h" |
18 | #include "zaprelocs.h" |
19 | #include "zapmetadata.h" |
20 | #include "zapimport.h" |
21 | |
22 | // |
23 | // IMAGE_COR20_HEADER |
24 | // |
25 | |
26 | void ZapImage::() |
27 | { |
28 | IMAGE_COR20_HEADER ; |
29 | |
30 | ZeroMemory(&corHeader, sizeof(corHeader)); |
31 | |
32 | corHeader.cb = VAL32(sizeof(IMAGE_COR20_HEADER)); |
33 | corHeader.MajorRuntimeVersion = VAL16(COR_VERSION_MAJOR); |
34 | corHeader.MinorRuntimeVersion = VAL16(COR_VERSION_MINOR); |
35 | corHeader.Flags = VAL32(COMIMAGE_FLAGS_IL_LIBRARY); |
36 | |
37 | #ifdef _TARGET_X86_ |
38 | if (IsReadyToRunCompilation()) |
39 | { |
40 | // Mark the ready-to-run image as x86-specific |
41 | corHeader.Flags |= VAL32(COMIMAGE_FLAGS_32BITREQUIRED); |
42 | } |
43 | #endif |
44 | |
45 | if (m_ModuleDecoder.HasManagedEntryPoint()) |
46 | corHeader.EntryPointToken = VAL32(m_ModuleDecoder.GetEntryPointToken()); |
47 | |
48 | SetDirectoryData(&corHeader.ManagedNativeHeader, m_pNativeHeader); |
49 | SetDirectoryData(&corHeader.Resources, m_pResources); |
50 | SetDirectoryData(&corHeader.MetaData, m_pILMetaData); |
51 | |
52 | Write(&corHeader, sizeof(corHeader)); |
53 | } |
54 | |
55 | // |
56 | // CORCOMPILE_HEADER |
57 | // |
58 | void ZapImage::() |
59 | { |
60 | CORCOMPILE_HEADER ; |
61 | |
62 | ZeroMemory(&nativeHeader, sizeof(nativeHeader)); |
63 | |
64 | nativeHeader.Signature = CORCOMPILE_SIGNATURE; |
65 | nativeHeader.MajorVersion = CORCOMPILE_MAJOR_VERSION; |
66 | nativeHeader.MinorVersion = CORCOMPILE_MINOR_VERSION; |
67 | |
68 | // |
69 | // Fill in data in native image header |
70 | // |
71 | |
72 | nativeHeader.ImageBase = (TADDR) GetNativeBaseAddress(); |
73 | |
74 | if (m_ModuleDecoder.HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_SECURITY)) |
75 | nativeHeader.Flags |= CORCOMPILE_HEADER_HAS_SECURITY_DIRECTORY; |
76 | |
77 | nativeHeader.COR20Flags = m_ModuleDecoder.GetCorHeader()->Flags; |
78 | |
79 | #ifdef CROSSGEN_COMPILE |
80 | if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_CrossGenAssumeInputSigned)) |
81 | { |
82 | // Bug fix #814972 |
83 | // In buildlabs NI images are produced before binaries are strongname signed or authenticode signed. |
84 | // which results in crossgen'ed NI different on the user box vs. the one from build lab. |
85 | // Setting source IL authenticode signed and strong name bit for crossgen'ed images should make both the images identical. |
86 | nativeHeader.Flags |= CORCOMPILE_HEADER_HAS_SECURITY_DIRECTORY; |
87 | |
88 | if (m_ModuleDecoder.GetCorHeader()->StrongNameSignature.Size != 0) |
89 | nativeHeader.COR20Flags |= COMIMAGE_FLAGS_STRONGNAMESIGNED; |
90 | } |
91 | #endif |
92 | |
93 | if (m_ModuleDecoder.HasReadyToRunHeader()) |
94 | { |
95 | // Pretend that ready-to-run images are IL-only |
96 | nativeHeader.COR20Flags |= COMIMAGE_FLAGS_ILONLY; |
97 | |
98 | // Pretend that ready-to-run images do not have a native header |
99 | nativeHeader.COR20Flags &= ~COMIMAGE_FLAGS_IL_LIBRARY; |
100 | |
101 | // Remember whether the source IL image had ReadyToRun header |
102 | nativeHeader.Flags |= CORCOMPILE_HEADER_IS_READY_TO_RUN; |
103 | } |
104 | |
105 | if (m_fHaveProfileData) |
106 | nativeHeader.Flags |= CORCOMPILE_HEADER_IS_IBC_OPTIMIZED; |
107 | |
108 | DWORD dwPEKind, dwMachine; |
109 | m_ModuleDecoder.GetPEKindAndMachine(&dwPEKind, &dwMachine); |
110 | nativeHeader.PEKind = dwPEKind; |
111 | nativeHeader.Machine = (WORD)dwMachine; |
112 | |
113 | nativeHeader.Characteristics = m_ModuleDecoder.GetCharacteristics(); |
114 | |
115 | |
116 | SetDirectoryData(&nativeHeader.EEInfoTable, m_pEEInfoTable); |
117 | SetDirectoryData(&nativeHeader.HelperTable, m_pHelperTableSection); |
118 | SetDirectoryData(&nativeHeader.ImportSections, m_pImportSectionsTable); |
119 | SetDirectoryData(&nativeHeader.StubsData, m_pStubsSection); |
120 | SetDirectoryData(&nativeHeader.VersionInfo, m_pVersionInfo); |
121 | SetDirectoryData(&nativeHeader.Dependencies, m_pDependencies); |
122 | SetDirectoryData(&nativeHeader.DebugMap, m_pDebugInfoTable); |
123 | SetDirectoryData(&nativeHeader.VirtualSectionsTable, m_pVirtualSectionsTable); |
124 | SetDirectoryData(&nativeHeader.ModuleImage, m_pPreloadSections[CORCOMPILE_SECTION_MODULE]); |
125 | SetDirectoryData(&nativeHeader.CodeManagerTable, m_pCodeManagerEntry); |
126 | SetDirectoryData(&nativeHeader.ProfileDataList, m_pInstrumentSection); |
127 | SetDirectoryData(&nativeHeader.ManifestMetaData, m_pAssemblyMetaData); |
128 | |
129 | Write(&nativeHeader, sizeof(nativeHeader)); |
130 | } |
131 | |
132 | // |
133 | // CORCOMPILE_CODE_MANAGER_ENTRY |
134 | // |
135 | void ZapImage::SaveCodeManagerEntry() |
136 | { |
137 | CORCOMPILE_CODE_MANAGER_ENTRY codeManagerEntry; |
138 | |
139 | ZeroMemory(&codeManagerEntry, sizeof(codeManagerEntry)); |
140 | |
141 | SetDirectoryData(&codeManagerEntry.HotCode, m_pHotCodeSection); |
142 | SetDirectoryData(&codeManagerEntry.Code, m_pCodeSection); |
143 | SetDirectoryData(&codeManagerEntry.ColdCode, m_pColdCodeSection); |
144 | |
145 | SetDirectoryData(&codeManagerEntry.ROData, m_pReadOnlyDataSection); |
146 | |
147 | // |
148 | //Initialize additional sections for diagnostics |
149 | // |
150 | |
151 | codeManagerEntry.HotIBCMethodOffset = (m_iIBCMethod < m_iUntrainedMethod && m_iIBCMethod < m_MethodCompilationOrder.GetCount()) ? |
152 | (m_MethodCompilationOrder[m_iIBCMethod]->GetCode()->GetRVA() - m_pHotCodeSection->GetRVA()) : m_pHotCodeSection->GetSize(); |
153 | |
154 | codeManagerEntry.HotGenericsMethodOffset = (m_iGenericsMethod < m_iUntrainedMethod && m_iGenericsMethod < m_MethodCompilationOrder.GetCount()) ? |
155 | (m_MethodCompilationOrder[m_iGenericsMethod]->GetCode()->GetRVA() - m_pHotCodeSection->GetRVA()) : m_pHotCodeSection->GetSize(); |
156 | |
157 | COUNT_T i; |
158 | for (i = m_iUntrainedMethod; i < m_MethodCompilationOrder.GetCount(); i++) |
159 | { |
160 | ZapNode * pColdCode = m_MethodCompilationOrder[i]->GetColdCode(); |
161 | if (pColdCode != NULL) |
162 | { |
163 | codeManagerEntry.ColdUntrainedMethodOffset = pColdCode->GetRVA() - m_pColdCodeSection->GetRVA(); |
164 | break; |
165 | } |
166 | } |
167 | if (i == m_MethodCompilationOrder.GetCount()) |
168 | codeManagerEntry.ColdUntrainedMethodOffset = m_pColdCodeSection->GetSize(); |
169 | |
170 | |
171 | if (m_stats) |
172 | { |
173 | #define ACCUM_SIZE(dest, src) if( src != NULL ) dest+= src->GetSize() |
174 | // this is probably supposed to mean Hot+Unprofiled |
175 | ACCUM_SIZE(m_stats->m_totalHotCodeSize, m_pHotCodeSection); |
176 | ACCUM_SIZE(m_stats->m_totalUnprofiledCodeSize, m_pCodeSection); |
177 | ACCUM_SIZE(m_stats->m_totalColdCodeSize, m_pColdCodeSection); |
178 | ACCUM_SIZE(m_stats->m_totalCodeSizeInProfiledMethods, m_pHotCodeSection); |
179 | #undef ACCUM_SIZE |
180 | m_stats->m_totalColdCodeSizeInProfiledMethods = codeManagerEntry.ColdUntrainedMethodOffset; |
181 | } |
182 | |
183 | Write(&codeManagerEntry, sizeof(codeManagerEntry)); |
184 | } |
185 | |
186 | // |
187 | // Version Resource |
188 | // |
189 | |
190 | // Needed for RT_VERSION. |
191 | #define MAKEINTRESOURCE(v) MAKEINTRESOURCEW(v) |
192 | |
193 | void ZapVersionResource::Save(ZapWriter * pZapWriter) |
194 | { |
195 | // Resources are binary-sorted tree structure. Since we are saving just one resource |
196 | // the binary structure is degenerated link list. By convention, Windows uses three levels |
197 | // for resources: Type, Name, Language. |
198 | |
199 | // See vctools\link\doc\pecoff.doc for detailed documentation of PE format. |
200 | |
201 | VersionResourceHeader ; |
202 | |
203 | ZeroMemory(&header, sizeof(header)); |
204 | |
205 | header.TypeDir.NumberOfIdEntries = 1; |
206 | header.TypeEntry.Id = (USHORT)((ULONG_PTR)RT_VERSION); |
207 | header.TypeEntry.OffsetToDirectory = offsetof(VersionResourceHeader, NameDir); |
208 | header.TypeEntry.DataIsDirectory = 1; |
209 | |
210 | header.NameDir.NumberOfIdEntries = 1; |
211 | header.NameEntry.Id = 1; |
212 | header.NameEntry.OffsetToDirectory = offsetof(VersionResourceHeader, LangDir); |
213 | header.NameEntry.DataIsDirectory = 1; |
214 | |
215 | header.LangDir.NumberOfIdEntries = 1; |
216 | header.LangEntry.OffsetToDirectory = offsetof(VersionResourceHeader, DataEntry); |
217 | |
218 | header.DataEntry.OffsetToData = m_pVersionData->GetRVA(); |
219 | header.DataEntry.Size = m_pVersionData->GetSize(); |
220 | |
221 | pZapWriter->Write(&header, sizeof(header)); |
222 | } |
223 | |
224 | void ZapImage::CopyWin32VersionResource() |
225 | { |
226 | #ifndef FEATURE_PAL |
227 | // Copy the version resource over so it is easy to see in the dumps where the ngened module came from |
228 | COUNT_T cbResourceData; |
229 | PVOID pResourceData = m_ModuleDecoder.GetWin32Resource(MAKEINTRESOURCE(1), RT_VERSION, &cbResourceData); |
230 | |
231 | if (!pResourceData || !cbResourceData) |
232 | return; |
233 | |
234 | ZapBlob * pVersionData = new (GetHeap()) ZapBlobPtr(pResourceData, cbResourceData); |
235 | |
236 | ZapVersionResource * pVersionResource = new (GetHeap()) ZapVersionResource(pVersionData); |
237 | |
238 | m_pWin32ResourceSection->Place(pVersionResource); |
239 | m_pWin32ResourceSection->Place(pVersionData); |
240 | |
241 | SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE, m_pWin32ResourceSection); |
242 | #endif |
243 | } |
244 | #undef MAKEINTRESOURCE |
245 | |
246 | |
247 | // |
248 | // Debug Directory |
249 | // |
250 | |
251 | void ZapDebugDirectory::SaveOriginalDebugDirectoryEntry(ZapWriter *pZapWriter) |
252 | { |
253 | if (m_ppDebugData != nullptr) |
254 | { |
255 | for (DWORD i = 0; i < m_nDebugDirectory; i++) |
256 | { |
257 | if (m_ppDebugData[i] != nullptr) |
258 | { |
259 | m_pDebugDirectory[i].SizeOfData = m_ppDebugData[i]->GetSize(); |
260 | m_pDebugDirectory[i].AddressOfRawData = m_ppDebugData[i]->GetRVA(); |
261 | |
262 | // Compute the absolute file (seek) pointer. We need to reach to the matching physical section to do that. |
263 | ZapPhysicalSection * pPhysicalSection = ZapImage::GetImage(pZapWriter)->m_pTextSection; |
264 | |
265 | DWORD dwOffset = m_ppDebugData[i]->GetRVA() - pPhysicalSection->GetRVA(); |
266 | _ASSERTE(dwOffset < pPhysicalSection->GetSize()); |
267 | |
268 | m_pDebugDirectory[i].PointerToRawData = pPhysicalSection->GetFilePos() + dwOffset; |
269 | } |
270 | else |
271 | { |
272 | m_pDebugDirectory[i].SizeOfData = 0; |
273 | m_pDebugDirectory[i].AddressOfRawData = 0; |
274 | m_pDebugDirectory[i].PointerToRawData = 0; |
275 | } |
276 | } |
277 | |
278 | pZapWriter->Write(m_pDebugDirectory, sizeof(IMAGE_DEBUG_DIRECTORY) * m_nDebugDirectory); |
279 | } |
280 | } |
281 | |
282 | void ZapDebugDirectory::SaveNGenDebugDirectoryEntry(ZapWriter *pZapWriter) |
283 | { |
284 | #if !defined(NO_NGENPDB) |
285 | _ASSERTE(pZapWriter); |
286 | |
287 | IMAGE_DEBUG_DIRECTORY debugDirectory = {0}; |
288 | if (m_nDebugDirectory > 0) |
289 | { |
290 | memcpy(&debugDirectory, m_pDebugDirectory, sizeof(IMAGE_DEBUG_DIRECTORY)); |
291 | } |
292 | debugDirectory.Type = IMAGE_DEBUG_TYPE_CODEVIEW; |
293 | debugDirectory.SizeOfData = m_pNGenPdbDebugData->GetSize(); |
294 | debugDirectory.AddressOfRawData = m_pNGenPdbDebugData->GetRVA(); |
295 | // Make sure the "is portable pdb" indicator (MinorVersion == 0x504d) is clear |
296 | // for the NGen debug directory entry since this debug directory is copied |
297 | // from an existing entry which could be a portable pdb. |
298 | debugDirectory.MinorVersion = 0; |
299 | { |
300 | ZapPhysicalSection *pPhysicalSection = ZapImage::GetImage(pZapWriter)->m_pTextSection; |
301 | DWORD dwOffset = m_pNGenPdbDebugData->GetRVA() - pPhysicalSection->GetRVA(); |
302 | _ASSERTE(dwOffset < pPhysicalSection->GetSize()); |
303 | debugDirectory.PointerToRawData = pPhysicalSection->GetFilePos() + dwOffset; |
304 | } |
305 | pZapWriter->Write(&debugDirectory, sizeof(debugDirectory)); |
306 | #endif // NO_NGENPDB |
307 | } |
308 | |
309 | void ZapDebugDirectory::Save(ZapWriter * pZapWriter) |
310 | { |
311 | _ASSERTE(pZapWriter); |
312 | |
313 | if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_NGenEnableCreatePdb)) { |
314 | SaveOriginalDebugDirectoryEntry(pZapWriter); |
315 | SaveNGenDebugDirectoryEntry(pZapWriter); |
316 | } else { |
317 | SaveNGenDebugDirectoryEntry(pZapWriter); |
318 | SaveOriginalDebugDirectoryEntry(pZapWriter); |
319 | } |
320 | } |
321 | |
322 | ZapPEExports::ZapPEExports(LPCWSTR dllPath) |
323 | { |
324 | m_dllFileName = wcsrchr(dllPath, DIRECTORY_SEPARATOR_CHAR_W); |
325 | if (m_dllFileName != NULL) |
326 | m_dllFileName++; |
327 | else |
328 | m_dllFileName = dllPath; |
329 | } |
330 | |
331 | DWORD ZapPEExports::GetSize() |
332 | { |
333 | return DWORD(sizeof(IMAGE_EXPORT_DIRECTORY) + wcslen(m_dllFileName) * sizeof(BYTE) + 1); |
334 | } |
335 | |
336 | void ZapPEExports::Save(ZapWriter * pZapWriter) |
337 | { |
338 | _ASSERTE(pZapWriter); |
339 | |
340 | IMAGE_EXPORT_DIRECTORY exports; |
341 | ZeroMemory(&exports, sizeof(exports)); |
342 | |
343 | exports.Name = pZapWriter->GetCurrentRVA() + sizeof(exports); |
344 | |
345 | // Write out exports header |
346 | pZapWriter->Write(&exports, sizeof(exports)); |
347 | |
348 | // Write out string that exports.Name points at. |
349 | for (LPCWSTR ptr = m_dllFileName; ; ptr++) |
350 | { |
351 | pZapWriter->Write((PVOID) ptr, 1); |
352 | if (*ptr == 0) |
353 | break; |
354 | } |
355 | } |
356 | |
357 | // If the IL image has IMAGE_DIRECTORY_ENTRY_DEBUG with information about the PDB, |
358 | // copy that information over to the ngen image. |
359 | // This lets the debugger find out information about the PDB without loading |
360 | // the IL image. |
361 | // Note that we support using ngen images (from the GAC) without |
362 | // loading the ngen image. So not only is this a perf optimization for the debugger |
363 | // scenario, but it is also needed for dump-debugging where loading the IL |
364 | // is not an option. |
365 | |
366 | void ZapImage::CopyDebugDirEntry() |
367 | { |
368 | // Insert an NGEN PDB debug directory entry *before* the IL PDB debug directory entry |
369 | // (if one exists), so that we don't break tools that look for an IL PDB. |
370 | { |
371 | // This entry is initially empty. It is filled in ZapImage::GenerateFile. |
372 | RSDS rsds = {0}; |
373 | m_pNGenPdbDebugData = ZapBlob::NewBlob(static_cast<ZapWriter *>(this), &rsds, sizeof rsds); |
374 | } |
375 | |
376 | // IL PDB entry: copy of the (first of possibly many) IMAGE_DEBUG_DIRECTORY entry |
377 | // in the IL image |
378 | DWORD nDebugEntry = 0; |
379 | PIMAGE_DEBUG_DIRECTORY pDebugDir = NULL; |
380 | ZapNode **ppDebugData = NULL; |
381 | |
382 | if (m_ModuleDecoder.HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG)) { |
383 | COUNT_T debugEntrySize; |
384 | TADDR pDebugEntry = m_ModuleDecoder.GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_DEBUG, &debugEntrySize); |
385 | |
386 | if (debugEntrySize != 0) { |
387 | |
388 | if (debugEntrySize < sizeof(IMAGE_DEBUG_DIRECTORY) || 0 != (debugEntrySize % sizeof(IMAGE_DEBUG_DIRECTORY))) { |
389 | m_zapper->Warning(W("IMAGE_DIRECTORY_ENTRY_DEBUG size (%d) should be a multiple of %d\n" ), |
390 | debugEntrySize, sizeof(IMAGE_DEBUG_DIRECTORY)); |
391 | } else { |
392 | |
393 | // Since pDebugEntry is an array of IMAGE_DEBUG_DIRECTORYs, debugEntrySize |
394 | // should be a multiple of sizeof(IMAGE_DEBUG_DIRECTORY). |
395 | _ASSERTE(0 == (debugEntrySize % sizeof(IMAGE_DEBUG_DIRECTORY))); |
396 | |
397 | nDebugEntry = DWORD(debugEntrySize / sizeof(IMAGE_DEBUG_DIRECTORY)); |
398 | pDebugDir = new (GetHeap()) IMAGE_DEBUG_DIRECTORY[nDebugEntry]; |
399 | memcpy(pDebugDir, (const void *)pDebugEntry, sizeof(IMAGE_DEBUG_DIRECTORY) * nDebugEntry); |
400 | ppDebugData = new (GetHeap()) ZapNode*[nDebugEntry]; |
401 | memset(ppDebugData, 0, nDebugEntry * sizeof(ZapNode*)); |
402 | |
403 | for (DWORD i = 0; i < nDebugEntry; i++) |
404 | { |
405 | // Some compilers set PointerToRawData but not AddressOfRawData as they put the |
406 | // data at the end of the file in an unmapped part of the file |
407 | |
408 | RVA rvaOfRawData = (pDebugDir[i].AddressOfRawData != NULL) |
409 | ? pDebugDir[i].AddressOfRawData : m_ModuleDecoder.OffsetToRva(pDebugDir[i].PointerToRawData); |
410 | |
411 | ULONG cbDebugData = pDebugDir[i].SizeOfData; |
412 | |
413 | if (cbDebugData != 0) { |
414 | if (!m_ModuleDecoder.CheckRva(rvaOfRawData, cbDebugData)) |
415 | m_zapper->Warning(W("IMAGE_DIRECTORY_ENTRY_DEBUG points to bad data\n" )); |
416 | else |
417 | ppDebugData[i] = new (GetHeap()) ZapBlobPtr((PVOID)m_ModuleDecoder.GetRvaData(rvaOfRawData), cbDebugData); |
418 | } |
419 | } |
420 | } |
421 | } |
422 | } |
423 | |
424 | ZapDebugDirectory * pDebugDirectory = new (GetHeap()) ZapDebugDirectory(m_pNGenPdbDebugData, |
425 | nDebugEntry, |
426 | pDebugDir, |
427 | ppDebugData); |
428 | |
429 | m_pDebugSection->Place(pDebugDirectory); |
430 | m_pDebugSection->Place(m_pNGenPdbDebugData); |
431 | if (ppDebugData) |
432 | { |
433 | for (DWORD i = 0; i < nDebugEntry; i++) |
434 | { |
435 | if (ppDebugData[i] != nullptr) |
436 | m_pDebugSection->Place(ppDebugData[i]); |
437 | } |
438 | } |
439 | |
440 | SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG, pDebugDirectory); |
441 | } |
442 | |
443 | DWORD ZapVirtualSectionsTable::GetSize() |
444 | { |
445 | DWORD nSectionInfos = 0; |
446 | |
447 | COUNT_T nPhysicalSections = m_pImage->GetPhysicalSectionCount(); |
448 | for (COUNT_T iPhysicalSection = 0; iPhysicalSection < nPhysicalSections; iPhysicalSection++) |
449 | { |
450 | ZapPhysicalSection * pPhysicalSection = m_pImage->GetPhysicalSection(iPhysicalSection); |
451 | |
452 | DWORD dwPreviousType = 0; |
453 | |
454 | COUNT_T nVirtualSections = pPhysicalSection->GetVirtualSectionCount(); |
455 | for (COUNT_T iVirtualSection = 0; iVirtualSection < nVirtualSections; iVirtualSection++) |
456 | { |
457 | ZapVirtualSection * pVirtualSection = pPhysicalSection->GetVirtualSection(iVirtualSection); |
458 | |
459 | if (pVirtualSection->GetNodeCount() == 0) |
460 | continue; |
461 | |
462 | DWORD dwSectionType = pVirtualSection->GetSectionType(); |
463 | if (dwSectionType == 0) |
464 | continue; |
465 | |
466 | // Fold sections with the same type together |
467 | if (dwPreviousType != dwSectionType) |
468 | { |
469 | dwPreviousType = dwSectionType; |
470 | nSectionInfos++; |
471 | } |
472 | } |
473 | } |
474 | |
475 | return nSectionInfos * sizeof(CORCOMPILE_VIRTUAL_SECTION_INFO); |
476 | } |
477 | |
478 | void ZapVirtualSectionsTable::Save(ZapWriter * pZapWriter) |
479 | { |
480 | COUNT_T nPhysicalSections = m_pImage->GetPhysicalSectionCount(); |
481 | for (COUNT_T iPhysicalSection = 0; iPhysicalSection < nPhysicalSections; iPhysicalSection++) |
482 | { |
483 | ZapPhysicalSection * pPhysicalSection = m_pImage->GetPhysicalSection(iPhysicalSection); |
484 | |
485 | CORCOMPILE_VIRTUAL_SECTION_INFO sectionInfo; |
486 | |
487 | sectionInfo.SectionType = 0; |
488 | |
489 | COUNT_T nVirtualSections = pPhysicalSection->GetVirtualSectionCount(); |
490 | for (COUNT_T iVirtualSection = 0; iVirtualSection < nVirtualSections; iVirtualSection++) |
491 | { |
492 | ZapVirtualSection * pVirtualSection = pPhysicalSection->GetVirtualSection(iVirtualSection); |
493 | |
494 | if (pVirtualSection->GetNodeCount() == 0) |
495 | continue; |
496 | |
497 | DWORD dwSectionType = pVirtualSection->GetSectionType(); |
498 | if (dwSectionType == 0) |
499 | continue; |
500 | |
501 | // Fold sections with the same type together |
502 | if (sectionInfo.SectionType != dwSectionType) |
503 | { |
504 | if (sectionInfo.SectionType != 0) |
505 | { |
506 | pZapWriter->Write(§ionInfo, sizeof(sectionInfo)); |
507 | } |
508 | |
509 | sectionInfo.SectionType = dwSectionType; |
510 | sectionInfo.VirtualAddress = pVirtualSection->GetRVA(); |
511 | } |
512 | |
513 | // Update section size |
514 | sectionInfo.Size = (pVirtualSection->GetRVA() + pVirtualSection->GetSize()) - sectionInfo.VirtualAddress; |
515 | } |
516 | |
517 | if (sectionInfo.SectionType != 0) |
518 | { |
519 | pZapWriter->Write(§ionInfo, sizeof(sectionInfo)); |
520 | } |
521 | } |
522 | } |
523 | |