2 Copyright (C) 2008-2011 Jeroen Frijters
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
25 using System.Diagnostics;
27 using System.Collections.Generic;
29 using IKVM.Reflection.Emit;
30 using IKVM.Reflection.Impl;
31 using IKVM.Reflection.Metadata;
33 namespace IKVM.Reflection.Writer
35 sealed class TextSection
37 private readonly PEWriter peWriter;
38 private readonly CliHeader cliHeader;
39 private readonly ModuleBuilder moduleBuilder;
40 private readonly uint strongNameSignatureLength;
41 private readonly ExportTables exportTables;
43 internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder, int strongNameSignatureLength)
45 this.peWriter = peWriter;
46 this.cliHeader = cliHeader;
47 this.moduleBuilder = moduleBuilder;
48 this.strongNameSignatureLength = (uint)strongNameSignatureLength;
49 if (moduleBuilder.unmanagedExports.Count != 0)
51 this.exportTables = new ExportTables(this);
55 internal uint PointerToRawData
57 get { return peWriter.ToFileAlignment(peWriter.HeaderSize); }
62 get { return 0x2000; }
65 internal uint ImportAddressTableRVA
67 get { return BaseRVA; }
70 internal uint ImportAddressTableLength
74 switch (peWriter.Headers.FileHeader.Machine)
76 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
78 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM:
86 internal uint ComDescriptorRVA
88 get { return ImportAddressTableRVA + ImportAddressTableLength; }
91 internal uint ComDescriptorLength
93 get { return cliHeader.Cb; }
96 internal uint MethodBodiesRVA
98 get { return (ComDescriptorRVA + ComDescriptorLength + 7) & ~7U; }
101 private uint MethodBodiesLength
103 get { return (uint)moduleBuilder.methodBodies.Length; }
106 private uint ResourcesRVA
110 switch (peWriter.Headers.FileHeader.Machine)
112 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
113 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM:
114 return (MethodBodiesRVA + MethodBodiesLength + 3) & ~3U;
116 return (MethodBodiesRVA + MethodBodiesLength + 15) & ~15U;
121 private uint ResourcesLength
123 get { return (uint)moduleBuilder.manifestResources.Length; }
126 internal uint StrongNameSignatureRVA
130 return (ResourcesRVA + ResourcesLength + 3) & ~3U;
134 internal uint StrongNameSignatureLength
138 return strongNameSignatureLength;
142 private uint MetadataRVA
146 return (StrongNameSignatureRVA + StrongNameSignatureLength + 3) & ~3U;
150 private uint MetadataLength
152 get { return (uint)moduleBuilder.MetadataLength; }
155 private uint VTableFixupsRVA
157 get { return (MetadataRVA + MetadataLength + 7) & ~7U; }
160 private uint VTableFixupsLength
162 get { return (uint)moduleBuilder.vtablefixups.Count * 8; }
165 internal uint DebugDirectoryRVA
167 get { return VTableFixupsRVA + VTableFixupsLength; }
170 internal uint DebugDirectoryLength
174 if (DebugDirectoryContentsLength != 0)
182 private uint DebugDirectoryContentsLength
186 if (moduleBuilder.symbolWriter != null)
188 IMAGE_DEBUG_DIRECTORY idd = new IMAGE_DEBUG_DIRECTORY();
189 return (uint)SymbolSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd).Length;
195 internal uint ExportDirectoryRVA
197 get { return (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength + 15) & ~15U; }
200 internal uint ExportDirectoryLength
202 get { return moduleBuilder.unmanagedExports.Count == 0 ? 0U : 40U; }
205 private uint ExportTablesRVA
207 get { return ExportDirectoryRVA + ExportDirectoryLength; }
210 private uint ExportTablesLength
212 get { return exportTables == null ? 0U : exportTables.Length; }
215 internal uint ImportDirectoryRVA
217 // on AMD64 (and probably IA64) the import directory needs to be 16 byte aligned (on I386 4 byte alignment is sufficient)
218 get { return (ExportTablesRVA + ExportTablesLength + 15) & ~15U; }
221 internal uint ImportDirectoryLength
225 switch (peWriter.Headers.FileHeader.Machine)
227 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM:
230 return (ImportHintNameTableRVA - ImportDirectoryRVA) + 27;
235 private uint ImportHintNameTableRVA
239 if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
241 return (ImportDirectoryRVA + 48 + 15) & ~15U;
245 return (ImportDirectoryRVA + 48 + 4 + 15) & ~15U;
250 internal uint StartupStubRVA
254 if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
256 // note that the alignment is driven by the requirement that the two relocation fixups are in a single page
257 return (ImportDirectoryRVA + ImportDirectoryLength + 15U) & ~15U;
261 // the additional 2 bytes padding are to align the address in the jump (which is a relocation fixup)
262 return 2 + ((ImportDirectoryRVA + ImportDirectoryLength + 3U) & ~3U);
267 internal uint StartupStubLength
271 switch (peWriter.Headers.FileHeader.Machine)
273 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
275 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
277 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64:
285 private void WriteRVA(MetadataWriter mw, uint rva)
287 switch (peWriter.Headers.FileHeader.Machine)
289 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
290 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM:
294 mw.Write((ulong)rva);
299 internal void Write(MetadataWriter mw, uint sdataRVA)
301 // Now that we're ready to start writing, we need to do some fix ups
302 moduleBuilder.TypeRef.Fixup(moduleBuilder);
303 moduleBuilder.MethodDef.Fixup(this);
304 moduleBuilder.MethodImpl.Fixup(moduleBuilder);
305 moduleBuilder.MethodSemantics.Fixup(moduleBuilder);
306 moduleBuilder.InterfaceImpl.Fixup();
307 moduleBuilder.ResolveInterfaceImplPseudoTokens();
308 moduleBuilder.MemberRef.Fixup(moduleBuilder);
309 moduleBuilder.Constant.Fixup(moduleBuilder);
310 moduleBuilder.FieldMarshal.Fixup(moduleBuilder);
311 moduleBuilder.DeclSecurity.Fixup(moduleBuilder);
312 moduleBuilder.GenericParam.Fixup(moduleBuilder);
313 moduleBuilder.CustomAttribute.Fixup(moduleBuilder);
314 moduleBuilder.FieldLayout.Fixup(moduleBuilder);
315 moduleBuilder.FieldRVA.Fixup(moduleBuilder, (int)sdataRVA, (int)this.MethodBodiesRVA);
316 moduleBuilder.ImplMap.Fixup(moduleBuilder);
317 moduleBuilder.ExportedType.Fixup(moduleBuilder);
318 moduleBuilder.ManifestResource.Fixup(moduleBuilder);
319 moduleBuilder.MethodSpec.Fixup(moduleBuilder);
320 moduleBuilder.GenericParamConstraint.Fixup(moduleBuilder);
322 // Import Address Table
323 AssertRVA(mw, ImportAddressTableRVA);
324 if (ImportAddressTableLength != 0)
326 WriteRVA(mw, ImportHintNameTableRVA);
331 AssertRVA(mw, ComDescriptorRVA);
332 cliHeader.MetaData.VirtualAddress = MetadataRVA;
333 cliHeader.MetaData.Size = MetadataLength;
334 if (ResourcesLength != 0)
336 cliHeader.Resources.VirtualAddress = ResourcesRVA;
337 cliHeader.Resources.Size = ResourcesLength;
339 if (StrongNameSignatureLength != 0)
341 cliHeader.StrongNameSignature.VirtualAddress = StrongNameSignatureRVA;
342 cliHeader.StrongNameSignature.Size = StrongNameSignatureLength;
344 if (VTableFixupsLength != 0)
346 cliHeader.VTableFixups.VirtualAddress = VTableFixupsRVA;
347 cliHeader.VTableFixups.Size = VTableFixupsLength;
352 for (int i = (int)(MethodBodiesRVA - (ComDescriptorRVA + ComDescriptorLength)); i > 0; i--)
358 mw.Write(moduleBuilder.methodBodies);
361 for (int i = (int)(ResourcesRVA - (MethodBodiesRVA + MethodBodiesLength)); i > 0; i--)
367 mw.Write(moduleBuilder.manifestResources);
369 // The strong name signature live here (if it exists), but it will written later
370 // and the following alignment padding will take care of reserving the space.
373 for (int i = (int)(MetadataRVA - (ResourcesRVA + ResourcesLength)); i > 0; i--)
379 AssertRVA(mw, MetadataRVA);
380 moduleBuilder.WriteMetadata(mw);
383 for (int i = (int)(VTableFixupsRVA - (MetadataRVA + MetadataLength)); i > 0; i--)
389 AssertRVA(mw, VTableFixupsRVA);
390 WriteVTableFixups(mw, sdataRVA);
393 AssertRVA(mw, DebugDirectoryRVA);
394 WriteDebugDirectory(mw);
397 for (int i = (int)(ExportDirectoryRVA - (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength)); i > 0; i--)
403 AssertRVA(mw, ExportDirectoryRVA);
404 WriteExportDirectory(mw);
407 AssertRVA(mw, ExportTablesRVA);
408 WriteExportTables(mw, sdataRVA);
411 for (int i = (int)(ImportDirectoryRVA - (ExportTablesRVA + ExportTablesLength)); i > 0; i--)
417 AssertRVA(mw, ImportDirectoryRVA);
418 if (ImportDirectoryLength != 0)
420 WriteImportDirectory(mw);
424 for (int i = (int)(StartupStubRVA - (ImportDirectoryRVA + ImportDirectoryLength)); i > 0; i--)
430 AssertRVA(mw, StartupStubRVA);
431 if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64)
434 * 48 A1 00 20 40 00 00 00 00 00 mov rax,qword ptr [0000000000402000h]
437 mw.Write((ushort)0xA148);
438 mw.Write(peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA);
439 mw.Write((ushort)0xE0FF);
441 else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
443 mw.Write(new byte[] {
444 0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40, 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00,
445 0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50, 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00
447 mw.Write(peWriter.Headers.OptionalHeader.ImageBase + StartupStubRVA);
448 mw.Write(peWriter.Headers.OptionalHeader.ImageBase + BaseRVA);
450 else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
452 mw.Write((ushort)0x25FF);
453 mw.Write((uint)peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA);
457 [Conditional("DEBUG")]
458 private void AssertRVA(MetadataWriter mw, uint rva)
460 Debug.Assert(mw.Position - PointerToRawData + BaseRVA == rva);
463 private void WriteVTableFixups(MetadataWriter mw, uint sdataRVA)
465 foreach (ModuleBuilder.VTableFixups fixups in moduleBuilder.vtablefixups)
467 mw.Write(fixups.initializedDataOffset + sdataRVA);
468 mw.Write(fixups.count);
469 mw.Write(fixups.type);
473 private void WriteDebugDirectory(MetadataWriter mw)
475 if (DebugDirectoryLength != 0)
477 IMAGE_DEBUG_DIRECTORY idd = new IMAGE_DEBUG_DIRECTORY();
478 idd.Characteristics = 0;
479 idd.TimeDateStamp = peWriter.Headers.FileHeader.TimeDateStamp;
480 byte[] buf = SymbolSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd);
481 idd.PointerToRawData = (DebugDirectoryRVA - BaseRVA) + DebugDirectoryLength + PointerToRawData;
482 mw.Write(idd.Characteristics);
483 mw.Write(idd.TimeDateStamp);
484 mw.Write(idd.MajorVersion);
485 mw.Write(idd.MinorVersion);
487 mw.Write(idd.SizeOfData);
488 mw.Write(idd.AddressOfRawData);
489 mw.Write(idd.PointerToRawData);
494 private sealed class ExportTables
496 private readonly TextSection text;
497 internal readonly uint entries;
498 internal readonly uint ordinalBase;
499 internal readonly uint nameCount;
500 internal readonly uint namesLength;
501 internal readonly uint exportAddressTableRVA;
502 internal readonly uint exportNamePointerTableRVA;
503 internal readonly uint exportOrdinalTableRVA;
504 internal readonly uint namesRVA;
505 internal readonly uint stubsRVA;
506 private readonly uint stubLength;
508 internal ExportTables(TextSection text)
511 ordinalBase = GetOrdinalBase(out entries);
512 namesLength = GetExportNamesLength(out nameCount);
513 exportAddressTableRVA = text.ExportTablesRVA;
514 exportNamePointerTableRVA = exportAddressTableRVA + 4 * entries;
515 exportOrdinalTableRVA = exportNamePointerTableRVA + 4 * nameCount;
516 namesRVA = exportOrdinalTableRVA + 2 * nameCount;
517 stubsRVA = (namesRVA + namesLength + 15) & ~15U;
518 // note that we align the stubs to avoid having to deal with the relocation crossing a page boundary
519 switch (text.peWriter.Headers.FileHeader.Machine)
521 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
524 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
528 throw new NotImplementedException();
534 get { return (stubsRVA + stubLength * (uint)text.moduleBuilder.unmanagedExports.Count) - text.ExportTablesRVA; }
537 private uint GetOrdinalBase(out uint entries)
539 uint min = uint.MaxValue;
540 uint max = uint.MinValue;
541 foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
543 uint ordinal = (uint)exp.ordinal;
544 min = Math.Min(min, ordinal);
545 max = Math.Max(max, ordinal);
547 entries = 1 + (max - min);
551 private uint GetExportNamesLength(out uint nameCount)
554 // the first name in the names list is the module name (the Export Directory contains a name of the current module)
555 uint length = (uint)text.moduleBuilder.fileName.Length + 1;
556 foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
558 if (exp.name != null)
561 length += (uint)exp.name.Length + 1;
567 internal void Write(MetadataWriter mw, uint sdataRVA)
569 // sort the exports by ordinal
570 text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportOrdinals);
572 // Now write the Export Address Table
573 text.AssertRVA(mw, exportAddressTableRVA);
574 for (int i = 0, pos = 0; i < entries; i++)
576 if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase)
578 mw.Write(stubsRVA + (uint)pos * stubLength);
587 // sort the exports by name
588 text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportNames);
590 // Now write the Export Name Pointer Table
591 text.AssertRVA(mw, exportNamePointerTableRVA);
592 uint nameOffset = (uint)text.moduleBuilder.fileName.Length + 1;
593 foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
595 if (exp.name != null)
597 mw.Write(namesRVA + nameOffset);
598 nameOffset += (uint)exp.name.Length + 1;
602 // Now write the Export Ordinal Table
603 text.AssertRVA(mw, exportOrdinalTableRVA);
604 foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
606 if (exp.name != null)
608 mw.Write((ushort)(exp.ordinal - ordinalBase));
612 // Now write the actual names
613 text.AssertRVA(mw, namesRVA);
614 mw.Write(Encoding.ASCII.GetBytes(text.moduleBuilder.fileName));
616 foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
618 if (exp.name != null)
620 mw.Write(Encoding.ASCII.GetBytes(exp.name));
624 text.AssertRVA(mw, namesRVA + namesLength);
627 for (int i = (int)(stubsRVA - (namesRVA + namesLength)); i > 0; i--)
632 // sort the exports by ordinal
633 text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportOrdinals);
635 // Now write the stubs
636 text.AssertRVA(mw, stubsRVA);
638 for (int i = 0, pos = 0; i < entries; i++)
640 if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase)
642 switch (text.peWriter.Headers.FileHeader.Machine)
644 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
645 mw.Write((byte)0xFF);
646 mw.Write((byte)0x25);
647 mw.Write((uint)text.peWriter.Headers.OptionalHeader.ImageBase + text.moduleBuilder.unmanagedExports[pos].rva.initializedDataOffset + sdataRVA);
648 mw.Write((short)0); // alignment
650 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
651 mw.Write((byte)0x48);
652 mw.Write((byte)0xA1);
653 mw.Write(text.peWriter.Headers.OptionalHeader.ImageBase + text.moduleBuilder.unmanagedExports[pos].rva.initializedDataOffset + sdataRVA);
654 mw.Write((byte)0xFF);
655 mw.Write((byte)0xE0);
656 mw.Write(0); // alignment
659 throw new NotImplementedException();
666 private static int CompareUnmanagedExportNames(UnmanagedExport x, UnmanagedExport y)
670 return y.name == null ? 0 : 1;
676 return x.name.CompareTo(y.name);
679 private static int CompareUnmanagedExportOrdinals(UnmanagedExport x, UnmanagedExport y)
681 return x.ordinal.CompareTo(y.ordinal);
684 internal void WriteRelocations(MetadataWriter mw)
686 // we assume that unmanagedExports is still sorted by ordinal
687 for (int i = 0, pos = 0; i < entries; i++)
689 if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase)
691 // both I386 and AMD64 have the address at offset 2
692 text.WriteRelocationBlock(mw, stubsRVA + 2 + (uint)pos * stubLength);
699 private uint GetOrdinalBase(out uint entries)
701 uint min = uint.MaxValue;
702 uint max = uint.MinValue;
703 foreach (UnmanagedExport exp in moduleBuilder.unmanagedExports)
705 uint ordinal = (uint)exp.ordinal;
706 min = Math.Min(min, ordinal);
707 max = Math.Max(max, ordinal);
709 entries = 1 + (max - min);
713 private uint GetExportNamesLength(out uint nameCount)
717 foreach (UnmanagedExport exp in moduleBuilder.unmanagedExports)
719 if (exp.name != null)
722 length += (uint)exp.name.Length + 1;
728 private void WriteExportDirectory(MetadataWriter mw)
730 if (ExportDirectoryLength != 0)
735 mw.Write(peWriter.Headers.FileHeader.TimeDateStamp);
741 mw.Write(exportTables.namesRVA);
743 mw.Write(exportTables.ordinalBase);
744 // Address Table Entries
745 mw.Write(exportTables.entries);
746 // Number of Name Pointers
747 mw.Write(exportTables.nameCount);
748 // Export Address Table RVA
749 mw.Write(exportTables.exportAddressTableRVA);
751 mw.Write(exportTables.exportNamePointerTableRVA);
753 mw.Write(exportTables.exportOrdinalTableRVA);
757 private void WriteExportTables(MetadataWriter mw, uint sdataRVA)
759 if (exportTables != null)
761 exportTables.Write(mw, sdataRVA);
765 private void WriteImportDirectory(MetadataWriter mw)
767 mw.Write(ImportDirectoryRVA + 40); // ImportLookupTable
768 mw.Write(0); // DateTimeStamp
769 mw.Write(0); // ForwarderChain
770 mw.Write(ImportHintNameTableRVA + 14); // Name
771 mw.Write(ImportAddressTableRVA);
772 mw.Write(new byte[20]);
773 // Import Lookup Table
774 mw.Write(ImportHintNameTableRVA); // Hint/Name Table RVA
776 if (peWriter.Headers.FileHeader.Machine != IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
784 for (int i = (int)(ImportHintNameTableRVA - (ImportDirectoryRVA + size)); i > 0; i--)
790 AssertRVA(mw, ImportHintNameTableRVA);
791 mw.Write((ushort)0); // Hint
792 if ((peWriter.Headers.FileHeader.Characteristics & IMAGE_FILE_HEADER.IMAGE_FILE_DLL) != 0)
794 mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorDllMain"));
798 mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorExeMain"));
802 mw.Write(System.Text.Encoding.ASCII.GetBytes("mscoree.dll"));
808 get { return (int)(StartupStubRVA - BaseRVA + StartupStubLength); }
811 internal void WriteRelocations(MetadataWriter mw)
813 uint relocAddress = this.StartupStubRVA;
814 switch (peWriter.Headers.FileHeader.Machine)
816 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
817 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
820 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64:
821 relocAddress += 0x20;
824 WriteRelocationBlock(mw, relocAddress);
825 if (exportTables != null)
827 exportTables.WriteRelocations(mw);
831 // note that we're lazy and write a new relocation block for every relocation
832 // even if they are in the same page (since there is typically only one anyway)
833 private void WriteRelocationBlock(MetadataWriter mw, uint relocAddress)
835 uint pageRVA = relocAddress & ~0xFFFU;
836 mw.Write(pageRVA); // PageRVA
837 mw.Write(0x000C); // Block Size
838 switch (peWriter.Headers.FileHeader.Machine)
840 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
841 mw.Write(0x3000 + relocAddress - pageRVA); // Type / Offset
843 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
844 mw.Write(0xA000 + relocAddress - pageRVA); // Type / Offset
846 case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64:
847 // on IA64 the StartupStubRVA is 16 byte aligned, so these two addresses won't cross a page boundary
848 mw.Write((short)(0xA000 + relocAddress - pageRVA)); // Type / Offset
849 mw.Write((short)(0xA000 + relocAddress - pageRVA + 8)); // Type / Offset