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
26void ZapImage::SaveCorHeader()
27{
28 IMAGE_COR20_HEADER corHeader;
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//
58void ZapImage::SaveNativeHeader()
59{
60 CORCOMPILE_HEADER nativeHeader;
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//
135void 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
193void 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 header;
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
224void 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
251void 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
282void 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
309void 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
322ZapPEExports::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
331DWORD ZapPEExports::GetSize()
332{
333 return DWORD(sizeof(IMAGE_EXPORT_DIRECTORY) + wcslen(m_dllFileName) * sizeof(BYTE) + 1);
334}
335
336void 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
366void 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
443DWORD 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
478void 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(&sectionInfo, 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(&sectionInfo, sizeof(sectionInfo));
520 }
521 }
522}
523