public void LinkSuffix1() { var builder1 = new BlobBuilder(16); builder1.WriteByte(1); builder1.WriteByte(2); builder1.WriteByte(3); var builder2 = new BlobBuilder(16); builder2.WriteByte(4); builder1.LinkSuffix(builder2); AssertEx.Equal(new byte[] { 1, 2, 3, 4 }, builder1.ToArray()); Assert.Equal(4, builder1.Count); Assert.Equal(1, builder2.Count); var builder3 = new BlobBuilder(16); builder3.WriteByte(5); var builder4 = new BlobBuilder(16); builder4.WriteByte(6); builder3.LinkSuffix(builder4); builder1.LinkSuffix(builder3); AssertEx.Equal(new byte[] { 1, 2, 3, 4, 5, 6 }, builder1.ToArray()); Assert.Equal(6, builder1.Count); Assert.Equal(2, builder3.Count); Assert.Equal(1, builder4.Count); }
public void Serialize(BlobBuilder builder, PEDirectoriesBuilder headers, out ContentId contentId) { var serializedSections = SerializeSections(); Blob stampFixup; WritePESignature(builder); WriteCoffHeader(builder, serializedSections, out stampFixup); WritePEHeader(builder, headers, serializedSections); WriteSectionHeaders(builder, serializedSections); builder.Align(FileAlignment); foreach (var section in serializedSections) { builder.LinkSuffix(section.Builder); builder.Align(FileAlignment); } contentId = IdProvider(builder); // patch timestamp in COFF header: var stampWriter = new BlobWriter(stampFixup); stampWriter.WriteBytes(contentId.Stamp); Debug.Assert(stampWriter.RemainingBytes == 0); }
public BlobContentId Serialize(BlobBuilder builder) { // Define and serialize sections in two steps. // We need to know about all sections before serializing them. var serializedSections = SerializeSections(); // The positions and sizes of directories are calculated during section serialization. var directories = GetDirectories(); Blob stampFixup; WritePESignature(builder); WriteCoffHeader(builder, serializedSections, out stampFixup); WritePEHeader(builder, directories, serializedSections); WriteSectionHeaders(builder, serializedSections); builder.Align(Header.FileAlignment); foreach (var section in serializedSections) { builder.LinkSuffix(section.Builder); builder.Align(Header.FileAlignment); } var contentId = IdProvider(builder.GetBlobs()); // patch timestamp in COFF header: var stampWriter = new BlobWriter(stampFixup); stampWriter.WriteUInt32(contentId.Stamp); Debug.Assert(stampWriter.RemainingBytes == 0); return(contentId); }
private static void WriteAligned(BlobBuilder source, BlobBuilder target) { int length = source.Count; target.LinkSuffix(source); target.WriteBytes(0, BitArithmeticUtilities.Align(length, 4) - length); }
/// <summary> /// Serialize the Debug Table and Data. /// </summary> /// <param name="builder">Builder.</param> /// <param name="sectionLocation">The containing PE section location.</param> /// <param name="sectionOffset">Offset of the table within the containing section.</param> internal void Serialize(BlobBuilder builder, SectionLocation sectionLocation, int sectionOffset) { int dataOffset = sectionOffset + TableSize; foreach (var entry in _entries) { int addressOfRawData; int pointerToRawData; if (entry.DataSize > 0) { addressOfRawData = sectionLocation.RelativeVirtualAddress + dataOffset; pointerToRawData = sectionLocation.PointerToRawData + dataOffset; } else { addressOfRawData = 0; pointerToRawData = 0; } builder.WriteUInt32(0); // characteristics, always 0 builder.WriteUInt32(entry.Stamp); builder.WriteUInt32(entry.Version); builder.WriteInt32((int)entry.Type); builder.WriteInt32(entry.DataSize); builder.WriteInt32(addressOfRawData); builder.WriteInt32(pointerToRawData); dataOffset += entry.DataSize; } builder.LinkSuffix(_dataBuilder); }
public void Link() { var builder1 = new BlobBuilder(16); builder1.WriteByte(1); var builder2 = new BlobBuilder(16); builder2.WriteByte(2); var builder3 = new BlobBuilder(16); builder3.WriteByte(3); var builder4 = new BlobBuilder(16); builder4.WriteByte(4); var builder5 = new BlobBuilder(16); builder5.WriteByte(5); builder2.LinkPrefix(builder1); AssertEx.Equal(new byte[] { 1, 2 }, builder2.ToArray()); Assert.Throws <InvalidOperationException>(() => builder1.ToArray()); Assert.Throws <InvalidOperationException>(() => builder2.LinkPrefix(builder1)); Assert.Throws <InvalidOperationException>(() => builder1.WriteByte(0xff)); Assert.Throws <InvalidOperationException>(() => builder1.WriteBytes(1, 10)); Assert.Throws <InvalidOperationException>(() => builder1.WriteBytes(new byte[] { 1 })); Assert.Throws <InvalidOperationException>(() => builder1.ReserveBytes(1)); Assert.Throws <InvalidOperationException>(() => builder1.GetBlobs()); Assert.Throws <InvalidOperationException>(() => builder1.ContentEquals(builder1)); Assert.Throws <InvalidOperationException>(() => builder1.WriteUTF16("str")); Assert.Throws <InvalidOperationException>(() => builder1.WriteUTF8("str", allowUnpairedSurrogates: false)); builder2.LinkSuffix(builder3); AssertEx.Equal(new byte[] { 1, 2, 3 }, builder2.ToArray()); Assert.Throws <InvalidOperationException>(() => builder3.LinkPrefix(builder5)); builder2.LinkPrefix(builder4); AssertEx.Equal(new byte[] { 4, 1, 2, 3 }, builder2.ToArray()); Assert.Throws <InvalidOperationException>(() => builder4.LinkPrefix(builder5)); builder2.LinkSuffix(builder5); AssertEx.Equal(new byte[] { 4, 1, 2, 3, 5 }, builder2.ToArray()); }
public void LinkSuffix_Empty2() { var builder1 = new BlobBuilder(16); var builder2 = new BlobBuilder(16); builder1.LinkSuffix(builder2); AssertEx.Equal(new byte[0], builder1.ToArray()); Assert.Equal(0, builder1.Count); Assert.Equal(0, builder2.Count); }
internal void SerializeMetadataTables(BlobBuilder writer) { var sizes = new Sizes(_blobHeapSize, _guidWriter.Count); SerializeHeader(writer, sizes); // tables: SerializeDocumentTable(writer, sizes); SerializeMethodTable(writer, sizes); // heaps: writer.LinkSuffix(_guidWriter); WriteBlobHeap(writer); }
public void LinkSuffix_Empty1() { var builder1 = new BlobBuilder(16); var builder2 = new BlobBuilder(16); builder2.WriteByte(2); builder1.LinkSuffix(builder2); AssertEx.Equal(new byte[] { 0x02 }, builder1.ToArray()); Assert.Equal(1, builder1.Count); Assert.Equal(1, builder2.Count); }
public void LinkSuffix1() { var builder1 = new BlobBuilder(16); builder1.WriteByte(1); builder1.WriteByte(2); builder1.WriteByte(3); var builder2 = new BlobBuilder(16); builder2.WriteByte(4); builder1.LinkSuffix(builder2); AssertEx.Equal(new byte[] { 1, 2, 3, 4 }, builder1.ToArray()); }
public void LinkSuffix2() { var builder1 = new BlobBuilder(16); builder1.WriteBytes(1, 16); var builder2 = new BlobBuilder(16); builder2.WriteBytes(2, 16); builder1.LinkSuffix(builder2); AssertEx.Equal(new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, builder1.ToArray()); Assert.Equal(32, builder1.Count); Assert.Equal(16, builder2.Count); }
public void LinkSuffix_Empty3() { var builder1 = new BlobBuilder(16); builder1.ReserveBytes(16); builder1.ReserveBytes(0); var builder2 = new BlobBuilder(16); builder2.ReserveBytes(16); builder2.ReserveBytes(0); builder1.LinkSuffix(builder2); AssertEx.Equal(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, builder1.ToArray()); Assert.Equal(32, builder1.Count); Assert.Equal(16, builder2.Count); }
public static void SerializeWin32Resources(BlobBuilder builder, IEnumerable <IWin32Resource> theResources, int resourcesRva) { theResources = SortResources(theResources); Directory typeDirectory = new Directory(string.Empty, 0); Directory nameDirectory = null; Directory languageDirectory = null; int lastTypeID = int.MinValue; string lastTypeName = null; int lastID = int.MinValue; string lastName = null; uint sizeOfDirectoryTree = 16; //EDMAURER note that this list is assumed to be sorted lowest to highest //first by typeId, then by Id. foreach (IWin32Resource r in theResources) { bool typeDifferent = (r.TypeId < 0 && r.TypeName != lastTypeName) || r.TypeId > lastTypeID; if (typeDifferent) { lastTypeID = r.TypeId; lastTypeName = r.TypeName; if (lastTypeID < 0) { Debug.Assert(typeDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with types encoded as strings precede those encoded as ints"); typeDirectory.NumberOfNamedEntries++; } else { typeDirectory.NumberOfIdEntries++; } sizeOfDirectoryTree += 24; typeDirectory.Entries.Add(nameDirectory = new Directory(lastTypeName, lastTypeID)); } if (typeDifferent || (r.Id < 0 && r.Name != lastName) || r.Id > lastID) { lastID = r.Id; lastName = r.Name; if (lastID < 0) { Debug.Assert(nameDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with names encoded as strings precede those encoded as ints"); nameDirectory.NumberOfNamedEntries++; } else { nameDirectory.NumberOfIdEntries++; } sizeOfDirectoryTree += 24; nameDirectory.Entries.Add(languageDirectory = new Directory(lastName, lastID)); } languageDirectory.NumberOfIdEntries++; sizeOfDirectoryTree += 8; languageDirectory.Entries.Add(r); } var dataWriter = new BlobBuilder(); //'dataWriter' is where opaque resource data goes as well as strings that are used as type or name identifiers WriteDirectory(typeDirectory, builder, 0, 0, sizeOfDirectoryTree, resourcesRva, dataWriter); builder.LinkSuffix(dataWriter); builder.WriteByte(0); builder.Align(4); }
/// <summary> /// Serializes .text section data into a specified <paramref name="builder"/>. /// </summary> /// <param name="builder">An empty builder to serialize section data to.</param> /// <param name="relativeVirtualAddess">Relative virtual address of the section within the containing PE file.</param> /// <param name="entryPointTokenOrRelativeVirtualAddress">Entry point token or RVA (<see cref="CorHeader.EntryPointTokenOrRelativeVirtualAddress"/>)</param> /// <param name="corFlags">COR Flags (<see cref="CorHeader.Flags"/>).</param> /// <param name="baseAddress">Base address of the PE image.</param> /// <param name="metadataBuilder"><see cref="BlobBuilder"/> containing metadata. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="ilBuilder"><see cref="BlobBuilder"/> containing IL stream. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="mappedFieldDataBuilder"><see cref="BlobBuilder"/> containing mapped field data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="resourceBuilder"><see cref="BlobBuilder"/> containing managed resource data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="debugTableBuilderOpt"><see cref="BlobBuilder"/> containing debug table data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> public void Serialize( BlobBuilder builder, int relativeVirtualAddess, int entryPointTokenOrRelativeVirtualAddress, CorFlags corFlags, ulong baseAddress, BlobBuilder metadataBuilder, BlobBuilder ilBuilder, BlobBuilder mappedFieldDataBuilder, BlobBuilder resourceBuilder, BlobBuilder debugTableBuilderOpt) { Debug.Assert(builder.Count == 0); Debug.Assert(metadataBuilder.Count == MetadataSize); Debug.Assert(metadataBuilder.Count % 4 == 0); Debug.Assert(ilBuilder.Count == ILStreamSize); Debug.Assert(mappedFieldDataBuilder.Count == MappedFieldDataSize); Debug.Assert(resourceBuilder.Count == ResourceDataSize); Debug.Assert(resourceBuilder.Count % 4 == 0); // TODO: avoid recalculation int importTableRva = GetImportTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; int importAddressTableRva = GetImportAddressTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; if (RequiresStartupStub) { WriteImportAddressTable(builder, importTableRva); } WriteCorHeader(builder, relativeVirtualAddess, entryPointTokenOrRelativeVirtualAddress, corFlags); // IL: ilBuilder.Align(4); builder.LinkSuffix(ilBuilder); // metadata: builder.LinkSuffix(metadataBuilder); // managed resources: builder.LinkSuffix(resourceBuilder); // strong name signature: builder.WriteBytes(0, StrongNameSignatureSize); if (debugTableBuilderOpt != null) { builder.LinkSuffix(debugTableBuilderOpt); } if (RequiresStartupStub) { WriteImportTable(builder, importTableRva, importAddressTableRva); WriteNameTable(builder); WriteRuntimeStartupStub(builder, importAddressTableRva, baseAddress); } // mapped field data: builder.LinkSuffix(mappedFieldDataBuilder); Debug.Assert(builder.Count == ComputeSizeOfTextSection()); }
/// <summary> /// Serializes .text section data into a specified <paramref name="builder"/>. /// </summary> /// <param name="builder">An empty builder to serialize section data to.</param> /// <param name="relativeVirtualAddess">Relative virtual address of the section within the containing PE file.</param> /// <param name="entryPointTokenOrRelativeVirtualAddress">Entry point token or RVA (<see cref="CorHeader.EntryPointTokenOrRelativeVirtualAddress"/>)</param> /// <param name="corFlags">COR Flags (<see cref="CorHeader.Flags"/>).</param> /// <param name="baseAddress">Base address of the PE image.</param> /// <param name="metadataBuilder"><see cref="BlobBuilder"/> containing metadata. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="ilBuilder"><see cref="BlobBuilder"/> containing IL stream. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="mappedFieldDataBuilderOpt"><see cref="BlobBuilder"/> containing mapped field data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="resourceBuilderOpt"><see cref="BlobBuilder"/> containing managed resource data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="debugDataBuilderOpt"><see cref="BlobBuilder"/> containing PE debug table and data. Must be populated with data. Linked into the <paramref name="builder"/> and can't be expanded afterwards.</param> /// <param name="strongNameSignature">Blob reserved in the <paramref name="builder"/> for strong name signature.</param> public void Serialize( BlobBuilder builder, int relativeVirtualAddess, int entryPointTokenOrRelativeVirtualAddress, CorFlags corFlags, ulong baseAddress, BlobBuilder metadataBuilder, BlobBuilder ilBuilder, BlobBuilder mappedFieldDataBuilderOpt, BlobBuilder resourceBuilderOpt, BlobBuilder debugDataBuilderOpt, out Blob strongNameSignature) { Debug.Assert(builder.Count == 0); Debug.Assert(metadataBuilder.Count == MetadataSize); Debug.Assert(metadataBuilder.Count % 4 == 0); Debug.Assert(ilBuilder.Count == ILStreamSize); Debug.Assert((mappedFieldDataBuilderOpt?.Count ?? 0) == MappedFieldDataSize); Debug.Assert((resourceBuilderOpt?.Count ?? 0) == ResourceDataSize); Debug.Assert((resourceBuilderOpt?.Count ?? 0) % 4 == 0); // TODO: avoid recalculation int importTableRva = GetImportTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; int importAddressTableRva = GetImportAddressTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; if (RequiresStartupStub) { WriteImportAddressTable(builder, importTableRva); } WriteCorHeader(builder, relativeVirtualAddess, entryPointTokenOrRelativeVirtualAddress, corFlags); // IL: ilBuilder.Align(4); builder.LinkSuffix(ilBuilder); // metadata: builder.LinkSuffix(metadataBuilder); // managed resources: if (resourceBuilderOpt != null) { builder.LinkSuffix(resourceBuilderOpt); } // strong name signature: strongNameSignature = builder.ReserveBytes(StrongNameSignatureSize); // The bytes are required to be 0 for the purpose of calculating hash of the PE content // when strong name signing. new BlobWriter(strongNameSignature).WriteBytes(0, StrongNameSignatureSize); // debug directory and data: if (debugDataBuilderOpt != null) { builder.LinkSuffix(debugDataBuilderOpt); } if (RequiresStartupStub) { WriteImportTable(builder, importTableRva, importAddressTableRva); WriteNameTable(builder); WriteRuntimeStartupStub(builder, importAddressTableRva, baseAddress); } // mapped field data: if (mappedFieldDataBuilderOpt != null) { builder.LinkSuffix(mappedFieldDataBuilderOpt); } Debug.Assert(builder.Count == ComputeSizeOfTextSection()); }
/// <summary> /// Output the section with a given name. For sections existent in the source MSIL PE file /// (.text, optionally .rsrc and .reloc), we first copy the content of the input MSIL PE file /// and then call the section serialization callback to emit the extra content after the input /// section content. /// </summary> /// <param name="name">Section name</param> /// <param name="location">RVA and file location where the section will be put</param> /// <returns>Blob builder representing the section data</returns> protected override BlobBuilder SerializeSection(string name, SectionLocation location) { BlobBuilder sectionDataBuilder = null; int sectionStartRva = location.RelativeVirtualAddress; int outputSectionIndex = _sections.Length - 1; while (outputSectionIndex >= 0 && _sections[outputSectionIndex].Name != name) { outputSectionIndex--; } if (!_target.IsWindows) { if (outputSectionIndex > 0) { sectionStartRva = Math.Max(sectionStartRva, _sectionRVAs[outputSectionIndex - 1] + _sectionRawSizes[outputSectionIndex - 1]); } const int RVAAlign = 1 << RVABitsToMatchFilePos; sectionStartRva = AlignmentHelper.AlignUp(sectionStartRva, RVAAlign); int rvaAdjust = (location.PointerToRawData - sectionStartRva) & (RVAAlign - 1); sectionStartRva += rvaAdjust; location = new SectionLocation(sectionStartRva, location.PointerToRawData); } if (outputSectionIndex >= 0) { _sectionRVAs[outputSectionIndex] = sectionStartRva; } int inputSectionIndex = _peReader.PEHeaders.SectionHeaders.Count() - 1; while (inputSectionIndex >= 0 && _peReader.PEHeaders.SectionHeaders[inputSectionIndex].Name != name) { inputSectionIndex--; } if (inputSectionIndex >= 0) { SectionHeader sectionHeader = _peReader.PEHeaders.SectionHeaders[inputSectionIndex]; int sectionOffset = (_peReader.IsLoadedImage ? sectionHeader.VirtualAddress : sectionHeader.PointerToRawData); int rvaDelta = location.RelativeVirtualAddress - sectionHeader.VirtualAddress; _sectionRvaDeltas.Add(new SectionRVADelta( startRVA: sectionHeader.VirtualAddress, endRVA: sectionHeader.VirtualAddress + Math.Max(sectionHeader.VirtualSize, sectionHeader.SizeOfRawData), deltaRVA: rvaDelta)); int bytesToRead = Math.Min(sectionHeader.SizeOfRawData, sectionHeader.VirtualSize); BlobReader inputSectionReader = _peReader.GetEntireImage().GetReader(sectionOffset, bytesToRead); if (name == RsrcSectionName) { // There seems to be a bug in BlobBuilder - when we LinkSuffix to an empty blob builder, // the blob data goes out of sync and WriteContentTo outputs garbage. sectionDataBuilder = PEResourceHelper.Relocate(inputSectionReader, rvaDelta); } int alignedSize = sectionHeader.VirtualSize; // When custom section data is present, align the section size to 4K to prevent // pre-generated MSIL relocations from tampering with native relocations. if (_customSections.Contains(name)) { alignedSize = (alignedSize + 0xFFF) & ~0xFFF; } if (sectionDataBuilder != null) { if (alignedSize > bytesToRead) { // If the number of bytes read from the source PE file is less than the virtual size, // zero pad to the end of virtual size before emitting extra section data sectionDataBuilder.WriteBytes(0, alignedSize - bytesToRead); } location = new SectionLocation( location.RelativeVirtualAddress + sectionDataBuilder.Count, location.PointerToRawData + sectionDataBuilder.Count); } } BlobBuilder extraData = _sectionBuilder.SerializeSection(name, location); if (extraData != null) { if (sectionDataBuilder == null) { // See above - there's a bug due to which LinkSuffix to an empty BlobBuilder screws up the blob content. sectionDataBuilder = extraData; } else { sectionDataBuilder.LinkSuffix(extraData); } } // Make sure the section has at least 1 byte, otherwise the PE emitter goes mad, // messes up the section map and corrups the output executable. if (sectionDataBuilder == null) { sectionDataBuilder = new BlobBuilder(); } if (sectionDataBuilder.Count == 0) { sectionDataBuilder.WriteByte(0); } if (outputSectionIndex >= 0) { _sectionRawSizes[outputSectionIndex] = sectionDataBuilder.Count; } return(sectionDataBuilder); }
public static ReadyToRunStandaloneMethodMetadata Compute(EcmaMethod wrappedMethod) { var metadataReader = wrappedMethod.MetadataReader; var _module = wrappedMethod.Module; var rva = wrappedMethod.MetadataReader.GetMethodDefinition(wrappedMethod.Handle).RelativeVirtualAddress; var _methodBody = _module.PEReader.GetMethodBody(rva); byte[] _alternateILStream = _methodBody.GetILBytes(); var exceptionRegions = _methodBody.ExceptionRegions; ILExceptionRegion[] _exceptionRegions; int length = exceptionRegions.Length; if (length == 0) { _exceptionRegions = Array.Empty <ILExceptionRegion>(); } else { _exceptionRegions = new ILExceptionRegion[length]; for (int i = 0; i < length; i++) { var exceptionRegion = exceptionRegions[i]; _exceptionRegions[i] = new ILExceptionRegion( (ILExceptionRegionKind)exceptionRegion.Kind, // assumes that ILExceptionRegionKind and ExceptionRegionKind enums are in sync exceptionRegion.TryOffset, exceptionRegion.TryLength, exceptionRegion.HandlerOffset, exceptionRegion.HandlerLength, MetadataTokens.GetToken(exceptionRegion.CatchType), exceptionRegion.FilterOffset); } } BlobReader localsBlob = default(BlobReader); if (!_methodBody.LocalSignature.IsNil) { localsBlob = wrappedMethod.MetadataReader.GetBlobReader(wrappedMethod.MetadataReader.GetStandaloneSignature(_methodBody.LocalSignature).Signature); } AlternativeTypeRefProvider alternateTypes = new AlternativeTypeRefProvider(); EcmaSignatureEncoder <AlternativeTypeRefProvider> alternateEncoder = new EcmaSignatureEncoder <AlternativeTypeRefProvider>(alternateTypes); Dictionary <int, int> _alternateNonTokenStrings = new Dictionary <int, int>(); BlobBuilder _alternateNonTypeRefStream = new BlobBuilder(); BlobBuilder _nonCodeAlternateBlob = new BlobBuilder(); { // Generate alternate stream for exceptions. _nonCodeAlternateBlob.WriteCompressedInteger(_exceptionRegions.Length); for (int i = 0; i < _exceptionRegions.Length; i++) { var region = _exceptionRegions[i]; _nonCodeAlternateBlob.WriteCompressedInteger((int)region.Kind); _nonCodeAlternateBlob.WriteCompressedInteger((int)region.TryOffset); _nonCodeAlternateBlob.WriteCompressedInteger((int)region.TryLength); _nonCodeAlternateBlob.WriteCompressedInteger((int)region.HandlerOffset); _nonCodeAlternateBlob.WriteCompressedInteger((int)region.HandlerLength); if (region.Kind == ILExceptionRegionKind.Catch) { int alternateToken = GetAlternateStreamToken(region.ClassToken); int encodedToken = CodedIndex.TypeDefOrRefOrSpec(MetadataTokens.EntityHandle(alternateToken)); _nonCodeAlternateBlob.WriteCompressedInteger(encodedToken); } else if (region.Kind == ILExceptionRegionKind.Filter) { _nonCodeAlternateBlob.WriteCompressedInteger(region.FilterOffset); } } if (localsBlob.Length == 0) { // No locals. Encode a 2 to indicate this _nonCodeAlternateBlob.WriteByte(2); } else { _nonCodeAlternateBlob.WriteByte(_methodBody.LocalVariablesInitialized ? (byte)1 : (byte)0); EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(localsBlob, _nonCodeAlternateBlob, GetAlternateStreamToken); sigTranslator.ParseLocalsSignature(); } } ILTokenReplacer.Replace(_alternateILStream, GetAlternateStreamToken); // Add all the streams together into the _nonCodeAlternateBlob int expectedFinalSize = _nonCodeAlternateBlob.Count + _alternateILStream.Length + _alternateNonTypeRefStream.Count; _nonCodeAlternateBlob.WriteBytes(_alternateILStream); _nonCodeAlternateBlob.LinkSuffix(_alternateNonTypeRefStream); Debug.Assert(expectedFinalSize == _nonCodeAlternateBlob.Count); ReadyToRunStandaloneMethodMetadata methodBlock = new ReadyToRunStandaloneMethodMetadata(); methodBlock.ConstantData = _nonCodeAlternateBlob.ToArray(); methodBlock.TypeRefs = alternateTypes._alternateTypeRefStream.ToArray(); return(methodBlock); ///// HELPER FUNCTIONS unsafe int GetAlternateStreamToken(int token) { if (token == 0 || !_alternateNonTokenStrings.TryGetValue(token, out int alternateToken)) { var handle = MetadataTokens.Handle(token); if (handle.Kind == HandleKind.TypeDefinition || handle.Kind == HandleKind.TypeReference) { EcmaType ecmaType = (EcmaType)wrappedMethod.Module.GetObject(MetadataTokens.EntityHandle(token)); alternateToken = MetadataTokens.GetToken(alternateTypes.GetTypeDefOrRefHandleForTypeDesc(ecmaType)); } else { BlobBuilder blob = new BlobBuilder(); int flag = 0; if (handle.Kind == HandleKind.UserString) { string strAlternate = metadataReader.GetUserString((UserStringHandle)handle); flag = 0x70000000; blob.WriteCompressedInteger(strAlternate.Length); fixed(char *charData = strAlternate) { blob.WriteBytes((byte *)charData, strAlternate.Length * 2); } // TODO: consider encoding via wtf-8, or possibly utf-8 } else if (handle.Kind == HandleKind.TypeSpecification) { flag = 0x1B000000; var sigBlob = metadataReader.GetBlobReader(metadataReader.GetTypeSpecification((TypeSpecificationHandle)handle).Signature); EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken); sigTranslator.ParseType(); } else if (handle.Kind == HandleKind.MemberReference) { flag = 0x0a000000; var memberReference = metadataReader.GetMemberReference((MemberReferenceHandle)handle); var sigBlob = metadataReader.GetBlobReader(memberReference.Signature); EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken); sigTranslator.ParseMemberRefSignature(); blob.WriteSerializedString(metadataReader.GetString(memberReference.Name)); blob.WriteCompressedInteger(CodedIndex.MemberRefParent(MetadataTokens.EntityHandle(GetAlternateStreamToken(MetadataTokens.GetToken(memberReference.Parent))))); } else if (handle.Kind == HandleKind.MethodDefinition) { flag = 0x0a000000; var methodDefinition = metadataReader.GetMethodDefinition((MethodDefinitionHandle)handle); var sigBlob = metadataReader.GetBlobReader(methodDefinition.Signature); EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken); sigTranslator.ParseMethodSignature(); blob.WriteSerializedString(metadataReader.GetString(methodDefinition.Name)); blob.WriteCompressedInteger(CodedIndex.MemberRefParent(MetadataTokens.EntityHandle(GetAlternateStreamToken(MetadataTokens.GetToken(methodDefinition.GetDeclaringType()))))); } else if (handle.Kind == HandleKind.FieldDefinition) { flag = 0x0a000000; var fieldDefinition = metadataReader.GetFieldDefinition((FieldDefinitionHandle)handle); var sigBlob = metadataReader.GetBlobReader(fieldDefinition.Signature); EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken); sigTranslator.ParseFieldSignature(); blob.WriteSerializedString(metadataReader.GetString(fieldDefinition.Name)); blob.WriteCompressedInteger(CodedIndex.MemberRefParent(MetadataTokens.EntityHandle(GetAlternateStreamToken(MetadataTokens.GetToken(fieldDefinition.GetDeclaringType()))))); } else if (handle.Kind == HandleKind.MethodSpecification) { flag = 0x2B000000; var methodSpecification = metadataReader.GetMethodSpecification((MethodSpecificationHandle)handle); var sigBlob = metadataReader.GetBlobReader(methodSpecification.Signature); blob.WriteCompressedInteger(MetadataTokens.GetRowNumber(MetadataTokens.EntityHandle(GetAlternateStreamToken(MetadataTokens.GetToken(methodSpecification.Method))))); EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken); sigTranslator.ParseMethodSpecSignature(); } else if (handle.Kind == HandleKind.StandaloneSignature) { flag = 0x11000000; var reader = wrappedMethod.Module.MetadataReader; var sigBlob = reader.GetBlobReader(reader.GetStandaloneSignature((StandaloneSignatureHandle)handle).Signature); EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken); sigTranslator.ParseMethodSignature(); } _alternateNonTypeRefStream.WriteBytes(blob.ToArray()); alternateToken = (_alternateNonTokenStrings.Count + 1) | flag; } _alternateNonTokenStrings.Add(token, alternateToken); } return(alternateToken); } }
public static void SerializeWin32Resources(BlobBuilder builder, IEnumerable<IWin32Resource> theResources, int resourcesRva) { theResources = SortResources(theResources); Directory typeDirectory = new Directory(string.Empty, 0); Directory nameDirectory = null; Directory languageDirectory = null; int lastTypeID = int.MinValue; string lastTypeName = null; int lastID = int.MinValue; string lastName = null; uint sizeOfDirectoryTree = 16; //EDMAURER note that this list is assumed to be sorted lowest to highest //first by typeId, then by Id. foreach (IWin32Resource r in theResources) { bool typeDifferent = (r.TypeId < 0 && r.TypeName != lastTypeName) || r.TypeId > lastTypeID; if (typeDifferent) { lastTypeID = r.TypeId; lastTypeName = r.TypeName; if (lastTypeID < 0) { Debug.Assert(typeDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with types encoded as strings precede those encoded as ints"); typeDirectory.NumberOfNamedEntries++; } else { typeDirectory.NumberOfIdEntries++; } sizeOfDirectoryTree += 24; typeDirectory.Entries.Add(nameDirectory = new Directory(lastTypeName, lastTypeID)); } if (typeDifferent || (r.Id < 0 && r.Name != lastName) || r.Id > lastID) { lastID = r.Id; lastName = r.Name; if (lastID < 0) { Debug.Assert(nameDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with names encoded as strings precede those encoded as ints"); nameDirectory.NumberOfNamedEntries++; } else { nameDirectory.NumberOfIdEntries++; } sizeOfDirectoryTree += 24; nameDirectory.Entries.Add(languageDirectory = new Directory(lastName, lastID)); } languageDirectory.NumberOfIdEntries++; sizeOfDirectoryTree += 8; languageDirectory.Entries.Add(r); } var dataWriter = new BlobBuilder(); //'dataWriter' is where opaque resource data goes as well as strings that are used as type or name identifiers WriteDirectory(typeDirectory, builder, 0, 0, sizeOfDirectoryTree, resourcesRva, dataWriter); builder.LinkSuffix(dataWriter); builder.WriteByte(0); builder.Align(4); }
public void Link() { var builder1 = new BlobBuilder(16); builder1.WriteByte(1); var builder2 = new BlobBuilder(16); builder2.WriteByte(2); var builder3 = new BlobBuilder(16); builder3.WriteByte(3); var builder4 = new BlobBuilder(16); builder4.WriteByte(4); var builder5 = new BlobBuilder(16); builder5.WriteByte(5); builder2.LinkPrefix(builder1); AssertEx.Equal(new byte[] { 1, 2 }, builder2.ToArray()); Assert.Throws<InvalidOperationException>(() => builder1.ToArray()); Assert.Throws<InvalidOperationException>(() => builder2.LinkPrefix(builder1)); Assert.Throws<InvalidOperationException>(() => builder1.WriteByte(0xff)); Assert.Throws<InvalidOperationException>(() => builder1.WriteBytes(1, 10)); Assert.Throws<InvalidOperationException>(() => builder1.WriteBytes(new byte[] { 1 })); Assert.Throws<InvalidOperationException>(() => builder1.ReserveBytes(1)); Assert.Throws<InvalidOperationException>(() => builder1.GetBlobs()); Assert.Throws<InvalidOperationException>(() => builder1.ContentEquals(builder1)); Assert.Throws<InvalidOperationException>(() => builder1.WriteUTF16("str")); Assert.Throws<InvalidOperationException>(() => builder1.WriteUTF8("str", allowUnpairedSurrogates: false)); builder2.LinkSuffix(builder3); AssertEx.Equal(new byte[] { 1, 2, 3 }, builder2.ToArray()); Assert.Throws<InvalidOperationException>(() => builder3.LinkPrefix(builder5)); builder2.LinkPrefix(builder4); AssertEx.Equal(new byte[] { 4, 1, 2, 3 }, builder2.ToArray()); Assert.Throws<InvalidOperationException>(() => builder4.LinkPrefix(builder5)); builder2.LinkSuffix(builder5); AssertEx.Equal(new byte[] { 4, 1, 2, 3, 5 }, builder2.ToArray()); }
/// <summary> /// Output the section with a given name. For sections existent in the source MSIL PE file /// (.text, optionally .rsrc and .reloc), we first copy the content of the input MSIL PE file /// and then call the section serialization callback to emit the extra content after the input /// section content. /// </summary> /// <param name="name">Section name</param> /// <param name="location">RVA and file location where the section will be put</param> /// <returns>Blob builder representing the section data</returns> protected override BlobBuilder SerializeSection(string name, SectionLocation location) { BlobBuilder sectionDataBuilder = null; int sectionStartRva = location.RelativeVirtualAddress; int outputSectionIndex = _sections.Length - 1; while (outputSectionIndex >= 0 && _sections[outputSectionIndex].Name != name) { outputSectionIndex--; } if (!_target.IsWindows) { if (outputSectionIndex > 0) { sectionStartRva = Math.Max(sectionStartRva, _sectionRVAs[outputSectionIndex - 1] + _sectionRawSizes[outputSectionIndex - 1]); } const int RVAAlign = 1 << RVABitsToMatchFilePos; sectionStartRva = AlignmentHelper.AlignUp(sectionStartRva, RVAAlign); int rvaAdjust = (location.PointerToRawData - sectionStartRva) & (RVAAlign - 1); sectionStartRva += rvaAdjust; location = new SectionLocation(sectionStartRva, location.PointerToRawData); } if (outputSectionIndex >= 0) { _sectionRVAs[outputSectionIndex] = sectionStartRva; } BlobBuilder extraData = _sectionBuilder.SerializeSection(name, location); if (extraData != null) { if (sectionDataBuilder == null) { // See above - there's a bug due to which LinkSuffix to an empty BlobBuilder screws up the blob content. sectionDataBuilder = extraData; } else { sectionDataBuilder.LinkSuffix(extraData); } } // Make sure the section has at least 1 byte, otherwise the PE emitter goes mad, // messes up the section map and corrups the output executable. if (sectionDataBuilder == null) { sectionDataBuilder = new BlobBuilder(); } if (sectionDataBuilder.Count == 0) { sectionDataBuilder.WriteByte(0); } if (outputSectionIndex >= 0) { _sectionRawSizes[outputSectionIndex] = sectionDataBuilder.Count; } return(sectionDataBuilder); }