| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System.Diagnostics; |
| | | 5 | | using System.Reflection.Internal; |
| | | 6 | | using System.Reflection.Metadata; |
| | | 7 | | |
| | | 8 | | namespace System.Reflection.PortableExecutable |
| | | 9 | | { |
| | | 10 | | /// <summary> |
| | | 11 | | /// Managed .text PE section. |
| | | 12 | | /// </summary> |
| | | 13 | | /// <remarks> |
| | | 14 | | /// Contains in the following order: |
| | | 15 | | /// - Import Address Table |
| | | 16 | | /// - COR Header |
| | | 17 | | /// - IL |
| | | 18 | | /// - Metadata |
| | | 19 | | /// - Managed Resource Data |
| | | 20 | | /// - Strong Name Signature |
| | | 21 | | /// - Debug Data (directory and extra info) |
| | | 22 | | /// - Import Table |
| | | 23 | | /// - Name Table |
| | | 24 | | /// - Runtime Startup Stub |
| | | 25 | | /// - Mapped Field Data |
| | | 26 | | /// </remarks> |
| | | 27 | | internal sealed class ManagedTextSection |
| | | 28 | | { |
| | 0 | 29 | | public Characteristics ImageCharacteristics { get; } |
| | 0 | 30 | | public Machine Machine { get; } |
| | | 31 | | |
| | | 32 | | /// <summary> |
| | | 33 | | /// The size of IL stream (unaligned). |
| | | 34 | | /// </summary> |
| | 0 | 35 | | public int ILStreamSize { get; } |
| | | 36 | | |
| | | 37 | | /// <summary> |
| | | 38 | | /// Total size of metadata (header and all streams). |
| | | 39 | | /// </summary> |
| | 0 | 40 | | public int MetadataSize { get; } |
| | | 41 | | |
| | | 42 | | /// <summary> |
| | | 43 | | /// The size of managed resource data stream. |
| | | 44 | | /// </summary> |
| | 0 | 45 | | public int ResourceDataSize { get; } |
| | | 46 | | |
| | | 47 | | /// <summary> |
| | | 48 | | /// Size of strong name hash. |
| | | 49 | | /// </summary> |
| | 0 | 50 | | public int StrongNameSignatureSize { get; } |
| | | 51 | | |
| | | 52 | | /// <summary> |
| | | 53 | | /// Size of Debug data. |
| | | 54 | | /// </summary> |
| | 0 | 55 | | public int DebugDataSize { get; } |
| | | 56 | | |
| | | 57 | | /// <summary> |
| | | 58 | | /// The size of mapped field data stream. |
| | | 59 | | /// Aligned to <see cref="MappedFieldDataAlignment"/>. |
| | | 60 | | /// </summary> |
| | 0 | 61 | | public int MappedFieldDataSize { get; } |
| | | 62 | | |
| | 0 | 63 | | public ManagedTextSection( |
| | 0 | 64 | | Characteristics imageCharacteristics, |
| | 0 | 65 | | Machine machine, |
| | 0 | 66 | | int ilStreamSize, |
| | 0 | 67 | | int metadataSize, |
| | 0 | 68 | | int resourceDataSize, |
| | 0 | 69 | | int strongNameSignatureSize, |
| | 0 | 70 | | int debugDataSize, |
| | 0 | 71 | | int mappedFieldDataSize) |
| | 0 | 72 | | { |
| | 0 | 73 | | MetadataSize = metadataSize; |
| | 0 | 74 | | ResourceDataSize = resourceDataSize; |
| | 0 | 75 | | ILStreamSize = ilStreamSize; |
| | 0 | 76 | | MappedFieldDataSize = mappedFieldDataSize; |
| | 0 | 77 | | StrongNameSignatureSize = strongNameSignatureSize; |
| | 0 | 78 | | ImageCharacteristics = imageCharacteristics; |
| | 0 | 79 | | Machine = machine; |
| | 0 | 80 | | DebugDataSize = debugDataSize; |
| | 0 | 81 | | } |
| | | 82 | | |
| | | 83 | | /// <summary> |
| | | 84 | | /// If set, the module must include a machine code stub that transfers control to the virtual execution system. |
| | | 85 | | /// </summary> |
| | 0 | 86 | | internal bool RequiresStartupStub => Machine == Machine.I386 || Machine == 0; |
| | | 87 | | |
| | | 88 | | /// <summary> |
| | | 89 | | /// If set, the module contains instructions that assume a 64 bit instruction set. For example it may depend on |
| | | 90 | | /// This may be true even if the module contains only IL instructions because of PlatformInvoke and COM interop. |
| | | 91 | | /// </summary> |
| | 0 | 92 | | internal bool Requires64bits => Machine == Machine.Amd64 || Machine == Machine.IA64 || Machine == Machine.Arm64; |
| | | 93 | | |
| | 0 | 94 | | public bool Is32Bit => !Requires64bits; |
| | | 95 | | |
| | | 96 | | public const int ManagedResourcesDataAlignment = 8; |
| | | 97 | | |
| | 0 | 98 | | private static ReadOnlySpan<byte> CorEntryPointDll => "mscoree.dll"u8; |
| | 0 | 99 | | private ReadOnlySpan<byte> CorEntryPointName => (ImageCharacteristics & Characteristics.Dll) != 0 ? "_CorDllMain |
| | | 100 | | |
| | 0 | 101 | | private int SizeOfImportAddressTable => RequiresStartupStub ? (Is32Bit ? 2 * sizeof(uint) : 2 * sizeof(ulong)) : |
| | | 102 | | |
| | | 103 | | // (_is32bit ? 66 : 70); |
| | | 104 | | private int SizeOfImportTable => |
| | 0 | 105 | | sizeof(uint) + // RVA |
| | 0 | 106 | | sizeof(uint) + // 0 |
| | 0 | 107 | | sizeof(uint) + // 0 |
| | 0 | 108 | | sizeof(uint) + // name RVA |
| | 0 | 109 | | sizeof(uint) + // import address table RVA |
| | 0 | 110 | | 20 + // ? |
| | 0 | 111 | | (Is32Bit ? 3 * sizeof(uint) : 2 * sizeof(ulong)) + // import lookup table |
| | 0 | 112 | | sizeof(ushort) + // hint |
| | 0 | 113 | | CorEntryPointName.Length + |
| | 0 | 114 | | 1; // NUL |
| | | 115 | | |
| | | 116 | | private static int SizeOfNameTable => |
| | 0 | 117 | | CorEntryPointDll.Length + 1 + sizeof(ushort); |
| | | 118 | | |
| | 0 | 119 | | private int SizeOfRuntimeStartupStub => Is32Bit ? 8 : 16; |
| | | 120 | | |
| | | 121 | | public const int MappedFieldDataAlignment = 8; |
| | | 122 | | |
| | | 123 | | internal int CalculateOffsetToMappedFieldDataStreamUnaligned() |
| | 0 | 124 | | { |
| | 0 | 125 | | int result = ComputeOffsetToImportTable(); |
| | | 126 | | |
| | 0 | 127 | | if (RequiresStartupStub) |
| | 0 | 128 | | { |
| | 0 | 129 | | result += SizeOfImportTable + SizeOfNameTable; |
| | 0 | 130 | | result = BitArithmetic.Align(result, Is32Bit ? 4 : 8); //optional padding to make startup stub's target |
| | 0 | 131 | | result += SizeOfRuntimeStartupStub; |
| | 0 | 132 | | } |
| | | 133 | | |
| | 0 | 134 | | return result; |
| | 0 | 135 | | } |
| | | 136 | | |
| | | 137 | | public int CalculateOffsetToMappedFieldDataStream() |
| | 0 | 138 | | { |
| | 0 | 139 | | int result = CalculateOffsetToMappedFieldDataStreamUnaligned(); |
| | 0 | 140 | | if (MappedFieldDataSize != 0) |
| | 0 | 141 | | { |
| | 0 | 142 | | result = BitArithmetic.Align(result, MappedFieldDataAlignment); |
| | 0 | 143 | | } |
| | 0 | 144 | | return result; |
| | 0 | 145 | | } |
| | | 146 | | |
| | | 147 | | internal int ComputeOffsetToDebugDirectory() |
| | 0 | 148 | | { |
| | 0 | 149 | | return |
| | 0 | 150 | | ComputeOffsetToMetadata() + |
| | 0 | 151 | | MetadataSize + |
| | 0 | 152 | | ResourceDataSize + |
| | 0 | 153 | | StrongNameSignatureSize; |
| | 0 | 154 | | } |
| | | 155 | | |
| | | 156 | | private int ComputeOffsetToImportTable() |
| | 0 | 157 | | { |
| | 0 | 158 | | return |
| | 0 | 159 | | ComputeOffsetToDebugDirectory() + |
| | 0 | 160 | | DebugDataSize; |
| | 0 | 161 | | } |
| | | 162 | | |
| | | 163 | | private const int CorHeaderSize = |
| | | 164 | | sizeof(int) + // header size |
| | | 165 | | sizeof(short) + // major runtime version |
| | | 166 | | sizeof(short) + // minor runtime version |
| | | 167 | | sizeof(long) + // metadata directory |
| | | 168 | | sizeof(int) + // COR flags |
| | | 169 | | sizeof(int) + // entry point |
| | | 170 | | sizeof(long) + // resources directory |
| | | 171 | | sizeof(long) + // strong name signature directory |
| | | 172 | | sizeof(long) + // code manager table directory |
| | | 173 | | sizeof(long) + // vtable fixups directory |
| | | 174 | | sizeof(long) + // export address table jumps directory |
| | | 175 | | sizeof(long); // managed-native header directory |
| | | 176 | | |
| | 0 | 177 | | public int OffsetToILStream => SizeOfImportAddressTable + CorHeaderSize; |
| | | 178 | | |
| | | 179 | | private int ComputeOffsetToMetadata() |
| | 0 | 180 | | { |
| | 0 | 181 | | return OffsetToILStream + BitArithmetic.Align(ILStreamSize, 4); |
| | 0 | 182 | | } |
| | | 183 | | |
| | | 184 | | public int ComputeSizeOfTextSection() |
| | 0 | 185 | | { |
| | 0 | 186 | | return CalculateOffsetToMappedFieldDataStream() + MappedFieldDataSize; |
| | 0 | 187 | | } |
| | | 188 | | |
| | | 189 | | public int GetEntryPointAddress(int rva) |
| | 0 | 190 | | { |
| | | 191 | | // TODO: constants |
| | 0 | 192 | | return RequiresStartupStub ? |
| | 0 | 193 | | rva + CalculateOffsetToMappedFieldDataStreamUnaligned() - (Is32Bit ? 6 : 10) : |
| | 0 | 194 | | 0; |
| | 0 | 195 | | } |
| | | 196 | | |
| | | 197 | | public DirectoryEntry GetImportAddressTableDirectoryEntry(int rva) |
| | 0 | 198 | | { |
| | 0 | 199 | | return RequiresStartupStub ? |
| | 0 | 200 | | new DirectoryEntry(rva, SizeOfImportAddressTable) : |
| | 0 | 201 | | default(DirectoryEntry); |
| | 0 | 202 | | } |
| | | 203 | | |
| | | 204 | | public DirectoryEntry GetImportTableDirectoryEntry(int rva) |
| | 0 | 205 | | { |
| | | 206 | | // TODO: constants |
| | 0 | 207 | | return RequiresStartupStub ? |
| | 0 | 208 | | new DirectoryEntry(rva + ComputeOffsetToImportTable(), (Is32Bit ? 66 : 70) + 13) : |
| | 0 | 209 | | default(DirectoryEntry); |
| | 0 | 210 | | } |
| | | 211 | | |
| | | 212 | | public DirectoryEntry GetCorHeaderDirectoryEntry(int rva) |
| | 0 | 213 | | { |
| | 0 | 214 | | return new DirectoryEntry(rva + SizeOfImportAddressTable, CorHeaderSize); |
| | 0 | 215 | | } |
| | | 216 | | |
| | | 217 | | #region Serialization |
| | | 218 | | |
| | | 219 | | /// <summary> |
| | | 220 | | /// Serializes .text section data into a specified <paramref name="builder"/>. |
| | | 221 | | /// </summary> |
| | | 222 | | /// <param name="builder">An empty builder to serialize section data to.</param> |
| | | 223 | | /// <param name="relativeVirtualAddess">Relative virtual address of the section within the containing PE file.</ |
| | | 224 | | /// <param name="entryPointTokenOrRelativeVirtualAddress">Entry point token or RVA (<see cref="CorHeader.EntryPo |
| | | 225 | | /// <param name="corFlags">COR Flags (<see cref="CorHeader.Flags"/>).</param> |
| | | 226 | | /// <param name="baseAddress">Base address of the PE image.</param> |
| | | 227 | | /// <param name="metadataBuilder"><see cref="BlobBuilder"/> containing metadata. Must be populated with data. Li |
| | | 228 | | /// <param name="ilBuilder"><see cref="BlobBuilder"/> containing IL stream. Must be populated with data. Linked |
| | | 229 | | /// <param name="mappedFieldDataBuilderOpt"><see cref="BlobBuilder"/> containing mapped field data. Must be popu |
| | | 230 | | /// <param name="resourceBuilderOpt"><see cref="BlobBuilder"/> containing managed resource data. Must be populat |
| | | 231 | | /// <param name="debugDataBuilderOpt"><see cref="BlobBuilder"/> containing PE debug table and data. Must be popu |
| | | 232 | | /// <param name="strongNameSignature">Blob reserved in the <paramref name="builder"/> for strong name signature. |
| | | 233 | | public void Serialize( |
| | | 234 | | BlobBuilder builder, |
| | | 235 | | int relativeVirtualAddess, |
| | | 236 | | int entryPointTokenOrRelativeVirtualAddress, |
| | | 237 | | CorFlags corFlags, |
| | | 238 | | ulong baseAddress, |
| | | 239 | | BlobBuilder metadataBuilder, |
| | | 240 | | BlobBuilder ilBuilder, |
| | | 241 | | BlobBuilder? mappedFieldDataBuilderOpt, |
| | | 242 | | BlobBuilder? resourceBuilderOpt, |
| | | 243 | | BlobBuilder? debugDataBuilderOpt, |
| | | 244 | | out Blob strongNameSignature) |
| | 0 | 245 | | { |
| | 0 | 246 | | Debug.Assert(builder.Count == 0); |
| | 0 | 247 | | Debug.Assert(metadataBuilder.Count == MetadataSize); |
| | 0 | 248 | | Debug.Assert(metadataBuilder.Count % 4 == 0); |
| | 0 | 249 | | Debug.Assert(ilBuilder.Count == ILStreamSize); |
| | 0 | 250 | | Debug.Assert((mappedFieldDataBuilderOpt?.Count ?? 0) == MappedFieldDataSize); |
| | 0 | 251 | | Debug.Assert((resourceBuilderOpt?.Count ?? 0) == ResourceDataSize); |
| | | 252 | | |
| | | 253 | | // TODO: avoid recalculation |
| | 0 | 254 | | int importTableRva = GetImportTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; |
| | 0 | 255 | | int importAddressTableRva = GetImportAddressTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddres |
| | | 256 | | |
| | 0 | 257 | | if (RequiresStartupStub) |
| | 0 | 258 | | { |
| | 0 | 259 | | WriteImportAddressTable(builder, importTableRva); |
| | 0 | 260 | | } |
| | | 261 | | |
| | 0 | 262 | | WriteCorHeader(builder, relativeVirtualAddess, entryPointTokenOrRelativeVirtualAddress, corFlags); |
| | | 263 | | |
| | | 264 | | // IL: |
| | 0 | 265 | | ilBuilder.Align(4); |
| | 0 | 266 | | builder.LinkSuffix(ilBuilder); |
| | | 267 | | |
| | | 268 | | // metadata: |
| | 0 | 269 | | builder.LinkSuffix(metadataBuilder); |
| | | 270 | | |
| | | 271 | | // managed resources: |
| | 0 | 272 | | if (resourceBuilderOpt != null) |
| | 0 | 273 | | { |
| | 0 | 274 | | builder.LinkSuffix(resourceBuilderOpt); |
| | 0 | 275 | | } |
| | | 276 | | |
| | | 277 | | // strong name signature: |
| | | 278 | | // The bytes are required to be 0 for the purpose of calculating hash of the PE content |
| | | 279 | | // when strong name signing. This is already handled by ReserveBytes. |
| | 0 | 280 | | strongNameSignature = builder.ReserveBytes(StrongNameSignatureSize); |
| | | 281 | | |
| | | 282 | | // debug directory and data: |
| | 0 | 283 | | if (debugDataBuilderOpt != null) |
| | 0 | 284 | | { |
| | 0 | 285 | | builder.LinkSuffix(debugDataBuilderOpt); |
| | 0 | 286 | | } |
| | | 287 | | |
| | 0 | 288 | | if (RequiresStartupStub) |
| | 0 | 289 | | { |
| | 0 | 290 | | WriteImportTable(builder, importTableRva, importAddressTableRva); |
| | 0 | 291 | | WriteNameTable(builder); |
| | 0 | 292 | | WriteRuntimeStartupStub(builder, importAddressTableRva, baseAddress); |
| | 0 | 293 | | } |
| | | 294 | | |
| | | 295 | | // mapped field data: |
| | 0 | 296 | | if (mappedFieldDataBuilderOpt != null) |
| | 0 | 297 | | { |
| | 0 | 298 | | if (mappedFieldDataBuilderOpt.Count != 0) |
| | 0 | 299 | | builder.Align(MappedFieldDataAlignment); |
| | 0 | 300 | | builder.LinkSuffix(mappedFieldDataBuilderOpt); |
| | 0 | 301 | | } |
| | | 302 | | |
| | 0 | 303 | | Debug.Assert(builder.Count == ComputeSizeOfTextSection()); |
| | 0 | 304 | | } |
| | | 305 | | |
| | | 306 | | private void WriteImportAddressTable(BlobBuilder builder, int importTableRva) |
| | 0 | 307 | | { |
| | 0 | 308 | | int start = builder.Count; |
| | | 309 | | |
| | 0 | 310 | | int ilRva = importTableRva + 40; |
| | 0 | 311 | | int hintRva = ilRva + (Is32Bit ? 12 : 16); |
| | | 312 | | |
| | | 313 | | // Import Address Table |
| | 0 | 314 | | if (Is32Bit) |
| | 0 | 315 | | { |
| | 0 | 316 | | builder.WriteUInt32((uint)hintRva); // 4 |
| | 0 | 317 | | builder.WriteUInt32(0); // 8 |
| | 0 | 318 | | } |
| | | 319 | | else |
| | 0 | 320 | | { |
| | 0 | 321 | | builder.WriteUInt64((uint)hintRva); // 8 |
| | 0 | 322 | | builder.WriteUInt64(0); // 16 |
| | 0 | 323 | | } |
| | | 324 | | |
| | 0 | 325 | | Debug.Assert(builder.Count - start == SizeOfImportAddressTable); |
| | 0 | 326 | | } |
| | | 327 | | |
| | | 328 | | private void WriteImportTable(BlobBuilder builder, int importTableRva, int importAddressTableRva) |
| | 0 | 329 | | { |
| | 0 | 330 | | int start = builder.Count; |
| | | 331 | | |
| | 0 | 332 | | int ilRVA = importTableRva + 40; |
| | 0 | 333 | | int hintRva = ilRVA + (Is32Bit ? 12 : 16); |
| | 0 | 334 | | int nameRva = hintRva + 12 + 2; |
| | | 335 | | |
| | | 336 | | // Import table |
| | 0 | 337 | | builder.WriteUInt32((uint)ilRVA); // 4 |
| | 0 | 338 | | builder.WriteUInt32(0); // 8 |
| | 0 | 339 | | builder.WriteUInt32(0); // 12 |
| | 0 | 340 | | builder.WriteUInt32((uint)nameRva); // 16 |
| | 0 | 341 | | builder.WriteUInt32((uint)importAddressTableRva); // 20 |
| | 0 | 342 | | builder.WriteBytes(0, 20); // 40 |
| | | 343 | | |
| | | 344 | | // Import Lookup table |
| | 0 | 345 | | if (Is32Bit) |
| | 0 | 346 | | { |
| | 0 | 347 | | builder.WriteUInt32((uint)hintRva); // 44 |
| | 0 | 348 | | builder.WriteUInt32(0); // 48 |
| | 0 | 349 | | builder.WriteUInt32(0); // 52 |
| | 0 | 350 | | } |
| | | 351 | | else |
| | 0 | 352 | | { |
| | 0 | 353 | | builder.WriteUInt64((uint)hintRva); // 48 |
| | 0 | 354 | | builder.WriteUInt64(0); // 56 |
| | 0 | 355 | | } |
| | | 356 | | |
| | | 357 | | // Hint table |
| | 0 | 358 | | builder.WriteUInt16(0); // Hint 54|58 |
| | | 359 | | |
| | 0 | 360 | | builder.WriteBytes(CorEntryPointName); // 65|69 |
| | 0 | 361 | | builder.WriteByte(0); // 66|70 |
| | 0 | 362 | | Debug.Assert(builder.Count - start == SizeOfImportTable); |
| | 0 | 363 | | } |
| | | 364 | | |
| | | 365 | | private static void WriteNameTable(BlobBuilder builder) |
| | 0 | 366 | | { |
| | 0 | 367 | | int start = builder.Count; |
| | | 368 | | |
| | 0 | 369 | | builder.WriteBytes(CorEntryPointDll); |
| | 0 | 370 | | builder.WriteByte(0); |
| | 0 | 371 | | builder.WriteUInt16(0); |
| | 0 | 372 | | Debug.Assert(builder.Count - start == SizeOfNameTable); |
| | 0 | 373 | | } |
| | | 374 | | |
| | | 375 | | private void WriteCorHeader(BlobBuilder builder, int textSectionRva, int entryPointTokenOrRva, CorFlags corFlags |
| | 0 | 376 | | { |
| | | 377 | | const ushort majorRuntimeVersion = 2; |
| | | 378 | | const ushort minorRuntimeVersion = 5; |
| | | 379 | | |
| | 0 | 380 | | int metadataRva = textSectionRva + ComputeOffsetToMetadata(); |
| | 0 | 381 | | int resourcesRva = metadataRva + MetadataSize; |
| | 0 | 382 | | int signatureRva = resourcesRva + ResourceDataSize; |
| | | 383 | | |
| | 0 | 384 | | int start = builder.Count; |
| | | 385 | | |
| | | 386 | | // Size: |
| | 0 | 387 | | builder.WriteUInt32(CorHeaderSize); |
| | | 388 | | |
| | | 389 | | // Version: |
| | 0 | 390 | | builder.WriteUInt16(majorRuntimeVersion); |
| | 0 | 391 | | builder.WriteUInt16(minorRuntimeVersion); |
| | | 392 | | |
| | | 393 | | // MetadataDirectory: |
| | 0 | 394 | | builder.WriteUInt32((uint)metadataRva); |
| | 0 | 395 | | builder.WriteUInt32((uint)MetadataSize); |
| | | 396 | | |
| | | 397 | | // COR Flags: |
| | 0 | 398 | | builder.WriteUInt32((uint)corFlags); |
| | | 399 | | |
| | | 400 | | // EntryPoint: |
| | 0 | 401 | | builder.WriteUInt32((uint)entryPointTokenOrRva); |
| | | 402 | | |
| | | 403 | | // ResourcesDirectory: |
| | 0 | 404 | | builder.WriteUInt32((uint)(ResourceDataSize == 0 ? 0 : resourcesRva)); // 28 |
| | 0 | 405 | | builder.WriteUInt32((uint)ResourceDataSize); |
| | | 406 | | |
| | | 407 | | // StrongNameSignatureDirectory: |
| | 0 | 408 | | builder.WriteUInt32((uint)(StrongNameSignatureSize == 0 ? 0 : signatureRva)); // 36 |
| | 0 | 409 | | builder.WriteUInt32((uint)StrongNameSignatureSize); |
| | | 410 | | |
| | | 411 | | // CodeManagerTableDirectory (not supported): |
| | 0 | 412 | | builder.WriteUInt32(0); |
| | 0 | 413 | | builder.WriteUInt32(0); |
| | | 414 | | |
| | | 415 | | // VtableFixupsDirectory (not supported): |
| | 0 | 416 | | builder.WriteUInt32(0); |
| | 0 | 417 | | builder.WriteUInt32(0); |
| | | 418 | | |
| | | 419 | | // ExportAddressTableJumpsDirectory (not supported): |
| | 0 | 420 | | builder.WriteUInt32(0); |
| | 0 | 421 | | builder.WriteUInt32(0); |
| | | 422 | | |
| | | 423 | | // ManagedNativeHeaderDirectory (not supported): |
| | 0 | 424 | | builder.WriteUInt32(0); |
| | 0 | 425 | | builder.WriteUInt32(0); |
| | | 426 | | |
| | 0 | 427 | | Debug.Assert(builder.Count - start == CorHeaderSize); |
| | 0 | 428 | | Debug.Assert(builder.Count % 4 == 0); |
| | 0 | 429 | | } |
| | | 430 | | |
| | | 431 | | private void WriteRuntimeStartupStub(BlobBuilder sectionBuilder, int importAddressTableRva, ulong baseAddress) |
| | 0 | 432 | | { |
| | | 433 | | // entry point code, consisting of a jump indirect to _CorXXXMain |
| | 0 | 434 | | if (Is32Bit) |
| | 0 | 435 | | { |
| | | 436 | | // Write zeros (nops) to pad the entry point code so that the target address is aligned on a 4 byte boun |
| | | 437 | | // Note that the section is aligned to FileAlignment, which is at least 512, so we can align relatively |
| | 0 | 438 | | sectionBuilder.Align(4); |
| | | 439 | | |
| | 0 | 440 | | sectionBuilder.WriteUInt16(0); |
| | 0 | 441 | | sectionBuilder.WriteByte(0xff); |
| | 0 | 442 | | sectionBuilder.WriteByte(0x25); //4 |
| | 0 | 443 | | sectionBuilder.WriteUInt32((uint)importAddressTableRva + (uint)baseAddress); //8 |
| | 0 | 444 | | } |
| | | 445 | | else |
| | 0 | 446 | | { |
| | | 447 | | // Write zeros (nops) to pad the entry point code so that the target address is aligned on a 8 byte boun |
| | | 448 | | // Note that the section is aligned to FileAlignment, which is at least 512, so we can align relatively |
| | 0 | 449 | | sectionBuilder.Align(8); |
| | | 450 | | |
| | 0 | 451 | | sectionBuilder.WriteUInt32(0); |
| | 0 | 452 | | sectionBuilder.WriteUInt16(0); |
| | 0 | 453 | | sectionBuilder.WriteByte(0xff); |
| | 0 | 454 | | sectionBuilder.WriteByte(0x25); //8 |
| | 0 | 455 | | sectionBuilder.WriteUInt64((ulong)importAddressTableRva + baseAddress); //16 |
| | 0 | 456 | | } |
| | 0 | 457 | | } |
| | | 458 | | |
| | | 459 | | #endregion |
| | | 460 | | } |
| | | 461 | | } |
| | | 462 | | |