зеркало из https://github.com/mono/ikvm-fork.git
Added support for saving to a stream instead of a file.
This commit is contained in:
Родитель
de0a5a6b15
Коммит
6abc738d3c
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче