JIT: Fix bug in finally cloning caused by unsound callfinally reordering
[platform/upstream/coreclr.git] / src / zap / zapheaders.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 // 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
26 void 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 //
58 void 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.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);
129
130     Write(&nativeHeader, sizeof(nativeHeader));
131 }
132
133 //
134 // CORCOMPILE_CODE_MANAGER_ENTRY
135 //
136 void ZapImage::SaveCodeManagerEntry()
137 {
138     CORCOMPILE_CODE_MANAGER_ENTRY codeManagerEntry;
139
140     ZeroMemory(&codeManagerEntry, sizeof(codeManagerEntry));
141
142     SetDirectoryData(&codeManagerEntry.HotCode, m_pHotCodeSection);
143     SetDirectoryData(&codeManagerEntry.Code, m_pCodeSection);
144     SetDirectoryData(&codeManagerEntry.ColdCode, m_pColdCodeSection);
145
146     SetDirectoryData(&codeManagerEntry.ROData, m_pReadOnlyDataSection);
147
148     //
149     //Initialize additional sections for diagnostics
150     //
151
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();
154
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();
157
158     COUNT_T i;
159     for (i = m_iUntrainedMethod; i < m_MethodCompilationOrder.GetCount(); i++)
160     {
161         ZapNode * pColdCode = m_MethodCompilationOrder[i]->GetColdCode();
162         if (pColdCode != NULL)
163         {
164             codeManagerEntry.ColdUntrainedMethodOffset = pColdCode->GetRVA() - m_pColdCodeSection->GetRVA();
165             break;
166         }
167     }
168     if (i == m_MethodCompilationOrder.GetCount())
169         codeManagerEntry.ColdUntrainedMethodOffset = m_pColdCodeSection->GetSize();
170
171
172     if (m_stats)
173     {
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);
180 #undef ACCUM_SIZE
181         m_stats->m_totalColdCodeSizeInProfiledMethods = codeManagerEntry.ColdUntrainedMethodOffset;
182     }
183
184     Write(&codeManagerEntry, sizeof(codeManagerEntry));
185 }
186
187 //
188 // Version Resource
189 //
190
191 // Needed for RT_VERSION.
192 #define MAKEINTRESOURCE(v) MAKEINTRESOURCEW(v)
193
194 void ZapVersionResource::Save(ZapWriter * pZapWriter)
195 {
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.
199
200     // See vctools\link\doc\pecoff.doc for detailed documentation of PE format.
201
202     VersionResourceHeader header;
203
204     ZeroMemory(&header, sizeof(header));
205
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;
210
211     header.NameDir.NumberOfIdEntries = 1;
212     header.NameEntry.Id = 1;
213     header.NameEntry.OffsetToDirectory = offsetof(VersionResourceHeader, LangDir);
214     header.NameEntry.DataIsDirectory = 1;
215
216     header.LangDir.NumberOfIdEntries = 1;
217     header.LangEntry.OffsetToDirectory = offsetof(VersionResourceHeader, DataEntry);
218
219     header.DataEntry.OffsetToData = m_pVersionData->GetRVA();
220     header.DataEntry.Size = m_pVersionData->GetSize();
221
222     pZapWriter->Write(&header, sizeof(header));
223 }
224
225 void ZapImage::CopyWin32VersionResource()
226 {
227 #ifndef FEATURE_PAL
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);
231
232     if (!pResourceData || !cbResourceData)
233         return;
234
235     ZapBlob * pVersionData = new (GetHeap()) ZapBlobPtr(pResourceData, cbResourceData);
236
237     ZapVersionResource * pVersionResource = new (GetHeap()) ZapVersionResource(pVersionData);
238
239     m_pWin32ResourceSection->Place(pVersionResource);
240     m_pWin32ResourceSection->Place(pVersionData);
241
242     SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE, m_pWin32ResourceSection);
243 #endif
244 }
245 #undef MAKEINTRESOURCE
246
247
248 //
249 // Debug Directory
250 //
251
252 void ZapDebugDirectory::SaveOriginalDebugDirectoryEntry(ZapWriter *pZapWriter)
253 {
254     if (m_ppDebugData != nullptr)
255     {
256         for (DWORD i = 0; i < m_nDebugDirectory; i++)
257         {
258             if (m_ppDebugData[i] != nullptr)
259             {
260                 m_pDebugDirectory[i].SizeOfData = m_ppDebugData[i]->GetSize();
261                 m_pDebugDirectory[i].AddressOfRawData = m_ppDebugData[i]->GetRVA();
262
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;
265
266                 DWORD dwOffset = m_ppDebugData[i]->GetRVA() - pPhysicalSection->GetRVA();
267                 _ASSERTE(dwOffset < pPhysicalSection->GetSize());
268
269                 m_pDebugDirectory[i].PointerToRawData = pPhysicalSection->GetFilePos() + dwOffset;
270             }
271             else
272             {
273                 m_pDebugDirectory[i].SizeOfData = 0;
274                 m_pDebugDirectory[i].AddressOfRawData = 0;
275                 m_pDebugDirectory[i].PointerToRawData = 0;
276             }
277         }
278
279         pZapWriter->Write(m_pDebugDirectory, sizeof(IMAGE_DEBUG_DIRECTORY) * m_nDebugDirectory);
280     }
281 }
282
283 void ZapDebugDirectory::SaveNGenDebugDirectoryEntry(ZapWriter *pZapWriter)
284 {
285 #if !defined(NO_NGENPDB)
286     _ASSERTE(pZapWriter);
287
288     IMAGE_DEBUG_DIRECTORY debugDirectory = {0};
289     if (m_nDebugDirectory > 0)
290     {
291         memcpy(&debugDirectory, m_pDebugDirectory, sizeof(IMAGE_DEBUG_DIRECTORY));
292     }
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;
300     {
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;
305     }
306     pZapWriter->Write(&debugDirectory, sizeof(debugDirectory));
307 #endif // NO_NGENPDB
308 }
309
310 void ZapDebugDirectory::Save(ZapWriter * pZapWriter)
311 {
312     _ASSERTE(pZapWriter);
313
314     if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_NGenEnableCreatePdb)) {
315         SaveOriginalDebugDirectoryEntry(pZapWriter);
316         SaveNGenDebugDirectoryEntry(pZapWriter);
317     } else {
318         SaveNGenDebugDirectoryEntry(pZapWriter);
319         SaveOriginalDebugDirectoryEntry(pZapWriter);
320     }
321 }
322
323 ZapPEExports::ZapPEExports(LPCWSTR dllPath) 
324 {
325         m_dllFileName = wcsrchr(dllPath, DIRECTORY_SEPARATOR_CHAR_W);
326         if (m_dllFileName != NULL)
327                 m_dllFileName++;
328         else 
329                 m_dllFileName = dllPath;
330 }
331
332 DWORD ZapPEExports::GetSize()
333 {
334         return DWORD(sizeof(IMAGE_EXPORT_DIRECTORY) + wcslen(m_dllFileName) * sizeof(BYTE) + 1);
335 }
336
337 void ZapPEExports::Save(ZapWriter * pZapWriter)
338 {
339         _ASSERTE(pZapWriter);
340
341         IMAGE_EXPORT_DIRECTORY exports;
342         ZeroMemory(&exports, sizeof(exports));
343
344         exports.Name = pZapWriter->GetCurrentRVA() + sizeof(exports);
345
346         // Write out exports header 
347         pZapWriter->Write(&exports, sizeof(exports));
348
349         // Write out string that exports.Name points at.  
350         for (LPCWSTR ptr = m_dllFileName; ; ptr++)
351         {
352                 pZapWriter->Write((PVOID) ptr, 1);
353                 if (*ptr == 0)
354                         break;
355         }
356 }
357
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
361 // the IL image.
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
365 // is not an option.
366
367 void ZapImage::CopyDebugDirEntry()
368 {
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.
371     {
372         // This entry is initially empty. It is filled in ZapImage::GenerateFile.
373         RSDS rsds = {0};
374         m_pNGenPdbDebugData = ZapBlob::NewBlob(static_cast<ZapWriter *>(this), &rsds, sizeof rsds);
375     }
376
377     // IL PDB entry: copy of the (first of possibly many) IMAGE_DEBUG_DIRECTORY entry 
378     // in the IL image
379     DWORD nDebugEntry = 0;
380     PIMAGE_DEBUG_DIRECTORY pDebugDir = NULL;
381     ZapNode **ppDebugData = NULL;
382
383     if (m_ModuleDecoder.HasDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG)) {
384         COUNT_T debugEntrySize;
385         TADDR pDebugEntry = m_ModuleDecoder.GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_DEBUG, &debugEntrySize);
386
387         if (debugEntrySize != 0) {
388
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));
392             } else {
393                 
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)));
397                 
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*));
403                 
404                 for (DWORD i = 0; i < nDebugEntry; i++)
405                 {
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
408
409                     RVA rvaOfRawData = (pDebugDir[i].AddressOfRawData != NULL)
410                         ? pDebugDir[i].AddressOfRawData : m_ModuleDecoder.OffsetToRva(pDebugDir[i].PointerToRawData);
411
412                     ULONG cbDebugData = pDebugDir[i].SizeOfData;
413
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"));
417                         else
418                             ppDebugData[i] = new (GetHeap()) ZapBlobPtr((PVOID)m_ModuleDecoder.GetRvaData(rvaOfRawData), cbDebugData);
419                     }
420                 }
421             }
422         }
423     }
424
425     ZapDebugDirectory * pDebugDirectory = new (GetHeap()) ZapDebugDirectory(m_pNGenPdbDebugData, 
426                                                                             nDebugEntry,
427                                                                             pDebugDir,
428                                                                             ppDebugData);
429
430     m_pDebugSection->Place(pDebugDirectory);
431     m_pDebugSection->Place(m_pNGenPdbDebugData);
432     if (ppDebugData)
433     {
434         for (DWORD i = 0; i < nDebugEntry; i++)
435         {
436             if (ppDebugData[i] != nullptr)
437                 m_pDebugSection->Place(ppDebugData[i]);
438         }
439     }
440
441     SetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG, pDebugDirectory);
442 }
443
444 DWORD ZapVirtualSectionsTable::GetSize()
445 {
446     DWORD nSectionInfos = 0;
447
448     COUNT_T nPhysicalSections = m_pImage->GetPhysicalSectionCount();
449     for (COUNT_T iPhysicalSection = 0; iPhysicalSection < nPhysicalSections; iPhysicalSection++)
450     {
451         ZapPhysicalSection * pPhysicalSection = m_pImage->GetPhysicalSection(iPhysicalSection);
452
453         DWORD dwPreviousType = 0;
454
455         COUNT_T nVirtualSections = pPhysicalSection->GetVirtualSectionCount();
456         for (COUNT_T iVirtualSection = 0; iVirtualSection < nVirtualSections; iVirtualSection++)
457         {
458             ZapVirtualSection * pVirtualSection = pPhysicalSection->GetVirtualSection(iVirtualSection);
459
460             if (pVirtualSection->GetNodeCount() == 0)
461                 continue;
462
463             DWORD dwSectionType = pVirtualSection->GetSectionType();
464             if (dwSectionType == 0)
465                 continue;
466
467             // Fold sections with the same type together
468             if (dwPreviousType != dwSectionType)
469             {
470                 dwPreviousType = dwSectionType;
471                 nSectionInfos++;
472             }
473         }
474     }
475
476     return nSectionInfos * sizeof(CORCOMPILE_VIRTUAL_SECTION_INFO);
477 }
478
479 void ZapVirtualSectionsTable::Save(ZapWriter * pZapWriter)
480 {
481     COUNT_T nPhysicalSections = m_pImage->GetPhysicalSectionCount();
482     for (COUNT_T iPhysicalSection = 0; iPhysicalSection < nPhysicalSections; iPhysicalSection++)
483     {
484         ZapPhysicalSection * pPhysicalSection = m_pImage->GetPhysicalSection(iPhysicalSection);
485
486         CORCOMPILE_VIRTUAL_SECTION_INFO sectionInfo;
487
488         sectionInfo.SectionType = 0;
489
490         COUNT_T nVirtualSections = pPhysicalSection->GetVirtualSectionCount();
491         for (COUNT_T iVirtualSection = 0; iVirtualSection < nVirtualSections; iVirtualSection++)
492         {
493             ZapVirtualSection * pVirtualSection = pPhysicalSection->GetVirtualSection(iVirtualSection);
494
495             if (pVirtualSection->GetNodeCount() == 0)
496                 continue;
497
498             DWORD dwSectionType = pVirtualSection->GetSectionType();
499             if (dwSectionType == 0)
500                 continue;
501
502             // Fold sections with the same type together
503             if (sectionInfo.SectionType != dwSectionType)
504             {
505                 if (sectionInfo.SectionType != 0)
506                 {
507                     pZapWriter->Write(&sectionInfo, sizeof(sectionInfo));
508                 }
509
510                 sectionInfo.SectionType = dwSectionType;
511                 sectionInfo.VirtualAddress = pVirtualSection->GetRVA();
512             }
513
514             // Update section size
515             sectionInfo.Size = (pVirtualSection->GetRVA() + pVirtualSection->GetSize()) - sectionInfo.VirtualAddress;
516         }
517
518         if (sectionInfo.SectionType != 0)
519         {
520             pZapWriter->Write(&sectionInfo, sizeof(sectionInfo));
521         }
522     }
523 }