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 = 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 = 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::() |
427 | { |
428 | SaveDosHeader(); |
429 | SaveSignature(); |
430 | SaveFileHeader(); |
431 | SaveOptionalHeader(); |
432 | SaveSections(); |
433 | } |
434 | |
435 | void ZapWriter::() |
436 | { |
437 | IMAGE_DOS_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::() |
463 | { |
464 | IMAGE_FILE_HEADER ; |
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::() |
489 | { |
490 | // Write the correct flavor of the optional header |
491 | union |
492 | { |
493 | IMAGE_OPTIONAL_HEADER32 ; |
494 | IMAGE_OPTIONAL_HEADER64 ; |
495 | } |
496 | ; |
497 | |
498 | ZeroMemory(&optionalHeader, sizeof(optionalHeader)); |
499 | |
500 | PIMAGE_OPTIONAL_HEADER = (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 = (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 = (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 ; |
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::() |
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 | } |
699 | |