46 const ulong DefaultExeBaseAddress32Bit = 0x00400000;
47 const ulong DefaultExeBaseAddress64Bit = 0x0000000140000000;
49 const ulong DefaultDllBaseAddress32Bit = 0x10000000;
50 const ulong DefaultDllBaseAddress64Bit = 0x0000000180000000;
52 const ulong DefaultSizeOfHeapReserve32Bit = 0x00100000;
53 const ulong DefaultSizeOfHeapReserve64Bit = 0x00400000;
55 const ulong DefaultSizeOfHeapCommit32Bit = 0x1000;
56 const ulong DefaultSizeOfHeapCommit64Bit = 0x2000;
58 const ulong DefaultSizeOfStackReserve32Bit = 0x00100000;
59 const ulong DefaultSizeOfStackReserve64Bit = 0x00400000;
61 const ulong DefaultSizeOfStackCommit32Bit = 0x1000;
62 const ulong DefaultSizeOfStackCommit64Bit = 0x4000;
64 const ushort DefaultFileAlignment32Bit = 0x200;
65 const ushort DefaultFileAlignment64Bit = 0x200;
67 const ushort DefaultSectionAlignment = 0x2000;
82 WriteModule(keyPair, publicKey, module, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint,
null,
null,
null,
null);
98 internal static void WriteModule(StrongNameKeyPair keyPair,
byte[] publicKey,
IKVM.
Reflection.
Emit.
ModuleBuilder module,
IKVM.
Reflection.
Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine,
ModuleResourceSectionBuilder nativeResources, MethodInfo entryPoint,
string peFileName, Stream peStream,
string pdbFileName, Stream pdbStream)
100 FileStream disposablePeStream =
null;
101 FileStream disposePdbStream =
null;
104 peFileName ??= module.FullyQualifiedName;
105 peStream ??= disposablePeStream =
new FileStream(peFileName, FileMode.Create);
108 if (module.GetSymWriter() is IMetadataSymbolWriter)
110 pdbFileName ??= Path.ChangeExtension(peFileName,
".pdb");
111 pdbStream ??= disposePdbStream =
new FileStream(pdbFileName, FileMode.Create);
116 WriteModuleImpl(keyPair, publicKey, module, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint, peFileName, peStream, pdbFileName, pdbStream);
120 disposablePeStream?.Dispose();
121 disposePdbStream?.Dispose();
140 static void WriteModuleImpl(StrongNameKeyPair keyPair,
byte[] publicKey,
IKVM.
Reflection.
Emit.
ModuleBuilder module,
IKVM.
Reflection.
Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine,
ModuleResourceSectionBuilder nativeResources, MethodInfo entryPoint,
string peFileName, Stream peStream,
string pdbFileName, Stream pdbStream)
143 module.Metadata.GetOrAddString(
"");
144 module.Metadata.GetOrAddUserString(
"");
145 module.Metadata.GetOrAddBlob(Array.Empty<
byte>());
146 module.Metadata.GetOrAddGuid(Guid.Empty);
149 WriteModuleImpl(module);
152 var is64BitArch = imageFileMachine is ImageFileMachine.AMD64 or ImageFileMachine.ARM64 or ImageFileMachine.IA64;
155 var peHeaderBuilder =
new PEHeaderBuilder(
156 machine: GetMachine(imageFileMachine),
157 sectionAlignment: GetSectionAlignment(module, is64BitArch),
158 fileAlignment: GetFileAlignment(module, is64BitArch),
159 imageBase: GetImageBase(module, fileKind, is64BitArch),
160 majorLinkerVersion: 0x30,
161 minorLinkerVersion: 0,
162 majorOperatingSystemVersion: 4,
163 minorOperatingSystemVersion: 0,
164 majorImageVersion: 0,
165 minorImageVersion: 0,
166 majorSubsystemVersion: GetMajorSubsystemVersion(imageFileMachine, fileKind),
167 minorSubsystemVersion: GetMinorSubsystemVersion(imageFileMachine, fileKind),
168 subsystem: GetSubsystem(fileKind),
169 dllCharacteristics: (
System.Reflection.PortableExecutable.DllCharacteristics)(
int)module.__DllCharacteristics,
170 imageCharacteristics: GetImageCharacteristics(imageFileMachine, fileKind),
171 sizeOfStackReserve: GetSizeOfStackReserve(module, is64BitArch),
172 sizeOfStackCommit: GetSizeOfStackCommit(module, is64BitArch),
173 sizeOfHeapReserve: GetSizeOfHeapReserve(module, is64BitArch),
174 sizeOfHeapCommit: GetSizeOfHeapCommit(module, is64BitArch));
177 var rootBuilder =
new MetadataRootBuilder(module.Metadata);
178 var debugBuilder =
default(DebugDirectoryBuilder);
181 if (module.GetSymWriter() is IMetadataSymbolWriter msym)
184 var pdbMetadata =
new MetadataBuilder();
185 pdbMetadata.GetOrAddString(
"");
186 pdbMetadata.GetOrAddUserString(
"");
187 pdbMetadata.GetOrAddBlob(Array.Empty<
byte>());
188 pdbMetadata.GetOrAddGuid(Guid.Empty);
189 msym.WriteTo(pdbMetadata, out var pdbUserEntryPoint);
192 var pdbContentHash = ImmutableArray<byte>.Empty;
193 var pdb =
new PortablePdbBuilder(
195 rootBuilder.Sizes.RowCounts,
196 pdbUserEntryPoint != 0 ? (MethodDefinitionHandle)MetadataTokens.EntityHandle(module.ResolvePseudoToken(pdbUserEntryPoint)) :
default,
197 module.Universe.Deterministic ?
new Func<IEnumerable<Blob>, BlobContentId>(content => BlobContentId.FromHash(pdbContentHash = CryptographicHashProvider.ComputeHash(module.Universe.PdbChecksumAlgorithm, content))) :
null);
200 var pdbContent =
new BlobBuilder();
201 var pdbContentId = pdb.Serialize(pdbContent);
204 debugBuilder =
new DebugDirectoryBuilder();
207 if (module.Universe.Deterministic)
208 debugBuilder.AddReproducibleEntry();
211 if (pdbContentHash.IsDefaultOrEmpty ==
false)
212 debugBuilder.AddPdbChecksumEntry(module.Universe.PdbChecksumAlgorithm.Name, pdbContentHash);
215 if (pdbStream !=
null)
218 if (peFileName !=
null)
219 pdbFileName ??= Path.ChangeExtension(peFileName,
".pdb");
222 if (pdbFileName !=
null)
223 pdbFileName = Path.GetFileName(pdbFileName);
226 debugBuilder.AddCodeViewEntry(PadPdbPath(pdbFileName), pdbContentId, pdb.FormatVersion);
229 pdbContent.WriteContentTo(pdbStream);
234 debugBuilder.AddEmbeddedPortablePdbEntry(pdbContent, pdb.FormatVersion);
239 var strongNameSignatureSize = ComputeStrongNameSignatureLength(publicKey);
240 var peBuilder =
new ManagedPEBuilder(
242 new MetadataRootBuilder(module.Metadata),
244 managedResources: module.ResourceStream,
245 nativeResources: nativeResources.
Count > 0 ? nativeResources :
null,
246 debugDirectoryBuilder: debugBuilder,
247 strongNameSignatureSize: strongNameSignatureSize,
248 entryPoint: entryPoint !=
null ? (MethodDefinitionHandle)MetadataTokens.EntityHandle(entryPoint.GetCurrentToken()) :
default,
249 flags: GetCorFlags(portableExecutableKind, keyPair),
250 deterministicIdProvider: GetDeterministicIdProvider(module));
253 var pe =
new BlobBuilder();
254 var peContentId = peBuilder.Serialize(pe);
257 var mvidId =
new BlobWriter(module.GetModuleVersionIdFixup().Content);
258 mvidId.WriteGuid(peContentId.Guid);
259 Debug.Assert(mvidId.RemainingBytes == 0);
263 peBuilder.Sign(pe, blobs => GetSignature(keyPair, blobs, strongNameSignatureSize));
266 pe.WriteContentTo(peStream);
277 static string PadPdbPath(
string path)
279 const int MinLength = 260;
280 return path +
new string(
'\0', Math.Max(0, MinLength - Encoding.UTF8.GetByteCount(path) - 1));
290 module.FixupMethodBodyTokens();
293 module.TypeRefTable.Fixup(module);
294 module.MethodImplTable.Fixup(module);
295 module.MethodSemanticsTable.Fixup(module);
296 module.InterfaceImplTable.Fixup(module);
297 module.ResolveInterfaceImplPseudoTokens();
298 module.MemberRefTable.Fixup(module);
299 module.ConstantTable.Fixup(module);
300 module.FieldMarshalTable.Fixup(module);
301 module.DeclSecurityTable.Fixup(module);
302 module.GenericParamTable.Fixup(module);
303 module.CustomAttributeTable.Fixup(module);
304 module.FieldLayoutTable.Fixup(module);
305 module.FieldRVATable.Fixup(module);
306 module.ImplMapTable.Fixup(module);
307 module.ExportedTypeTable.Fixup(module);
308 module.ManifestResourceTable.Fixup(module);
309 module.MethodSpecTable.Fixup(module);
310 module.GenericParamConstraint.Fixup(module);
313 module.GetSymWriter()?.Close();
316 module.WriteResources();
317 module.WriteMetadata();
326 static Machine GetMachine(ImageFileMachine imageFileMachine)
328 return imageFileMachine
switch
330 ImageFileMachine.UNKNOWN => Machine.Unknown,
331 ImageFileMachine.I386 => Machine.I386,
332 ImageFileMachine.ARM => Machine.Arm,
333 ImageFileMachine.AMD64 => Machine.Amd64,
334 ImageFileMachine.IA64 => Machine.IA64,
335 ImageFileMachine.ARM64 => Machine.Arm64,
336 _ =>
throw new ArgumentOutOfRangeException(
"imageFileMachine"),
348 return DefaultSectionAlignment;
359 if (module.__FileAlignment == 0)
360 return is64BitArch ? DefaultFileAlignment64Bit : DefaultFileAlignment32Bit;
362 return (
int)module.__FileAlignment;
375 var baseAddress = unchecked(module.__ImageBase + 0x8000) & (is64BitArch ? 0xffffffffffff0000 : 0x00000000ffff0000);
378 if (baseAddress == 0)
381 return is64BitArch ? DefaultExeBaseAddress64Bit : DefaultExeBaseAddress32Bit;
383 return is64BitArch ? DefaultDllBaseAddress64Bit : DefaultDllBaseAddress32Bit;
393 static ushort GetMajorSubsystemVersion(ImageFileMachine imageFileMachine,
IKVM.
Reflection.
Emit.PEFileKinds fileKinds)
395 return imageFileMachine == ImageFileMachine.ARM ? (ushort)6 : (ushort)4;
402 static ushort GetMinorSubsystemVersion(ImageFileMachine imageFileMachine,
IKVM.
Reflection.
Emit.PEFileKinds fileKinds)
404 return imageFileMachine == ImageFileMachine.ARM ? (ushort)2 : (ushort)0;
412 static Subsystem GetSubsystem(
IKVM.
Reflection.
Emit.PEFileKinds fileKind) => fileKind
switch
414 IKVM.Reflection.Emit.PEFileKinds.WindowApplication => Subsystem.WindowsGui,
415 _ => Subsystem.WindowsCui,
425 static Characteristics GetImageCharacteristics(ImageFileMachine imageFileMachine,
IKVM.
Reflection.
Emit.PEFileKinds fileKind)
427 var characteristics = Characteristics.ExecutableImage;
429 switch (imageFileMachine)
431 case ImageFileMachine.UNKNOWN:
433 case ImageFileMachine.I386:
434 characteristics |= Characteristics.Bit32Machine;
436 case ImageFileMachine.ARM:
437 characteristics |= Characteristics.Bit32Machine | Characteristics.LargeAddressAware;
439 case ImageFileMachine.AMD64:
440 case ImageFileMachine.IA64:
441 case ImageFileMachine.ARM64:
442 characteristics |= Characteristics.LargeAddressAware;
445 throw new ArgumentOutOfRangeException(
"imageFileMachine");
451 characteristics |= Characteristics.Dll;
455 return characteristics;
466 return is64BitArch ? DefaultSizeOfStackReserve64Bit : DefaultSizeOfStackReserve32Bit;
477 return is64BitArch ? DefaultSizeOfStackCommit64Bit : DefaultSizeOfStackCommit32Bit;
488 return is64BitArch ? DefaultSizeOfHeapReserve64Bit : DefaultSizeOfHeapReserve32Bit;
499 return is64BitArch ? DefaultSizeOfHeapCommit64Bit : DefaultSizeOfHeapCommit32Bit;
508 static CorFlags GetCorFlags(PortableExecutableKinds portableExecutableKind, StrongNameKeyPair keyPair)
510 var flags =
default(CorFlags);
512 if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0)
513 flags |= CorFlags.ILOnly;
514 if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0)
515 flags |= CorFlags.Requires32Bit;
516 if ((portableExecutableKind & PortableExecutableKinds.Preferred32Bit) != 0)
517 flags |= CorFlags.Requires32Bit | CorFlags.Prefers32Bit;
519 flags |= CorFlags.StrongNameSigned;
531 if (module.Universe.Deterministic)
532 return e => BlobContentId.FromHash(CryptographicHashProvider.ComputeHash(HashAlgorithmName.SHA256, e));
542 static int ComputeStrongNameSignatureLength(
byte[] publicKey)
544 if (publicKey ==
null)
548 else if (publicKey.Length == 16)
557 return publicKey.Length - 32;
568 static byte[] GetSignature(StrongNameKeyPair keyPair, IEnumerable<Blob> blobs,
int strongNameSignatureSize)
571 using var rsa = keyPair.CreateRSA();
572 var signature = rsa.SignHash(CryptographicHashProvider.ComputeHash(HashAlgorithmName.SHA1, blobs).ToArray(), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
573 Array.Reverse(signature);
576 if (signature.Length != strongNameSignatureSize)
577 throw new InvalidOperationException(
"Signature length mismatch.");