Beispiel #1
0
        public void WriteData(BlobBuilder resourceWriter)
        {
            if (_fileReference == null)
            {
                try
                {
                    using (Stream stream = _streamProvider())
                    {
                        if (stream == null)
                        {
                            throw new InvalidOperationException(CodeAnalysisResources.ResourceStreamProviderShouldReturnNonNullStream);
                        }

                        var count = (int)(stream.Length - stream.Position);
                        resourceWriter.WriteInt32(count);

                        int bytesWritten = resourceWriter.TryWriteBytes(stream, count);
                        if (bytesWritten != count)
                        {
                            throw new EndOfStreamException(
                                    string.Format(CultureInfo.CurrentUICulture, CodeAnalysisResources.ResourceStreamEndedUnexpectedly, bytesWritten, count));
                        }
                        resourceWriter.Align(8);
                    }
                }
                catch (Exception e)
                {
                    throw new ResourceException(_name, e);
                }
            }
        }
        private static void WriteFakeILWithBranches(BlobBuilder builder, ControlFlowBuilder branchBuilder, int size)
        {
            Assert.Equal(0, builder.Count);

            const byte filling = 0x01;
            int ilOffset = 0;
            foreach (var branch in branchBuilder.Branches)
            {
                builder.WriteBytes(filling, branch.ILOffset - ilOffset);

                Assert.Equal(branch.ILOffset, builder.Count);
                builder.WriteByte((byte)branch.OpCode);

                int operandSize = branch.OpCode.GetBranchOperandSize();
                if (operandSize == 1)
                {
                    builder.WriteSByte(-1);
                }
                else
                {
                    builder.WriteInt32(-1);
                }

                ilOffset = branch.ILOffset + sizeof(byte) + operandSize;
            }

            builder.WriteBytes(filling, size - ilOffset);
            Assert.Equal(size, builder.Count);
        }
        /// <summary>
        /// Serialized #Pdb stream.
        /// </summary>
        protected override void SerializeStandalonePdbStream(BlobBuilder builder)
        {
            int startPosition = builder.Count;

            // the id will be filled in later
            _pdbIdBlob = builder.ReserveBytes(MetadataSizes.PdbIdSize);
            
            builder.WriteInt32(_entryPoint.IsNil ? 0 : MetadataTokens.GetToken(_entryPoint));

            builder.WriteUInt64(MetadataSizes.ExternalTablesMask);
            MetadataWriterUtilities.SerializeRowCounts(builder, MetadataSizes.ExternalRowCounts);

            int endPosition = builder.Count;
            Debug.Assert(MetadataSizes.CalculateStandalonePdbStreamSize() == endPosition - startPosition);
        }
Beispiel #4
0
        public void CountClear()
        {
            var builder = new BlobBuilder();
            Assert.Equal(0, builder.Count);

            builder.WriteByte(1);
            Assert.Equal(1, builder.Count);

            builder.WriteInt32(4);
            Assert.Equal(5, builder.Count);

            builder.Clear();
            Assert.Equal(0, builder.Count);

            builder.WriteInt64(1);
            Assert.Equal(8, builder.Count);

            AssertEx.Equal(new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, builder.ToArray());
        }
Beispiel #5
0
        public void WritePrimitive()
        {
            var writer = new BlobBuilder(4);

            writer.WriteUInt32(0x11223344);
            writer.WriteUInt16(0x5566);
            writer.WriteByte(0x77);
            writer.WriteUInt64(0x8899aabbccddeeff);
            writer.WriteInt32(-1);
            writer.WriteInt16(-2);
            writer.WriteSByte(-3);
            writer.WriteBoolean(true);
            writer.WriteBoolean(false);
            writer.WriteInt64(unchecked ((long)0xfedcba0987654321));
            writer.WriteDateTime(new DateTime(0x1112223334445556));
            writer.WriteDecimal(102030405060.70m);
            writer.WriteDouble(double.NaN);
            writer.WriteSingle(float.NegativeInfinity);

            AssertEx.Equal(new byte[]
            {
                0x44, 0x33, 0x22, 0x11,
                0x66, 0x55,
                0x77,
                0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
                0xff, 0xff, 0xff, 0xff,
                0xfe, 0xff,
                0xfd,
                0x01,
                0x00,
                0x21, 0x43, 0x65, 0x87, 0x09, 0xBA, 0xDC, 0xFE,
                0x56, 0x55, 0x44, 0x34, 0x33, 0x22, 0x12, 0x11,
                0x02, 0xD6, 0xE0, 0x9A, 0x94, 0x47, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
                0x00, 0x00, 0x80, 0xFF
            }, writer.ToArray());
        }
Beispiel #6
0
        /// <summary>
        /// Creates the blob to be saved to the PDB.
        /// </summary>
        internal static ImmutableArray <byte> CreateBlob(Stream stream)
        {
            long length2 = stream.Length;

            if (length2 > int.MaxValue)
            {
                throw new IOException("Stream is too long");
            }
            stream.Seek(0L, SeekOrigin.Begin);
            int length = (int)length2;

            if (length < 200)
            {
                BlobBuilder pooledBlobBuilder = new BlobBuilder();
                pooledBlobBuilder.WriteInt32(0);
                int bytesWritten = pooledBlobBuilder.TryWriteBytes(stream, length);
                if (length != bytesWritten)
                {
                    throw new EndOfStreamException();
                }
                return(pooledBlobBuilder.ToImmutableArray());
            }
            using (BlobBuildingStream builder = BlobBuildingStream.GetInstance())
            {
                builder.WriteInt32(length);
                using (CountingDeflateStream deflater = new CountingDeflateStream(builder, CompressionLevel.Optimal, leaveOpen: true))
                {
                    stream.CopyTo(deflater);
                    if (length != deflater.BytesWritten)
                    {
                        throw new EndOfStreamException();
                    }
                }
                return(builder.ToImmutableArray());
            }
        }
        private static void WriteDirectory(Directory directory, BlobBuilder writer, uint offset, uint level, uint sizeOfDirectoryTree, int virtualAddressBase, BlobBuilder dataWriter)
        {
            writer.WriteUInt32(0); // Characteristics
            writer.WriteUInt32(0); // Timestamp
            writer.WriteUInt32(0); // Version
            writer.WriteUInt16(directory.NumberOfNamedEntries);
            writer.WriteUInt16(directory.NumberOfIdEntries);
            uint n = (uint)directory.Entries.Count;
            uint k = offset + 16 + n * 8;

            for (int i = 0; i < n; i++)
            {
                int       id;
                string    name;
                uint      nameOffset      = (uint)dataWriter.Count + sizeOfDirectoryTree;
                uint      directoryOffset = k;
                Directory subDir          = directory.Entries[i] as Directory;
                if (subDir != null)
                {
                    id   = subDir.ID;
                    name = subDir.Name;
                    if (level == 0)
                    {
                        k += SizeOfDirectory(subDir);
                    }
                    else
                    {
                        k += 16 + 8 * (uint)subDir.Entries.Count;
                    }
                }
                else
                {
                    //EDMAURER write out an IMAGE_RESOURCE_DATA_ENTRY followed
                    //immediately by the data that it refers to. This results
                    //in a layout different than that produced by pulling the resources
                    //from an OBJ. In that case all of the data bits of a resource are
                    //contiguous in .rsrc$02. After processing these will end up at
                    //the end of .rsrc following all of the directory
                    //info and IMAGE_RESOURCE_DATA_ENTRYs
                    IWin32Resource r = (IWin32Resource)directory.Entries[i];
                    id   = level == 0 ? r.TypeId : level == 1 ? r.Id : (int)r.LanguageId;
                    name = level == 0 ? r.TypeName : level == 1 ? r.Name : null;
                    dataWriter.WriteUInt32((uint)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.Count));
                    byte[] data = new List <byte>(r.Data).ToArray();
                    dataWriter.WriteUInt32((uint)data.Length);
                    dataWriter.WriteUInt32(r.CodePage);
                    dataWriter.WriteUInt32(0);
                    dataWriter.WriteBytes(data);
                    while ((dataWriter.Count % 4) != 0)
                    {
                        dataWriter.WriteByte(0);
                    }
                }

                if (id >= 0)
                {
                    writer.WriteInt32(id);
                }
                else
                {
                    if (name == null)
                    {
                        name = string.Empty;
                    }

                    writer.WriteUInt32(nameOffset | 0x80000000);
                    dataWriter.WriteUInt16((ushort)name.Length);
                    dataWriter.WriteUTF16(name);
                }

                if (subDir != null)
                {
                    writer.WriteUInt32(directoryOffset | 0x80000000);
                }
                else
                {
                    writer.WriteUInt32(nameOffset);
                }
            }

            k = offset + 16 + n * 8;
            for (int i = 0; i < n; i++)
            {
                Directory subDir = directory.Entries[i] as Directory;
                if (subDir != null)
                {
                    WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataWriter);
                    if (level == 0)
                    {
                        k += SizeOfDirectory(subDir);
                    }
                    else
                    {
                        k += 16 + 8 * (uint)subDir.Entries.Count;
                    }
                }
            }
        }
Beispiel #8
0
 /// <summary>
 /// Serialize a directory entry into an output blob builder.
 /// </summary>
 /// <param name="directoryEntry">Directory entry to serialize</param>
 /// <param name="builder">Output blob builder to receive the serialized entry</param>
 private static void WriteDirectoryEntry(DirectoryEntry directoryEntry, BlobBuilder builder)
 {
     builder.WriteInt32(directoryEntry.RelativeVirtualAddress);
     builder.WriteInt32(directoryEntry.Size);
 }
Beispiel #9
0
        /// <exception cref="InvalidOperationException" />
        internal void CopyCodeAndFixupBranches(BlobBuilder srcBuilder, BlobBuilder dstBuilder)
        {
            var branch      = _branches[0];
            int branchIndex = 0;

            // offset within the source builder
            int srcOffset = 0;

            // current offset within the current source blob
            int srcBlobOffset = 0;

            foreach (Blob srcBlob in srcBuilder.GetBlobs())
            {
                Debug.Assert(
                    srcBlobOffset == 0 ||
                    srcBlobOffset == 1 && srcBlob.Buffer[0] == 0xff ||
                    srcBlobOffset == 4 && srcBlob.Buffer[0] == 0xff && srcBlob.Buffer[1] == 0xff && srcBlob.Buffer[2] == 0xff && srcBlob.Buffer[3] == 0xff);

                while (true)
                {
                    // copy bytes preceding the next branch, or till the end of the blob:
                    int chunkSize = Math.Min(branch.ILOffset - srcOffset, srcBlob.Length - srcBlobOffset);
                    dstBuilder.WriteBytes(srcBlob.Buffer, srcBlobOffset, chunkSize);
                    srcOffset     += chunkSize;
                    srcBlobOffset += chunkSize;

                    // there is no branch left in the blob:
                    if (srcBlobOffset == srcBlob.Length)
                    {
                        srcBlobOffset = 0;
                        break;
                    }

                    Debug.Assert(srcBlob.Buffer[srcBlobOffset] == (byte)branch.OpCode);

                    int  operandSize        = branch.OpCode.GetBranchOperandSize();
                    bool isShortInstruction = operandSize == 1;

                    // Note: the 4B operand is contiguous since we wrote it via BlobBuilder.WriteInt32()
                    Debug.Assert(
                        srcBlobOffset + 1 == srcBlob.Length ||
                        (isShortInstruction ?
                         srcBlob.Buffer[srcBlobOffset + 1] == 0xff :
                         BitConverter.ToUInt32(srcBlob.Buffer, srcBlobOffset + 1) == 0xffffffff));

                    // write branch opcode:
                    dstBuilder.WriteByte(srcBlob.Buffer[srcBlobOffset]);

                    int branchDistance = branch.GetBranchDistance(_labels, branch.OpCode, srcOffset, isShortInstruction);

                    // write branch operand:
                    if (isShortInstruction)
                    {
                        dstBuilder.WriteSByte((sbyte)branchDistance);
                    }
                    else
                    {
                        dstBuilder.WriteInt32(branchDistance);
                    }

                    srcOffset += sizeof(byte) + operandSize;

                    // next branch:
                    branchIndex++;
                    if (branchIndex == _branches.Count)
                    {
                        branch = new BranchInfo(int.MaxValue, label: default, opCode: default);
        private void SerializeHeader(BlobBuilder writer, Sizes sizes)
        {
            // signature:
            writer.WriteByte((byte)'D');
            writer.WriteByte((byte)'A');
            writer.WriteByte((byte)'M');
            writer.WriteByte((byte)'D');

            // version: 0.2
            writer.WriteByte(0);
            writer.WriteByte(2);

            // table sizes:
            writer.WriteInt32(_documentTable.Count);
            writer.WriteInt32(_methodTable.Count);

            // blob heap sizes:
            writer.WriteInt32(sizes.GuidHeapSize);
            writer.WriteInt32(sizes.BlobHeapSize);
        }
Beispiel #11
0
        public void WritePrimitive()
        {
            var writer = new BlobBuilder(17);

            writer.WriteUInt32(0x11223344);
            writer.WriteUInt16(0x5566);
            writer.WriteByte(0x77);
            writer.WriteUInt64(0x8899aabbccddeeff);
            writer.WriteInt32(-1);
            writer.WriteInt16(-2);
            writer.WriteSByte(-3);
            writer.WriteBoolean(true);
            writer.WriteBoolean(false);
            writer.WriteInt64(unchecked((long)0xfedcba0987654321));
            writer.WriteDateTime(new DateTime(0x1112223334445556));
            writer.WriteDecimal(102030405060.70m);
            writer.WriteDouble(double.NaN);
            writer.WriteSingle(float.NegativeInfinity);

            var guid = new Guid("01020304-0506-0708-090A-0B0C0D0E0F10");
            writer.WriteBytes(guid.ToByteArray());
            writer.WriteGuid(guid);

            AssertEx.Equal(new byte[]
            {
                0x44, 0x33, 0x22, 0x11,
                0x66, 0x55,
                0x77,
                0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
                0xff, 0xff, 0xff, 0xff,
                0xfe, 0xff,
                0xfd,
                0x01,
                0x00,
                0x21, 0x43, 0x65, 0x87, 0x09, 0xBA, 0xDC, 0xFE,
                0x56, 0x55, 0x44, 0x34, 0x33, 0x22, 0x12, 0x11,
                0x02, 0xD6, 0xE0, 0x9A, 0x94, 0x47, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
                0x00, 0x00, 0x80, 0xFF,
                0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
                0x04, 0x03, 0x02, 0x01, 0x06, 0x05, 0x08, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
            }, writer.ToArray());
        }
Beispiel #12
0
        private static void SerializeStreamHeader(ref int offsetFromStartOfMetadata, int alignedStreamSize, string streamName, BlobBuilder builder)
        {
            // 4 for the first uint (offset), 4 for the second uint (padded size), length of stream name + 1 for null terminator (then padded)
            int sizeOfStreamHeader = MetadataSizes.GetMetadataStreamHeaderSize(streamName);
            builder.WriteInt32(offsetFromStartOfMetadata);
            builder.WriteInt32(alignedStreamSize);
            foreach (char ch in streamName)
            {
                builder.WriteByte((byte)ch);
            }

            // After offset, size, and stream name, write 0-bytes until we reach our padded size.
            for (uint i = 8 + (uint)streamName.Length; i < sizeOfStreamHeader; i++)
            {
                builder.WriteByte(0);
            }

            offsetFromStartOfMetadata += alignedStreamSize;
        }
Beispiel #13
0
        internal static void SerializeMetadataHeader(BlobBuilder builder, string metadataVersion, MetadataSizes sizes)
        {
            int startOffset = builder.Count;

            // signature
            builder.WriteUInt32(0x424A5342);

            // major version
            builder.WriteUInt16(1);

            // minor version
            builder.WriteUInt16(1);

            // reserved
            builder.WriteUInt32(0);

            // Spec (section 24.2.1 Metadata Root):
            // Length ... Number of bytes allocated to hold version string (including null terminator), call this x.
            //            Call the length of the string (including the terminator) m (we require m <= 255);
            //            the length x is m rounded up to a multiple of four.
            builder.WriteInt32(sizes.MetadataVersionPaddedLength);

            int metadataVersionStart = builder.Count;
            builder.WriteUTF8(metadataVersion);
            builder.WriteByte(0);
            int metadataVersionEnd = builder.Count;

            for (int i = 0; i < sizes.MetadataVersionPaddedLength - (metadataVersionEnd - metadataVersionStart); i++)
            {
                builder.WriteByte(0);
            }

            // reserved
            builder.WriteUInt16(0);

            // number of streams
            builder.WriteUInt16((ushort)(5 + (sizes.IsEncDelta ? 1 : 0) + (sizes.IsStandaloneDebugMetadata ? 1 : 0)));

            // stream headers
            int offsetFromStartOfMetadata = sizes.MetadataHeaderSize;

            // emit the #Pdb stream first so that only a single page has to be read in order to find out PDB ID
            if (sizes.IsStandaloneDebugMetadata)
            {
                SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.StandalonePdbStreamSize, "#Pdb", builder);
            }

            // Spec: Some compilers store metadata in a #- stream, which holds an uncompressed, or non-optimized, representation of metadata tables;
            // this includes extra metadata -Ptr tables. Such PE files do not form part of ECMA-335 standard.
            //
            // Note: EnC delta is stored as uncompressed metadata stream.
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.MetadataTableStreamSize, (sizes.IsCompressed ? "#~" : "#-"), builder);

            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", builder);

            if (sizes.IsEncDelta)
            {
                SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", builder);
            }

            int endOffset = builder.Count;
            Debug.Assert(endOffset - startOffset == sizes.MetadataHeaderSize);
        }
Beispiel #14
0
        internal void FixupBranches(BlobBuilder srcBuilder, BlobBuilder dstBuilder)
        {
            int srcOffset = 0;
            var branch = _branches[0];
            int branchIndex = 0;
            int blobOffset = 0;
            foreach (Blob blob in srcBuilder.GetBlobs())
            {
                Debug.Assert(blobOffset == 0 || blobOffset == 1 && blob.Buffer[blobOffset - 1] == 0xff);

                while (true)
                {
                    // copy bytes preceding the next branch, or till the end of the blob:
                    int chunkSize = Math.Min(branch.ILOffset - srcOffset, blob.Length - blobOffset);
                    dstBuilder.WriteBytes(blob.Buffer, blobOffset, chunkSize);
                    srcOffset += chunkSize;
                    blobOffset += chunkSize;

                    // there is no branch left in the blob:
                    if (blobOffset == blob.Length)
                    {
                        blobOffset = 0;
                        break;
                    }

                    Debug.Assert(blob.Buffer[blobOffset] == branch.ShortOpCode && (blobOffset + 1 == blob.Length || blob.Buffer[blobOffset + 1] == 0xff));
                    srcOffset += sizeof(byte) + sizeof(sbyte);

                    // write actual branch instruction:
                    int branchDistance;
                    if (branch.IsShortBranchDistance(_labels, out branchDistance))
                    {
                        dstBuilder.WriteByte(branch.ShortOpCode);
                        dstBuilder.WriteSByte((sbyte)branchDistance);
                    }
                    else
                    {
                        dstBuilder.WriteByte((byte)((ILOpCode)branch.ShortOpCode).GetLongBranch());
                        dstBuilder.WriteInt32(branchDistance);
                    }

                    // next branch:
                    branchIndex++;
                    if (branchIndex == _branches.Count)
                    {
                        branch = new BranchInfo(int.MaxValue, default(LabelHandle), 0);
                    }
                    else
                    {
                        branch = _branches[branchIndex];
                    }

                    // the branch starts at the very end and its operand is in the next blob:
                    if (blobOffset == blob.Length - 1)
                    {
                        blobOffset = 1;
                        break;
                    }

                    // skip fake branch instruction:
                    blobOffset += sizeof(byte) + sizeof(sbyte);
                }
            }
        }
Beispiel #15
0
        /// <summary>
        /// Serialize the export symbol table into the export section.
        /// </summary>
        /// <param name="location">RVA and file location of the .edata section</param>
        private BlobBuilder SerializeExportSection(SectionLocation sectionLocation)
        {
            _exportSymbols.MergeSort((es1, es2) => StringComparer.Ordinal.Compare(es1.Name, es2.Name));

            BlobBuilder builder = new BlobBuilder();

            int minOrdinal = int.MaxValue;
            int maxOrdinal = int.MinValue;

            // First, emit the name table and store the name RVA's for the individual export symbols
            // Also, record the ordinal range.
            foreach (ExportSymbol symbol in _exportSymbols)
            {
                symbol.NameRVAWhenPlaced = sectionLocation.RelativeVirtualAddress + builder.Count;
                builder.WriteUTF8(symbol.Name);
                builder.WriteByte(0);

                if (symbol.Ordinal < minOrdinal)
                {
                    minOrdinal = symbol.Ordinal;
                }
                if (symbol.Ordinal > maxOrdinal)
                {
                    maxOrdinal = symbol.Ordinal;
                }
            }

            // Emit the DLL name
            int dllNameRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            builder.WriteUTF8(_dllNameForExportDirectoryTable);
            builder.WriteByte(0);

            int[] addressTable = new int[maxOrdinal - minOrdinal + 1];

            // Emit the name pointer table; it should be alphabetically sorted.
            // Also, we can now fill in the export address table as we've detected its size
            // in the previous pass.
            int namePointerTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            foreach (ExportSymbol symbol in _exportSymbols)
            {
                builder.WriteInt32(symbol.NameRVAWhenPlaced);
                SymbolTarget symbolTarget  = _symbolMap[symbol.Symbol];
                Section      symbolSection = _sections[symbolTarget.SectionIndex];
                Debug.Assert(symbolSection.RVAWhenPlaced != 0);
                addressTable[symbol.Ordinal - minOrdinal] = symbolSection.RVAWhenPlaced + symbolTarget.Offset;
            }

            // Emit the ordinal table
            int ordinalTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            foreach (ExportSymbol symbol in _exportSymbols)
            {
                builder.WriteUInt16((ushort)(symbol.Ordinal - minOrdinal));
            }

            // Emit the address table
            int addressTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            foreach (int addressTableEntry in addressTable)
            {
                builder.WriteInt32(addressTableEntry);
            }

            // Emit the export directory table
            int exportDirectoryTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            // +0x00: reserved
            builder.WriteInt32(0);
            // +0x04: TODO: time/date stamp
            builder.WriteInt32(0);
            // +0x08: major version
            builder.WriteInt16(0);
            // +0x0A: minor version
            builder.WriteInt16(0);
            // +0x0C: DLL name RVA
            builder.WriteInt32(dllNameRVA);
            // +0x10: ordinal base
            builder.WriteInt32(minOrdinal);
            // +0x14: number of entries in the address table
            builder.WriteInt32(addressTable.Length);
            // +0x18: number of name pointers
            builder.WriteInt32(_exportSymbols.Count);
            // +0x1C: export address table RVA
            builder.WriteInt32(addressTableRVA);
            // +0x20: name pointer RVV
            builder.WriteInt32(namePointerTableRVA);
            // +0x24: ordinal table RVA
            builder.WriteInt32(ordinalTableRVA);
            int exportDirectorySize = sectionLocation.RelativeVirtualAddress + builder.Count - exportDirectoryTableRVA;

            _exportDirectoryEntry = new DirectoryEntry(relativeVirtualAddress: exportDirectoryTableRVA, size: exportDirectorySize);

            return(builder);
        }
 protected internal override void Serialize(BlobBuilder builder, SectionLocation location)
 {
     builder.WriteInt32(0x12345678);
     builder.WriteInt32(location.PointerToRawData);
     builder.WriteInt32(location.RelativeVirtualAddress);
 }
Beispiel #17
0
        internal static void WriteConstant(BlobBuilder writer, object value)
        {
            if (value == null)
            {
                // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 32-bit.
                writer.WriteUInt32(0);
                return;
            }

            var type = value.GetType();

            if (type.GetTypeInfo().IsEnum)
            {
                type = Enum.GetUnderlyingType(type);
            }

            if (type == typeof(bool))
            {
                writer.WriteBoolean((bool)value);
            }
            else if (type == typeof(int))
            {
                writer.WriteInt32((int)value);
            }
            else if (type == typeof(string))
            {
                writer.WriteUTF16((string)value);
            }
            else if (type == typeof(byte))
            {
                writer.WriteByte((byte)value);
            }
            else if (type == typeof(char))
            {
                writer.WriteUInt16((char)value);
            }
            else if (type == typeof(double))
            {
                writer.WriteDouble((double)value);
            }
            else if (type == typeof(short))
            {
                writer.WriteInt16((short)value);
            }
            else if (type == typeof(long))
            {
                writer.WriteInt64((long)value);
            }
            else if (type == typeof(sbyte))
            {
                writer.WriteSByte((sbyte)value);
            }
            else if (type == typeof(float))
            {
                writer.WriteSingle((float)value);
            }
            else if (type == typeof(ushort))
            {
                writer.WriteUInt16((ushort)value);
            }
            else if (type == typeof(uint))
            {
                writer.WriteUInt32((uint)value);
            }
            else if (type == typeof(ulong))
            {
                writer.WriteUInt64((ulong)value);
            }
            else
            {
                // TODO: message
                throw new ArgumentException();
            }
        }
Beispiel #18
0
        public static void Write(
            BlobBuilder writer,
            IReadOnlyList <Instruction> il,
            Func <string, StringHandle> getString,
            IReadOnlyDictionary <Guid, EntityHandle> typeHandles,
            IReadOnlyDictionary <ConstructorInfo, MemberReferenceHandle> ctorRefHandles,
            IReadOnlyDictionary <FieldInfo, FieldDefinitionHandle> fieldHandles,
            IReadOnlyDictionary <MethodInfo, MethodDefinitionHandle> methodHandles)
        {
            var targetOffsets = new ArrayMapper <int>();

            //var offsetIndex = new Dictionary<int, int>();

            for (var i = 0; i < il.Count; i++)
            {
                //offsetIndex.Add(il[i].Offset, i);

                var opCode = il[i].OpCode;

                opCode.WriteOpCode(writer.WriteByte);

                switch (opCode.OperandType)
                {
                case OperandType.InlineNone:
                    break;

                case OperandType.InlineSwitch:
                    var branches = (int[])il[i].Operand;
                    writer.WriteInt32(branches.Length);
                    for (var k = 0; k < branches.Length; k++)
                    {
                        var branchOffset = branches[k];
                        writer.WriteInt32(targetOffsets.Add(
                                              branchOffset + il[i].Offset + opCode.Size + 4 * (branches.Length + 1)));
                    }

                    break;

                case OperandType.ShortInlineBrTarget:
                    var offset8 = (sbyte)il[i].Operand;
                    // offset convention in IL: zero is at next instruction
                    writer.WriteSByte((sbyte)targetOffsets.Add(offset8 + il[i].Offset + opCode.Size + 1));
                    break;

                case OperandType.InlineBrTarget:
                    var offset32 = (int)il[i].Operand;
                    // offset convention in IL: zero is at next instruction
                    writer.WriteInt32(targetOffsets.Add(offset32 + il[i].Offset + opCode.Size + 4));
                    break;

                case OperandType.ShortInlineI:
                    if (opCode == OpCodes.Ldc_I4_S)
                    {
                        writer.WriteSByte((sbyte)il[i].Operand);
                    }
                    else
                    {
                        writer.WriteByte((byte)il[i].Operand);
                    }

                    break;

                case OperandType.InlineI:
                    writer.WriteInt32((int)il[i].Operand);
                    break;

                case OperandType.ShortInlineR:
                    writer.WriteSingle((float)il[i].Operand);
                    break;

                case OperandType.InlineR:
                    writer.WriteDouble((double)il[i].Operand);
                    break;

                case OperandType.InlineI8:
                    writer.WriteInt64((long)il[i].Operand);
                    break;

                case OperandType.InlineSig:
                    writer.WriteBytes((byte[])il[i].Operand);
                    break;

                case OperandType.InlineString:
                    writer.WriteInt32(MetadataTokens.GetToken(getString((string)il[i].Operand)));
                    break;

                case OperandType.InlineType:
                case OperandType.InlineTok:
                case OperandType.InlineMethod:
                case OperandType.InlineField:
                    switch (il[i].Operand)
                    {
                    case Type type:
                        writer.WriteInt32(MetadataTokens.GetToken(typeHandles[type.GUID]));
                        break;

                    case ConstructorInfo constructorInfo:
                        writer.WriteInt32(MetadataTokens.GetToken(ctorRefHandles[constructorInfo]));
                        break;

                    case FieldInfo fieldInfo:
                        writer.WriteInt32(MetadataTokens.GetToken(fieldHandles[fieldInfo]));
                        break;

                    case MethodInfo methodInfo:
                        writer.WriteInt32(MetadataTokens.GetToken(methodHandles[methodInfo]));
                        break;

                    default:
                        throw new NotSupportedException();
                    }

                    break;

                case OperandType.ShortInlineVar:
                    var bLocalVariableInfo = il[i].Operand as LocalVariableInfo;
                    var bParameterInfo     = il[i].Operand as ParameterInfo;

                    if (bLocalVariableInfo != null)
                    {
                        writer.WriteByte((byte)bLocalVariableInfo.LocalIndex);
                    }
                    else if (bParameterInfo != null)
                    {
                        writer.WriteByte((byte)bParameterInfo.Position);
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }

                    break;

                case OperandType.InlineVar:
                    var sLocalVariableInfo = il[i].Operand as LocalVariableInfo;
                    var sParameterInfo     = il[i].Operand as ParameterInfo;

                    if (sLocalVariableInfo != null)
                    {
                        writer.WriteUInt16((ushort)sLocalVariableInfo.LocalIndex);
                    }
                    else if (sParameterInfo != null)
                    {
                        writer.WriteUInt16((ushort)sParameterInfo.Position);
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }

                    break;

                default:
                    throw new NotSupportedException();
                }
            }
        }
 internal static void SerializeRowCounts(BlobBuilder writer, ImmutableArray<int> rowCounts)
 {
     for (int i = 0; i < rowCounts.Length; i++)
     {
         int rowCount = rowCounts[i];
         if (rowCount > 0)
         {
             writer.WriteInt32(rowCount);
         }
     }
 }
Beispiel #20
0
        internal static void WriteConstant(BlobBuilder writer, object value)
        {
            if (value == null)
            {
                // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 32-bit.
                writer.WriteUInt32(0);
                return;
            }

            var type = value.GetType();
            if (type.GetTypeInfo().IsEnum)
            {
                type = Enum.GetUnderlyingType(type);
            }

            if (type == typeof(bool))
            {
                writer.WriteBoolean((bool)value);
            }
            else if (type == typeof(int))
            {
                writer.WriteInt32((int)value);
            }
            else if (type == typeof(string))
            {
                writer.WriteUTF16((string)value);
            }
            else if (type == typeof(byte))
            {
                writer.WriteByte((byte)value);
            }
            else if (type == typeof(char))
            {
                writer.WriteUInt16((char)value);
            }
            else if (type == typeof(double))
            {
                writer.WriteDouble((double)value);
            }
            else if (type == typeof(short))
            {
                writer.WriteInt16((short)value);
            }
            else if (type == typeof(long))
            {
                writer.WriteInt64((long)value);
            }
            else if (type == typeof(sbyte))
            {
                writer.WriteSByte((sbyte)value);
            }
            else if (type == typeof(float))
            {
                writer.WriteSingle((float)value);
            }
            else if (type == typeof(ushort))
            {
                writer.WriteUInt16((ushort)value);
            }
            else if (type == typeof(uint))
            {
                writer.WriteUInt32((uint)value);
            }
            else if (type == typeof(ulong))
            {
                writer.WriteUInt64((ulong)value);
            }
            else
            {
                // TODO: message
                throw new ArgumentException();
            }
        }
Beispiel #21
0
        /// <exception cref="InvalidOperationException" />
        internal void CopyCodeAndFixupBranches(BlobBuilder srcBuilder, BlobBuilder dstBuilder)
        {
            var branch      = _branches[0];
            int branchIndex = 0;

            // offset within the source builder
            int srcOffset = 0;

            // current offset within the current source blob
            int srcBlobOffset = 0;

            foreach (Blob srcBlob in srcBuilder.GetBlobs())
            {
                Debug.Assert(
                    srcBlobOffset == 0 ||
                    srcBlobOffset == 1 && srcBlob.Buffer[0] == 0xff ||
                    srcBlobOffset == 4 && srcBlob.Buffer[0] == 0xff && srcBlob.Buffer[1] == 0xff && srcBlob.Buffer[2] == 0xff && srcBlob.Buffer[3] == 0xff);

                while (true)
                {
                    // copy bytes preceding the next branch, or till the end of the blob:
                    int chunkSize = Math.Min(branch.ILOffset - srcOffset, srcBlob.Length - srcBlobOffset);
                    dstBuilder.WriteBytes(srcBlob.Buffer, srcBlobOffset, chunkSize);
                    srcOffset     += chunkSize;
                    srcBlobOffset += chunkSize;

                    // there is no branch left in the blob:
                    if (srcBlobOffset == srcBlob.Length)
                    {
                        srcBlobOffset = 0;
                        break;
                    }

                    Debug.Assert(srcBlob.Buffer[srcBlobOffset] == (byte)branch.OpCode);

                    int  operandSize        = branch.OpCode.GetBranchOperandSize();
                    bool isShortInstruction = operandSize == 1;

                    // Note: the 4B operand is contiguous since we wrote it via BlobBuilder.WriteInt32()
                    Debug.Assert(
                        srcBlobOffset + 1 == srcBlob.Length ||
                        (isShortInstruction ?
                         srcBlob.Buffer[srcBlobOffset + 1] == 0xff :
                         BitConverter.ToUInt32(srcBlob.Buffer, srcBlobOffset + 1) == 0xffffffff));

                    // write branch opcode:
                    dstBuilder.WriteByte(srcBlob.Buffer[srcBlobOffset]);

                    // write branch operand:
                    int  branchDistance;
                    bool isShortDistance = branch.IsShortBranchDistance(_labels, out branchDistance);

                    if (isShortInstruction && !isShortDistance)
                    {
                        // We could potentially implement algortihm that automatically fixes up the branch instructions as well to accomodate bigger distances,
                        // however an optimal algorithm would be rather complex (something like: calculate topological ordering of crossing branch instructions
                        // and then use fixed point to eliminate cycles). If the caller doesn't care about optimal IL size they can use long branches whenever the
                        // distance is unknown upfront. If they do they probably already implement more sophisticad algorithm for IL layout optimization already.
                        throw new InvalidOperationException(SR.Format(SR.DistanceBetweenInstructionAndLabelTooBig, branch.OpCode, srcOffset, branchDistance));
                    }

                    if (isShortInstruction)
                    {
                        dstBuilder.WriteSByte((sbyte)branchDistance);
                    }
                    else
                    {
                        dstBuilder.WriteInt32(branchDistance);
                    }

                    srcOffset += sizeof(byte) + operandSize;

                    // next branch:
                    branchIndex++;
                    if (branchIndex == _branches.Count)
                    {
                        branch = new BranchInfo(int.MaxValue, default(LabelHandle), 0);
                    }
                    else
                    {
                        branch = _branches[branchIndex];
                    }

                    // the branch starts at the very end and its operand is in the next blob:
                    if (srcBlobOffset == srcBlob.Length - 1)
                    {
                        srcBlobOffset = operandSize;
                        break;
                    }

                    // skip fake branch instruction:
                    srcBlobOffset += sizeof(byte) + operandSize;
                }
            }
        }
 public void WriteInt32(int value)
 {
     _builder.WriteInt32(value);
 }
Beispiel #23
0
        private void WriteDirectory(Directory directory, BlobBuilder writer, uint offset, uint level, uint sizeOfDirectoryTree, int virtualAddressBase, BlobBuilder dataWriter)
        {
            writer.WriteUInt32(0); // Characteristics
            writer.WriteUInt32(0); // Timestamp
            writer.WriteUInt32(0); // Version
            writer.WriteUInt16(directory.NumberOfNamedEntries);
            writer.WriteUInt16(directory.NumberOfIdEntries);
            uint n = (uint)directory.Entries.Count;
            uint k = offset + 16 + n * 8;
            for (int i = 0; i < n; i++)
            {
                int id;
                string name;
                uint nameOffset = (uint)dataWriter.Position + sizeOfDirectoryTree;
                uint directoryOffset = k;
                Directory subDir = directory.Entries[i] as Directory;
                if (subDir != null)
                {
                    id = subDir.ID;
                    name = subDir.Name;
                    if (level == 0)
                    {
                        k += SizeOfDirectory(subDir);
                    }
                    else
                    {
                        k += 16 + 8 * (uint)subDir.Entries.Count;
                    }
                }
                else
                {
                    //EDMAURER write out an IMAGE_RESOURCE_DATA_ENTRY followed
                    //immediately by the data that it refers to. This results
                    //in a layout different than that produced by pulling the resources
                    //from an OBJ. In that case all of the data bits of a resource are
                    //contiguous in .rsrc$02. After processing these will end up at
                    //the end of .rsrc following all of the directory
                    //info and IMAGE_RESOURCE_DATA_ENTRYs
                    IWin32Resource r = (IWin32Resource)directory.Entries[i];
                    id = level == 0 ? r.TypeId : level == 1 ? r.Id : (int)r.LanguageId;
                    name = level == 0 ? r.TypeName : level == 1 ? r.Name : null;
                    dataWriter.WriteUInt32((uint)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.Position));
                    byte[] data = new List<byte>(r.Data).ToArray();
                    dataWriter.WriteUInt32((uint)data.Length);
                    dataWriter.WriteUInt32(r.CodePage);
                    dataWriter.WriteUInt32(0);
                    dataWriter.WriteBytes(data);
                    while ((dataWriter.Count % 4) != 0)
                    {
                        dataWriter.WriteByte(0);
                    }
                }

                if (id >= 0)
                {
                    writer.WriteInt32(id);
                }
                else
                {
                    if (name == null)
                    {
                        name = string.Empty;
                    }

                    writer.WriteUInt32(nameOffset | 0x80000000);
                    dataWriter.WriteUInt16((ushort)name.Length);
                    dataWriter.WriteUTF16(name);
                }

                if (subDir != null)
                {
                    writer.WriteUInt32(directoryOffset | 0x80000000);
                }
                else
                {
                    writer.WriteUInt32(nameOffset);
                }
            }

            k = offset + 16 + n * 8;
            for (int i = 0; i < n; i++)
            {
                Directory subDir = directory.Entries[i] as Directory;
                if (subDir != null)
                {
                    this.WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataWriter);
                    if (level == 0)
                    {
                        k += SizeOfDirectory(subDir);
                    }
                    else
                    {
                        k += 16 + 8 * (uint)subDir.Entries.Count;
                    }
                }
            }
        }
Beispiel #24
0
        internal void FixupBranches(BlobBuilder srcBuilder, BlobBuilder dstBuilder)
        {
            int srcOffset   = 0;
            var branch      = _branches[0];
            int branchIndex = 0;
            int blobOffset  = 0;

            foreach (Blob blob in srcBuilder.GetBlobs())
            {
                Debug.Assert(blobOffset == 0 || blobOffset == 1 && blob.Buffer[blobOffset - 1] == 0xff);

                while (true)
                {
                    // copy bytes preceding the next branch, or till the end of the blob:
                    int chunkSize = Math.Min(branch.ILOffset - srcOffset, blob.Length - blobOffset);
                    dstBuilder.WriteBytes(blob.Buffer, blobOffset, chunkSize);
                    srcOffset  += chunkSize;
                    blobOffset += chunkSize;

                    // there is no branch left in the blob:
                    if (blobOffset == blob.Length)
                    {
                        blobOffset = 0;
                        break;
                    }

                    Debug.Assert(blob.Buffer[blobOffset] == branch.ShortOpCode && (blobOffset + 1 == blob.Length || blob.Buffer[blobOffset + 1] == 0xff));
                    srcOffset += sizeof(byte) + sizeof(sbyte);

                    // write actual branch instruction:
                    int branchDistance;
                    if (branch.IsShortBranchDistance(_labels, out branchDistance))
                    {
                        dstBuilder.WriteByte(branch.ShortOpCode);
                        dstBuilder.WriteSByte((sbyte)branchDistance);
                    }
                    else
                    {
                        dstBuilder.WriteByte((byte)((ILOpCode)branch.ShortOpCode).GetLongBranch());
                        dstBuilder.WriteInt32(branchDistance);
                    }

                    // next branch:
                    branchIndex++;
                    if (branchIndex == _branches.Count)
                    {
                        branch = new BranchInfo(int.MaxValue, default(LabelHandle), 0);
                    }
                    else
                    {
                        branch = _branches[branchIndex];
                    }

                    // the branch starts at the very end and its operand is in the next blob:
                    if (blobOffset == blob.Length - 1)
                    {
                        blobOffset = 1;
                        break;
                    }

                    // skip fake branch instruction:
                    blobOffset += sizeof(byte) + sizeof(sbyte);
                }
            }
        }
Beispiel #25
0
        internal static void SerializeMetadataHeader(BlobBuilder builder, string metadataVersion, MetadataSizes sizes)
        {
            int startOffset = builder.Count;

            // signature
            builder.WriteUInt32(0x424A5342);

            // major version
            builder.WriteUInt16(1);

            // minor version
            builder.WriteUInt16(1);

            // reserved
            builder.WriteUInt32(0);

            // Spec (section 24.2.1 Metadata Root):
            // Length ... Number of bytes allocated to hold version string (including null terminator), call this x.
            //            Call the length of the string (including the terminator) m (we require m <= 255);
            //            the length x is m rounded up to a multiple of four.
            builder.WriteInt32(sizes.MetadataVersionPaddedLength);

            int metadataVersionStart = builder.Count;

            builder.WriteUTF8(metadataVersion);
            builder.WriteByte(0);
            int metadataVersionEnd = builder.Count;

            for (int i = 0; i < sizes.MetadataVersionPaddedLength - (metadataVersionEnd - metadataVersionStart); i++)
            {
                builder.WriteByte(0);
            }

            // reserved
            builder.WriteUInt16(0);

            // number of streams
            builder.WriteUInt16((ushort)(5 + (sizes.IsEncDelta ? 1 : 0) + (sizes.IsStandaloneDebugMetadata ? 1 : 0)));

            // stream headers
            int offsetFromStartOfMetadata = sizes.MetadataHeaderSize;

            // emit the #Pdb stream first so that only a single page has to be read in order to find out PDB ID
            if (sizes.IsStandaloneDebugMetadata)
            {
                SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.StandalonePdbStreamSize, "#Pdb", builder);
            }

            // Spec: Some compilers store metadata in a #- stream, which holds an uncompressed, or non-optimized, representation of metadata tables;
            // this includes extra metadata -Ptr tables. Such PE files do not form part of ECMA-335 standard.
            //
            // Note: EnC delta is stored as uncompressed metadata stream.
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.MetadataTableStreamSize, (sizes.IsCompressed ? "#~" : "#-"), builder);

            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", builder);
            SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", builder);

            if (sizes.IsEncDelta)
            {
                SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", builder);
            }

            int endOffset = builder.Count;

            Debug.Assert(endOffset - startOffset == sizes.MetadataHeaderSize);
        }
Beispiel #26
0
        /// <exception cref="InvalidOperationException" />
        internal void CopyCodeAndFixupBranches(BlobBuilder srcBuilder, BlobBuilder dstBuilder)
        {
            var branch = _branches[0];
            int branchIndex = 0;

            // offset within the source builder
            int srcOffset = 0;
            
            // current offset within the current source blob
            int srcBlobOffset = 0;

            foreach (Blob srcBlob in srcBuilder.GetBlobs())
            {
                Debug.Assert(
                    srcBlobOffset == 0 || 
                    srcBlobOffset == 1 && srcBlob.Buffer[0] == 0xff ||
                    srcBlobOffset == 4 && srcBlob.Buffer[0] == 0xff && srcBlob.Buffer[1] == 0xff && srcBlob.Buffer[2] == 0xff && srcBlob.Buffer[3] == 0xff);

                while (true)
                {
                    // copy bytes preceding the next branch, or till the end of the blob:
                    int chunkSize = Math.Min(branch.ILOffset - srcOffset, srcBlob.Length - srcBlobOffset);
                    dstBuilder.WriteBytes(srcBlob.Buffer, srcBlobOffset, chunkSize);
                    srcOffset += chunkSize;
                    srcBlobOffset += chunkSize;

                    // there is no branch left in the blob:
                    if (srcBlobOffset == srcBlob.Length)
                    {
                        srcBlobOffset = 0;
                        break;
                    }

                    Debug.Assert(srcBlob.Buffer[srcBlobOffset] == (byte)branch.OpCode);

                    int operandSize = branch.OpCode.GetBranchOperandSize();
                    bool isShortInstruction = operandSize == 1;

                    // Note: the 4B operand is contiguous since we wrote it via BlobBuilder.WriteInt32()
                    Debug.Assert(
                        srcBlobOffset + 1 == srcBlob.Length || 
                        (isShortInstruction ? 
                           srcBlob.Buffer[srcBlobOffset + 1] == 0xff :
                           BitConverter.ToUInt32(srcBlob.Buffer, srcBlobOffset + 1) == 0xffffffff));

                    // write branch opcode:
                    dstBuilder.WriteByte(srcBlob.Buffer[srcBlobOffset]);

                    // write branch operand:
                    int branchDistance;
                    bool isShortDistance = branch.IsShortBranchDistance(_labels, out branchDistance);

                    if (isShortInstruction && !isShortDistance)
                    {
                        // We could potentially implement algortihm that automatically fixes up the branch instructions as well to accomodate bigger distances,
                        // however an optimal algorithm would be rather complex (something like: calculate topological ordering of crossing branch instructions 
                        // and then use fixed point to eliminate cycles). If the caller doesn't care about optimal IL size they can use long branches whenever the 
                        // distance is unknown upfront. If they do they probably already implement more sophisticad algorithm for IL layout optimization already. 
                        throw new InvalidOperationException(SR.Format(SR.DistanceBetweenInstructionAndLabelTooBig, branch.OpCode, srcOffset, branchDistance));
                    }

                    if (isShortInstruction)
                    {
                        dstBuilder.WriteSByte((sbyte)branchDistance);
                    }
                    else
                    {
                        dstBuilder.WriteInt32(branchDistance);
                    }

                    srcOffset += sizeof(byte) + operandSize;

                    // next branch:
                    branchIndex++;
                    if (branchIndex == _branches.Count)
                    {
                        branch = new BranchInfo(int.MaxValue, default(LabelHandle), 0);
                    }
                    else
                    {
                        branch = _branches[branchIndex];
                    }

                    // the branch starts at the very end and its operand is in the next blob:
                    if (srcBlobOffset == srcBlob.Length - 1)
                    {
                        srcBlobOffset = operandSize;
                        break;
                    }

                    // skip fake branch instruction:
                    srcBlobOffset += sizeof(byte) + operandSize;
                }
            }
        }