private static void SerializeStateMachineLocalScopes(IMethodBody methodBody, ArrayBuilder <BlobWriter> customDebugInfo) { var scopes = methodBody.StateMachineHoistedLocalScopes; if (scopes.IsDefaultOrEmpty) { return; } uint numberOfScopes = (uint)scopes.Length; var cmw = new BlobWriter(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindStateMachineHoistedLocalScopes); cmw.Align(4); cmw.WriteUint(12 + numberOfScopes * 8); cmw.WriteUint(numberOfScopes); foreach (var scope in scopes) { if (scope.IsDefault) { cmw.WriteUint(0); cmw.WriteUint(0); } else { // Dev12 C# emits end-inclusive range cmw.WriteUint((uint)scope.StartOffset); cmw.WriteUint((uint)scope.EndOffset - 1); } } customDebugInfo.Add(cmw); }
private static void WriteAligned(BlobWriter source, BlobWriter target) { int length = source.Length; source.WriteTo(target); target.Write(0, BitArithmeticUtilities.Align(length, 4) - length); }
public void WriteData(BlobWriter 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.WriteInt(count); resourceWriter.Write(stream, count); resourceWriter.Align(8); } } catch (Exception e) { throw new ResourceException(_name, e); } } }
// internal for testing internal static byte[] SerializeCustomDebugMetadata(ArrayBuilder <PooledBlobBuilder> recordWriters) { if (recordWriters.Count == 0) { return(null); } int records = 0; foreach (var rec in recordWriters) { records += rec.Count; } var result = new byte[ sizeof(byte) + // version sizeof(byte) + // record count sizeof(ushort) + // padding records // records ]; var cmw = new BlobWriter(result); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte((byte)recordWriters.Count); // count cmw.WriteInt16(0); foreach (var recordWriter in recordWriters) { cmw.WriteBytes(recordWriter); } return(result); }
public void WriteData(BlobWriter 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.WriteInt(count); var position = (int)resourceWriter.Position; resourceWriter.Position = (uint)(position + count); resourceWriter.Align(8); var buffer = resourceWriter.Buffer; stream.Read(buffer, position, count); } } catch (Exception e) { throw new ResourceException(_name, e); } } }
private static BlobWriter SerializeRecord(byte kind, Action <BlobWriter> data) { var cmw = new BlobWriter(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.WriteByte(0); // alignment size (will be patched) int alignmentSizeAndLengthPosition = cmw.Position; cmw.WriteByte(0); // length (will be patched) cmw.WriteUint(0); data(cmw); int length = cmw.Position; int alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); for (int i = 0; i < alignmentSize; i++) { cmw.WriteByte(0); } cmw.Position = alignmentSizeAndLengthPosition; cmw.WriteByte(alignmentSize); cmw.WriteUint((uint)alignedLength); cmw.Position = length; return(cmw); }
internal static void WriteCompressedSignedInteger(ref BlobWriter writer, int value) { unchecked { const int b6 = (1 << 6) - 1; const int b13 = (1 << 13) - 1; const int b28 = (1 << 28) - 1; // 0xffffffff for negative value // 0x00000000 for non-negative int signMask = value >> 31; if ((value & ~b6) == (signMask & ~b6)) { int n = ((value & b6) << 1) | (signMask & 1); writer.WriteByte((byte)n); } else if ((value & ~b13) == (signMask & ~b13)) { int n = ((value & b13) << 1) | (signMask & 1); writer.WriteUInt16BE((ushort)(0x8000 | n)); } else if ((value & ~b28) == (signMask & ~b28)) { int n = ((value & b28) << 1) | (signMask & 1); writer.WriteUInt32BE(0xc0000000 | (uint)n); } else { ThrowValueArgumentOutOfRange(); } } }
private static PooledBlobBuilder SerializeRecord( byte kind, EditAndContinueMethodDebugInformation debugInfo, Action <EditAndContinueMethodDebugInformation, BlobBuilder> recordSerializer) { var cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.WriteByte(0); // alignment size and length (will be patched) var alignmentSizeAndLengthWriter = new BlobWriter(cmw.ReserveBytes(sizeof(byte) + sizeof(uint))); recordSerializer(debugInfo, cmw); int length = cmw.Count; int alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); cmw.WriteBytes(0, alignmentSize); // fill in alignment size and length: alignmentSizeAndLengthWriter.WriteByte(alignmentSize); alignmentSizeAndLengthWriter.WriteUInt32((uint)alignedLength); return(cmw); }
private static PooledBlobBuilder SerializeRecord <T>( CustomDebugInfoKind kind, T debugInfo, Action <T, BlobBuilder> recordSerializer) { PooledBlobBuilder cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CustomDebugInfoConstants.Version); cmw.WriteByte((byte)kind); cmw.WriteByte(0); // alignment size and length (will be patched) BlobWriter alignmentSizeAndLengthWriter = new BlobWriter(cmw.ReserveBytes(sizeof(byte) + sizeof(uint))); recordSerializer(debugInfo, cmw); int length = cmw.Count; int alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); cmw.WriteBytes(0, alignmentSize); // fill in alignment size and length: alignmentSizeAndLengthWriter.WriteByte(alignmentSize); alignmentSizeAndLengthWriter.WriteUInt32((uint)alignedLength); return(cmw); }
private static void PatchModuleVersionIds( Blob guidFixup, Blob guidSectionFixup, Blob stringFixup, Guid mvid ) { if (!guidFixup.IsDefault) { var writer = new BlobWriter(guidFixup); writer.WriteGuid(mvid); Debug.Assert(writer.RemainingBytes == 0); } if (!guidSectionFixup.IsDefault) { var writer = new BlobWriter(guidSectionFixup); writer.WriteGuid(mvid); Debug.Assert(writer.RemainingBytes == 0); } if (!stringFixup.IsDefault) { var writer = new BlobWriter(stringFixup); writer.WriteUserString(mvid.ToString()); Debug.Assert(writer.RemainingBytes == 0); } }
public void WriteTo(BlobWriter stream, out int guidHeapStartOffset) { WriteAligned(_stringWriter, stream); WriteAligned(_userStringWriter, stream); guidHeapStartOffset = stream.Position; WriteAligned(_guidWriter, stream); WriteAligned(_blobWriter, stream); }
private void SerializeReferenceToPreviousMethodWithUsingInfo(ArrayBuilder <BlobWriter> customDebugInfo) { BlobWriter cmw = new BlobWriter(12); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindForwardInfo); cmw.Align(4); cmw.WriteUint(12); cmw.WriteUint((uint)_previousMethodTokenWithUsingInfo); customDebugInfo.Add(cmw); }
/// <exception cref="ArgumentNullException"><paramref name="destination"/> is default(<see cref="BlobWriter"/>).</exception> /// <exception cref="InvalidOperationException">Content is not available, the builder has been linked with another one.</exception> public void WriteContentTo(ref BlobWriter destination) { if (destination.IsDefault) { throw new ArgumentNullException(nameof(destination)); } foreach (var chunk in GetChunks()) { destination.WriteBytes(chunk._buffer, 0, chunk.Length); } }
private BlobBuilder SerializeMvidSection(SectionLocation location) { var sectionBuilder = new BlobBuilder(); // The guid will be filled in later: _mvidSectionFixup = sectionBuilder.ReserveBytes(SizeOfGuid); var mvidWriter = new BlobWriter(_mvidSectionFixup); mvidWriter.WriteBytes(0, _mvidSectionFixup.Length); Debug.Assert(mvidWriter.RemainingBytes == 0); return(sectionBuilder); }
public int GetConstantBlobIndex(object value) { string str = value as string; if (str != null) { return(this.GetBlobIndex(str)); } var writer = new BlobWriter(); writer.WriteConstant(value); return(this.GetBlobIndex(writer)); }
internal PdbLogger(bool logging) { _logging = logging; if (logging) { _logData = BlobWriter.GetInstance(); _hashAlgorithm = new SHA1CryptoServiceProvider(); Debug.Assert(_hashAlgorithm.SupportsTransform); } else { _logData = null; _hashAlgorithm = null; } }
private void SerializeNamespaceScopeMetadata(EmitContext context, IMethodBody methodBody, ArrayBuilder <BlobWriter> customDebugInfo) { if (context.Module.GenerateVisualBasicStylePdb) { return; } if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody)) { Debug.Assert(!ReferenceEquals(_previousMethodBodyWithUsingInfo, methodBody)); SerializeReferenceToPreviousMethodWithUsingInfo(customDebugInfo); return; } List <ushort> usingCounts = new List <ushort>(); var cmw = new BlobWriter(); for (IImportScope scope = methodBody.ImportScope; scope != null; scope = scope.Parent) { usingCounts.Add((ushort)scope.GetUsedNamespaces().Length); } // ACASEY: This originally wrote (uint)12, (ushort)1, (ushort)0 in the // case where usingCounts was empty, but I'm not sure why. if (usingCounts.Count > 0) { uint streamLength; cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindUsingInfo); cmw.Align(4); cmw.WriteUint(streamLength = BitArithmeticUtilities.Align((uint)usingCounts.Count * 2 + 10, 4)); cmw.WriteUshort((ushort)usingCounts.Count); foreach (ushort uc in usingCounts) { cmw.WriteUshort(uc); } cmw.Align(4); Debug.Assert(streamLength == cmw.Length); customDebugInfo.Add(cmw); } if (_methodBodyWithModuleInfo != null && !ReferenceEquals(_methodBodyWithModuleInfo, methodBody)) { SerializeReferenceToMethodWithModuleInfo(customDebugInfo); } }
public static void SerializeWin32Resources(BlobBuilder builder, ResourceSection resourceSections, int resourcesRva) { var sectionWriter = new BlobWriter(builder.ReserveBytes(resourceSections.SectionBytes.Length)); sectionWriter.WriteBytes(resourceSections.SectionBytes); var readStream = new MemoryStream(resourceSections.SectionBytes); var reader = new BinaryReader(readStream); foreach (int addressToFixup in resourceSections.Relocations) { sectionWriter.Offset = addressToFixup; reader.BaseStream.Position = addressToFixup; sectionWriter.WriteUInt32(reader.ReadUInt32() + (uint)resourcesRva); } }
private void WriteBlobHeap(BlobBuilder builder) { var writer = new BlobWriter(builder.ReserveBytes(_blobHeapSize)); // Perf consideration: With large heap the following loop may cause a lot of cache misses // since the order of entries in _blobs dictionary depends on the hash of the array values, // which is not correlated to the heap index. If we observe such issue we should order // the entries by heap position before running this loop. foreach (var entry in _blobs) { int heapOffset = MetadataTokens.GetHeapOffset(entry.Value); var blob = entry.Key; writer.Offset = heapOffset; writer.WriteCompressedInteger(blob.Length); writer.WriteBytes(blob); } }
internal static void WriteCompressedInteger(ref BlobWriter writer, uint value) { unchecked { if (value <= SingleByteCompressedIntegerMaxValue) { writer.WriteByte((byte)value); } else if (value <= TwoByteCompressedIntegerMaxValue) { writer.WriteUInt16BE((ushort)(0x8000 | value)); } else if (value <= MaxCompressedIntegerValue) { writer.WriteUInt32BE(0xc0000000 | value); } else { ThrowValueArgumentOutOfRange(); } } }
// internal for testing internal static byte[] SerializeCustomDebugMetadata(ArrayBuilder <BlobWriter> recordWriters) { if (recordWriters.Count == 0) { return(null); } BlobWriter cmw = BlobWriter.GetInstance(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte((byte)recordWriters.Count); // count cmw.Align(4); foreach (BlobWriter recordWriter in recordWriters) { recordWriter.WriteTo(cmw); } var result = cmw.ToArray(); cmw.Free(); return(result); }
public void WritePrimitive() { var writer = new BlobWriter(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()); }
private static void SerializeReferenceToIteratorClass(string iteratorClassName, ArrayBuilder <BlobWriter> customDebugInfo) { if (iteratorClassName == null) { return; } var cmw = new BlobWriter(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindForwardIterator); cmw.Align(4); uint length = 10 + (uint)iteratorClassName.Length * 2; if ((length & 3) != 0) { length += 4 - (length & 3); } cmw.WriteUint(length); cmw.WriteUTF16(iteratorClassName); cmw.WriteShort(0); cmw.Align(4); Debug.Assert(cmw.Position == length); customDebugInfo.Add(cmw); }
internal int GetBlobIndex(BlobWriter stream) { // TODO: avoid making a copy if the blob exists in the index return(GetBlobIndex(stream.ToImmutableArray())); }
private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder <BlobWriter> customDebugInfo) { if (!methodBody.HasDynamicLocalVariables) { return; //There are no dynamic locals } var dynamicLocals = ArrayBuilder <ILocalDefinition> .GetInstance(); foreach (ILocalDefinition local in methodBody.LocalVariables) { if (local.IsDynamic) { dynamicLocals.Add(local); } } int dynamicVariableCount = dynamicLocals.Count; foreach (var currentScope in methodBody.LocalScopes) { foreach (var localConstant in currentScope.Constants) { if (localConstant.IsDynamic) { dynamicLocals.Add(localConstant); } } } Debug.Assert(dynamicLocals.Any()); // There must be at least one dynamic local if this point is reached const int blobSize = 200; //DynamicAttribute - 64, DynamicAttributeLength - 4, SlotIndex -4, IdentifierName - 128 var cmw = new BlobWriter(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindDynamicLocals); cmw.Align(4); // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob)) cmw.WriteUint(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUint((uint)dynamicLocals.Count); int localIndex = 0; foreach (ILocalDefinition local in dynamicLocals) { if (local.Name.Length > 63)//Ignore and push empty information { cmw.WriteBytes(0, blobSize); continue; } var dynamicTransformFlags = local.DynamicTransformFlags; if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= 64) { byte[] flag = new byte[64]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if ((bool)dynamicTransformFlags[k].Value) { flag[k] = 1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUint((uint)dynamicTransformFlags.Length); //Written Length } else { cmw.WriteBytes(0, 68); //Empty flag array and size. } if (localIndex < dynamicVariableCount) { // Dynamic variable cmw.WriteUint((uint)local.SlotIndex); } else { // Dynamic constant cmw.WriteUint(0); } char[] localName = new char[64]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteUTF16(localName); localIndex++; } dynamicLocals.Free(); customDebugInfo.Add(cmw); }
/// <summary> /// Compares the current content of this writer with another one. /// </summary> public bool ContentEquals(BlobWriter other) { return(Length == other.Length && ByteSequenceComparer.Equals(_buffer, _start, other._buffer, other._start, Length)); }
private void WriteDirectory(Directory directory, BlobWriter writer, uint offset, uint level, uint sizeOfDirectoryTree, uint virtualAddressBase, BlobWriter dataWriter) { writer.WriteUint(0); // Characteristics writer.WriteUint(0); // Timestamp writer.WriteUint(0); // Version writer.WriteUshort(directory.NumberOfNamedEntries); writer.WriteUshort(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.WriteUint(virtualAddressBase + sizeOfDirectoryTree + 16 + (uint)dataWriter.Position); byte[] data = new List<byte>(r.Data).ToArray(); dataWriter.WriteUint((uint)data.Length); dataWriter.WriteUint(r.CodePage); dataWriter.WriteUint(0); dataWriter.WriteBytes(data); while ((dataWriter.Length % 4) != 0) { dataWriter.WriteByte(0); } } if (id >= 0) { writer.WriteInt(id); } else { if (name == null) { name = string.Empty; } writer.WriteUint(nameOffset | 0x80000000); dataWriter.WriteUshort((ushort)name.Length); dataWriter.WriteUTF16(name); } if (subDir != null) { writer.WriteUint(directoryOffset | 0x80000000); } else { writer.WriteUint(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; } } } }
private void WriteRelocSection(Stream peStream) { if (!_emitRuntimeStartupStub) { //No need to write out a reloc section, but there is still a need to pad out the peStream so that it is an even multiple of module.FileAlignment if (_relocSection.PointerToRawData != peStream.Position) { //for example, the resource section did not end bang on the alignment boundary peStream.Position = _relocSection.PointerToRawData - 1; peStream.WriteByte(0); } return; } peStream.Position = _relocSection.PointerToRawData; var writer = new BlobWriter(_module.FileAlignment); writer.WriteUint(((_ntHeader.AddressOfEntryPoint + 2) / 0x1000) * 0x1000); writer.WriteUint(_module.Requires64bits && !_module.RequiresAmdInstructionSet ? 14u : 12u); uint offsetWithinPage = (_ntHeader.AddressOfEntryPoint + 2) % 0x1000; uint relocType = _module.Requires64bits ? 10u : 3u; ushort s = (ushort)((relocType << 12) | offsetWithinPage); writer.WriteUshort(s); if (_module.Requires64bits && !_module.RequiresAmdInstructionSet) { writer.WriteUint(relocType << 12); } writer.WriteUshort(0); // next chunk's RVA writer.Position = (int)_module.FileAlignment; writer.WriteTo(peStream); }
private void WriteDebugTable(Stream peStream, ContentId nativePdbContentId, MetadataSizes metadataSizes) { if (!EmitPdb) { return; } var writer = new BlobWriter(); // characteristics: writer.WriteUint(0); // PDB stamp writer.WriteBytes(nativePdbContentId.Stamp); // version writer.WriteUint(0); // type: const int ImageDebugTypeCodeView = 2; writer.WriteUint(ImageDebugTypeCodeView); // size of data: writer.WriteUint((uint)ComputeSizeOfDebugDirectoryData()); uint dataOffset = (uint)ComputeOffsetToDebugTable(metadataSizes) + ImageDebugDirectoryBaseSize; // PointerToRawData (RVA of the data): writer.WriteUint(_textSection.RelativeVirtualAddress + dataOffset); // AddressOfRawData (position of the data in the PE stream): writer.WriteUint(_textSection.PointerToRawData + dataOffset); writer.WriteByte((byte)'R'); writer.WriteByte((byte)'S'); writer.WriteByte((byte)'D'); writer.WriteByte((byte)'S'); // PDB id: writer.WriteBytes(nativePdbContentId.Guid); // age writer.WriteUint(PdbWriter.Age); // UTF-8 encoded zero-terminated path to PDB writer.WriteUTF8(_pdbPathOpt); writer.WriteByte(0); writer.WriteTo(peStream); writer.Free(); }
private static void WriteMetadata(Stream peStream, BlobWriter metadataStream) { metadataStream.WriteTo(peStream); while (peStream.Position % 4 != 0) { peStream.WriteByte(0); } }
public void EmptyWrites() { var writer = new BlobWriter(16); writer.WriteBytes(1, 16); writer.WriteBytes(new byte[] { }); writer.WriteBytes(2, 0); writer.WriteUTF8("", allowUnpairedSurrogates: false); writer.WriteUTF16(""); Assert.Equal(16, writer.Length); }
private static void TestCompressedSignedInteger(byte[] expected, int value) { var writer = new BlobWriter(4); writer.WriteCompressedSignedInteger(value); AssertEx.Equal(expected, writer.ToArray()); var builder = new BlobBuilder(); builder.WriteCompressedSignedInteger(value); AssertEx.Equal(expected, builder.ToArray()); }
private void WriteRuntimeStartupStub(Stream peStream, int importAddressTableRva) { var writer = new BlobWriter(16); // entry point code, consisting of a jump indirect to _CorXXXMain if (_is32bit) { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 4 byte boundary. for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 4) - peStream.Position); i < n; i++) { writer.WriteByte(0); } writer.WriteUshort(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //4 writer.WriteUint((uint)importAddressTableRva + (uint)_properties.BaseAddress); //8 } else { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 8 byte boundary. for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 8) - peStream.Position); i < n; i++) { writer.WriteByte(0); } writer.WriteUint(0); writer.WriteUshort(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //8 writer.WriteUlong((ulong)importAddressTableRva + _properties.BaseAddress); //16 } writer.WriteTo(peStream); }
private void WriteRelocSection(Stream peStream, SectionHeader relocSection, int entryPointAddress) { peStream.Position = relocSection.PointerToRawData; var writer = new BlobWriter(relocSection.SizeOfRawData); writer.WriteUint((((uint)entryPointAddress + 2) / 0x1000) * 0x1000); writer.WriteUint(_properties.Requires64bits && !_properties.RequiresAmdInstructionSet ? 14u : 12u); uint offsetWithinPage = ((uint)entryPointAddress + 2) % 0x1000; uint relocType = _properties.Requires64bits ? 10u : 3u; ushort s = (ushort)((relocType << 12) | offsetWithinPage); writer.WriteUshort(s); if (_properties.Requires64bits && !_properties.RequiresAmdInstructionSet) { writer.WriteUint(relocType << 12); } writer.WriteUshort(0); // next chunk's RVA writer.Position = relocSection.SizeOfRawData; writer.WriteTo(peStream); }
internal static void WriteConstant(ref BlobWriter 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(); } }
private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream, Func<Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt) { // TODO: we can precalculate the exact size of IL stream var ilWriter = new BlobWriter(32 * 1024); var metadataWriter = new BlobWriter(16 * 1024); var mappedFieldDataWriter = new BlobWriter(); var managedResourceWriter = new BlobWriter(1024); var debugMetadataWriterOpt = (getPortablePdbStreamOpt != null) ? new BlobWriter(16 * 1024) : null; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(_properties.PersistentIdentifier == default(Guid)); int sectionCount = 1; if (_properties.RequiresStartupStub) sectionCount++; //.reloc if (!IteratorHelper.EnumerableIsEmpty(_nativeResourcesOpt) || _nativeResourceSectionOpt != null) sectionCount++; //.rsrc; int sizeOfPeHeaders = ComputeSizeOfPeHeaders(sectionCount); int textSectionRva = BitArithmeticUtilities.Align(sizeOfPeHeaders, _properties.SectionAlignment); int moduleVersionIdOffsetInMetadataStream; int methodBodyStreamRva = textSectionRva + OffsetToILStream; int entryPointToken; MetadataSizes metadataSizes; mdWriter.SerializeMetadataAndIL( metadataWriter, debugMetadataWriterOpt, nativePdbWriterOpt, ilWriter, mappedFieldDataWriter, managedResourceWriter, methodBodyStreamRva, mdSizes => CalculateMappedFieldDataStreamRva(textSectionRva, mdSizes), out moduleVersionIdOffsetInMetadataStream, out entryPointToken, out metadataSizes); ContentId nativePdbContentId; if (nativePdbWriterOpt != null) { if (entryPointToken != 0) { nativePdbWriterOpt.SetEntryPoint((uint)entryPointToken); } var assembly = mdWriter.Module.AsAssembly; if (assembly != null && assembly.Kind == OutputKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in an winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap()); #endif } nativePdbContentId = nativePdbWriterOpt.GetContentId(); // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; } else { nativePdbContentId = default(ContentId); } // Only the size of the fixed part of the debug table goes here. DirectoryEntry debugDirectory = default(DirectoryEntry); DirectoryEntry importTable = default(DirectoryEntry); DirectoryEntry importAddressTable = default(DirectoryEntry); int entryPointAddress = 0; if (EmitPdb) { debugDirectory = new DirectoryEntry(textSectionRva + ComputeOffsetToDebugTable(metadataSizes), ImageDebugDirectoryBaseSize); } if (_properties.RequiresStartupStub) { importAddressTable = new DirectoryEntry(textSectionRva, SizeOfImportAddressTable); entryPointAddress = CalculateMappedFieldDataStreamRva(textSectionRva, metadataSizes) - (_is32bit ? 6 : 10); // TODO: constants importTable = new DirectoryEntry(textSectionRva + ComputeOffsetToImportTable(metadataSizes), (_is32bit ? 66 : 70) + 13); // TODO: constants } var corHeaderDirectory = new DirectoryEntry(textSectionRva + SizeOfImportAddressTable, size: CorHeaderSize); long ntHeaderTimestampPosition; long metadataPosition; List<SectionHeader> sectionHeaders = CreateSectionHeaders(metadataSizes, sectionCount); CoffHeader coffHeader; NtHeader ntHeader; FillInNtHeader(sectionHeaders, entryPointAddress, corHeaderDirectory, importTable, importAddressTable, debugDirectory, out coffHeader, out ntHeader); Stream peStream = getPeStream(); if (peStream == null) { return false; } WriteHeaders(peStream, ntHeader, coffHeader, sectionHeaders, out ntHeaderTimestampPosition); WriteTextSection( peStream, sectionHeaders[0], importTable.RelativeVirtualAddress, importAddressTable.RelativeVirtualAddress, entryPointToken, metadataWriter, ilWriter, mappedFieldDataWriter, managedResourceWriter, metadataSizes, nativePdbContentId, out metadataPosition); var resourceSection = sectionHeaders.FirstOrDefault(s => s.Name == ResourceSectionName); if (resourceSection != null) { WriteResourceSection(peStream, resourceSection); } var relocSection = sectionHeaders.FirstOrDefault(s => s.Name == RelocationSectionName); if (relocSection != null) { WriteRelocSection(peStream, relocSection, entryPointAddress); } if (_deterministic) { var mvidPosition = metadataPosition + moduleVersionIdOffsetInMetadataStream; WriteDeterministicGuidAndTimestamps(peStream, mvidPosition, ntHeaderTimestampPosition); } return true; }
private void WriteHeaders(Stream peStream, NtHeader ntHeader, CoffHeader coffHeader, List<SectionHeader> sectionHeaders, out long ntHeaderTimestampPosition) { var writer = new BlobWriter(1024); // MS-DOS stub (128 bytes) writer.WriteBytes(s_dosHeader); // PE Signature "PE\0\0" writer.WriteUint(0x00004550); // COFF Header (20 bytes) writer.WriteUshort((ushort)coffHeader.Machine); writer.WriteUshort((ushort)coffHeader.NumberOfSections); ntHeaderTimestampPosition = writer.Position + peStream.Position; writer.WriteUint((uint)coffHeader.TimeDateStamp); writer.WriteUint((uint)coffHeader.PointerToSymbolTable); writer.WriteUint((uint)coffHeader.NumberOfSymbols); writer.WriteUshort((ushort)(_is32bit ? 224 : 240)); // SizeOfOptionalHeader writer.WriteUshort((ushort)coffHeader.Characteristics); // PE Headers: writer.WriteUshort((ushort)(_is32bit ? PEMagic.PE32 : PEMagic.PE32Plus)); // 2 writer.WriteByte(ntHeader.MajorLinkerVersion); // 3 writer.WriteByte(ntHeader.MinorLinkerVersion); // 4 writer.WriteUint((uint)ntHeader.SizeOfCode); // 8 writer.WriteUint((uint)ntHeader.SizeOfInitializedData); // 12 writer.WriteUint((uint)ntHeader.SizeOfUninitializedData); // 16 writer.WriteUint((uint)ntHeader.AddressOfEntryPoint); // 20 writer.WriteUint((uint)ntHeader.BaseOfCode); // 24 if (_is32bit) { writer.WriteUint((uint)ntHeader.BaseOfData); // 28 writer.WriteUint((uint)ntHeader.ImageBase); // 32 } else { writer.WriteUlong(ntHeader.ImageBase); // 32 } // NT additional fields: writer.WriteUint((uint)ntHeader.SectionAlignment); // 36 writer.WriteUint((uint)ntHeader.FileAlignment); // 40 writer.WriteUshort(ntHeader.MajorOperatingSystemVersion); // 42 writer.WriteUshort(ntHeader.MinorOperatingSystemVersion); // 44 writer.WriteUshort(ntHeader.MajorImageVersion); // 46 writer.WriteUshort(ntHeader.MinorImageVersion); // 48 writer.WriteUshort(ntHeader.MajorSubsystemVersion); // MajorSubsystemVersion 50 writer.WriteUshort(ntHeader.MinorSubsystemVersion); // MinorSubsystemVersion 52 // Win32VersionValue (reserved, should be 0) writer.WriteUint(0); // 56 writer.WriteUint((uint)ntHeader.SizeOfImage); // 60 writer.WriteUint((uint)ntHeader.SizeOfHeaders); // 64 writer.WriteUint(ntHeader.Checksum); // 68 writer.WriteUshort((ushort)ntHeader.Subsystem); // 70 writer.WriteUshort((ushort)ntHeader.DllCharacteristics); if (_is32bit) { writer.WriteUint((uint)ntHeader.SizeOfStackReserve); // 76 writer.WriteUint((uint)ntHeader.SizeOfStackCommit); // 80 writer.WriteUint((uint)ntHeader.SizeOfHeapReserve); // 84 writer.WriteUint((uint)ntHeader.SizeOfHeapCommit); // 88 } else { writer.WriteUlong(ntHeader.SizeOfStackReserve); // 80 writer.WriteUlong(ntHeader.SizeOfStackCommit); // 88 writer.WriteUlong(ntHeader.SizeOfHeapReserve); // 96 writer.WriteUlong(ntHeader.SizeOfHeapCommit); // 104 } // LoaderFlags writer.WriteUint(0); // 92|108 // The number of data-directory entries in the remainder of the header. writer.WriteUint(16); // 96|112 // directory entries: writer.WriteUint((uint)ntHeader.ExportTable.RelativeVirtualAddress); // 100|116 writer.WriteUint((uint)ntHeader.ExportTable.Size); // 104|120 writer.WriteUint((uint)ntHeader.ImportTable.RelativeVirtualAddress); // 108|124 writer.WriteUint((uint)ntHeader.ImportTable.Size); // 112|128 writer.WriteUint((uint)ntHeader.ResourceTable.RelativeVirtualAddress); // 116|132 writer.WriteUint((uint)ntHeader.ResourceTable.Size); // 120|136 writer.WriteUint((uint)ntHeader.ExceptionTable.RelativeVirtualAddress); // 124|140 writer.WriteUint((uint)ntHeader.ExceptionTable.Size); // 128|144 writer.WriteUint((uint)ntHeader.CertificateTable.RelativeVirtualAddress); // 132|148 writer.WriteUint((uint)ntHeader.CertificateTable.Size); // 136|152 writer.WriteUint((uint)ntHeader.BaseRelocationTable.RelativeVirtualAddress); // 140|156 writer.WriteUint((uint)ntHeader.BaseRelocationTable.Size); // 144|160 writer.WriteUint((uint)ntHeader.DebugTable.RelativeVirtualAddress); // 148|164 writer.WriteUint((uint)ntHeader.DebugTable.Size); // 152|168 writer.WriteUint((uint)ntHeader.CopyrightTable.RelativeVirtualAddress); // 156|172 writer.WriteUint((uint)ntHeader.CopyrightTable.Size); // 160|176 writer.WriteUint((uint)ntHeader.GlobalPointerTable.RelativeVirtualAddress); // 164|180 writer.WriteUint((uint)ntHeader.GlobalPointerTable.Size); // 168|184 writer.WriteUint((uint)ntHeader.ThreadLocalStorageTable.RelativeVirtualAddress); // 172|188 writer.WriteUint((uint)ntHeader.ThreadLocalStorageTable.Size); // 176|192 writer.WriteUint((uint)ntHeader.LoadConfigTable.RelativeVirtualAddress); // 180|196 writer.WriteUint((uint)ntHeader.LoadConfigTable.Size); // 184|200 writer.WriteUint((uint)ntHeader.BoundImportTable.RelativeVirtualAddress); // 188|204 writer.WriteUint((uint)ntHeader.BoundImportTable.Size); // 192|208 writer.WriteUint((uint)ntHeader.ImportAddressTable.RelativeVirtualAddress); // 196|212 writer.WriteUint((uint)ntHeader.ImportAddressTable.Size); // 200|216 writer.WriteUint((uint)ntHeader.DelayImportTable.RelativeVirtualAddress); // 204|220 writer.WriteUint((uint)ntHeader.DelayImportTable.Size); // 208|224 writer.WriteUint((uint)ntHeader.CliHeaderTable.RelativeVirtualAddress); // 212|228 writer.WriteUint((uint)ntHeader.CliHeaderTable.Size); // 216|232 writer.WriteUlong(0); // 224|240 // Section Headers foreach (var sectionHeader in sectionHeaders) { WriteSectionHeader(sectionHeader, writer); } writer.WriteTo(peStream); }
private static void WriteMappedFieldData(Stream peStream, BlobWriter dataStream) { dataStream.WriteTo(peStream); while (peStream.Position % 4 != 0) { peStream.WriteByte(0); } }
private void WriteHeaders(Stream peStream, out long ntHeaderTimestampPosition) { IModule module = _module; NtHeader ntHeader = _ntHeader; var writer = _headerWriter; // MS-DOS stub (128 bytes) writer.WriteBytes(s_dosHeader); // TODO: provide an option to suppress the second half of the DOS header? // PE Signature (4 bytes) writer.WriteUint(0x00004550); /* "PE\0\0" */ // COFF Header 20 bytes writer.WriteUshort((ushort)module.Machine); writer.WriteUshort(ntHeader.NumberOfSections); ntHeaderTimestampPosition = writer.Position + peStream.Position; writer.WriteUint(ntHeader.TimeDateStamp); writer.WriteUint(ntHeader.PointerToSymbolTable); writer.WriteUint(0); // NumberOfSymbols writer.WriteUshort((ushort)(!module.Requires64bits ? 224 : 240)); // SizeOfOptionalHeader // ushort characteristics = 0x0002|0x0004|0x0008; // executable | no COFF line nums | no COFF symbols (as required by the standard) ushort characteristics = 0x0002; // executable (as required by the Linker team). if (module.Kind == ModuleKind.DynamicallyLinkedLibrary || module.Kind == ModuleKind.WindowsRuntimeMetadata) { characteristics |= 0x2000; } if (module.Requires32bits) { characteristics |= 0x0100; // 32 bit machine (The standard says to always set this, the linker team says otherwise) //The loader team says that this is not used for anything in the OS. } else { characteristics |= 0x0020; // large address aware (the standard says never to set this, the linker team says otherwise). //The loader team says that this is not overridden for managed binaries and will be respected if set. } writer.WriteUshort(characteristics); // PE Header (224 bytes if 32 bits, 240 bytes if 64 bit) if (!module.Requires64bits) { writer.WriteUshort(0x10B); // Magic = PE32 // 2 } else { writer.WriteUshort(0x20B); // Magic = PE32+ // 2 } writer.WriteByte(module.LinkerMajorVersion); // 3 writer.WriteByte(module.LinkerMinorVersion); // 4 writer.WriteUint(ntHeader.SizeOfCode); // 8 writer.WriteUint(ntHeader.SizeOfInitializedData); // 12 writer.WriteUint(ntHeader.SizeOfUninitializedData); // 16 writer.WriteUint(ntHeader.AddressOfEntryPoint); // 20 writer.WriteUint(ntHeader.BaseOfCode); // 24 if (!module.Requires64bits) { writer.WriteUint(ntHeader.BaseOfData); // 28 writer.WriteUint((uint)module.BaseAddress); // 32 } else { writer.WriteUlong(module.BaseAddress); // 32 } writer.WriteUint(0x2000); // SectionAlignment 36 writer.WriteUint(module.FileAlignment); // 40 writer.WriteUshort(4); // MajorOperatingSystemVersion 42 writer.WriteUshort(0); // MinorOperatingSystemVersion 44 writer.WriteUshort(0); // MajorImageVersion 46 writer.WriteUshort(0); // MinorImageVersion 48 writer.WriteUshort(module.MajorSubsystemVersion); // MajorSubsystemVersion 50 writer.WriteUshort(module.MinorSubsystemVersion); // MinorSubsystemVersion 52 writer.WriteUint(0); // Win32VersionValue 56 writer.WriteUint(ntHeader.SizeOfImage); // 60 writer.WriteUint(ntHeader.SizeOfHeaders); // 64 writer.WriteUint(0); // CheckSum 68 switch (module.Kind) { case ModuleKind.ConsoleApplication: case ModuleKind.DynamicallyLinkedLibrary: case ModuleKind.WindowsRuntimeMetadata: writer.WriteUshort(3); // 70 break; case ModuleKind.WindowsApplication: writer.WriteUshort(2); // 70 break; default: writer.WriteUshort(0); // break; } writer.WriteUshort(module.DllCharacteristics); if (!module.Requires64bits) { writer.WriteUint((uint)module.SizeOfStackReserve); // 76 writer.WriteUint((uint)module.SizeOfStackCommit); // 80 writer.WriteUint((uint)module.SizeOfHeapReserve); // 84 writer.WriteUint((uint)module.SizeOfHeapCommit); // 88 } else { writer.WriteUlong(module.SizeOfStackReserve); // 80 writer.WriteUlong(module.SizeOfStackCommit); // 88 writer.WriteUlong(module.SizeOfHeapReserve); // 96 writer.WriteUlong(module.SizeOfHeapCommit); // 104 } writer.WriteUint(0); // LoaderFlags 92|108 writer.WriteUint(16); // numberOfDataDirectories 96|112 writer.WriteUint(ntHeader.ExportTable.RelativeVirtualAddress); // 100|116 writer.WriteUint(ntHeader.ExportTable.Size); // 104|120 writer.WriteUint(ntHeader.ImportTable.RelativeVirtualAddress); // 108|124 writer.WriteUint(ntHeader.ImportTable.Size); // 112|128 writer.WriteUint(ntHeader.ResourceTable.RelativeVirtualAddress); // 116|132 writer.WriteUint(ntHeader.ResourceTable.Size); // 120|136 writer.WriteUint(ntHeader.ExceptionTable.RelativeVirtualAddress); // 124|140 writer.WriteUint(ntHeader.ExceptionTable.Size); // 128|144 writer.WriteUint(ntHeader.CertificateTable.RelativeVirtualAddress); // 132|148 writer.WriteUint(ntHeader.CertificateTable.Size); // 136|152 writer.WriteUint(ntHeader.BaseRelocationTable.RelativeVirtualAddress); // 140|156 writer.WriteUint(ntHeader.BaseRelocationTable.Size); // 144|160 writer.WriteUint(ntHeader.DebugTable.RelativeVirtualAddress); // 148|164 writer.WriteUint(ntHeader.DebugTable.Size); // 152|168 writer.WriteUint(ntHeader.CopyrightTable.RelativeVirtualAddress); // 156|172 writer.WriteUint(ntHeader.CopyrightTable.Size); // 160|176 writer.WriteUint(ntHeader.GlobalPointerTable.RelativeVirtualAddress); // 164|180 writer.WriteUint(ntHeader.GlobalPointerTable.Size); // 168|184 writer.WriteUint(ntHeader.ThreadLocalStorageTable.RelativeVirtualAddress); // 172|188 writer.WriteUint(ntHeader.ThreadLocalStorageTable.Size); // 176|192 writer.WriteUint(ntHeader.LoadConfigTable.RelativeVirtualAddress); // 180|196 writer.WriteUint(ntHeader.LoadConfigTable.Size); // 184|200 writer.WriteUint(ntHeader.BoundImportTable.RelativeVirtualAddress); // 188|204 writer.WriteUint(ntHeader.BoundImportTable.Size); // 192|208 writer.WriteUint(ntHeader.ImportAddressTable.RelativeVirtualAddress); // 196|212 writer.WriteUint(ntHeader.ImportAddressTable.Size); // 200|216 writer.WriteUint(ntHeader.DelayImportTable.RelativeVirtualAddress); // 204|220 writer.WriteUint(ntHeader.DelayImportTable.Size); // 208|224 writer.WriteUint(ntHeader.CliHeaderTable.RelativeVirtualAddress); // 212|228 writer.WriteUint(ntHeader.CliHeaderTable.Size); // 216|232 writer.WriteUlong(0); // 224|240 // Section Headers WriteSectionHeader(_textSection, writer); WriteSectionHeader(_rdataSection, writer); WriteSectionHeader(_sdataSection, writer); WriteSectionHeader(_coverSection, writer); WriteSectionHeader(_resourceSection, writer); WriteSectionHeader(_relocSection, writer); WriteSectionHeader(_tlsSection, writer); writer.WriteTo(peStream); _headerWriter = _emptyStream; }
private static void WriteManagedResources(Stream peStream, BlobWriter managedResourceStream) { managedResourceStream.WriteTo(peStream); while (peStream.Position % 4 != 0) { peStream.WriteByte(0); } }
private static void WriteSectionHeader(SectionHeader sectionHeader, BlobWriter writer) { if (sectionHeader.VirtualSize == 0) { return; } for (int j = 0, m = sectionHeader.Name.Length; j < 8; j++) { if (j < m) { writer.WriteByte((byte)sectionHeader.Name[j]); } else { writer.WriteByte(0); } } writer.WriteUint(sectionHeader.VirtualSize); writer.WriteUint(sectionHeader.RelativeVirtualAddress); writer.WriteUint(sectionHeader.SizeOfRawData); writer.WriteUint(sectionHeader.PointerToRawData); writer.WriteUint(sectionHeader.PointerToRelocations); writer.WriteUint(sectionHeader.PointerToLinenumbers); writer.WriteUshort(sectionHeader.NumberOfRelocations); writer.WriteUshort(sectionHeader.NumberOfLinenumbers); writer.WriteUint(sectionHeader.Characteristics); }
private void WriteRuntimeStartupStub(Stream peStream) { var writer = new BlobWriter(16); // entry point code, consisting of a jump indirect to _CorXXXMain if (!_module.Requires64bits) { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 4 byte boundary. for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 4) - peStream.Position); i < n; i++) { writer.WriteByte(0); } writer.WriteUshort(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //4 writer.WriteUint(_ntHeader.ImportAddressTable.RelativeVirtualAddress + (uint)_module.BaseAddress); //8 } else { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 8 byte boundary. for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 8) - peStream.Position); i < n; i++) { writer.WriteByte(0); } writer.WriteUint(0); writer.WriteUshort(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //8 writer.WriteUlong(_ntHeader.ImportAddressTable.RelativeVirtualAddress + _module.BaseAddress); //16 } writer.WriteTo(peStream); }
private void WriteTextSection( Stream peStream, CorHeader corHeader, BlobWriter metadataWriter, BlobWriter ilStream, BlobWriter mappedFieldDataWriter, BlobWriter managedResourceWriter, MetadataSizes metadataSizes, ContentId pdbContentId, out long metadataPosition) { peStream.Position = _textSection.PointerToRawData; if (_emitRuntimeStartupStub) { this.WriteImportAddressTable(peStream); } WriteCorHeader(peStream, corHeader); WriteIL(peStream, ilStream); metadataPosition = peStream.Position; WriteMetadata(peStream, metadataWriter); WriteManagedResources(peStream, managedResourceWriter); WriteSpaceForHash(peStream, (int)corHeader.StrongNameSignature.Size); WriteDebugTable(peStream, pdbContentId, metadataSizes); if (_emitRuntimeStartupStub) { WriteImportTable(peStream); WriteNameTable(peStream); WriteRuntimeStartupStub(peStream); } WriteMappedFieldData(peStream, mappedFieldDataWriter); }
private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream, Func<Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt) { // TODO: we can precalculate the exact size of IL stream var ilWriter = new BlobWriter(32 * 1024); var metadataWriter = new BlobWriter(16 * 1024); var mappedFieldDataWriter = new BlobWriter(); var managedResourceWriter = new BlobWriter(1024); var debugMetadataWriterOpt = (getPortablePdbStreamOpt != null) ? new BlobWriter(16 * 1024) : null; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(_module.PersistentIdentifier == default(Guid)); int moduleVersionIdOffsetInMetadataStream; var calculateMethodBodyStreamRva = new Func<MetadataSizes, int>(mdSizes => { FillInTextSectionHeader(mdSizes); return (int)_textSection.RelativeVirtualAddress + _sizeOfImportAddressTable + 72; }); int entryPointToken; MetadataSizes metadataSizes; mdWriter.SerializeMetadataAndIL( metadataWriter, debugMetadataWriterOpt, nativePdbWriterOpt, ilWriter, mappedFieldDataWriter, managedResourceWriter, calculateMethodBodyStreamRva, CalculateMappedFieldDataStreamRva, out moduleVersionIdOffsetInMetadataStream, out entryPointToken, out metadataSizes); ContentId nativePdbContentId; if (nativePdbWriterOpt != null) { if (entryPointToken != 0) { nativePdbWriterOpt.SetEntryPoint((uint)entryPointToken); } var assembly = _module.AsAssembly; if (assembly != null && assembly.Kind == ModuleKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(_module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in an winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(_module.GetSymbolToLocationMap()); #endif } nativePdbContentId = nativePdbWriterOpt.GetContentId(); // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; } else { nativePdbContentId = default(ContentId); } FillInSectionHeaders(); // fill in header fields. FillInNtHeader(metadataSizes, CalculateMappedFieldDataStreamRva(metadataSizes)); var corHeader = CreateCorHeader(metadataSizes, entryPointToken); // write to PE stream. Stream peStream = getPeStream(); if (peStream == null) { return false; } long ntHeaderTimestampPosition; long metadataPosition; WriteHeaders(peStream, out ntHeaderTimestampPosition); WriteTextSection( peStream, corHeader, metadataWriter, ilWriter, mappedFieldDataWriter, managedResourceWriter, metadataSizes, nativePdbContentId, out metadataPosition); WriteRdataSection(peStream); WriteSdataSection(peStream); WriteCoverSection(peStream); WriteTlsSection(peStream); WriteResourceSection(peStream); WriteRelocSection(peStream); if (_deterministic) { var mvidPosition = metadataPosition + moduleVersionIdOffsetInMetadataStream; WriteDeterministicGuidAndTimestamps(peStream, mvidPosition, ntHeaderTimestampPosition); } return true; }
private void WriteImportAddressTable(Stream peStream) { var writer = new BlobWriter(16); bool use32bitAddresses = !_module.Requires64bits; uint importTableRVA = _ntHeader.ImportTable.RelativeVirtualAddress; uint ilRVA = importTableRVA + 40; uint hintRva = ilRVA + (use32bitAddresses ? 12u : 16u); // Import Address Table if (use32bitAddresses) { writer.WriteUint(hintRva); // 4 writer.WriteUint(0); // 8 } else { writer.WriteUlong(hintRva); // 8 writer.WriteUlong(0); // 16 } writer.WriteTo(peStream); }
internal void WriteTo(BlobWriter stream) { stream.Write(_buffer, 0, _length); }
private void WriteImportTable(Stream peStream) { var writer = new BlobWriter(70); bool use32bitAddresses = !_module.Requires64bits; uint importTableRVA = _ntHeader.ImportTable.RelativeVirtualAddress; uint ilRVA = importTableRVA + 40; uint hintRva = ilRVA + (use32bitAddresses ? 12u : 16u); uint nameRva = hintRva + 12 + 2; // Import table writer.WriteUint(ilRVA); // 4 writer.WriteUint(0); // 8 writer.WriteUint(0); // 12 writer.WriteUint(nameRva); // 16 writer.WriteUint(_ntHeader.ImportAddressTable.RelativeVirtualAddress); // 20 writer.Position += 20; // 40 // Import Lookup table if (use32bitAddresses) { writer.WriteUint(hintRva); // 44 writer.WriteUint(0); // 48 writer.WriteUint(0); // 52 } else { writer.WriteUlong(hintRva); // 48 writer.WriteUlong(0); // 56 } // Hint table writer.WriteUshort(0); // Hint 54|58 string entryPointName = (_module.Kind == ModuleKind.DynamicallyLinkedLibrary || _module.Kind == ModuleKind.WindowsRuntimeMetadata) ? "_CorDllMain" : "_CorExeMain"; foreach (char ch in entryPointName) { writer.WriteByte((byte)ch); // 65|69 } writer.WriteByte(0); // 66|70 writer.WriteTo(peStream); }
private static void WriteNameTable(Stream peStream) { var writer = new BlobWriter(14); foreach (char ch in "mscoree.dll") { writer.WriteByte((byte)ch); // 11 } writer.WriteByte(0); // 12 writer.WriteUshort(0); // 14 writer.WriteTo(peStream); }
private static void WriteCorHeader(Stream peStream, CorHeader corHeader) { var writer = new BlobWriter(72); writer.WriteUint(72); // Number of bytes in this header 4 writer.WriteUshort(corHeader.MajorRuntimeVersion); // 6 writer.WriteUshort(corHeader.MinorRuntimeVersion); // 8 writer.WriteUint(corHeader.MetadataDirectory.RelativeVirtualAddress); // 12 writer.WriteUint(corHeader.MetadataDirectory.Size); // 16 writer.WriteUint((uint)corHeader.Flags); // 20 writer.WriteUint(corHeader.EntryPointToken); // 24 writer.WriteUint(corHeader.Resources.Size == 0 ? 0u : corHeader.Resources.RelativeVirtualAddress); // 28 writer.WriteUint(corHeader.Resources.Size); // 32 writer.WriteUint(corHeader.StrongNameSignature.Size == 0 ? 0u : corHeader.StrongNameSignature.RelativeVirtualAddress); // 36 writer.WriteUint(corHeader.StrongNameSignature.Size); // 40 writer.WriteUint(corHeader.CodeManagerTable.RelativeVirtualAddress); // 44 writer.WriteUint(corHeader.CodeManagerTable.Size); // 48 writer.WriteUint(corHeader.VTableFixups.RelativeVirtualAddress); // 52 writer.WriteUint(corHeader.VTableFixups.Size); // 56 writer.WriteUint(corHeader.ExportAddressTableJumps.RelativeVirtualAddress); // 60 writer.WriteUint(corHeader.ExportAddressTableJumps.Size); // 64 writer.WriteUlong(0); // 72 writer.WriteTo(peStream); }
private static void WriteIL(Stream peStream, BlobWriter ilStream) { ilStream.WriteTo(peStream); while (peStream.Position % 4 != 0) { peStream.WriteByte(0); } }
internal void WriteTo(BlobWriter stream) { stream.Write(this.Buffer, 0, (int)this.Length); }
/// <summary> /// Compares the current content of this writer with another one. /// </summary> public bool ContentEquals(BlobWriter other) { return Length == other.Length && ByteSequenceComparer.Equals(_buffer, _start, other._buffer, other._start, Length); }
public static bool WritePeToStream( EmitContext context, CommonMessageProvider messageProvider, Func <Stream> getPeStream, Func <Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt, string pdbPathOpt, bool allowMissingMethodBodies, bool isDeterministic, CancellationToken cancellationToken) { // If PDB writer is given, we have to have PDB path. Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null); var mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, isDeterministic, getPortablePdbStreamOpt != null, cancellationToken); var properties = context.Module.Properties; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(properties.PersistentIdentifier == default(Guid)); var ilBuilder = new BlobBuilder(32 * 1024); var mappedFieldDataBuilder = new BlobBuilder(); var managedResourceBuilder = new BlobBuilder(1024); Blob mvidFixup; mdWriter.BuildMetadataAndIL( nativePdbWriterOpt, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, out mvidFixup); MethodDefinitionHandle entryPointHandle; MethodDefinitionHandle debugEntryPointHandle; mdWriter.GetEntryPoints(out entryPointHandle, out debugEntryPointHandle); if (!debugEntryPointHandle.IsNil) { nativePdbWriterOpt?.SetEntryPoint((uint)MetadataTokens.GetToken(debugEntryPointHandle)); } if (nativePdbWriterOpt != null) { var assembly = mdWriter.Module.AsAssembly; if (assembly != null && assembly.Kind == OutputKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in an winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap()); #endif } } Stream peStream = getPeStream(); if (peStream == null) { return(false); } BlobContentId pdbContentId = nativePdbWriterOpt?.GetContentId() ?? default(BlobContentId); // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; ushort portablePdbVersion = 0; var metadataSerializer = mdWriter.GetTypeSystemMetadataSerializer(); var peHeaderBuilder = new PEHeaderBuilder( machine: properties.Machine, sectionAlignment: properties.SectionAlignment, fileAlignment: properties.FileAlignment, imageBase: properties.BaseAddress, majorLinkerVersion: properties.LinkerMajorVersion, minorLinkerVersion: properties.LinkerMinorVersion, majorOperatingSystemVersion: 4, minorOperatingSystemVersion: 0, majorImageVersion: 0, minorImageVersion: 0, majorSubsystemVersion: properties.MajorSubsystemVersion, minorSubsystemVersion: properties.MinorSubsystemVersion, subsystem: properties.Subsystem, dllCharacteristics: properties.DllCharacteristics, imageCharacteristics: properties.ImageCharacteristics, sizeOfStackReserve: properties.SizeOfStackReserve, sizeOfStackCommit: properties.SizeOfStackCommit, sizeOfHeapReserve: properties.SizeOfHeapReserve, sizeOfHeapCommit: properties.SizeOfHeapCommit); var deterministicIdProvider = isDeterministic ? new Func <IEnumerable <Blob>, BlobContentId>(content => BlobContentId.FromHash(CryptographicHashProvider.ComputeSha1(content))) : null; if (mdWriter.EmitStandaloneDebugMetadata) { Debug.Assert(getPortablePdbStreamOpt != null); var debugMetadataBuilder = new BlobBuilder(); var debugMetadataSerializer = mdWriter.GetStandaloneDebugMetadataSerializer(metadataSerializer.MetadataSizes, debugEntryPointHandle, deterministicIdProvider); debugMetadataSerializer.SerializeMetadata(debugMetadataBuilder, out pdbContentId); portablePdbVersion = debugMetadataSerializer.FormatVersion; // write to Portable PDB stream: Stream portablePdbStream = getPortablePdbStreamOpt(); if (portablePdbStream != null) { debugMetadataBuilder.WriteContentTo(portablePdbStream); } } DebugDirectoryBuilder debugDirectoryBuilder; if (pdbPathOpt != null || isDeterministic) { debugDirectoryBuilder = new DebugDirectoryBuilder(); if (pdbPathOpt != null) { string paddedPath = isDeterministic ? pdbPathOpt : PadPdbPath(pdbPathOpt); debugDirectoryBuilder.AddCodeViewEntry(paddedPath, pdbContentId, portablePdbVersion); } if (isDeterministic) { debugDirectoryBuilder.AddReproducibleEntry(); } } else { debugDirectoryBuilder = null; } var peBuilder = new ManagedPEBuilder( peHeaderBuilder, metadataSerializer, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, CreateNativeResourceSectionSerializer(context.Module), debugDirectoryBuilder, CalculateStrongNameSignatureSize(context.Module), entryPointHandle, properties.CorFlags, deterministicIdProvider); var peBlob = new BlobBuilder(); BlobContentId peContentId; peBuilder.Serialize(peBlob, out peContentId); // Patch MVID if (!mvidFixup.IsDefault) { var writer = new BlobWriter(mvidFixup); writer.WriteGuid(peContentId.Guid); Debug.Assert(writer.RemainingBytes == 0); } try { peBlob.WriteContentTo(peStream); } catch (Exception e) when(!(e is OperationCanceledException)) { throw new PeWritingException(e); } return(true); }
public void WriteContentToBlobWriter() { var builder = new BlobBuilder(16); for (int i = 0; i < 20; i++) { builder.WriteByte((byte)i); } var writer = new BlobWriter(256); builder.WriteContentTo(ref writer); AssertEx.Equal(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 }, writer.ToArray()); builder.WriteByte(0xff); builder.WriteContentTo(ref writer); AssertEx.Equal(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xff, }, writer.ToArray()); }