Example #1
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.
            builder.Align(4);
            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
            builder.Align(4);
            int addressTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

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

            // Emit the export directory table
            builder.Align(4);
            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);
        }
Example #2
0
        /// <summary>
        /// Emit the .reloc section based on file relocation information in the individual blocks.
        /// We rely on the fact that the .reloc section is emitted last so that, by the time
        /// it's getting serialized, all other sections that may contain relocations have already
        /// been laid out.
        /// </summary>
        private BlobBuilder SerializeRelocationSection(SectionLocation sectionLocation)
        {
            // There are 12 bits for the relative offset
            const int RelocationTypeShift      = 12;
            const int MaxRelativeOffsetInBlock = (1 << RelocationTypeShift) - 1;

            // Even though the format doesn't dictate it, it seems customary
            // to align the base RVA's on 4K boundaries.
            const int BaseRVAAlignment = 1 << RelocationTypeShift;

            BlobBuilder   builder         = new BlobBuilder();
            int           baseRVA         = 0;
            List <ushort> offsetsAndTypes = null;

            Section relocSection = FindSection(R2RPEBuilder.RelocSectionName);

            if (relocSection != null)
            {
                relocSection.FilePosWhenPlaced = sectionLocation.PointerToRawData;
                relocSection.RVAWhenPlaced     = sectionLocation.RelativeVirtualAddress;
                builder = relocSection.Content;
            }

            // Traverse relocations in all sections in their RVA order
            // By now, all "normal" sections with relocations should already have been laid out
            foreach (Section section in _sections.OrderBy((sec) => sec.RVAWhenPlaced))
            {
                foreach (PlacedObjectData placedObjectData in section.PlacedObjectDataToRelocate)
                {
                    for (int relocIndex = 0; relocIndex < placedObjectData.Relocs.Length; relocIndex++)
                    {
                        RelocType relocType     = placedObjectData.Relocs[relocIndex].RelocType;
                        RelocType fileRelocType = Relocation.GetFileRelocationType(relocType);
                        if (fileRelocType != RelocType.IMAGE_REL_BASED_ABSOLUTE)
                        {
                            int relocationRVA = section.RVAWhenPlaced + placedObjectData.Offset + placedObjectData.Relocs[relocIndex].Offset;
                            if (offsetsAndTypes != null && relocationRVA - baseRVA > MaxRelativeOffsetInBlock)
                            {
                                // Need to flush relocation block as the current RVA is too far from base RVA
                                FlushRelocationBlock(builder, baseRVA, offsetsAndTypes);
                                offsetsAndTypes = null;
                            }
                            if (offsetsAndTypes == null)
                            {
                                // Create new relocation block
                                baseRVA         = relocationRVA & -BaseRVAAlignment;
                                offsetsAndTypes = new List <ushort>();
                            }
                            ushort offsetAndType = (ushort)(((ushort)fileRelocType << RelocationTypeShift) | (relocationRVA - baseRVA));
                            offsetsAndTypes.Add(offsetAndType);
                        }
                    }
                }
            }

            if (offsetsAndTypes != null)
            {
                FlushRelocationBlock(builder, baseRVA, offsetsAndTypes);
            }

            if (builder.Count != 0)
            {
                _relocationDirectoryEntry = new DirectoryEntry(sectionLocation.RelativeVirtualAddress, builder.Count);
            }

            return(builder);
        }
Example #3
0
 public void AddSection(Section section)
 {
     _sections.Add(section);
 }
Example #4
0
        /// <summary>
        /// Add an ObjectData block to a given section.
        /// </summary>
        /// <param name="data">Block to add</param>
        /// <param name="sectionIndex">Section index</param>
        /// <param name="name">Node name to emit in the map file</param>
        /// <param name="outputInfoBuilder">Optional output info to collect (used for creating maps and symbols)</param>
        public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, string name, OutputInfoBuilder outputInfoBuilder)
        {
            Section section = _sections[sectionIndex];

            // Calculate alignment padding - apparently ObjectDataBuilder can produce an alignment of 0
            int alignedOffset = section.Content.Count;

            if (objectData.Alignment > 1)
            {
                alignedOffset = (section.Content.Count + objectData.Alignment - 1) & -objectData.Alignment;
                int padding = alignedOffset - section.Content.Count;
                if (padding > 0)
                {
                    if ((section.Characteristics & SectionCharacteristics.ContainsCode) != 0)
                    {
                        uint cp = _codePadding;
                        while (padding >= sizeof(uint))
                        {
                            section.Content.WriteUInt32(cp);
                            padding -= sizeof(uint);
                        }
                        if (padding >= 2)
                        {
                            section.Content.WriteUInt16(unchecked ((ushort)cp));
                            cp >>= 16;
                        }
                        if ((padding & 1) != 0)
                        {
                            section.Content.WriteByte(unchecked ((byte)cp));
                        }
                    }
                    else
                    {
                        section.Content.WriteBytes(0, padding);
                    }
                }
            }

            if (outputInfoBuilder != null)
            {
                var node = new OutputNode(sectionIndex, alignedOffset, objectData.Data.Length, name);
                outputInfoBuilder.AddNode(node, objectData.DefinedSymbols[0]);
                if (objectData.Relocs != null)
                {
                    foreach (Relocation reloc in objectData.Relocs)
                    {
                        RelocType fileReloc = Relocation.GetFileRelocationType(reloc.RelocType);
                        if (fileReloc != RelocType.IMAGE_REL_BASED_ABSOLUTE)
                        {
                            outputInfoBuilder.AddRelocation(node, fileReloc);
                        }
                    }
                }
            }

            section.Content.WriteBytes(objectData.Data);

            if (objectData.DefinedSymbols != null)
            {
                foreach (ISymbolDefinitionNode symbol in objectData.DefinedSymbols)
                {
                    if (outputInfoBuilder != null)
                    {
                        Utf8StringBuilder sb = new Utf8StringBuilder();
                        symbol.AppendMangledName(GetNameMangler(), sb);
                        int sectionRelativeOffset = alignedOffset + symbol.Offset;
                        outputInfoBuilder.AddSymbol(new OutputSymbol(sectionIndex, sectionRelativeOffset, sb.ToString()));
                    }
                    _symbolMap.Add(symbol, new SymbolTarget(
                                       sectionIndex: sectionIndex,
                                       offset: alignedOffset + symbol.Offset,
                                       size: objectData.Data.Length));
                }
            }

            if (objectData.Relocs != null && objectData.Relocs.Length != 0)
            {
                section.PlacedObjectDataToRelocate.Add(new PlacedObjectData(alignedOffset, objectData));
            }
        }
Example #5
0
        /// <summary>
        /// Add an ObjectData block to a given section.
        /// </summary>
        /// <param name="data">Block to add</param>
        /// <param name="sectionIndex">Section index</param>
        /// <param name="name">Node name to emit in the map file</param>
        /// <param name="mapFile">Optional map file to emit</param>
        public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, string name, TextWriter mapFile)
        {
            Section section = _sections[sectionIndex];

            // Calculate alignment padding - apparently ObjectDataBuilder can produce an alignment of 0
            int alignedOffset = section.Content.Count;

            if (objectData.Alignment > 1)
            {
                alignedOffset = (section.Content.Count + objectData.Alignment - 1) & -objectData.Alignment;
                int padding = alignedOffset - section.Content.Count;
                if (padding > 0)
                {
                    if ((section.Characteristics & SectionCharacteristics.ContainsCode) != 0)
                    {
                        uint cp = _codePadding;
                        while (padding >= sizeof(uint))
                        {
                            section.Content.WriteUInt32(cp);
                            padding -= sizeof(uint);
                        }
                        if (padding >= 2)
                        {
                            section.Content.WriteUInt16(unchecked ((ushort)cp));
                            cp >>= 16;
                        }
                        if ((padding & 1) != 0)
                        {
                            section.Content.WriteByte(unchecked ((byte)cp));
                        }
                    }
                    else
                    {
                        section.Content.WriteBytes(0, padding);
                    }
                }
            }

            if (mapFile != null)
            {
                mapFile.WriteLine($@"S{sectionIndex}+0x{alignedOffset:X4}..{(alignedOffset + objectData.Data.Length):X4}: {objectData.Data.Length:X4} * {name}");
            }

            section.Content.WriteBytes(objectData.Data);

            if (objectData.DefinedSymbols != null)
            {
                foreach (ISymbolDefinitionNode symbol in objectData.DefinedSymbols)
                {
                    if (mapFile != null)
                    {
                        Utf8StringBuilder sb = new Utf8StringBuilder();
                        symbol.AppendMangledName(GetNameMangler(), sb);
                        int sectionRelativeOffset = alignedOffset + symbol.Offset;
                        mapFile.WriteLine($@"  +0x{sectionRelativeOffset:X4}: {sb.ToString()}");
                    }
                    _symbolMap.Add(symbol, new SymbolTarget(
                                       sectionIndex: sectionIndex,
                                       offset: alignedOffset + symbol.Offset,
                                       size: objectData.Data.Length));
                }
            }

            if (objectData.Relocs != null && objectData.Relocs.Length != 0)
            {
                section.PlacedObjectDataToRelocate.Add(new PlacedObjectData(alignedOffset, objectData));
            }
        }