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.
9 // Zapping of headers (IMAGE_COR20_HEADER, CORCOMPILE_HEADER, etc.)
11 // ======================================================================================
15 #include "zapheaders.h"
18 #include "zaprelocs.h"
19 #include "zapmetadata.h"
20 #include "zapimport.h"
26 void ZapImage::SaveCorHeader()
28 IMAGE_COR20_HEADER corHeader;
30 ZeroMemory(&corHeader, sizeof(corHeader));
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);
38 if (IsReadyToRunCompilation())
40 // Mark the ready-to-run image as x86-specific
41 corHeader.Flags |= VAL32(COMIMAGE_FLAGS_32BITREQUIRED);
45 if (m_ModuleDecoder.HasManagedEntryPoint())
46 corHeader.EntryPointToken = VAL32(m_ModuleDecoder.GetEntryPointToken());
48 SetDirectoryData(&corHeader.ManagedNativeHeader, m_pNativeHeader);
49 SetDirectoryData(&corHeader.Resources, m_pResources);
50 SetDirectoryData(&corHeader.MetaData, m_pILMetaData);
52 Write(&corHeader, sizeof(corHeader));
58 void ZapImage::SaveNativeHeader()
60 CORCOMPILE_HEADER nativeHeader;
62 ZeroMemory(&nativeHeader, sizeof(nativeHeader));
64 nativeHeader.Signature = CORCOMPILE_SIGNATURE;
65 nativeHeader.MajorVersion = CORCOMPILE_MAJOR_VERSION;
66 nativeHeader.MinorVersion = CORCOMPILE_MINOR_VERSION;
69 // Fill in data in native image header
72 nativeHeader.ImageBase = (TADDR) GetNativeBaseAddress();
74 if (m_ModuleDecoder.HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_SECURITY))
75 nativeHeader.Flags |= CORCOMPILE_HEADER_HAS_SECURITY_DIRECTORY;
77 nativeHeader.COR20Flags = m_ModuleDecoder.GetCorHeader()->Flags;
79 #ifdef CROSSGEN_COMPILE
80 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_CrossGenAssumeInputSigned))
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;
88 if (m_ModuleDecoder.GetCorHeader()->StrongNameSignature.Size != 0)
89 nativeHeader.COR20Flags |= COMIMAGE_FLAGS_STRONGNAMESIGNED;
93 if (m_ModuleDecoder.HasReadyToRunHeader())
95 // Pretend that ready-to-run images are IL-only
96 nativeHeader.COR20Flags |= COMIMAGE_FLAGS_ILONLY;
98 // Pretend that ready-to-run images do not have a native header
99 nativeHeader.COR20Flags &= ~COMIMAGE_FLAGS_IL_LIBRARY;
101 // Remember whether the source IL image had ReadyToRun header
102 nativeHeader.Flags |= CORCOMPILE_HEADER_IS_READY_TO_RUN;
105 if (m_fHaveProfileData)
106 nativeHeader.Flags |= CORCOMPILE_HEADER_IS_IBC_OPTIMIZED;
108 DWORD dwPEKind, dwMachine;
109 m_ModuleDecoder.GetPEKindAndMachine(&dwPEKind, &dwMachine);
110 nativeHeader.PEKind = dwPEKind;
111 nativeHeader.Machine = (WORD)dwMachine;
113 nativeHeader.Characteristics = m_ModuleDecoder.GetCharacteristics();
116 SetDirectoryData(&nativeHeader.EEInfoTable, m_pEEInfoTable);
117 SetDirectoryData(&nativeHeader.HelperTable, m_pHelperTableSection);
118 SetDirectoryData(&nativeHeader.ImportSections, m_pImportSectionsTable);
119 SetDirectoryData(&nativeHeader.ImportTable, m_pImportTable);
120 SetDirectoryData(&nativeHeader.StubsData, m_pStubsSection);
121 SetDirectoryData(&nativeHeader.VersionInfo, m_pVersionInfo);
122 SetDirectoryData(&nativeHeader.Dependencies, m_pDependencies);
123 SetDirectoryData(&nativeHeader.DebugMap, m_pDebugInfoTable);
124 SetDirectoryData(&nativeHeader.VirtualSectionsTable, m_pVirtualSectionsTable);
125 SetDirectoryData(&nativeHeader.ModuleImage, m_pPreloadSections[CORCOMPILE_SECTION_MODULE]);
126 SetDirectoryData(&nativeHeader.CodeManagerTable, m_pCodeManagerEntry);
127 SetDirectoryData(&nativeHeader.ProfileDataList, m_pInstrumentSection);
128 SetDirectoryData(&nativeHeader.ManifestMetaData, m_pAssemblyMetaData);
130 Write(&nativeHeader, sizeof(nativeHeader));
134 // CORCOMPILE_CODE_MANAGER_ENTRY
136 void ZapImage::SaveCodeManagerEntry()
138 CORCOMPILE_CODE_MANAGER_ENTRY codeManagerEntry;
140 ZeroMemory(&codeManagerEntry, sizeof(codeManagerEntry));
142 SetDirectoryData(&codeManagerEntry.HotCode, m_pHotCodeSection);
143 SetDirectoryData(&codeManagerEntry.Code, m_pCodeSection);
144 SetDirectoryData(&codeManagerEntry.ColdCode, m_pColdCodeSection);
146 SetDirectoryData(&codeManagerEntry.ROData, m_pReadOnlyDataSection);
149 //Initialize additional sections for diagnostics
152 codeManagerEntry.HotIBCMethodOffset = (m_iIBCMethod < m_iUntrainedMethod && m_iIBCMethod < m_MethodCompilationOrder.GetCount()) ?
153 (m_MethodCompilationOrder[m_iIBCMethod]->GetCode()->GetRVA() - m_pHotCodeSection->GetRVA()) : m_pHotCodeSection->GetSize();
155 codeManagerEntry.HotGenericsMethodOffset = (m_iGenericsMethod < m_iUntrainedMethod && m_iGenericsMethod < m_MethodCompilationOrder.GetCount()) ?
156 (m_MethodCompilationOrder[m_iGenericsMethod]->GetCode()->GetRVA() - m_pHotCodeSection->GetRVA()) : m_pHotCodeSection->GetSize();
159 for (i = m_iUntrainedMethod; i < m_MethodCompilationOrder.GetCount(); i++)
161 ZapNode * pColdCode = m_MethodCompilationOrder[i]->GetColdCode();
162 if (pColdCode != NULL)
164 codeManagerEntry.ColdUntrainedMethodOffset = pColdCode->GetRVA() - m_pColdCodeSection->GetRVA();
168 if (i == m_MethodCompilationOrder.GetCount())
169 codeManagerEntry.ColdUntrainedMethodOffset = m_pColdCodeSection->GetSize();
174 #define ACCUM_SIZE(dest, src) if( src != NULL ) dest+= src->GetSize()
175 // this is probably supposed to mean Hot+Unprofiled
176 ACCUM_SIZE(m_stats->m_totalHotCodeSize, m_pHotCodeSection);
177 ACCUM_SIZE(m_stats->m_totalUnprofiledCodeSize, m_pCodeSection);
178 ACCUM_SIZE(m_stats->m_totalColdCodeSize, m_pColdCodeSection);
179 ACCUM_SIZE(m_stats->m_totalCodeSizeInProfiledMethods, m_pHotCodeSection);
181 m_stats->m_totalColdCodeSizeInProfiledMethods = codeManagerEntry.ColdUntrainedMethodOffset;
184 Write(&codeManagerEntry, sizeof(codeManagerEntry));
191 // Needed for RT_VERSION.
192 #define MAKEINTRESOURCE(v) MAKEINTRESOURCEW(v)
194 void ZapVersionResource::Save(ZapWriter * pZapWriter)
196 // Resources are binary-sorted tree structure. Since we are saving just one resource
197 // the binary structure is degenerated link list. By convention, Windows uses three levels
198 // for resources: Type, Name, Language.
200 // See vctools\link\doc\pecoff.doc for detailed documentation of PE format.
202 VersionResourceHeader header;
204 ZeroMemory(&header, sizeof(header));
206 header.TypeDir.NumberOfIdEntries = 1;
207 header.TypeEntry.Id = (USHORT)((ULONG_PTR)RT_VERSION);
208 header.TypeEntry.OffsetToDirectory = offsetof(VersionResourceHeader, NameDir);
209 header.TypeEntry.DataIsDirectory = 1;
211 header.NameDir.NumberOfIdEntries = 1;
212 header.NameEntry.Id = 1;
213 header.NameEntry.OffsetToDirectory = offsetof(VersionResourceHeader, LangDir);
214 header.NameEntry.DataIsDirectory = 1;
216 header.LangDir.NumberOfIdEntries = 1;
217 header.LangEntry.OffsetToDirectory = offsetof(VersionResourceHeader, DataEntry);
219 header.DataEntry.OffsetToData = m_pVersionData->GetRVA();
220 header.DataEntry.Size = m_pVersionData->GetSize();
222 pZapWriter->Write(&header, sizeof(header));
225 void ZapImage::CopyWin32VersionResource()
228 // Copy the version resource over so it is easy to see in the dumps where the ngened module came from
229 COUNT_T cbResourceData;
230 PVOID pResourceData = m_ModuleDecoder.GetWin32Resource(MAKEINTRESOURCE(1), RT_VERSION, &cbResourceData);
232 if (!pResourceData || !cbResourceData)
235 ZapBlob * pVersionData = new (GetHeap()) ZapBlobPtr(pResourceData, cbResourceData);
237 ZapVersionResource * pVersionResource = new (GetHeap()) ZapVersionResource(pVersionData);
239 m_pWin32ResourceSection->Place(pVersionResource);
240 m_pWin32ResourceSection->Place(pVersionData);
242 SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE, m_pWin32ResourceSection);
245 #undef MAKEINTRESOURCE
252 void ZapDebugDirectory::SaveOriginalDebugDirectoryEntry(ZapWriter *pZapWriter)
254 if (m_ppDebugData != nullptr)
256 for (DWORD i = 0; i < m_nDebugDirectory; i++)
258 if (m_ppDebugData[i] != nullptr)
260 m_pDebugDirectory[i].SizeOfData = m_ppDebugData[i]->GetSize();
261 m_pDebugDirectory[i].AddressOfRawData = m_ppDebugData[i]->GetRVA();
263 // Compute the absolute file (seek) pointer. We need to reach to the matching physical section to do that.
264 ZapPhysicalSection * pPhysicalSection = ZapImage::GetImage(pZapWriter)->m_pTextSection;
266 DWORD dwOffset = m_ppDebugData[i]->GetRVA() - pPhysicalSection->GetRVA();
267 _ASSERTE(dwOffset < pPhysicalSection->GetSize());
269 m_pDebugDirectory[i].PointerToRawData = pPhysicalSection->GetFilePos() + dwOffset;
273 m_pDebugDirectory[i].SizeOfData = 0;
274 m_pDebugDirectory[i].AddressOfRawData = 0;
275 m_pDebugDirectory[i].PointerToRawData = 0;
279 pZapWriter->Write(m_pDebugDirectory, sizeof(IMAGE_DEBUG_DIRECTORY) * m_nDebugDirectory);
283 void ZapDebugDirectory::SaveNGenDebugDirectoryEntry(ZapWriter *pZapWriter)
285 #if !defined(NO_NGENPDB)
286 _ASSERTE(pZapWriter);
288 IMAGE_DEBUG_DIRECTORY debugDirectory = {0};
289 if (m_nDebugDirectory > 0)
291 memcpy(&debugDirectory, m_pDebugDirectory, sizeof(IMAGE_DEBUG_DIRECTORY));
293 debugDirectory.Type = IMAGE_DEBUG_TYPE_CODEVIEW;
294 debugDirectory.SizeOfData = m_pNGenPdbDebugData->GetSize();
295 debugDirectory.AddressOfRawData = m_pNGenPdbDebugData->GetRVA();
296 // Make sure the "is portable pdb" indicator (MinorVersion == 0x504d) is clear
297 // for the NGen debug directory entry since this debug directory is copied
298 // from an existing entry which could be a portable pdb.
299 debugDirectory.MinorVersion = 0;
301 ZapPhysicalSection *pPhysicalSection = ZapImage::GetImage(pZapWriter)->m_pTextSection;
302 DWORD dwOffset = m_pNGenPdbDebugData->GetRVA() - pPhysicalSection->GetRVA();
303 _ASSERTE(dwOffset < pPhysicalSection->GetSize());
304 debugDirectory.PointerToRawData = pPhysicalSection->GetFilePos() + dwOffset;
306 pZapWriter->Write(&debugDirectory, sizeof(debugDirectory));
310 void ZapDebugDirectory::Save(ZapWriter * pZapWriter)
312 _ASSERTE(pZapWriter);
314 if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_NGenEnableCreatePdb)) {
315 SaveOriginalDebugDirectoryEntry(pZapWriter);
316 SaveNGenDebugDirectoryEntry(pZapWriter);
318 SaveNGenDebugDirectoryEntry(pZapWriter);
319 SaveOriginalDebugDirectoryEntry(pZapWriter);
323 ZapPEExports::ZapPEExports(LPCWSTR dllPath)
325 m_dllFileName = wcsrchr(dllPath, DIRECTORY_SEPARATOR_CHAR_W);
326 if (m_dllFileName != NULL)
329 m_dllFileName = dllPath;
332 DWORD ZapPEExports::GetSize()
334 return DWORD(sizeof(IMAGE_EXPORT_DIRECTORY) + wcslen(m_dllFileName) * sizeof(BYTE) + 1);
337 void ZapPEExports::Save(ZapWriter * pZapWriter)
339 _ASSERTE(pZapWriter);
341 IMAGE_EXPORT_DIRECTORY exports;
342 ZeroMemory(&exports, sizeof(exports));
344 exports.Name = pZapWriter->GetCurrentRVA() + sizeof(exports);
346 // Write out exports header
347 pZapWriter->Write(&exports, sizeof(exports));
349 // Write out string that exports.Name points at.
350 for (LPCWSTR ptr = m_dllFileName; ; ptr++)
352 pZapWriter->Write((PVOID) ptr, 1);
358 // If the IL image has IMAGE_DIRECTORY_ENTRY_DEBUG with information about the PDB,
359 // copy that information over to the ngen image.
360 // This lets the debugger find out information about the PDB without loading
362 // Note that we support using ngen images (from the GAC) without
363 // loading the ngen image. So not only is this a perf optimization for the debugger
364 // scenario, but it is also needed for dump-debugging where loading the IL
367 void ZapImage::CopyDebugDirEntry()
369 // Insert an NGEN PDB debug directory entry *before* the IL PDB debug directory entry
370 // (if one exists), so that we don't break tools that look for an IL PDB.
372 // This entry is initially empty. It is filled in ZapImage::GenerateFile.
374 m_pNGenPdbDebugData = ZapBlob::NewBlob(static_cast<ZapWriter *>(this), &rsds, sizeof rsds);
377 // IL PDB entry: copy of the (first of possibly many) IMAGE_DEBUG_DIRECTORY entry
379 DWORD nDebugEntry = 0;
380 PIMAGE_DEBUG_DIRECTORY pDebugDir = NULL;
381 ZapNode **ppDebugData = NULL;
383 if (m_ModuleDecoder.HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG)) {
384 COUNT_T debugEntrySize;
385 TADDR pDebugEntry = m_ModuleDecoder.GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_DEBUG, &debugEntrySize);
387 if (debugEntrySize != 0) {
389 if (debugEntrySize < sizeof(IMAGE_DEBUG_DIRECTORY) || 0 != (debugEntrySize % sizeof(IMAGE_DEBUG_DIRECTORY))) {
390 m_zapper->Warning(W("IMAGE_DIRECTORY_ENTRY_DEBUG size (%d) should be a multiple of %d\n"),
391 debugEntrySize, sizeof(IMAGE_DEBUG_DIRECTORY));
394 // Since pDebugEntry is an array of IMAGE_DEBUG_DIRECTORYs, debugEntrySize
395 // should be a multiple of sizeof(IMAGE_DEBUG_DIRECTORY).
396 _ASSERTE(0 == (debugEntrySize % sizeof(IMAGE_DEBUG_DIRECTORY)));
398 nDebugEntry = DWORD(debugEntrySize / sizeof(IMAGE_DEBUG_DIRECTORY));
399 pDebugDir = new (GetHeap()) IMAGE_DEBUG_DIRECTORY[nDebugEntry];
400 memcpy(pDebugDir, (const void *)pDebugEntry, sizeof(IMAGE_DEBUG_DIRECTORY) * nDebugEntry);
401 ppDebugData = new (GetHeap()) ZapNode*[nDebugEntry];
402 memset(ppDebugData, 0, nDebugEntry * sizeof(ZapNode*));
404 for (DWORD i = 0; i < nDebugEntry; i++)
406 // Some compilers set PointerToRawData but not AddressOfRawData as they put the
407 // data at the end of the file in an unmapped part of the file
409 RVA rvaOfRawData = (pDebugDir[i].AddressOfRawData != NULL)
410 ? pDebugDir[i].AddressOfRawData : m_ModuleDecoder.OffsetToRva(pDebugDir[i].PointerToRawData);
412 ULONG cbDebugData = pDebugDir[i].SizeOfData;
414 if (cbDebugData != 0) {
415 if (!m_ModuleDecoder.CheckRva(rvaOfRawData, cbDebugData))
416 m_zapper->Warning(W("IMAGE_DIRECTORY_ENTRY_DEBUG points to bad data\n"));
418 ppDebugData[i] = new (GetHeap()) ZapBlobPtr((PVOID)m_ModuleDecoder.GetRvaData(rvaOfRawData), cbDebugData);
425 ZapDebugDirectory * pDebugDirectory = new (GetHeap()) ZapDebugDirectory(m_pNGenPdbDebugData,
430 m_pDebugSection->Place(pDebugDirectory);
431 m_pDebugSection->Place(m_pNGenPdbDebugData);
434 for (DWORD i = 0; i < nDebugEntry; i++)
436 if (ppDebugData[i] != nullptr)
437 m_pDebugSection->Place(ppDebugData[i]);
441 SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG, pDebugDirectory);
444 DWORD ZapVirtualSectionsTable::GetSize()
446 DWORD nSectionInfos = 0;
448 COUNT_T nPhysicalSections = m_pImage->GetPhysicalSectionCount();
449 for (COUNT_T iPhysicalSection = 0; iPhysicalSection < nPhysicalSections; iPhysicalSection++)
451 ZapPhysicalSection * pPhysicalSection = m_pImage->GetPhysicalSection(iPhysicalSection);
453 DWORD dwPreviousType = 0;
455 COUNT_T nVirtualSections = pPhysicalSection->GetVirtualSectionCount();
456 for (COUNT_T iVirtualSection = 0; iVirtualSection < nVirtualSections; iVirtualSection++)
458 ZapVirtualSection * pVirtualSection = pPhysicalSection->GetVirtualSection(iVirtualSection);
460 if (pVirtualSection->GetNodeCount() == 0)
463 DWORD dwSectionType = pVirtualSection->GetSectionType();
464 if (dwSectionType == 0)
467 // Fold sections with the same type together
468 if (dwPreviousType != dwSectionType)
470 dwPreviousType = dwSectionType;
476 return nSectionInfos * sizeof(CORCOMPILE_VIRTUAL_SECTION_INFO);
479 void ZapVirtualSectionsTable::Save(ZapWriter * pZapWriter)
481 COUNT_T nPhysicalSections = m_pImage->GetPhysicalSectionCount();
482 for (COUNT_T iPhysicalSection = 0; iPhysicalSection < nPhysicalSections; iPhysicalSection++)
484 ZapPhysicalSection * pPhysicalSection = m_pImage->GetPhysicalSection(iPhysicalSection);
486 CORCOMPILE_VIRTUAL_SECTION_INFO sectionInfo;
488 sectionInfo.SectionType = 0;
490 COUNT_T nVirtualSections = pPhysicalSection->GetVirtualSectionCount();
491 for (COUNT_T iVirtualSection = 0; iVirtualSection < nVirtualSections; iVirtualSection++)
493 ZapVirtualSection * pVirtualSection = pPhysicalSection->GetVirtualSection(iVirtualSection);
495 if (pVirtualSection->GetNodeCount() == 0)
498 DWORD dwSectionType = pVirtualSection->GetSectionType();
499 if (dwSectionType == 0)
502 // Fold sections with the same type together
503 if (sectionInfo.SectionType != dwSectionType)
505 if (sectionInfo.SectionType != 0)
507 pZapWriter->Write(§ionInfo, sizeof(sectionInfo));
510 sectionInfo.SectionType = dwSectionType;
511 sectionInfo.VirtualAddress = pVirtualSection->GetRVA();
514 // Update section size
515 sectionInfo.Size = (pVirtualSection->GetRVA() + pVirtualSection->GetSize()) - sectionInfo.VirtualAddress;
518 if (sectionInfo.SectionType != 0)
520 pZapWriter->Write(§ionInfo, sizeof(sectionInfo));