From 6abc738d3c5bd2468dcdc3e2d9d009dbf0e27376 Mon Sep 17 00:00:00 2001 From: jfrijters Date: Tue, 18 Jan 2011 07:11:23 +0000 Subject: [PATCH] Added support for saving to a stream instead of a file. --- reflect/Emit/AssemblyBuilder.cs | 22 +- reflect/Emit/ModuleBuilder.cs | 16 +- reflect/Writer/ModuleWriter.cs | 479 +++++++++++++++++--------------- 3 files changed, 285 insertions(+), 232 deletions(-) diff --git a/reflect/Emit/AssemblyBuilder.cs b/reflect/Emit/AssemblyBuilder.cs index 9919fd3b..5f2ce743 100644 --- a/reflect/Emit/AssemblyBuilder.cs +++ b/reflect/Emit/AssemblyBuilder.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2008-2010 Jeroen Frijters + Copyright (C) 2008-2011 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -253,12 +253,30 @@ namespace IKVM.Reflection.Emit this.fileKind = fileKind; } + public void __Save(Stream stream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) + { + if (!stream.CanRead || !stream.CanWrite || !stream.CanSeek || stream.Position != 0) + { + throw new ArgumentException("Stream must support read/write/seek and current position must be zero.", "stream"); + } + if (modules.Count != 1) + { + throw new NotSupportedException("Saving to a stream is only supported for single module assemblies."); + } + SaveImpl(modules[0].fileName, stream, portableExecutableKind, imageFileMachine); + } + public void Save(string assemblyFileName) { Save(assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386); } public void Save(string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) + { + SaveImpl(assemblyFileName, null, portableExecutableKind, imageFileMachine); + } + + private void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) { ModuleBuilder manifestModule = null; @@ -398,7 +416,7 @@ namespace IKVM.Reflection.Emit } // finally, write the manifest module - ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, unmanagedResources ?? manifestModule.unmanagedResources, entryPointToken); + ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, unmanagedResources ?? manifestModule.unmanagedResources, entryPointToken, streamOrNull); } private int AddFile(ModuleBuilder manifestModule, string fileName, int flags) diff --git a/reflect/Emit/ModuleBuilder.cs b/reflect/Emit/ModuleBuilder.cs index 04937b5f..ada466b3 100644 --- a/reflect/Emit/ModuleBuilder.cs +++ b/reflect/Emit/ModuleBuilder.cs @@ -1185,6 +1185,20 @@ namespace IKVM.Reflection.Emit } public void __Save(PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) + { + SaveImpl(null, portableExecutableKind, imageFileMachine); + } + + public void __Save(Stream stream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) + { + if (!stream.CanRead || !stream.CanWrite || !stream.CanSeek || stream.Position != 0) + { + throw new ArgumentException("Stream must support read/write/seek and current position must be zero.", "stream"); + } + SaveImpl(stream, portableExecutableKind, imageFileMachine); + } + + private void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) { PopulatePropertyAndEventTables(); IList attributes = asm.GetCustomAttributesData(null); @@ -1224,7 +1238,7 @@ namespace IKVM.Reflection.Emit } } FillAssemblyRefTable(); - ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, 0); + ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, 0, streamOrNull); } public void __AddAssemblyReference(AssemblyName assemblyName) diff --git a/reflect/Writer/ModuleWriter.cs b/reflect/Writer/ModuleWriter.cs index c4208f8f..12146821 100644 --- a/reflect/Writer/ModuleWriter.cs +++ b/reflect/Writer/ModuleWriter.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2008 Jeroen Frijters + Copyright (C) 2008-2011 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,6 +37,30 @@ namespace IKVM.Reflection.Writer internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken) + { + WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, null); + } + + internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, + PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, + ResourceSection resources, int entryPointToken, Stream stream) + { + if (stream == null) + { + using (FileStream fs = new FileStream(moduleBuilder.FullyQualifiedName, FileMode.Create)) + { + WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, fs); + } + } + else + { + WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, stream); + } + } + + private static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, + PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, + ResourceSection resources, int entryPointToken, Stream stream) { moduleBuilder.FixupMethodBodyTokens(); @@ -53,243 +77,240 @@ namespace IKVM.Reflection.Writer resources.Finish(); } - using (FileStream fs = new FileStream(moduleBuilder.FullyQualifiedName, FileMode.Create)) + PEWriter writer = new PEWriter(stream); + switch (imageFileMachine) { - PEWriter writer = new PEWriter(fs); - switch (imageFileMachine) - { - case ImageFileMachine.I386: - writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386; - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE; - break; - case ImageFileMachine.AMD64: - writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64; - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE; - writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0; - writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC; - writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000; - writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000; - writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000; - break; - case ImageFileMachine.IA64: - writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64; - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE; - writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0; - writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC; - writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000; - writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000; - writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000; - break; - default: - throw new ArgumentOutOfRangeException("imageFileMachine"); - } - if (fileKind == PEFileKinds.Dll) - { - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_DLL; - } + case ImageFileMachine.I386: + writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386; + writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE; + break; + case ImageFileMachine.AMD64: + writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64; + writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE; + writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0; + writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC; + writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000; + writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000; + writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000; + break; + case ImageFileMachine.IA64: + writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64; + writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE; + writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0; + writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC; + writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000; + writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000; + writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000; + break; + default: + throw new ArgumentOutOfRangeException("imageFileMachine"); + } + if (fileKind == PEFileKinds.Dll) + { + writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_DLL; + } - switch (fileKind) - { - case PEFileKinds.WindowApplication: - writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_GUI; - break; - default: - writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_CUI; - break; - } - writer.Headers.OptionalHeader.DllCharacteristics = - IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | - IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NO_SEH | - IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NX_COMPAT | - IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; + switch (fileKind) + { + case PEFileKinds.WindowApplication: + writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_GUI; + break; + default: + writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_CUI; + break; + } + writer.Headers.OptionalHeader.DllCharacteristics = + IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | + IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NO_SEH | + IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NX_COMPAT | + IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; - CliHeader cliHeader = new CliHeader(); - cliHeader.Cb = 0x48; - cliHeader.MajorRuntimeVersion = 2; - cliHeader.MinorRuntimeVersion = moduleBuilder.MDStreamVersion < 0x20000 ? (ushort)0 : (ushort)5; - if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0) - { - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_ILONLY; - } - if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0) - { - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED; - } - if (keyPair != null) - { - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED; - } - if (moduleBuilder.IsPseudoToken(entryPointToken)) - { - entryPointToken = moduleBuilder.ResolvePseudoToken(entryPointToken); - } - cliHeader.EntryPointToken = (uint)entryPointToken; + CliHeader cliHeader = new CliHeader(); + cliHeader.Cb = 0x48; + cliHeader.MajorRuntimeVersion = 2; + cliHeader.MinorRuntimeVersion = moduleBuilder.MDStreamVersion < 0x20000 ? (ushort)0 : (ushort)5; + if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0) + { + cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_ILONLY; + } + if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0) + { + cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED; + } + if (keyPair != null) + { + cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED; + } + if (moduleBuilder.IsPseudoToken(entryPointToken)) + { + entryPointToken = moduleBuilder.ResolvePseudoToken(entryPointToken); + } + cliHeader.EntryPointToken = (uint)entryPointToken; - moduleBuilder.Strings.Freeze(); - moduleBuilder.UserStrings.Freeze(); - moduleBuilder.Guids.Freeze(); - moduleBuilder.Blobs.Freeze(); - MetadataWriter mw = new MetadataWriter(moduleBuilder, fs); - moduleBuilder.Tables.Freeze(mw); - TextSection code = new TextSection(writer, cliHeader, moduleBuilder, ComputeStrongNameSignatureLength(publicKey)); + moduleBuilder.Strings.Freeze(); + moduleBuilder.UserStrings.Freeze(); + moduleBuilder.Guids.Freeze(); + moduleBuilder.Blobs.Freeze(); + MetadataWriter mw = new MetadataWriter(moduleBuilder, stream); + moduleBuilder.Tables.Freeze(mw); + TextSection code = new TextSection(writer, cliHeader, moduleBuilder, ComputeStrongNameSignatureLength(publicKey)); - // Import Directory - writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA; - writer.Headers.OptionalHeader.DataDirectory[1].Size = code.ImportDirectoryLength; + // Import Directory + writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA; + writer.Headers.OptionalHeader.DataDirectory[1].Size = code.ImportDirectoryLength; - // Import Address Table Directory - writer.Headers.OptionalHeader.DataDirectory[12].VirtualAddress = code.ImportAddressTableRVA; - writer.Headers.OptionalHeader.DataDirectory[12].Size = code.ImportAddressTableLength; + // Import Address Table Directory + writer.Headers.OptionalHeader.DataDirectory[12].VirtualAddress = code.ImportAddressTableRVA; + writer.Headers.OptionalHeader.DataDirectory[12].Size = code.ImportAddressTableLength; - // COM Descriptor Directory - writer.Headers.OptionalHeader.DataDirectory[14].VirtualAddress = code.ComDescriptorRVA; - writer.Headers.OptionalHeader.DataDirectory[14].Size = code.ComDescriptorLength; + // COM Descriptor Directory + writer.Headers.OptionalHeader.DataDirectory[14].VirtualAddress = code.ComDescriptorRVA; + writer.Headers.OptionalHeader.DataDirectory[14].Size = code.ComDescriptorLength; - // Debug Directory - if (code.DebugDirectoryLength != 0) - { - writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA; - writer.Headers.OptionalHeader.DataDirectory[6].Size = code.DebugDirectoryLength; - } + // Debug Directory + if (code.DebugDirectoryLength != 0) + { + writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA; + writer.Headers.OptionalHeader.DataDirectory[6].Size = code.DebugDirectoryLength; + } - writer.Headers.FileHeader.NumberOfSections = 2; + writer.Headers.FileHeader.NumberOfSections = 2; - if (moduleBuilder.initializedData.Length != 0) - { - writer.Headers.FileHeader.NumberOfSections++; - } + if (moduleBuilder.initializedData.Length != 0) + { + writer.Headers.FileHeader.NumberOfSections++; + } - if (resources != null && resources.Length != 0) - { - writer.Headers.FileHeader.NumberOfSections++; - } + if (resources != null && resources.Length != 0) + { + writer.Headers.FileHeader.NumberOfSections++; + } - SectionHeader text = new SectionHeader(); - text.Name = ".text"; - text.VirtualAddress = code.BaseRVA; - text.VirtualSize = (uint)code.Length; - text.PointerToRawData = code.PointerToRawData; - text.SizeOfRawData = writer.ToFileAlignment((uint)code.Length); - text.Characteristics = SectionHeader.IMAGE_SCN_CNT_CODE | SectionHeader.IMAGE_SCN_MEM_EXECUTE | SectionHeader.IMAGE_SCN_MEM_READ; + SectionHeader text = new SectionHeader(); + text.Name = ".text"; + text.VirtualAddress = code.BaseRVA; + text.VirtualSize = (uint)code.Length; + text.PointerToRawData = code.PointerToRawData; + text.SizeOfRawData = writer.ToFileAlignment((uint)code.Length); + text.Characteristics = SectionHeader.IMAGE_SCN_CNT_CODE | SectionHeader.IMAGE_SCN_MEM_EXECUTE | SectionHeader.IMAGE_SCN_MEM_READ; - SectionHeader sdata = new SectionHeader(); - sdata.Name = ".sdata"; - sdata.VirtualAddress = text.VirtualAddress + writer.ToSectionAlignment(text.VirtualSize); - sdata.VirtualSize = (uint)moduleBuilder.initializedData.Length; - sdata.PointerToRawData = text.PointerToRawData + text.SizeOfRawData; - sdata.SizeOfRawData = writer.ToFileAlignment((uint)moduleBuilder.initializedData.Length); - sdata.Characteristics = SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_MEM_WRITE; + SectionHeader sdata = new SectionHeader(); + sdata.Name = ".sdata"; + sdata.VirtualAddress = text.VirtualAddress + writer.ToSectionAlignment(text.VirtualSize); + sdata.VirtualSize = (uint)moduleBuilder.initializedData.Length; + sdata.PointerToRawData = text.PointerToRawData + text.SizeOfRawData; + sdata.SizeOfRawData = writer.ToFileAlignment((uint)moduleBuilder.initializedData.Length); + sdata.Characteristics = SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_MEM_WRITE; - SectionHeader rsrc = new SectionHeader(); - rsrc.Name = ".rsrc"; - rsrc.VirtualAddress = sdata.VirtualAddress + writer.ToSectionAlignment(sdata.VirtualSize); - rsrc.PointerToRawData = sdata.PointerToRawData + sdata.SizeOfRawData; - rsrc.VirtualSize = resources == null ? 0 : (uint)resources.Length; - rsrc.SizeOfRawData = writer.ToFileAlignment(rsrc.VirtualSize); - rsrc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA; + SectionHeader rsrc = new SectionHeader(); + rsrc.Name = ".rsrc"; + rsrc.VirtualAddress = sdata.VirtualAddress + writer.ToSectionAlignment(sdata.VirtualSize); + rsrc.PointerToRawData = sdata.PointerToRawData + sdata.SizeOfRawData; + rsrc.VirtualSize = resources == null ? 0 : (uint)resources.Length; + rsrc.SizeOfRawData = writer.ToFileAlignment(rsrc.VirtualSize); + rsrc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA; - if (rsrc.SizeOfRawData != 0) - { - // Resource Directory - writer.Headers.OptionalHeader.DataDirectory[2].VirtualAddress = rsrc.VirtualAddress; - writer.Headers.OptionalHeader.DataDirectory[2].Size = rsrc.VirtualSize; - } + if (rsrc.SizeOfRawData != 0) + { + // Resource Directory + writer.Headers.OptionalHeader.DataDirectory[2].VirtualAddress = rsrc.VirtualAddress; + writer.Headers.OptionalHeader.DataDirectory[2].Size = rsrc.VirtualSize; + } - SectionHeader reloc = new SectionHeader(); - reloc.Name = ".reloc"; - reloc.VirtualAddress = rsrc.VirtualAddress + writer.ToSectionAlignment(rsrc.VirtualSize); - reloc.VirtualSize = 12; - reloc.PointerToRawData = rsrc.PointerToRawData + rsrc.SizeOfRawData; - reloc.SizeOfRawData = writer.ToFileAlignment(reloc.VirtualSize); - reloc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_DISCARDABLE; + SectionHeader reloc = new SectionHeader(); + reloc.Name = ".reloc"; + reloc.VirtualAddress = rsrc.VirtualAddress + writer.ToSectionAlignment(rsrc.VirtualSize); + reloc.VirtualSize = 12; + reloc.PointerToRawData = rsrc.PointerToRawData + rsrc.SizeOfRawData; + reloc.SizeOfRawData = writer.ToFileAlignment(reloc.VirtualSize); + reloc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_DISCARDABLE; - // Base Relocation Directory - writer.Headers.OptionalHeader.DataDirectory[5].VirtualAddress = reloc.VirtualAddress; - writer.Headers.OptionalHeader.DataDirectory[5].Size = reloc.VirtualSize; + // Base Relocation Directory + writer.Headers.OptionalHeader.DataDirectory[5].VirtualAddress = reloc.VirtualAddress; + writer.Headers.OptionalHeader.DataDirectory[5].Size = reloc.VirtualSize; - writer.Headers.OptionalHeader.SizeOfCode = text.SizeOfRawData; - writer.Headers.OptionalHeader.SizeOfInitializedData = sdata.SizeOfRawData + rsrc.SizeOfRawData + reloc.SizeOfRawData; - writer.Headers.OptionalHeader.SizeOfUninitializedData = 0; - writer.Headers.OptionalHeader.SizeOfImage = reloc.VirtualAddress + writer.ToSectionAlignment(reloc.VirtualSize); - writer.Headers.OptionalHeader.SizeOfHeaders = text.PointerToRawData; - writer.Headers.OptionalHeader.BaseOfCode = code.BaseRVA; - writer.Headers.OptionalHeader.BaseOfData = sdata.VirtualAddress; - writer.Headers.OptionalHeader.ImageBase = (ulong)moduleBuilder.__ImageBase; + writer.Headers.OptionalHeader.SizeOfCode = text.SizeOfRawData; + writer.Headers.OptionalHeader.SizeOfInitializedData = sdata.SizeOfRawData + rsrc.SizeOfRawData + reloc.SizeOfRawData; + writer.Headers.OptionalHeader.SizeOfUninitializedData = 0; + writer.Headers.OptionalHeader.SizeOfImage = reloc.VirtualAddress + writer.ToSectionAlignment(reloc.VirtualSize); + writer.Headers.OptionalHeader.SizeOfHeaders = text.PointerToRawData; + writer.Headers.OptionalHeader.BaseOfCode = code.BaseRVA; + writer.Headers.OptionalHeader.BaseOfData = sdata.VirtualAddress; + writer.Headers.OptionalHeader.ImageBase = (ulong)moduleBuilder.__ImageBase; - if (imageFileMachine == ImageFileMachine.IA64) - { - // apparently for IA64 AddressOfEntryPoint points to the address of the entry point - // (i.e. there is an additional layer of indirection), so we add the offset to the pointer - writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + 0x20; - } - else - { - writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA; - } + if (imageFileMachine == ImageFileMachine.IA64) + { + // apparently for IA64 AddressOfEntryPoint points to the address of the entry point + // (i.e. there is an additional layer of indirection), so we add the offset to the pointer + writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + 0x20; + } + else + { + writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA; + } - writer.WritePEHeaders(); - writer.WriteSectionHeader(text); - if (sdata.SizeOfRawData != 0) - { - writer.WriteSectionHeader(sdata); - } - if (rsrc.SizeOfRawData != 0) - { - writer.WriteSectionHeader(rsrc); - } - writer.WriteSectionHeader(reloc); + writer.WritePEHeaders(); + writer.WriteSectionHeader(text); + if (sdata.SizeOfRawData != 0) + { + writer.WriteSectionHeader(sdata); + } + if (rsrc.SizeOfRawData != 0) + { + writer.WriteSectionHeader(rsrc); + } + writer.WriteSectionHeader(reloc); - fs.Seek(text.PointerToRawData, SeekOrigin.Begin); - code.Write(mw, (int)sdata.VirtualAddress); + stream.Seek(text.PointerToRawData, SeekOrigin.Begin); + code.Write(mw, (int)sdata.VirtualAddress); - fs.Seek(sdata.PointerToRawData, SeekOrigin.Begin); - mw.Write(moduleBuilder.initializedData); + stream.Seek(sdata.PointerToRawData, SeekOrigin.Begin); + mw.Write(moduleBuilder.initializedData); - if (rsrc.SizeOfRawData != 0) - { - fs.Seek(rsrc.PointerToRawData, SeekOrigin.Begin); - resources.Write(mw, rsrc.VirtualAddress); - } + if (rsrc.SizeOfRawData != 0) + { + stream.Seek(rsrc.PointerToRawData, SeekOrigin.Begin); + resources.Write(mw, rsrc.VirtualAddress); + } - fs.Seek(reloc.PointerToRawData, SeekOrigin.Begin); - // .reloc section - uint relocAddress = code.StartupStubRVA; - switch (imageFileMachine) - { - case ImageFileMachine.I386: - case ImageFileMachine.AMD64: - relocAddress += 2; - break; - case ImageFileMachine.IA64: - relocAddress += 0x20; - break; - } - uint pageRVA = relocAddress & ~0xFFFU; - mw.Write(pageRVA); // PageRVA - mw.Write(0x000C); // Block Size - if (imageFileMachine == ImageFileMachine.I386) - { - mw.Write(0x3000 + relocAddress - pageRVA); // Type / Offset - } - else if (imageFileMachine == ImageFileMachine.AMD64) - { - mw.Write(0xA000 + relocAddress - pageRVA); // Type / Offset - } - else if (imageFileMachine == ImageFileMachine.IA64) - { - // on IA64 the StartupStubRVA is 16 byte aligned, so these two addresses won't cross a page boundary - mw.Write((short)(0xA000 + relocAddress - pageRVA)); // Type / Offset - mw.Write((short)(0xA000 + relocAddress - pageRVA + 8)); // Type / Offset - } + stream.Seek(reloc.PointerToRawData, SeekOrigin.Begin); + // .reloc section + uint relocAddress = code.StartupStubRVA; + switch (imageFileMachine) + { + case ImageFileMachine.I386: + case ImageFileMachine.AMD64: + relocAddress += 2; + break; + case ImageFileMachine.IA64: + relocAddress += 0x20; + break; + } + uint pageRVA = relocAddress & ~0xFFFU; + mw.Write(pageRVA); // PageRVA + mw.Write(0x000C); // Block Size + if (imageFileMachine == ImageFileMachine.I386) + { + mw.Write(0x3000 + relocAddress - pageRVA); // Type / Offset + } + else if (imageFileMachine == ImageFileMachine.AMD64) + { + mw.Write(0xA000 + relocAddress - pageRVA); // Type / Offset + } + else if (imageFileMachine == ImageFileMachine.IA64) + { + // on IA64 the StartupStubRVA is 16 byte aligned, so these two addresses won't cross a page boundary + mw.Write((short)(0xA000 + relocAddress - pageRVA)); // Type / Offset + mw.Write((short)(0xA000 + relocAddress - pageRVA + 8)); // Type / Offset + } - // file alignment - mw.Write(new byte[writer.Headers.OptionalHeader.FileAlignment - reloc.VirtualSize]); + // file alignment + mw.Write(new byte[writer.Headers.OptionalHeader.FileAlignment - reloc.VirtualSize]); - // do the strong naming - if (keyPair != null) - { - StrongName(fs, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength); - } + // do the strong naming + if (keyPair != null) + { + StrongName(stream, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength); } if (moduleBuilder.symbolWriter != null) @@ -318,18 +339,18 @@ namespace IKVM.Reflection.Writer } } - private static void StrongName(FileStream fs, StrongNameKeyPair keyPair, uint headerLength, uint textSectionFileOffset, uint strongNameSignatureFileOffset, uint strongNameSignatureLength) + private static void StrongName(Stream stream, StrongNameKeyPair keyPair, uint headerLength, uint textSectionFileOffset, uint strongNameSignatureFileOffset, uint strongNameSignatureLength) { SHA1Managed hash = new SHA1Managed(); using (CryptoStream cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write)) { - fs.Seek(0, SeekOrigin.Begin); + stream.Seek(0, SeekOrigin.Begin); byte[] buf = new byte[8192]; - HashChunk(fs, cs, buf, (int)headerLength); - fs.Seek(textSectionFileOffset, SeekOrigin.Begin); - HashChunk(fs, cs, buf, (int)(strongNameSignatureFileOffset - textSectionFileOffset)); - fs.Seek(strongNameSignatureLength, SeekOrigin.Current); - HashChunk(fs, cs, buf, (int)(fs.Length - (strongNameSignatureFileOffset + strongNameSignatureLength))); + HashChunk(stream, cs, buf, (int)headerLength); + stream.Seek(textSectionFileOffset, SeekOrigin.Begin); + HashChunk(stream, cs, buf, (int)(strongNameSignatureFileOffset - textSectionFileOffset)); + stream.Seek(strongNameSignatureLength, SeekOrigin.Current); + HashChunk(stream, cs, buf, (int)(stream.Length - (strongNameSignatureFileOffset + strongNameSignatureLength))); } using (RSA rsa = CryptoHack.CreateRSA(keyPair)) { @@ -340,14 +361,14 @@ namespace IKVM.Reflection.Writer { throw new InvalidOperationException("Signature length mismatch"); } - fs.Seek(strongNameSignatureFileOffset, SeekOrigin.Begin); - fs.Write(signature, 0, signature.Length); + stream.Seek(strongNameSignatureFileOffset, SeekOrigin.Begin); + stream.Write(signature, 0, signature.Length); } // compute the PE checksum - fs.Seek(0, SeekOrigin.Begin); - int count = (int)fs.Length / 4; - BinaryReader br = new BinaryReader(fs); + stream.Seek(0, SeekOrigin.Begin); + int count = (int)stream.Length / 4; + BinaryReader br = new BinaryReader(stream); long sum = 0; for (int i = 0; i < count; i++) { @@ -360,20 +381,20 @@ namespace IKVM.Reflection.Writer { sum = (sum & 0xFFFF) + (sum >> 16); } - sum += fs.Length; + sum += stream.Length; // write the PE checksum, note that it is always at offset 0xD8 in the file ByteBuffer bb = new ByteBuffer(4); bb.Write((int)sum); - fs.Seek(0xD8, SeekOrigin.Begin); - bb.WriteTo(fs); + stream.Seek(0xD8, SeekOrigin.Begin); + bb.WriteTo(stream); } - internal static void HashChunk(FileStream fs, CryptoStream cs, byte[] buf, int length) + internal static void HashChunk(Stream stream, CryptoStream cs, byte[] buf, int length) { while (length > 0) { - int read = fs.Read(buf, 0, Math.Min(buf.Length, length)); + int read = stream.Read(buf, 0, Math.Min(buf.Length, length)); cs.Write(buf, 0, read); length -= read; }