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); }
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()); }
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()); }
/// <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; } } } }
/// <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); }
/// <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); }
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()); }
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; }
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); }
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); } } }
/// <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); }
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(); } }
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); } } }
/// <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); }
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; } } } }