internal void Freeze(MetadataWriter mw) { if (frozen) throw new InvalidOperationException(); frozen = true; unalignedlength = GetLength(mw); }
internal void Write(MetadataWriter mw, uint rva) { foreach (int offset in linkOffsets) { bb.Position = offset; bb.Write(bb.GetInt32AtCurrentPosition() + (int)rva); } mw.Write(bb); }
internal void Write(MetadataWriter mw) { int pos = mw.Position; WriteImpl(mw); Debug.Assert(mw.Position == pos + unalignedlength); int align = Length - unalignedlength; for (int i = 0; i < align; i++) { mw.Write((byte)0); } }
internal void WriteTypeDefRecord(MetadataWriter mw, ref int fieldList, ref int methodList) { mw.Write((int)attribs); mw.WriteStringIndex(typeName); mw.WriteStringIndex(typeNameSpace); mw.WriteTypeDefOrRef(extends); mw.WriteField(fieldList); mw.WriteMethodDef(methodList); methodList += methods.Count; fieldList += fields.Count; }
internal void WriteMethodDefRecord(int baseRVA, MetadataWriter mw, ref int paramList) { if (rva != -1) { mw.Write(rva + baseRVA); } else { mw.Write(0); } mw.Write((short)implFlags); mw.Write((short)attributes); mw.WriteStringIndex(nameIndex); mw.WriteBlobIndex(signature); mw.WriteParam(paramList); if (parameters != null) { paramList += parameters.Count; } }
protected override void WriteImpl(MetadataWriter mw) { mw.Write(buf); }
protected override void WriteImpl(MetadataWriter mw) { foreach (Guid guid in list) { mw.Write(guid.ToByteArray()); } }
protected override void WriteImpl(MetadataWriter mw) { foreach (string str in list) { mw.Write(System.Text.Encoding.UTF8.GetBytes(str)); mw.Write((byte)0); } }
private static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken, Stream stream) { moduleBuilder.ApplyUnmanagedExports(imageFileMachine); moduleBuilder.FixupMethodBodyTokens(); moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleBuilder.Guids.Add(moduleBuilder.ModuleVersionId), 0, 0); if (moduleBuilder.UserStrings.IsEmpty) { // for compat with Ref.Emit, if there aren't any user strings, we add one moduleBuilder.UserStrings.Add(" "); } if (resources != null) { resources.Finish(); } PEWriter writer = new PEWriter(stream); writer.Headers.OptionalHeader.FileAlignment = (uint)moduleBuilder.__FileAlignment; 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; writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000); break; case ImageFileMachine.ARM: writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM; writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE; writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000); 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 = moduleBuilder.GetStackReserve(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 = moduleBuilder.GetStackReserve(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 = (ushort)moduleBuilder.__DllCharacteristics; 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 ((portableExecutableKind & PortableExecutableKinds.Preferred32Bit) != 0) { cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED; } 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, stream); moduleBuilder.Tables.Freeze(mw); TextSection code = new TextSection(writer, cliHeader, moduleBuilder, ComputeStrongNameSignatureLength(publicKey)); // Export Directory if (code.ExportDirectoryLength != 0) { writer.Headers.OptionalHeader.DataDirectory[0].VirtualAddress = code.ExportDirectoryRVA; writer.Headers.OptionalHeader.DataDirectory[0].Size = code.ExportDirectoryLength; } // Import Directory if (code.ImportDirectoryLength != 0) { writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA; writer.Headers.OptionalHeader.DataDirectory[1].Size = code.ImportDirectoryLength; } // Import Address Table Directory if (code.ImportAddressTableLength != 0) { 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; // Debug Directory if (code.DebugDirectoryLength != 0) { writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA; writer.Headers.OptionalHeader.DataDirectory[6].Size = code.DebugDirectoryLength; } // we need to start by computing the number of sections, because code.PointerToRawData depends on that writer.Headers.FileHeader.NumberOfSections = 1; if (moduleBuilder.initializedData.Length != 0) { // .sdata writer.Headers.FileHeader.NumberOfSections++; } if (resources != null) { // .rsrc writer.Headers.FileHeader.NumberOfSections++; } if (imageFileMachine != ImageFileMachine.ARM) { // .reloc 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 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; 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); if (imageFileMachine != ImageFileMachine.ARM) { reloc.VirtualSize = ((uint)moduleBuilder.unmanagedExports.Count + 1) * 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; if (reloc.SizeOfRawData != 0) { // 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; 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 if (imageFileMachine != ImageFileMachine.ARM) { 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); } if (reloc.SizeOfRawData != 0) { writer.WriteSectionHeader(reloc); } stream.Seek(text.PointerToRawData, SeekOrigin.Begin); code.Write(mw, sdata.VirtualAddress); if (sdata.SizeOfRawData != 0) { stream.Seek(sdata.PointerToRawData, SeekOrigin.Begin); mw.Write(moduleBuilder.initializedData); } if (rsrc.SizeOfRawData != 0) { stream.Seek(rsrc.PointerToRawData, SeekOrigin.Begin); resources.Write(mw, rsrc.VirtualAddress); } if (reloc.SizeOfRawData != 0) { stream.Seek(reloc.PointerToRawData, SeekOrigin.Begin); code.WriteRelocations(mw); } // file alignment stream.SetLength(reloc.PointerToRawData + reloc.SizeOfRawData); // 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) { moduleBuilder.WriteSymbolTokenMap(); moduleBuilder.symbolWriter.Close(); } }
internal void Write(MetadataWriter mw, uint sdataRVA) { // sort the exports by ordinal text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportOrdinals); // Now write the Export Address Table text.AssertRVA(mw, exportAddressTableRVA); for (int i = 0, pos = 0; i < entries; i++) { if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase) { mw.Write(stubsRVA + (uint)pos * stubLength); pos++; } else { mw.Write(0); } } // sort the exports by name text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportNames); // Now write the Export Name Pointer Table text.AssertRVA(mw, exportNamePointerTableRVA); uint nameOffset = (uint)text.moduleBuilder.fileName.Length + 1; foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports) { if (exp.name != null) { mw.Write(namesRVA + nameOffset); nameOffset += (uint)exp.name.Length + 1; } } // Now write the Export Ordinal Table text.AssertRVA(mw, exportOrdinalTableRVA); foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports) { if (exp.name != null) { mw.Write((ushort)(exp.ordinal - ordinalBase)); } } // Now write the actual names text.AssertRVA(mw, namesRVA); mw.Write(Encoding.ASCII.GetBytes(text.moduleBuilder.fileName)); mw.Write((byte)0); foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports) { if (exp.name != null) { mw.Write(Encoding.ASCII.GetBytes(exp.name)); mw.Write((byte)0); } } text.AssertRVA(mw, namesRVA + namesLength); // alignment padding for (int i = (int)(stubsRVA - (namesRVA + namesLength)); i > 0; i--) { mw.Write((byte)0); } // sort the exports by ordinal text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportOrdinals); // Now write the stubs text.AssertRVA(mw, stubsRVA); for (int i = 0, pos = 0; i < entries; i++) { if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase) { switch (text.peWriter.Headers.FileHeader.Machine) { case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: mw.Write((byte)0xFF); mw.Write((byte)0x25); mw.Write((uint)text.peWriter.Headers.OptionalHeader.ImageBase + text.moduleBuilder.unmanagedExports[pos].rva.initializedDataOffset + sdataRVA); mw.Write((short)0); // alignment break; case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: mw.Write((byte)0x48); mw.Write((byte)0xA1); mw.Write(text.peWriter.Headers.OptionalHeader.ImageBase + text.moduleBuilder.unmanagedExports[pos].rva.initializedDataOffset + sdataRVA); mw.Write((byte)0xFF); mw.Write((byte)0xE0); mw.Write(0); // alignment break; default: throw new NotImplementedException(); } pos++; } } }
private void WriteDebugDirectory(MetadataWriter mw) { if (DebugDirectoryLength != 0) { IMAGE_DEBUG_DIRECTORY idd = new IMAGE_DEBUG_DIRECTORY(); idd.Characteristics = 0; idd.TimeDateStamp = peWriter.Headers.FileHeader.TimeDateStamp; byte[] buf = SymbolSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd); idd.PointerToRawData = (DebugDirectoryRVA - BaseRVA) + DebugDirectoryLength + PointerToRawData; mw.Write(idd.Characteristics); mw.Write(idd.TimeDateStamp); mw.Write(idd.MajorVersion); mw.Write(idd.MinorVersion); mw.Write(idd.Type); mw.Write(idd.SizeOfData); mw.Write(idd.AddressOfRawData); mw.Write(idd.PointerToRawData); mw.Write(buf); } }
private void WriteVTableFixups(MetadataWriter mw, uint sdataRVA) { foreach (ModuleBuilder.VTableFixups fixups in moduleBuilder.vtablefixups) { mw.Write(fixups.initializedDataOffset + sdataRVA); mw.Write(fixups.count); mw.Write(fixups.type); } }
private void AssertRVA(MetadataWriter mw, uint rva) { Debug.Assert(mw.Position - PointerToRawData + BaseRVA == rva); }
internal void WriteParamRecords(MetadataWriter mw) { foreach (MethodBuilder mb in methods) { mb.WriteParamRecords(mw); } }
internal void Write(MetadataWriter mw, uint sdataRVA, out uint guidHeapOffset) { // Now that we're ready to start writing, we need to do some fix ups moduleBuilder.TypeRef.Fixup(moduleBuilder); moduleBuilder.MethodDef.Fixup(this); moduleBuilder.MethodImpl.Fixup(moduleBuilder); moduleBuilder.MethodSemantics.Fixup(moduleBuilder); moduleBuilder.InterfaceImpl.Fixup(); moduleBuilder.ResolveInterfaceImplPseudoTokens(); moduleBuilder.MemberRef.Fixup(moduleBuilder); moduleBuilder.Constant.Fixup(moduleBuilder); moduleBuilder.FieldMarshal.Fixup(moduleBuilder); moduleBuilder.DeclSecurity.Fixup(moduleBuilder); moduleBuilder.GenericParam.Fixup(moduleBuilder); moduleBuilder.CustomAttribute.Fixup(moduleBuilder); moduleBuilder.FieldLayout.Fixup(moduleBuilder); moduleBuilder.FieldRVA.Fixup(moduleBuilder, (int)sdataRVA, (int)this.MethodBodiesRVA); moduleBuilder.ImplMap.Fixup(moduleBuilder); moduleBuilder.ExportedType.Fixup(moduleBuilder); moduleBuilder.ManifestResource.Fixup(moduleBuilder); moduleBuilder.MethodSpec.Fixup(moduleBuilder); moduleBuilder.GenericParamConstraint.Fixup(moduleBuilder); // Import Address Table AssertRVA(mw, ImportAddressTableRVA); if (ImportAddressTableLength != 0) { WriteRVA(mw, ImportHintNameTableRVA); WriteRVA(mw, 0); } // CLI Header AssertRVA(mw, ComDescriptorRVA); cliHeader.MetaData.VirtualAddress = MetadataRVA; cliHeader.MetaData.Size = MetadataLength; if (ResourcesLength != 0) { cliHeader.Resources.VirtualAddress = ResourcesRVA; cliHeader.Resources.Size = ResourcesLength; } if (StrongNameSignatureLength != 0) { cliHeader.StrongNameSignature.VirtualAddress = StrongNameSignatureRVA; cliHeader.StrongNameSignature.Size = StrongNameSignatureLength; } if (VTableFixupsLength != 0) { cliHeader.VTableFixups.VirtualAddress = VTableFixupsRVA; cliHeader.VTableFixups.Size = VTableFixupsLength; } cliHeader.Write(mw); // alignment padding for (int i = (int)(MethodBodiesRVA - (ComDescriptorRVA + ComDescriptorLength)); i > 0; i--) { mw.Write((byte)0); } // Method Bodies mw.Write(moduleBuilder.methodBodies); // alignment padding for (int i = (int)(ResourcesRVA - (MethodBodiesRVA + MethodBodiesLength)); i > 0; i--) { mw.Write((byte)0); } // Resources moduleBuilder.WriteResources(mw); // The strong name signature live here (if it exists), but it will written later // and the following alignment padding will take care of reserving the space. // alignment padding for (int i = (int)(MetadataRVA - (ResourcesRVA + ResourcesLength)); i > 0; i--) { mw.Write((byte)0); } // Metadata AssertRVA(mw, MetadataRVA); moduleBuilder.WriteMetadata(mw, out guidHeapOffset); // alignment padding for (int i = (int)(VTableFixupsRVA - (MetadataRVA + MetadataLength)); i > 0; i--) { mw.Write((byte)0); } // VTableFixups AssertRVA(mw, VTableFixupsRVA); WriteVTableFixups(mw, sdataRVA); // Debug Directory AssertRVA(mw, DebugDirectoryRVA); WriteDebugDirectory(mw); // alignment padding for (int i = (int)(ExportDirectoryRVA - (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength)); i > 0; i--) { mw.Write((byte)0); } // Export Directory AssertRVA(mw, ExportDirectoryRVA); WriteExportDirectory(mw); // Export Tables AssertRVA(mw, ExportTablesRVA); WriteExportTables(mw, sdataRVA); // alignment padding for (int i = (int)(ImportDirectoryRVA - (ExportTablesRVA + ExportTablesLength)); i > 0; i--) { mw.Write((byte)0); } // Import Directory AssertRVA(mw, ImportDirectoryRVA); if (ImportDirectoryLength != 0) { WriteImportDirectory(mw); } // alignment padding for (int i = (int)(StartupStubRVA - (ImportDirectoryRVA + ImportDirectoryLength)); i > 0; i--) { mw.Write((byte)0); } // Startup Stub AssertRVA(mw, StartupStubRVA); if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64) { /* * 48 A1 00 20 40 00 00 00 00 00 mov rax,qword ptr [0000000000402000h] * FF E0 jmp rax */ mw.Write((ushort)0xA148); mw.Write(peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA); mw.Write((ushort)0xE0FF); } else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64) { mw.Write(new byte[] { 0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40, 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50, 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00 }); mw.Write(peWriter.Headers.OptionalHeader.ImageBase + StartupStubRVA); mw.Write(peWriter.Headers.OptionalHeader.ImageBase + BaseRVA); } else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386) { mw.Write((ushort)0x25FF); mw.Write((uint)peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA); } else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM) { uint rva = (uint)peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA; ushort lo = (ushort)rva; ushort hi = (ushort)(rva >> 16); mw.Write((ushort)(0xF240 + (lo >> 12))); mw.Write((ushort)(0x0C00 + ((lo << 4) & 0xF000) + (lo & 0xFF))); mw.Write((ushort)(0xF2C0 + (hi >> 12))); mw.Write((ushort)(0x0C00 + ((hi << 4) & 0xF000) + (hi & 0xFF))); mw.Write((ushort)0xF8DC); mw.Write((ushort)0xF000); } else { throw new NotSupportedException(); } }
internal void WriteRelocations(MetadataWriter mw) { // we assume that unmanagedExports is still sorted by ordinal for (int i = 0, pos = 0; i < entries; i++) { if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase) { // both I386 and AMD64 have the address at offset 2 text.WriteRelocationBlock(mw, stubsRVA + 2 + (uint)pos * stubLength); pos++; } } }
private static int GetLength(MetadataWriter mw) { int len = 4 + 4 + 8 + 8; foreach (Table table in mw.ModuleBuilder.GetTables()) { if (table != null && table.RowCount > 0) { len += 4; // row count len += table.GetLength(mw); } } // note that we pad one extra (unexplained) byte return len + 1; }
private void WriteExportDirectory(MetadataWriter mw) { if (ExportDirectoryLength != 0) { // Flags mw.Write(0); // Date/Time Stamp mw.Write(peWriter.Headers.FileHeader.TimeDateStamp); // Major Version mw.Write((short)0); // Minor Version mw.Write((short)0); // Name RVA mw.Write(exportTables.namesRVA); // Ordinal Base mw.Write(exportTables.ordinalBase); // Address Table Entries mw.Write(exportTables.entries); // Number of Name Pointers mw.Write(exportTables.nameCount); // Export Address Table RVA mw.Write(exportTables.exportAddressTableRVA); // Name Pointer RVA mw.Write(exportTables.exportNamePointerTableRVA); // Ordinal Table RVA mw.Write(exportTables.exportOrdinalTableRVA); } }
protected override void WriteImpl(MetadataWriter mw) { mw.Write((byte)0); foreach (string str in list) { mw.WriteCompressedInt(str.Length * 2 + 1); byte hasSpecialChars = 0; foreach (char ch in str) { mw.Write((ushort)ch); if (hasSpecialChars == 0 && (ch < 0x20 || ch > 0x7E)) { if (ch > 0x7E || (ch >= 0x01 && ch <= 0x08) || (ch >= 0x0E && ch <= 0x1F) || ch == 0x27 || ch == 0x2D) { hasSpecialChars = 1; } } } mw.Write(hasSpecialChars); } }
private void WriteExportTables(MetadataWriter mw, uint sdataRVA) { if (exportTables != null) { exportTables.Write(mw, sdataRVA); } }
private void WriteImportDirectory(MetadataWriter mw) { mw.Write(ImportDirectoryRVA + 40); // ImportLookupTable mw.Write(0); // DateTimeStamp mw.Write(0); // ForwarderChain mw.Write(ImportHintNameTableRVA + 14); // Name mw.Write(ImportAddressTableRVA); mw.Write(new byte[20]); // Import Lookup Table mw.Write(ImportHintNameTableRVA); // Hint/Name Table RVA int size = 48; if (peWriter.Headers.FileHeader.Machine != IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386) { size += 4; mw.Write(0); } mw.Write(0); // alignment padding for (int i = (int)(ImportHintNameTableRVA - (ImportDirectoryRVA + size)); i > 0; i--) { mw.Write((byte)0); } // Hint/Name Table AssertRVA(mw, ImportHintNameTableRVA); mw.Write((ushort)0); // Hint if ((peWriter.Headers.FileHeader.Characteristics & IMAGE_FILE_HEADER.IMAGE_FILE_DLL) != 0) { mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorDllMain")); } else { mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorExeMain")); } mw.Write((byte)0); // Name mw.Write(System.Text.Encoding.ASCII.GetBytes("mscoree.dll")); mw.Write((ushort)0); }
internal void WriteRelocations(MetadataWriter mw) { uint relocAddress = this.StartupStubRVA; switch (peWriter.Headers.FileHeader.Machine) { case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: relocAddress += 2; break; case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64: relocAddress += 0x20; break; } WriteRelocationBlock(mw, relocAddress); if (exportTables != null) { exportTables.WriteRelocations(mw); } }
protected abstract void WriteImpl(MetadataWriter mw);
// note that we're lazy and write a new relocation block for every relocation // even if they are in the same page (since there is typically only one anyway) private void WriteRelocationBlock(MetadataWriter mw, uint relocAddress) { uint pageRVA = relocAddress & ~0xFFFU; mw.Write(pageRVA); // PageRVA mw.Write(0x000C); // Block Size switch (peWriter.Headers.FileHeader.Machine) { case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: mw.Write(0x3000 + relocAddress - pageRVA); // Type / Offset break; case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: mw.Write(0xA000 + relocAddress - pageRVA); // Type / Offset break; case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_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 break; } }
protected override void WriteImpl(MetadataWriter mw) { Table[] tables = mw.ModuleBuilder.GetTables(); // Header mw.Write(0); // Reserved int ver = mw.ModuleBuilder.MDStreamVersion; mw.Write((byte)(ver >> 16)); // MajorVersion mw.Write((byte)ver); // MinorVersion byte heapSizes = 0; if (mw.ModuleBuilder.Strings.IsBig) { heapSizes |= 0x01; } if (mw.ModuleBuilder.Guids.IsBig) { heapSizes |= 0x02; } if (mw.ModuleBuilder.Blobs.IsBig) { heapSizes |= 0x04; } mw.Write(heapSizes);// HeapSizes // LAMESPEC spec says reserved, but .NET 2.0 Ref.Emit sets it to 0x10 mw.Write((byte)0x10); // Reserved long bit = 1; long valid = 0; foreach (Table table in tables) { if (table != null && table.RowCount > 0) { valid |= bit; } bit <<= 1; } mw.Write(valid); // Valid mw.Write(0x0016003301FA00L); // Sorted // Rows foreach (Table table in tables) { if (table != null && table.RowCount > 0) { mw.Write(table.RowCount); } } // Tables foreach (Table table in tables) { if (table != null && table.RowCount > 0) { int pos = mw.Position; table.Write(mw); Debug.Assert(mw.Position - pos == table.GetLength(mw)); } } // unexplained extra padding mw.Write((byte)0); }
internal void WriteFieldRecords(MetadataWriter mw) { mw.Write((short)attribs); mw.WriteStringIndex(nameIndex); mw.WriteBlobIndex(signature); }
internal void WriteParamRecords(MetadataWriter mw) { if (parameters != null) { foreach (ParameterBuilder pb in parameters) { pb.WriteParamRecord(mw); } } }
internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ByteBuffer versionInfoData, byte[] unmanagedResources, int entryPointToken) { moduleBuilder.FixupMethodBodyTokens(); moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleBuilder.Guids.Add(moduleBuilder.ModuleVersionId), 0, 0); if (moduleBuilder.UserStrings.IsEmpty) { // for compat with Ref.Emit, if there aren't any user strings, we add one moduleBuilder.UserStrings.Add(" "); } using (FileStream fs = new FileStream(moduleBuilder.FullyQualifiedName, FileMode.Create)) { 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; } 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; 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, publicKey != null); ResourceSection resources = new ResourceSection(versionInfoData, unmanagedResources); // 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; // 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; } writer.Headers.FileHeader.NumberOfSections = 2; if (moduleBuilder.initializedData.Length != 0) { writer.Headers.FileHeader.NumberOfSections++; } if (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 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 = (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; } 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; 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; } 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); fs.Seek(sdata.PointerToRawData, SeekOrigin.Begin); mw.Write(moduleBuilder.initializedData); if (rsrc.SizeOfRawData != 0) { fs.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 } // 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); } } if (moduleBuilder.symbolWriter != null) { moduleBuilder.WriteSymbolTokenMap(); moduleBuilder.symbolWriter.Close(); } }
internal void WriteMethodDefRecords(int baseRVA, MetadataWriter mw, ref int paramList) { foreach (MethodBuilder mb in methods) { mb.WriteMethodDefRecord(baseRVA, mw, ref paramList); } }
internal void WriteParamRecord(MetadataWriter mw) { mw.Write(flags); mw.Write(sequence); mw.WriteStringIndex(nameIndex); }
internal void WriteFieldRecords(MetadataWriter mw) { foreach (FieldBuilder fb in fields) { fb.WriteFieldRecords(mw); } }
private static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken, Stream stream) { moduleBuilder.ApplyUnmanagedExports(imageFileMachine); moduleBuilder.FixupMethodBodyTokens(); int moduleVersionIdIndex = moduleBuilder.Guids.Add(moduleBuilder.GetModuleVersionIdOrEmpty()); moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleVersionIdIndex, 0, 0); if (moduleBuilder.UserStrings.IsEmpty) { // for compat with Ref.Emit, if there aren't any user strings, we add one moduleBuilder.UserStrings.Add(" "); } if (resources != null) { resources.Finish(); } PEWriter writer = new PEWriter(stream); writer.Headers.OptionalHeader.FileAlignment = (uint)moduleBuilder.__FileAlignment; 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; writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000); break; case ImageFileMachine.ARM: writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM; writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE; writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000); writer.Headers.OptionalHeader.SectionAlignment = 0x1000; 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 = moduleBuilder.GetStackReserve(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 = moduleBuilder.GetStackReserve(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 = (ushort)moduleBuilder.__DllCharacteristics; 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 ((portableExecutableKind & PortableExecutableKinds.Preferred32Bit) != 0) { cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED; } 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, stream); moduleBuilder.Tables.Freeze(mw); TextSection code = new TextSection(writer, cliHeader, moduleBuilder, ComputeStrongNameSignatureLength(publicKey)); // Export Directory if (code.ExportDirectoryLength != 0) { writer.Headers.OptionalHeader.DataDirectory[0].VirtualAddress = code.ExportDirectoryRVA; writer.Headers.OptionalHeader.DataDirectory[0].Size = code.ExportDirectoryLength; } // Import Directory if (code.ImportDirectoryLength != 0) { writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA; writer.Headers.OptionalHeader.DataDirectory[1].Size = code.ImportDirectoryLength; } // Import Address Table Directory if (code.ImportAddressTableLength != 0) { 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; // Debug Directory if (code.DebugDirectoryLength != 0) { writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA; writer.Headers.OptionalHeader.DataDirectory[6].Size = code.DebugDirectoryLength; } // Set the PE File timestamp writer.Headers.FileHeader.TimeDateStamp = moduleBuilder.GetTimeDateStamp(); // we need to start by computing the number of sections, because code.PointerToRawData depends on that writer.Headers.FileHeader.NumberOfSections = 2; if (moduleBuilder.initializedData.Length != 0) { // .sdata writer.Headers.FileHeader.NumberOfSections++; } if (resources != null) { // .rsrc 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 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; 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 = code.PackRelocations(); 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; if (reloc.SizeOfRawData != 0) { // 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; 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.Thumb; } writer.WritePEHeaders(); writer.WriteSectionHeader(text); if (sdata.SizeOfRawData != 0) { writer.WriteSectionHeader(sdata); } if (rsrc.SizeOfRawData != 0) { writer.WriteSectionHeader(rsrc); } if (reloc.SizeOfRawData != 0) { writer.WriteSectionHeader(reloc); } stream.Seek(text.PointerToRawData, SeekOrigin.Begin); uint guidHeapOffset; code.Write(mw, sdata.VirtualAddress, out guidHeapOffset); if (sdata.SizeOfRawData != 0) { stream.Seek(sdata.PointerToRawData, SeekOrigin.Begin); mw.Write(moduleBuilder.initializedData); } if (rsrc.SizeOfRawData != 0) { stream.Seek(rsrc.PointerToRawData, SeekOrigin.Begin); resources.Write(mw, rsrc.VirtualAddress); } if (reloc.SizeOfRawData != 0) { stream.Seek(reloc.PointerToRawData, SeekOrigin.Begin); code.WriteRelocations(mw); } // file alignment stream.SetLength(reloc.PointerToRawData + reloc.SizeOfRawData); // if we don't have a guid, generate one based on the contents of the assembly if (moduleBuilder.universe.Deterministic && moduleBuilder.GetModuleVersionIdOrEmpty() == Guid.Empty) { Guid guid = GenerateModuleVersionId(stream); stream.Position = guidHeapOffset + (moduleVersionIdIndex - 1) * 16; stream.Write(guid.ToByteArray(), 0, 16); moduleBuilder.__SetModuleVersionId(guid); } // do the strong naming if (keyPair != null) { StrongName(stream, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength); } #if !NO_SYMBOL_WRITER if (moduleBuilder.symbolWriter != null) { moduleBuilder.WriteSymbolTokenMap(); moduleBuilder.symbolWriter.Close(); } #endif }