Added support for saving to a stream instead of a file.

This commit is contained in:
jfrijters 2011-01-18 07:11:23 +00:00
Родитель de0a5a6b15
Коммит 6abc738d3c
3 изменённых файлов: 285 добавлений и 232 удалений

Просмотреть файл

@ -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)

Просмотреть файл

@ -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<CustomAttributeData> 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)

Просмотреть файл

@ -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;
}