JIT: Fix bug in finally cloning caused by unsound callfinally reordering
[platform/upstream/coreclr.git] / src / zap / zapwriter.cpp
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 // ZapWriter.cpp
6 //
7
8 //
9 // Infrastructure for writing PE files. (Not NGEN specific)
10 // 
11 // ======================================================================================
12
13 #include "common.h"
14
15 //---------------------------------------------------------------------------------------
16 // ZapNode
17
18 void * operator new(size_t size, ZapHeap * pHeap)
19 {
20     return ((LoaderHeap*)pHeap)->AllocMem(S_SIZE_T(size));
21 }
22
23 void * operator new[](size_t size, ZapHeap * pHeap)
24 {
25     return ((LoaderHeap*)pHeap)->AllocMem(S_SIZE_T(size));
26 }
27
28 //---------------------------------------------------------------------------------------
29 // ZapWriter
30
31 ZapWriter::ZapWriter()
32 {
33 }
34
35 ZapWriter::~ZapWriter()
36 {
37     for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
38     {
39         ZapPhysicalSection * pPhysicalSection = m_Sections[iPhysicalSection];
40         pPhysicalSection->~ZapPhysicalSection();
41     }
42     delete (LoaderHeap*)m_pHeap;
43 }
44
45 void ZapWriter::Initialize()
46 {
47     const DWORD dwReserveSize = 0x1000000;
48     const DWORD dwCommitSize  = 0x10000;
49
50     m_pHeap = reinterpret_cast<ZapHeap*>(new LoaderHeap(dwReserveSize, dwCommitSize));
51
52     m_isDll = true;
53
54     // Default file alignment
55     m_FileAlignment = 0x200;
56 }
57
58 #if defined(FEATURE_PAL) && defined(_TARGET_64BIT_)
59 #define SECTION_ALIGNMENT   m_FileAlignment
60 #define PAL_MAX_PAGE_SIZE   0x10000
61 #else
62 #define SECTION_ALIGNMENT   0x1000
63 #define PAL_MAX_PAGE_SIZE   0
64 #endif
65
66 void ZapWriter::Save(IStream * pStream)
67 {
68     INDEBUG(m_fSaving = TRUE;)
69
70     InitializeWriter(pStream);
71
72     _ASSERTE(m_Sections.GetCount() > 0);
73
74     ZapPhysicalSection * pLastPhysicalSection = m_Sections[m_Sections.GetCount() - 1];
75
76     ULARGE_INTEGER estimatedFileSize;
77     estimatedFileSize.QuadPart = pLastPhysicalSection->m_dwFilePos + pLastPhysicalSection->m_dwSizeOfRawData;
78
79     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NGenSimulateDiskFull) != 0)
80     {
81         ThrowHR(HRESULT_FROM_WIN32(ERROR_DISK_FULL));
82     }
83     
84     // Set the file size upfront to reduce disk fragmentation
85     IfFailThrow(pStream->SetSize(estimatedFileSize));
86
87     LARGE_INTEGER zero;
88     zero.QuadPart = 0;
89
90     // Write the content of all sections
91     IfFailThrow(pStream->Seek(zero, STREAM_SEEK_SET, NULL));
92     SaveContent();
93     FlushWriter();
94
95     // Finally write the NT headers
96     IfFailThrow(pStream->Seek(zero, STREAM_SEEK_SET, NULL));
97     SaveHeaders();
98     FlushWriter();
99 }
100
101 DWORD ZapNode::ComputeRVA(ZapWriter * pZapWriter, DWORD dwPos)
102 {
103     dwPos = AlignUp(dwPos, GetAlignment());
104
105     SetRVA(dwPos);
106
107     dwPos += GetSize();
108
109     return dwPos;
110 }
111
112 void ZapWriter::ComputeRVAs()
113 {
114     DWORD dwHeaderSize = GetSizeOfNTHeaders();
115
116     DWORD dwPos = dwHeaderSize;
117     DWORD dwFilePos = dwHeaderSize;
118
119     for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
120     {
121         ZapPhysicalSection * pPhysicalSection = m_Sections[iPhysicalSection];
122
123         DWORD dwAlignedFilePos = AlignUp(dwFilePos, m_FileAlignment);
124         dwFilePos = dwAlignedFilePos;
125
126         pPhysicalSection->m_dwFilePos = dwFilePos;
127
128         dwPos = AlignUp(dwPos, SECTION_ALIGNMENT) + PAL_MAX_PAGE_SIZE;
129         pPhysicalSection->SetRVA(dwPos);
130
131         DWORD dwEndOfRawData = dwPos;
132
133 #ifdef REDHAWK
134         printf("Physical Section \"%s\" {\n", pPhysicalSection->m_pszName);
135 #endif // REDHAWK
136
137         for (COUNT_T iVirtualSection = 0; iVirtualSection < pPhysicalSection->m_Sections.GetCount(); iVirtualSection++)
138         {
139             ZapVirtualSection * pVirtualSection = pPhysicalSection->m_Sections[iVirtualSection];
140
141             // Do not bother with empty virtual sections
142             if (pVirtualSection->m_Nodes.GetCount() == 0)
143                 continue;
144
145             dwPos = AlignUp(dwPos, pVirtualSection->m_dwAlignment);
146             pVirtualSection->SetRVA(dwPos);
147
148             for (COUNT_T iNode = 0; iNode < pVirtualSection->m_Nodes.GetCount(); iNode++)
149             {
150                 ZapNode * pNode = pVirtualSection->m_Nodes[iNode];
151
152                 DWORD dwNextPos = pNode->ComputeRVA(this, dwPos);
153                 _ASSERTE(dwNextPos >= dwPos);
154
155                 if (dwNextPos < dwPos || dwNextPos > ZAPWRITER_MAX_SIZE)
156                     ThrowHR(COR_E_OVERFLOW);
157
158                 dwPos = dwNextPos;
159             }
160
161             pVirtualSection->m_dwSize = dwPos - pVirtualSection->GetRVA();
162
163             if (iVirtualSection < pPhysicalSection->m_Sections.GetCount() - pPhysicalSection->m_nBssSections)
164                 dwEndOfRawData = dwPos;
165 #ifdef REDHAWK
166             if (pVirtualSection->m_dwSize > 0)
167             {
168                 printf("    %08x (%6u bytes): %s\n", pVirtualSection->GetRVA(), pVirtualSection->m_dwSize, pVirtualSection->m_pszTag);
169             }
170 #endif // REDHAWK
171         }
172
173         pPhysicalSection->m_dwSize = dwPos - pPhysicalSection->GetRVA();
174
175         pPhysicalSection->m_dwSizeOfRawData = dwEndOfRawData - pPhysicalSection->GetRVA();
176
177         dwFilePos += pPhysicalSection->m_dwSizeOfRawData;
178
179 #ifdef REDHAWK
180         printf("    %08x: end\n", dwPos);
181         printf("}\n");
182 #endif // REDHAWK
183     }
184 }
185
186 void ZapWriter::SaveContent()
187 {
188     DWORD dwHeaderSize = GetSizeOfNTHeaders();
189
190     WritePad(dwHeaderSize);
191
192     DWORD dwPos = dwHeaderSize;
193     DWORD dwFilePos = dwHeaderSize;
194
195     for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
196     {
197         ZapPhysicalSection * pPhysicalSection = m_Sections[iPhysicalSection];
198         DWORD dwAlignedFilePos = AlignUp(dwFilePos, m_FileAlignment);
199         WritePad(dwAlignedFilePos - dwFilePos);
200         dwFilePos = dwAlignedFilePos;
201
202         dwPos = AlignUp(dwPos, SECTION_ALIGNMENT) + PAL_MAX_PAGE_SIZE;
203
204         if (m_fWritingRelocs)
205         {
206             pPhysicalSection->m_RVA = dwPos;
207             pPhysicalSection->m_dwFilePos = dwFilePos;
208         }
209         _ASSERTE(pPhysicalSection->GetRVA() == dwPos);
210         _ASSERTE(pPhysicalSection->m_dwFilePos == dwFilePos);
211         _ASSERTE(m_dwWriterFilePos == dwFilePos);
212
213         for (COUNT_T iVirtualSection = 0; iVirtualSection < pPhysicalSection->m_Sections.GetCount() - pPhysicalSection->m_nBssSections; iVirtualSection++)
214         {
215             ZapVirtualSection * pVirtualSection = pPhysicalSection->m_Sections[iVirtualSection];
216
217             // Do not bother with empty virtual sections
218             if (pVirtualSection->m_Nodes.GetCount() == 0)
219                 continue;
220
221             if (m_fWritingRelocs)
222             {
223                 pVirtualSection->m_RVA = dwPos;
224
225                 _ASSERTE(pVirtualSection->m_Nodes.GetCount() == 1);
226                 pVirtualSection->m_Nodes[0]->m_RVA = dwPos;
227             }
228
229             DWORD dwVirtualSectionPos = pVirtualSection->GetRVA();
230             if (dwVirtualSectionPos != dwPos)
231                 WritePad(dwVirtualSectionPos - dwPos);
232             dwPos = dwVirtualSectionPos;
233
234             for (COUNT_T iNode = 0; iNode < pVirtualSection->m_Nodes.GetCount(); iNode++)
235             {
236                 ZapNode * pNode = pVirtualSection->m_Nodes[iNode];
237
238                 DWORD dwNodePos = pNode->GetRVA();
239                 if (dwNodePos != dwPos)
240                     WritePad(dwNodePos - dwPos, pVirtualSection->m_defaultFill);
241                 dwPos = dwNodePos;
242
243                 m_dwCurrentRVA = dwPos;
244                 pNode->Save(this);
245
246 #ifdef _DEBUG
247                 if (dwPos + pNode->GetSize() != m_dwCurrentRVA)
248                 {
249                     _ASSERTE(!"Mismatch between ZapNode::GetSize() and ZapNode::Save() implementations");
250                     pNode->GetSize();
251                     pNode->Save(this);
252                 }
253 #endif
254
255                 dwPos = m_dwCurrentRVA;
256             }
257
258             DWORD dwVirtualSectionSize = dwPos - pVirtualSection->GetRVA();
259             if (m_fWritingRelocs)
260             {
261                 pVirtualSection->m_dwSize = dwVirtualSectionSize;
262             }
263             _ASSERTE(pVirtualSection->m_dwSize == dwVirtualSectionSize);
264         }
265
266         DWORD dwPhysicalSectionSize = dwPos - pPhysicalSection->GetRVA();
267         if (m_fWritingRelocs)
268         {
269             pPhysicalSection->m_dwSize = dwPhysicalSectionSize;
270             pPhysicalSection->m_dwSizeOfRawData = dwPhysicalSectionSize;
271         }
272         _ASSERTE(pPhysicalSection->m_dwSizeOfRawData == dwPhysicalSectionSize);
273
274         dwPos = pPhysicalSection->GetRVA() + pPhysicalSection->m_dwSize;
275
276         dwFilePos += pPhysicalSection->m_dwSizeOfRawData;
277     }
278
279     WritePad(AlignmentPad(dwFilePos, m_FileAlignment));
280 }
281
282 //---------------------------------------------------------------------------------------
283 //
284 // ZapVirtualSection
285 //
286 #ifdef REDHAWK
287 UINT32 ZapVirtualSection::FillInNodeOffsetMap(MapSHash<ZapNode *, UINT32> * pMap)
288 {
289     UINT32 dataSize = 0;
290     for (int i = 0; i < m_Nodes.GetCount(); i++)
291     {
292         ZapNode* pNode = m_Nodes[i];
293         pMap->Add(pNode, dataSize);
294         dataSize += pNode->GetSize();
295     }
296
297     return dataSize;
298 }
299 #endif // REDHAWK
300
301 //---------------------------------------------------------------------------------------
302 // Simple buffered writer
303
304 #define WRITE_BUFFER_SIZE   0x10000
305
306 void ZapWriter::InitializeWriter(IStream * pStream)
307 {
308     m_pBuffer = new (GetHeap()) BYTE[WRITE_BUFFER_SIZE];
309     m_nBufferPos = 0;
310
311     m_pStream = pStream;
312
313     INDEBUG(m_dwWriterFilePos = 0;)
314 }
315
316 void ZapWriter::FlushWriter()
317 {
318     if (m_nBufferPos > 0)
319     {
320         ULONG cbWritten;
321         IfFailThrow(m_pStream->Write(m_pBuffer, m_nBufferPos, &cbWritten));
322         _ASSERTE(cbWritten == m_nBufferPos);
323
324         m_nBufferPos = 0;
325     }
326 }
327
328 void ZapWriter::Write(PVOID p, DWORD dwSize)
329 {
330     m_dwCurrentRVA += dwSize;
331     INDEBUG(m_dwWriterFilePos += dwSize;)
332
333     if (m_dwCurrentRVA >= ZAPWRITER_MAX_SIZE)
334         ThrowHR(COR_E_OVERFLOW);
335
336     DWORD cbAvailable = min(dwSize, WRITE_BUFFER_SIZE - m_nBufferPos);
337     
338     memcpy(m_pBuffer + m_nBufferPos, p, cbAvailable);
339     p = (PBYTE)p + cbAvailable;
340     dwSize -= cbAvailable;
341
342     m_nBufferPos += cbAvailable;
343
344     if (m_nBufferPos < WRITE_BUFFER_SIZE)
345         return;
346     
347     FlushWriter();
348
349     if (dwSize == 0)
350         return;
351
352     cbAvailable = AlignDown(dwSize, WRITE_BUFFER_SIZE);
353
354     if (cbAvailable > 0)
355     {
356         ULONG cbWritten;
357         IfFailThrow(m_pStream->Write(p, cbAvailable, &cbWritten));
358         _ASSERTE(cbWritten == cbAvailable);
359
360         p = (PBYTE)p + cbAvailable;
361         dwSize -= cbAvailable;
362     }
363
364     _ASSERTE(m_nBufferPos == 0);
365     memcpy(m_pBuffer, p, dwSize);
366     m_nBufferPos = dwSize;
367 }
368
369 void ZapWriter::WritePad(DWORD dwSize, BYTE fill)
370 {
371     m_dwCurrentRVA += dwSize;
372     INDEBUG(m_dwWriterFilePos += dwSize;)
373
374     if (m_dwCurrentRVA >= ZAPWRITER_MAX_SIZE)
375         ThrowHR(COR_E_OVERFLOW);
376
377     DWORD cbAvailable = min(dwSize, WRITE_BUFFER_SIZE - m_nBufferPos);
378     
379     memset(m_pBuffer + m_nBufferPos, fill, cbAvailable);
380     dwSize -= cbAvailable;
381
382     m_nBufferPos += cbAvailable;
383
384     if (m_nBufferPos < WRITE_BUFFER_SIZE)
385         return;
386     
387     FlushWriter();
388
389     if (dwSize == 0)
390         return;
391
392     memset(m_pBuffer, fill, min(WRITE_BUFFER_SIZE, dwSize));
393
394     while (dwSize >= WRITE_BUFFER_SIZE)
395     {
396         ULONG cbWritten;
397         cbAvailable = min(WRITE_BUFFER_SIZE, dwSize);
398         IfFailThrow(m_pStream->Write(m_pBuffer, cbAvailable, &cbWritten));
399         _ASSERTE(cbWritten == cbAvailable);
400
401         dwSize -= cbAvailable;
402     }
403
404     m_nBufferPos = dwSize;
405 }
406
407 STDMETHODIMP ZapWriter::Write(void const *pv, ULONG cb, ULONG *pcbWritten)
408 {
409     HRESULT hr = S_OK;
410
411     EX_TRY
412     {
413         Write((PVOID)pv, cb);
414
415         if (pcbWritten != 0)
416             *pcbWritten = cb;
417     }
418     EX_CATCH_HRESULT(hr)
419
420     return hr;
421 }
422
423 //---------------------------------------------------------------------------------------
424 // NT Headers
425
426 void ZapWriter::SaveHeaders()
427 {
428     SaveDosHeader();
429     SaveSignature();
430     SaveFileHeader();
431     SaveOptionalHeader();
432     SaveSections();
433 }
434
435 void ZapWriter::SaveDosHeader()
436 {
437     IMAGE_DOS_HEADER header;
438
439     ZeroMemory(&header, sizeof(header));
440
441     header.e_magic = VAL16(IMAGE_DOS_SIGNATURE);
442     header.e_lfanew = VAL32(sizeof(IMAGE_DOS_HEADER));
443
444     // Legacy tools depend on e_lfarlc to be 0x40
445     header.e_lfarlc = VAL16(0x40);
446
447     // We put the PE Signature at 0x80 so that we are the same offset for IL Images
448
449     header.e_lfanew = VAL32(sizeof(IMAGE_DOS_HEADER) + 0x40);
450     Write(&header, sizeof(header));
451
452     // Write out padding to get to offset 0x80 
453     WritePad(0x40);
454 }
455
456 void ZapWriter::SaveSignature()
457 {
458     ULONG Signature = VAL32(IMAGE_NT_SIGNATURE);
459     Write(&Signature, sizeof(Signature));
460 }
461
462 void ZapWriter::SaveFileHeader()
463 {
464     IMAGE_FILE_HEADER fileHeader;
465     ZeroMemory(&fileHeader, sizeof(fileHeader));
466
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));
470
471     // Count the number of non-empty physical sections
472     int nSections = 0;
473     for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
474     {
475         if (m_Sections[iPhysicalSection]->m_dwSize != 0)
476             nSections++;
477     }
478     fileHeader.NumberOfSections = VAL16(nSections);
479
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) );
484
485     Write(&fileHeader, sizeof(fileHeader));
486 }
487
488 void ZapWriter::SaveOptionalHeader()
489 {
490     // Write the correct flavor of the optional header
491     union
492     {
493         IMAGE_OPTIONAL_HEADER32 header32;
494         IMAGE_OPTIONAL_HEADER64 header64;
495     }
496     optionalHeader;
497
498     ZeroMemory(&optionalHeader, sizeof(optionalHeader));
499
500     PIMAGE_OPTIONAL_HEADER pHeader = (PIMAGE_OPTIONAL_HEADER)&optionalHeader;
501
502     // Common fields between 32-bit and 64-bit
503
504     // Linker version should be consistent with current VC level
505     pHeader->MajorLinkerVersion = 11;
506
507     pHeader->SectionAlignment = VAL32(SECTION_ALIGNMENT);
508     pHeader->FileAlignment = VAL32(m_FileAlignment);
509
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);
513
514     pHeader->MajorSubsystemVersion = pHeader->MajorOperatingSystemVersion;
515     pHeader->MinorSubsystemVersion = pHeader->MinorOperatingSystemVersion;
516
517 #ifdef REDHAWK
518     pHeader->AddressOfEntryPoint = m_entryPointRVA;
519 #endif
520
521     ZapPhysicalSection * pLastPhysicalSection = m_Sections[m_Sections.GetCount() - 1];
522     pHeader->SizeOfImage = VAL32(AlignUp(pLastPhysicalSection->GetRVA() + pLastPhysicalSection->m_dwSize, SECTION_ALIGNMENT));
523
524     pHeader->SizeOfHeaders = VAL32(AlignUp(GetSizeOfNTHeaders(), m_FileAlignment));
525
526     pHeader->Subsystem = VAL16(m_Subsystem);
527     pHeader->DllCharacteristics = VAL16(m_DllCharacteristics);
528
529
530     // Different fields between 32-bit and 64-bit
531
532     PIMAGE_DATA_DIRECTORY pDataDirectory;
533
534     if (Is64Bit())
535     {
536         PIMAGE_OPTIONAL_HEADER64 pHeader64 = (PIMAGE_OPTIONAL_HEADER64)pHeader;
537
538         pHeader64->Magic = VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC);
539
540         pHeader64->ImageBase             = VAL64(m_BaseAddress);
541         pHeader64->NumberOfRvaAndSizes   = VAL32(IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
542
543         pHeader64->SizeOfStackReserve = VAL64(m_SizeOfStackReserve);
544         pHeader64->SizeOfStackCommit = VAL64(m_SizeOfStackCommit);
545
546         pDataDirectory = pHeader64->DataDirectory;
547     }
548     else
549     {
550         PIMAGE_OPTIONAL_HEADER32 pHeader32 = (PIMAGE_OPTIONAL_HEADER32)pHeader;
551
552         pHeader32->Magic = VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC);
553
554         pHeader32->ImageBase             = VAL32((ULONG)m_BaseAddress);
555         pHeader32->NumberOfRvaAndSizes   = VAL32(IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
556
557         pHeader32->SizeOfStackReserve = VAL32((ULONG)m_SizeOfStackReserve);
558         pHeader32->SizeOfStackCommit = VAL32((ULONG)m_SizeOfStackCommit);
559
560         pDataDirectory = pHeader32->DataDirectory;
561     }
562
563     for (int i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
564     {
565         SetDirectoryData(&pDataDirectory[i], m_DirectoryEntries[i]);
566     }
567
568     Write(&optionalHeader, Is64Bit() ? sizeof(IMAGE_OPTIONAL_HEADER64) : sizeof(IMAGE_OPTIONAL_HEADER32));
569 }
570
571 void ZapWriter::SaveSections()
572 {
573     for (COUNT_T iPhysicalSection = 0; iPhysicalSection < m_Sections.GetCount(); iPhysicalSection++)
574     {
575         ZapPhysicalSection * pPhysicalSection = m_Sections[iPhysicalSection];
576
577         // Do not save empty sections
578         if (pPhysicalSection->m_dwSize == 0)
579             continue;
580
581         IMAGE_SECTION_HEADER header;
582         ZeroMemory(&header, sizeof(header));
583
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));
587
588         header.Misc.VirtualSize = VAL32(pPhysicalSection->m_dwSize);
589         header.VirtualAddress = VAL32(pPhysicalSection->GetRVA());
590
591         header.SizeOfRawData = VAL32(AlignUp(pPhysicalSection->m_dwSizeOfRawData, m_FileAlignment));
592
593         if (header.SizeOfRawData != 0)
594             header.PointerToRawData = VAL32(pPhysicalSection->m_dwFilePos);
595
596         header.Characteristics = VAL32(pPhysicalSection->m_dwCharacteristics);
597
598         Write(&header, sizeof(header));
599     }
600 }
601
602 DWORD ZapWriter::GetSizeOfNTHeaders()
603 {
604     return  sizeof(IMAGE_DOS_HEADER) + 0x40 + /* Padding for DOS Header */
605             sizeof(ULONG) +
606             sizeof(IMAGE_FILE_HEADER) +
607             (Is64Bit() ? sizeof(IMAGE_OPTIONAL_HEADER64) : sizeof(IMAGE_OPTIONAL_HEADER32)) +
608             (m_Sections.GetCount() * sizeof(IMAGE_SECTION_HEADER));
609 }
610
611 void ZapWriter::SetDirectoryData(IMAGE_DATA_DIRECTORY * pDir, ZapNode * pZapNode)
612 {
613     DWORD size = (pZapNode != NULL) ? pZapNode->GetSize() : 0;
614
615     if (size != 0)
616     {
617         pDir->VirtualAddress = pZapNode->GetRVA();
618         pDir->Size = size;
619     }
620     else
621     {
622         pDir->VirtualAddress = 0;
623         pDir->Size = 0;
624     }
625 }
626
627 //---------------------------------------------------------------------------------------
628 // ZapBlob
629
630 ZapBlob * ZapBlob::NewBlob(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize)
631 {
632     S_SIZE_T cbAllocSize = S_SIZE_T(sizeof(ZapBlob)) + S_SIZE_T(cbSize);
633     if(cbAllocSize.IsOverflow())
634         ThrowHR(COR_E_OVERFLOW);
635
636     void * pMemory = new (pWriter->GetHeap()) BYTE[cbAllocSize.Value()];
637
638     ZapBlob * pZapBlob = new (pMemory) ZapBlob(cbSize);
639     
640     if (pData != NULL)
641         memcpy((void*)(pZapBlob + 1), pData, cbSize);
642
643     return pZapBlob;
644 }
645
646 template <UINT alignment>
647 class ZapAlignedBlobConst : public ZapBlob
648 {
649 protected:
650     ZapAlignedBlobConst(SIZE_T cbSize)
651         : ZapBlob(cbSize)
652     {
653     }
654
655 public:
656     virtual UINT GetAlignment()
657     {
658         return alignment;
659     }
660
661     static ZapBlob * NewBlob(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize)
662     {
663         S_SIZE_T cbAllocSize = S_SIZE_T(sizeof(ZapAlignedBlobConst<alignment>)) + S_SIZE_T(cbSize);
664         if(cbAllocSize.IsOverflow())
665             ThrowHR(COR_E_OVERFLOW);
666         
667         void * pMemory = new (pWriter->GetHeap()) BYTE[cbAllocSize.Value()];
668
669         ZapAlignedBlobConst<alignment> * pZapBlob = new (pMemory) ZapAlignedBlobConst<alignment>(cbSize);
670
671         if (pData != NULL)
672             memcpy((void *)(pZapBlob + 1), pData, cbSize);
673
674         return pZapBlob;
675     }
676 };
677
678 ZapBlob * ZapBlob::NewAlignedBlob(ZapWriter * pWriter, PVOID pData, SIZE_T cbSize, SIZE_T cbAlignment)
679 {
680     switch (cbAlignment)
681     {
682     case 4:
683         return ZapAlignedBlobConst<4>::NewBlob(pWriter, pData, cbSize);
684     case 8:
685         return ZapAlignedBlobConst<8>::NewBlob(pWriter, pData, cbSize);
686     case 16:
687         return ZapAlignedBlobConst<16>::NewBlob(pWriter, pData, cbSize);
688
689     default:
690         _ASSERTE(!"Requested alignment not supported");
691         return NULL;
692     }
693 }
694
695 void ZapBlob::Save(ZapWriter * pZapWriter)
696 {
697     pZapWriter->Write(GetData(), GetSize());
698 }