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 // Infrastructure for writing PE files. (Not NGEN specific)
11 // ======================================================================================
15 //---------------------------------------------------------------------------------------
18 void * operator new(size_t size, ZapHeap * pHeap)
20 return ((LoaderHeap*)pHeap)->AllocMem(S_SIZE_T(size));
23 void * operator new[](size_t size, ZapHeap * pHeap)
25 return ((LoaderHeap*)pHeap)->AllocMem(S_SIZE_T(size));
28 //---------------------------------------------------------------------------------------
31 ZapWriter::ZapWriter()
35 ZapWriter::~ZapWriter()
37 for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
39 ZapPhysicalSection * pPhysicalSection = m_Sections[iPhysicalSection];
40 pPhysicalSection->~ZapPhysicalSection();
42 delete (LoaderHeap*)m_pHeap;
45 void ZapWriter::Initialize()
47 const DWORD dwReserveSize = 0x1000000;
48 const DWORD dwCommitSize = 0x10000;
50 m_pHeap = reinterpret_cast<ZapHeap*>(new LoaderHeap(dwReserveSize, dwCommitSize));
54 // Default file alignment
55 m_FileAlignment = 0x200;
58 #if defined(FEATURE_PAL) && defined(_TARGET_64BIT_)
59 #define SECTION_ALIGNMENT m_FileAlignment
60 #define PAL_MAX_PAGE_SIZE 0x10000
62 #define SECTION_ALIGNMENT 0x1000
63 #define PAL_MAX_PAGE_SIZE 0
66 void ZapWriter::Save(IStream * pStream)
68 INDEBUG(m_fSaving = TRUE;)
70 InitializeWriter(pStream);
72 _ASSERTE(m_Sections.GetCount() > 0);
74 ZapPhysicalSection * pLastPhysicalSection = m_Sections[m_Sections.GetCount() - 1];
76 ULARGE_INTEGER estimatedFileSize;
77 estimatedFileSize.QuadPart = pLastPhysicalSection->m_dwFilePos + pLastPhysicalSection->m_dwSizeOfRawData;
79 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NGenSimulateDiskFull) != 0)
81 ThrowHR(HRESULT_FROM_WIN32(ERROR_DISK_FULL));
84 // Set the file size upfront to reduce disk fragmentation
85 IfFailThrow(pStream->SetSize(estimatedFileSize));
90 // Write the content of all sections
91 IfFailThrow(pStream->Seek(zero, STREAM_SEEK_SET, NULL));
95 // Finally write the NT headers
96 IfFailThrow(pStream->Seek(zero, STREAM_SEEK_SET, NULL));
101 DWORD ZapNode::ComputeRVA(ZapWriter * pZapWriter, DWORD dwPos)
103 dwPos = AlignUp(dwPos, GetAlignment());
112 void ZapWriter::ComputeRVAs()
114 DWORD dwHeaderSize = GetSizeOfNTHeaders();
116 DWORD dwPos = dwHeaderSize;
117 DWORD dwFilePos = dwHeaderSize;
119 for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
121 ZapPhysicalSection * pPhysicalSection = m_Sections[iPhysicalSection];
123 DWORD dwAlignedFilePos = AlignUp(dwFilePos, m_FileAlignment);
124 dwFilePos = dwAlignedFilePos;
126 pPhysicalSection->m_dwFilePos = dwFilePos;
128 dwPos = AlignUp(dwPos, SECTION_ALIGNMENT) + PAL_MAX_PAGE_SIZE;
129 pPhysicalSection->SetRVA(dwPos);
131 DWORD dwEndOfRawData = dwPos;
134 printf("Physical Section \"%s\" {\n", pPhysicalSection->m_pszName);
137 for (COUNT_T iVirtualSection = 0; iVirtualSection < pPhysicalSection->m_Sections.GetCount(); iVirtualSection++)
139 ZapVirtualSection * pVirtualSection = pPhysicalSection->m_Sections[iVirtualSection];
141 // Do not bother with empty virtual sections
142 if (pVirtualSection->m_Nodes.GetCount() == 0)
145 dwPos = AlignUp(dwPos, pVirtualSection->m_dwAlignment);
146 pVirtualSection->SetRVA(dwPos);
148 for (COUNT_T iNode = 0; iNode < pVirtualSection->m_Nodes.GetCount(); iNode++)
150 ZapNode * pNode = pVirtualSection->m_Nodes[iNode];
152 DWORD dwNextPos = pNode->ComputeRVA(this, dwPos);
153 _ASSERTE(dwNextPos >= dwPos);
155 if (dwNextPos < dwPos || dwNextPos > ZAPWRITER_MAX_SIZE)
156 ThrowHR(COR_E_OVERFLOW);
161 pVirtualSection->m_dwSize = dwPos - pVirtualSection->GetRVA();
163 if (iVirtualSection < pPhysicalSection->m_Sections.GetCount() - pPhysicalSection->m_nBssSections)
164 dwEndOfRawData = dwPos;
166 if (pVirtualSection->m_dwSize > 0)
168 printf(" %08x (%6u bytes): %s\n", pVirtualSection->GetRVA(), pVirtualSection->m_dwSize, pVirtualSection->m_pszTag);
173 pPhysicalSection->m_dwSize = dwPos - pPhysicalSection->GetRVA();
175 pPhysicalSection->m_dwSizeOfRawData = dwEndOfRawData - pPhysicalSection->GetRVA();
177 dwFilePos += pPhysicalSection->m_dwSizeOfRawData;
180 printf(" %08x: end\n", dwPos);
186 void ZapWriter::SaveContent()
188 DWORD dwHeaderSize = GetSizeOfNTHeaders();
190 WritePad(dwHeaderSize);
192 DWORD dwPos = dwHeaderSize;
193 DWORD dwFilePos = dwHeaderSize;
195 for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
197 ZapPhysicalSection * pPhysicalSection = m_Sections[iPhysicalSection];
198 DWORD dwAlignedFilePos = AlignUp(dwFilePos, m_FileAlignment);
199 WritePad(dwAlignedFilePos - dwFilePos);
200 dwFilePos = dwAlignedFilePos;
202 dwPos = AlignUp(dwPos, SECTION_ALIGNMENT) + PAL_MAX_PAGE_SIZE;
204 if (m_fWritingRelocs)
206 pPhysicalSection->m_RVA = dwPos;
207 pPhysicalSection->m_dwFilePos = dwFilePos;
209 _ASSERTE(pPhysicalSection->GetRVA() == dwPos);
210 _ASSERTE(pPhysicalSection->m_dwFilePos == dwFilePos);
211 _ASSERTE(m_dwWriterFilePos == dwFilePos);
213 for (COUNT_T iVirtualSection = 0; iVirtualSection < pPhysicalSection->m_Sections.GetCount() - pPhysicalSection->m_nBssSections; iVirtualSection++)
215 ZapVirtualSection * pVirtualSection = pPhysicalSection->m_Sections[iVirtualSection];
217 // Do not bother with empty virtual sections
218 if (pVirtualSection->m_Nodes.GetCount() == 0)
221 if (m_fWritingRelocs)
223 pVirtualSection->m_RVA = dwPos;
225 _ASSERTE(pVirtualSection->m_Nodes.GetCount() == 1);
226 pVirtualSection->m_Nodes[0]->m_RVA = dwPos;
229 DWORD dwVirtualSectionPos = pVirtualSection->GetRVA();
230 if (dwVirtualSectionPos != dwPos)
231 WritePad(dwVirtualSectionPos - dwPos);
232 dwPos = dwVirtualSectionPos;
234 for (COUNT_T iNode = 0; iNode < pVirtualSection->m_Nodes.GetCount(); iNode++)
236 ZapNode * pNode = pVirtualSection->m_Nodes[iNode];
238 DWORD dwNodePos = pNode->GetRVA();
239 if (dwNodePos != dwPos)
240 WritePad(dwNodePos - dwPos, pVirtualSection->m_defaultFill);
243 m_dwCurrentRVA = dwPos;
247 if (dwPos + pNode->GetSize() != m_dwCurrentRVA)
249 _ASSERTE(!"Mismatch between ZapNode::GetSize() and ZapNode::Save() implementations");
255 dwPos = m_dwCurrentRVA;
258 DWORD dwVirtualSectionSize = dwPos - pVirtualSection->GetRVA();
259 if (m_fWritingRelocs)
261 pVirtualSection->m_dwSize = dwVirtualSectionSize;
263 _ASSERTE(pVirtualSection->m_dwSize == dwVirtualSectionSize);
266 DWORD dwPhysicalSectionSize = dwPos - pPhysicalSection->GetRVA();
267 if (m_fWritingRelocs)
269 pPhysicalSection->m_dwSize = dwPhysicalSectionSize;
270 pPhysicalSection->m_dwSizeOfRawData = dwPhysicalSectionSize;
272 _ASSERTE(pPhysicalSection->m_dwSizeOfRawData == dwPhysicalSectionSize);
274 dwPos = pPhysicalSection->GetRVA() + pPhysicalSection->m_dwSize;
276 dwFilePos += pPhysicalSection->m_dwSizeOfRawData;
279 WritePad(AlignmentPad(dwFilePos, m_FileAlignment));
282 //---------------------------------------------------------------------------------------
287 UINT32 ZapVirtualSection::FillInNodeOffsetMap(MapSHash<ZapNode *, UINT32> * pMap)
290 for (int i = 0; i < m_Nodes.GetCount(); i++)
292 ZapNode* pNode = m_Nodes[i];
293 pMap->Add(pNode, dataSize);
294 dataSize += pNode->GetSize();
301 //---------------------------------------------------------------------------------------
302 // Simple buffered writer
304 #define WRITE_BUFFER_SIZE 0x10000
306 void ZapWriter::InitializeWriter(IStream * pStream)
308 m_pBuffer = new (GetHeap()) BYTE[WRITE_BUFFER_SIZE];
313 INDEBUG(m_dwWriterFilePos = 0;)
316 void ZapWriter::FlushWriter()
318 if (m_nBufferPos > 0)
321 IfFailThrow(m_pStream->Write(m_pBuffer, m_nBufferPos, &cbWritten));
322 _ASSERTE(cbWritten == m_nBufferPos);
328 void ZapWriter::Write(PVOID p, DWORD dwSize)
330 m_dwCurrentRVA += dwSize;
331 INDEBUG(m_dwWriterFilePos += dwSize;)
333 if (m_dwCurrentRVA >= ZAPWRITER_MAX_SIZE)
334 ThrowHR(COR_E_OVERFLOW);
336 DWORD cbAvailable = min(dwSize, WRITE_BUFFER_SIZE - m_nBufferPos);
338 memcpy(m_pBuffer + m_nBufferPos, p, cbAvailable);
339 p = (PBYTE)p + cbAvailable;
340 dwSize -= cbAvailable;
342 m_nBufferPos += cbAvailable;
344 if (m_nBufferPos < WRITE_BUFFER_SIZE)
352 cbAvailable = AlignDown(dwSize, WRITE_BUFFER_SIZE);
357 IfFailThrow(m_pStream->Write(p, cbAvailable, &cbWritten));
358 _ASSERTE(cbWritten == cbAvailable);
360 p = (PBYTE)p + cbAvailable;
361 dwSize -= cbAvailable;
364 _ASSERTE(m_nBufferPos == 0);
365 memcpy(m_pBuffer, p, dwSize);
366 m_nBufferPos = dwSize;
369 void ZapWriter::WritePad(DWORD dwSize, BYTE fill)
371 m_dwCurrentRVA += dwSize;
372 INDEBUG(m_dwWriterFilePos += dwSize;)
374 if (m_dwCurrentRVA >= ZAPWRITER_MAX_SIZE)
375 ThrowHR(COR_E_OVERFLOW);
377 DWORD cbAvailable = min(dwSize, WRITE_BUFFER_SIZE - m_nBufferPos);
379 memset(m_pBuffer + m_nBufferPos, fill, cbAvailable);
380 dwSize -= cbAvailable;
382 m_nBufferPos += cbAvailable;
384 if (m_nBufferPos < WRITE_BUFFER_SIZE)
392 memset(m_pBuffer, fill, min(WRITE_BUFFER_SIZE, dwSize));
394 while (dwSize >= WRITE_BUFFER_SIZE)
397 cbAvailable = min(WRITE_BUFFER_SIZE, dwSize);
398 IfFailThrow(m_pStream->Write(m_pBuffer, cbAvailable, &cbWritten));
399 _ASSERTE(cbWritten == cbAvailable);
401 dwSize -= cbAvailable;
404 m_nBufferPos = dwSize;
407 STDMETHODIMP ZapWriter::Write(void const *pv, ULONG cb, ULONG *pcbWritten)
413 Write((PVOID)pv, cb);
423 //---------------------------------------------------------------------------------------
426 void ZapWriter::SaveHeaders()
431 SaveOptionalHeader();
435 void ZapWriter::SaveDosHeader()
437 IMAGE_DOS_HEADER header;
439 ZeroMemory(&header, sizeof(header));
441 header.e_magic = VAL16(IMAGE_DOS_SIGNATURE);
442 header.e_lfanew = VAL32(sizeof(IMAGE_DOS_HEADER));
444 // Legacy tools depend on e_lfarlc to be 0x40
445 header.e_lfarlc = VAL16(0x40);
447 // We put the PE Signature at 0x80 so that we are the same offset for IL Images
449 header.e_lfanew = VAL32(sizeof(IMAGE_DOS_HEADER) + 0x40);
450 Write(&header, sizeof(header));
452 // Write out padding to get to offset 0x80
456 void ZapWriter::SaveSignature()
458 ULONG Signature = VAL32(IMAGE_NT_SIGNATURE);
459 Write(&Signature, sizeof(Signature));
462 void ZapWriter::SaveFileHeader()
464 IMAGE_FILE_HEADER fileHeader;
465 ZeroMemory(&fileHeader, sizeof(fileHeader));
467 fileHeader.Machine = VAL16(GetMachine());
468 fileHeader.TimeDateStamp = VAL32(m_dwTimeDateStamp);
469 fileHeader.SizeOfOptionalHeader = Is64Bit() ? VAL16(sizeof(IMAGE_OPTIONAL_HEADER64)) : VAL16(sizeof(IMAGE_OPTIONAL_HEADER32));
471 // Count the number of non-empty physical sections
473 for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
475 if (m_Sections[iPhysicalSection]->m_dwSize != 0)
478 fileHeader.NumberOfSections = VAL16(nSections);
480 fileHeader.Characteristics = VAL16(IMAGE_FILE_EXECUTABLE_IMAGE |
481 (Is64Bit() ? 0 : IMAGE_FILE_32BIT_MACHINE) |
482 (m_isDll ? IMAGE_FILE_DLL : 0) |
483 (Is64Bit() ? IMAGE_FILE_LARGE_ADDRESS_AWARE : 0) );
485 Write(&fileHeader, sizeof(fileHeader));
488 void ZapWriter::SaveOptionalHeader()
490 // Write the correct flavor of the optional header
493 IMAGE_OPTIONAL_HEADER32 header32;
494 IMAGE_OPTIONAL_HEADER64 header64;
498 ZeroMemory(&optionalHeader, sizeof(optionalHeader));
500 PIMAGE_OPTIONAL_HEADER pHeader = (PIMAGE_OPTIONAL_HEADER)&optionalHeader;
502 // Common fields between 32-bit and 64-bit
504 // Linker version should be consistent with current VC level
505 pHeader->MajorLinkerVersion = 11;
507 pHeader->SectionAlignment = VAL32(SECTION_ALIGNMENT);
508 pHeader->FileAlignment = VAL32(m_FileAlignment);
510 // Win2k = 5.0 for 32-bit images, Win2003 = 5.2 for 64-bit images
511 pHeader->MajorOperatingSystemVersion = VAL16(5);
512 pHeader->MinorOperatingSystemVersion = Is64Bit() ? VAL16(2) : VAL16(0);
514 pHeader->MajorSubsystemVersion = pHeader->MajorOperatingSystemVersion;
515 pHeader->MinorSubsystemVersion = pHeader->MinorOperatingSystemVersion;
518 pHeader->AddressOfEntryPoint = m_entryPointRVA;
521 ZapPhysicalSection * pLastPhysicalSection = m_Sections[m_Sections.GetCount() - 1];
522 pHeader->SizeOfImage = VAL32(AlignUp(pLastPhysicalSection->GetRVA() + pLastPhysicalSection->m_dwSize, SECTION_ALIGNMENT));
524 pHeader->SizeOfHeaders = VAL32(AlignUp(GetSizeOfNTHeaders(), m_FileAlignment));
526 pHeader->Subsystem = VAL16(m_Subsystem);
527 pHeader->DllCharacteristics = VAL16(m_DllCharacteristics);
530 // Different fields between 32-bit and 64-bit
532 PIMAGE_DATA_DIRECTORY pDataDirectory;
536 PIMAGE_OPTIONAL_HEADER64 pHeader64 = (PIMAGE_OPTIONAL_HEADER64)pHeader;
538 pHeader64->Magic = VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC);
540 pHeader64->ImageBase = VAL64(m_BaseAddress);
541 pHeader64->NumberOfRvaAndSizes = VAL32(IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
543 pHeader64->SizeOfStackReserve = VAL64(m_SizeOfStackReserve);
544 pHeader64->SizeOfStackCommit = VAL64(m_SizeOfStackCommit);
546 pDataDirectory = pHeader64->DataDirectory;
550 PIMAGE_OPTIONAL_HEADER32 pHeader32 = (PIMAGE_OPTIONAL_HEADER32)pHeader;
552 pHeader32->Magic = VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC);
554 pHeader32->ImageBase = VAL32((ULONG)m_BaseAddress);
555 pHeader32->NumberOfRvaAndSizes = VAL32(IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
557 pHeader32->SizeOfStackReserve = VAL32((ULONG)m_SizeOfStackReserve);
558 pHeader32->SizeOfStackCommit = VAL32((ULONG)m_SizeOfStackCommit);
560 pDataDirectory = pHeader32->DataDirectory;
563 for (int i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
565 SetDirectoryData(&pDataDirectory[i], m_DirectoryEntries[i]);
568 Write(&optionalHeader, Is64Bit() ? sizeof(IMAGE_OPTIONAL_HEADER64) : sizeof(IMAGE_OPTIONAL_HEADER32));
571 void ZapWriter::SaveSections()
573 for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
575 ZapPhysicalSection * pPhysicalSection = m_Sections[iPhysicalSection];
577 // Do not save empty sections
578 if (pPhysicalSection->m_dwSize == 0)
581 IMAGE_SECTION_HEADER header;
582 ZeroMemory(&header, sizeof(header));
584 SIZE_T cbName = strlen(pPhysicalSection->m_pszName);
585 _ASSERTE(cbName <= sizeof(header.Name));
586 memcpy(header.Name, pPhysicalSection->m_pszName, min(sizeof(header.Name), cbName));
588 header.Misc.VirtualSize = VAL32(pPhysicalSection->m_dwSize);
589 header.VirtualAddress = VAL32(pPhysicalSection->GetRVA());
591 header.SizeOfRawData = VAL32(AlignUp(pPhysicalSection->m_dwSizeOfRawData, m_FileAlignment));
593 if (header.SizeOfRawData != 0)
594 header.PointerToRawData = VAL32(pPhysicalSection->m_dwFilePos);
596 header.Characteristics = VAL32(pPhysicalSection->m_dwCharacteristics);
598 Write(&header, sizeof(header));
602 DWORD ZapWriter::GetSizeOfNTHeaders()
604 return sizeof(IMAGE_DOS_HEADER) + 0x40 + /* Padding for DOS Header */
606 sizeof(IMAGE_FILE_HEADER) +
607 (Is64Bit() ? sizeof(IMAGE_OPTIONAL_HEADER64) : sizeof(IMAGE_OPTIONAL_HEADER32)) +
608 (m_Sections.GetCount() * sizeof(IMAGE_SECTION_HEADER));
611 void ZapWriter::SetDirectoryData(IMAGE_DATA_DIRECTORY * pDir, ZapNode * pZapNode)
613 DWORD size = (pZapNode != NULL) ? pZapNode->GetSize() : 0;
617 pDir->VirtualAddress = pZapNode->GetRVA();
622 pDir->VirtualAddress = 0;
627 //---------------------------------------------------------------------------------------
630 ZapBlob * ZapBlob::NewBlob(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize)
632 S_SIZE_T cbAllocSize = S_SIZE_T(sizeof(ZapBlob)) + S_SIZE_T(cbSize);
633 if(cbAllocSize.IsOverflow())
634 ThrowHR(COR_E_OVERFLOW);
636 void * pMemory = new (pWriter->GetHeap()) BYTE[cbAllocSize.Value()];
638 ZapBlob * pZapBlob = new (pMemory) ZapBlob(cbSize);
641 memcpy((void*)(pZapBlob + 1), pData, cbSize);
646 template <UINT alignment>
647 class ZapAlignedBlobConst : public ZapBlob
650 ZapAlignedBlobConst(SIZE_T cbSize)
656 virtual UINT GetAlignment()
661 static ZapBlob * NewBlob(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize)
663 S_SIZE_T cbAllocSize = S_SIZE_T(sizeof(ZapAlignedBlobConst<alignment>)) + S_SIZE_T(cbSize);
664 if(cbAllocSize.IsOverflow())
665 ThrowHR(COR_E_OVERFLOW);
667 void * pMemory = new (pWriter->GetHeap()) BYTE[cbAllocSize.Value()];
669 ZapAlignedBlobConst<alignment> * pZapBlob = new (pMemory) ZapAlignedBlobConst<alignment>(cbSize);
672 memcpy((void *)(pZapBlob + 1), pData, cbSize);
678 ZapBlob * ZapBlob::NewAlignedBlob(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize, SIZE_T cbAlignment)
683 return ZapAlignedBlobConst<4>::NewBlob(pWriter, pData, cbSize);
685 return ZapAlignedBlobConst<8>::NewBlob(pWriter, pData, cbSize);
687 return ZapAlignedBlobConst<16>::NewBlob(pWriter, pData, cbSize);
690 _ASSERTE(!"Requested alignment not supported");
695 void ZapBlob::Save(ZapWriter * pZapWriter)
697 pZapWriter->Write(GetData(), GetSize());