Exemplo n.º 1
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);
            }

            _relocationDirectoryEntry = new DirectoryEntry(sectionLocation.RelativeVirtualAddress, builder.Count);

            return(builder);
        }
Exemplo n.º 2
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="mapFileBuilder">Optional map file to emit</param>
        public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, string name, MapFileBuilder mapFileBuilder)
        {
            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 (mapFileBuilder != null)
            {
                MapFileNode node = new MapFileNode(sectionIndex, alignedOffset, objectData.Data.Length, name);
                mapFileBuilder.AddNode(node);
                if (objectData.Relocs != null)
                {
                    foreach (Relocation reloc in objectData.Relocs)
                    {
                        RelocType fileReloc = Relocation.GetFileRelocationType(reloc.RelocType);
                        if (fileReloc != RelocType.IMAGE_REL_BASED_ABSOLUTE)
                        {
                            mapFileBuilder.AddRelocation(node, fileReloc);
                        }
                    }
                }
            }

            section.Content.WriteBytes(objectData.Data);

            if (objectData.DefinedSymbols != null)
            {
                foreach (ISymbolDefinitionNode symbol in objectData.DefinedSymbols)
                {
                    if (mapFileBuilder != null)
                    {
                        Utf8StringBuilder sb = new Utf8StringBuilder();
                        symbol.AppendMangledName(GetNameMangler(), sb);
                        int sectionRelativeOffset = alignedOffset + symbol.Offset;
                        mapFileBuilder.AddSymbol(new MapFileSymbol(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));
            }
        }