+namespace {
+class FragmentWriter {
+ bool IsLittleEndian;
+
+public:
+ FragmentWriter(bool IsLittleEndian);
+ template <typename T> void write(MCDataFragment &F, T Val);
+};
+
+typedef DenseMap<const MCSectionELF *, uint32_t> SectionIndexMapTy;
+
+class SymbolTableWriter {
+ MCAssembler &Asm;
+ FragmentWriter &FWriter;
+ bool Is64Bit;
+ SectionIndexMapTy &SectionIndexMap;
+
+ // The symbol .symtab fragment we are writting to.
+ MCDataFragment *SymtabF;
+
+ // .symtab_shndx fragment we are writting to.
+ MCDataFragment *ShndxF;
+
+ // The numbel of symbols written so far.
+ unsigned NumWritten;
+
+ void createSymtabShndx();
+
+ template <typename T> void write(MCDataFragment &F, T Value);
+
+public:
+ SymbolTableWriter(MCAssembler &Asm, FragmentWriter &FWriter, bool Is64Bit,
+ SectionIndexMapTy &SectionIndexMap,
+ MCDataFragment *SymtabF);
+
+ void writeSymbol(uint32_t name, uint8_t info, uint64_t value, uint64_t size,
+ uint8_t other, uint32_t shndx, bool Reserved);
+};
+
+struct ELFRelocationEntry {
+ uint64_t Offset; // Where is the relocation.
+ bool UseSymbol; // Relocate with a symbol, not the section.
+ union {
+ const MCSymbol *Symbol; // The symbol to relocate with.
+ const MCSectionData *Section; // The section to relocate with.
+ };
+ unsigned Type; // The type of the relocation.
+ uint64_t Addend; // The addend to use.
+
+ ELFRelocationEntry(uint64_t Offset, const MCSymbol *Symbol, unsigned Type,
+ uint64_t Addend)
+ : Offset(Offset), UseSymbol(true), Symbol(Symbol), Type(Type),
+ Addend(Addend) {}
+
+ ELFRelocationEntry(uint64_t Offset, const MCSectionData *Section,
+ unsigned Type, uint64_t Addend)
+ : Offset(Offset), UseSymbol(false), Section(Section), Type(Type),
+ Addend(Addend) {}
+};
+
+class ELFObjectWriter : public MCObjectWriter {
+ FragmentWriter FWriter;
+
+ protected:
+
+ static bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind);
+ static bool RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant);
+ static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout);
+ static bool isInSymtab(const MCAsmLayout &Layout, const MCSymbolData &Data,
+ bool Used, bool Renamed);
+ static bool isLocal(const MCSymbolData &Data, bool isUsedInReloc);
+ static bool IsELFMetaDataSection(const MCSectionData &SD);
+ static uint64_t DataSectionSize(const MCSectionData &SD);
+ static uint64_t GetSectionFileSize(const MCAsmLayout &Layout,
+ const MCSectionData &SD);
+ static uint64_t GetSectionAddressSize(const MCAsmLayout &Layout,
+ const MCSectionData &SD);
+
+ void WriteDataSectionData(MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCSectionELF &Section);
+
+ /*static bool isFixupKindX86RIPRel(unsigned Kind) {
+ return Kind == X86::reloc_riprel_4byte ||
+ Kind == X86::reloc_riprel_4byte_movq_load;
+ }*/
+
+ /// ELFSymbolData - Helper struct for containing some precomputed
+ /// information on symbols.
+ struct ELFSymbolData {
+ MCSymbolData *SymbolData;
+ uint64_t StringIndex;
+ uint32_t SectionIndex;
+ StringRef Name;
+
+ // Support lexicographic sorting.
+ bool operator<(const ELFSymbolData &RHS) const {
+ return Name < RHS.Name;
+ }
+ };
+
+ /// The target specific ELF writer instance.
+ std::unique_ptr<MCELFObjectTargetWriter> TargetObjectWriter;
+
+ SmallPtrSet<const MCSymbol *, 16> UsedInReloc;
+ SmallPtrSet<const MCSymbol *, 16> WeakrefUsedInReloc;
+ DenseMap<const MCSymbol *, const MCSymbol *> Renames;
+
+ llvm::DenseMap<const MCSectionData *, std::vector<ELFRelocationEntry>>
+ Relocations;
+ StringTableBuilder ShStrTabBuilder;
+
+ /// @}
+ /// @name Symbol Table Data
+ /// @{
+
+ StringTableBuilder StrTabBuilder;
+ std::vector<uint64_t> FileSymbolData;
+ std::vector<ELFSymbolData> LocalSymbolData;
+ std::vector<ELFSymbolData> ExternalSymbolData;
+ std::vector<ELFSymbolData> UndefinedSymbolData;
+
+ /// @}
+
+ bool NeedsGOT;
+
+ // This holds the symbol table index of the last local symbol.
+ unsigned LastLocalSymbolIndex;
+ // This holds the .strtab section index.
+ unsigned StringTableIndex;
+ // This holds the .symtab section index.
+ unsigned SymbolTableIndex;
+
+ unsigned ShstrtabIndex;
+
+
+ // TargetObjectWriter wrappers.
+ bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
+ bool hasRelocationAddend() const {
+ return TargetObjectWriter->hasRelocationAddend();
+ }
+ unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
+ bool IsPCRel) const {
+ return TargetObjectWriter->GetRelocType(Target, Fixup, IsPCRel);
+ }
+
+ public:
+ ELFObjectWriter(MCELFObjectTargetWriter *MOTW, raw_ostream &_OS,
+ bool IsLittleEndian)
+ : MCObjectWriter(_OS, IsLittleEndian), FWriter(IsLittleEndian),
+ TargetObjectWriter(MOTW), NeedsGOT(false) {}
+
+ virtual ~ELFObjectWriter();
+
+ void WriteWord(uint64_t W) {
+ if (is64Bit())
+ Write64(W);
+ else
+ Write32(W);
+ }
+
+ template <typename T> void write(MCDataFragment &F, T Value) {
+ FWriter.write(F, Value);
+ }
+
+ void WriteHeader(const MCAssembler &Asm,
+ uint64_t SectionDataSize,
+ unsigned NumberOfSections);
+
+ void WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD,
+ const MCAsmLayout &Layout);
+
+ void WriteSymbolTable(MCDataFragment *SymtabF, MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ SectionIndexMapTy &SectionIndexMap);
+
+ bool shouldRelocateWithSymbol(const MCAssembler &Asm,
+ const MCSymbolRefExpr *RefA,
+ const MCSymbolData *SD, uint64_t C,
+ unsigned Type) const;
+
+ void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFragment *Fragment, const MCFixup &Fixup,
+ MCValue Target, bool &IsPCRel,
+ uint64_t &FixedValue) override;
+
+ uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm,
+ const MCSymbol *S);
+
+ // Map from a group section to the signature symbol
+ typedef DenseMap<const MCSectionELF*, const MCSymbol*> GroupMapTy;
+ // Map from a signature symbol to the group section
+ typedef DenseMap<const MCSymbol*, const MCSectionELF*> RevGroupMapTy;
+ // Map from a section to the section with the relocations
+ typedef DenseMap<const MCSectionELF*, const MCSectionELF*> RelMapTy;
+ // Map from a section to its offset
+ typedef DenseMap<const MCSectionELF*, uint64_t> SectionOffsetMapTy;
+
+ /// Compute the symbol table data
+ ///
+ /// \param Asm - The assembler.
+ /// \param SectionIndexMap - Maps a section to its index.
+ /// \param RevGroupMap - Maps a signature symbol to the group section.
+ /// \param NumRegularSections - Number of non-relocation sections.
+ void computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout,
+ const SectionIndexMapTy &SectionIndexMap,
+ RevGroupMapTy RevGroupMap,
+ unsigned NumRegularSections);
+
+ void ComputeIndexMap(MCAssembler &Asm,
+ SectionIndexMapTy &SectionIndexMap,
+ const RelMapTy &RelMap);
+
+ void CreateRelocationSections(MCAssembler &Asm, MCAsmLayout &Layout,
+ RelMapTy &RelMap);
+
+ void CompressDebugSections(MCAssembler &Asm, MCAsmLayout &Layout);
+
+ void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout,
+ const RelMapTy &RelMap);
+
+ void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout,
+ SectionIndexMapTy &SectionIndexMap,
+ const RelMapTy &RelMap);
+
+ // Create the sections that show up in the symbol table. Currently
+ // those are the .note.GNU-stack section and the group sections.
+ void CreateIndexedSections(MCAssembler &Asm, MCAsmLayout &Layout,
+ GroupMapTy &GroupMap,
+ RevGroupMapTy &RevGroupMap,
+ SectionIndexMapTy &SectionIndexMap,
+ const RelMapTy &RelMap);
+
+ void ExecutePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) override;
+
+ void WriteSectionHeader(MCAssembler &Asm, const GroupMapTy &GroupMap,
+ const MCAsmLayout &Layout,
+ const SectionIndexMapTy &SectionIndexMap,
+ const SectionOffsetMapTy &SectionOffsetMap);
+
+ void ComputeSectionOrder(MCAssembler &Asm,
+ std::vector<const MCSectionELF*> &Sections);
+
+ void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
+ uint64_t Address, uint64_t Offset,
+ uint64_t Size, uint32_t Link, uint32_t Info,
+ uint64_t Alignment, uint64_t EntrySize);
+
+ void WriteRelocationsFragment(const MCAssembler &Asm,
+ MCDataFragment *F,
+ const MCSectionData *SD);
+
+ bool
+ IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
+ const MCSymbolData &DataA,
+ const MCFragment &FB,
+ bool InSet,
+ bool IsPCRel) const override;
+
+ void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
+ void WriteSection(MCAssembler &Asm,
+ const SectionIndexMapTy &SectionIndexMap,
+ uint32_t GroupSymbolIndex,
+ uint64_t Offset, uint64_t Size, uint64_t Alignment,
+ const MCSectionELF &Section);
+ };
+}
+
+FragmentWriter::FragmentWriter(bool IsLittleEndian)
+ : IsLittleEndian(IsLittleEndian) {}
+
+template <typename T> void FragmentWriter::write(MCDataFragment &F, T Val) {
+ if (IsLittleEndian)
+ Val = support::endian::byte_swap<T, support::little>(Val);
+ else
+ Val = support::endian::byte_swap<T, support::big>(Val);
+ const char *Start = (const char *)&Val;
+ F.getContents().append(Start, Start + sizeof(T));
+}
+
+void SymbolTableWriter::createSymtabShndx() {
+ if (ShndxF)
+ return;
+
+ MCContext &Ctx = Asm.getContext();
+ const MCSectionELF *SymtabShndxSection =
+ Ctx.getELFSection(".symtab_shndxr", ELF::SHT_SYMTAB_SHNDX, 0,
+ SectionKind::getReadOnly(), 4, "");
+ MCSectionData *SymtabShndxSD =
+ &Asm.getOrCreateSectionData(*SymtabShndxSection);
+ SymtabShndxSD->setAlignment(4);
+ ShndxF = new MCDataFragment(SymtabShndxSD);
+ unsigned Index = SectionIndexMap.size() + 1;
+ SectionIndexMap[SymtabShndxSection] = Index;
+
+ for (unsigned I = 0; I < NumWritten; ++I)
+ write(*ShndxF, uint32_t(0));
+}
+
+template <typename T>
+void SymbolTableWriter::write(MCDataFragment &F, T Value) {
+ FWriter.write(F, Value);
+}
+
+SymbolTableWriter::SymbolTableWriter(MCAssembler &Asm, FragmentWriter &FWriter,
+ bool Is64Bit,
+ SectionIndexMapTy &SectionIndexMap,
+ MCDataFragment *SymtabF)
+ : Asm(Asm), FWriter(FWriter), Is64Bit(Is64Bit),
+ SectionIndexMap(SectionIndexMap), SymtabF(SymtabF), ShndxF(nullptr),
+ NumWritten(0) {}
+
+void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value,
+ uint64_t size, uint8_t other,
+ uint32_t shndx, bool Reserved) {
+ bool LargeIndex = shndx >= ELF::SHN_LORESERVE && !Reserved;
+
+ if (LargeIndex)
+ createSymtabShndx();
+
+ if (ShndxF) {
+ if (LargeIndex)
+ write(*ShndxF, shndx);
+ else
+ write(*ShndxF, uint32_t(0));
+ }
+
+ uint16_t Index = LargeIndex ? uint16_t(ELF::SHN_XINDEX) : shndx;
+
+ raw_svector_ostream OS(SymtabF->getContents());
+
+ if (Is64Bit) {
+ write(*SymtabF, name); // st_name
+ write(*SymtabF, info); // st_info
+ write(*SymtabF, other); // st_other
+ write(*SymtabF, Index); // st_shndx
+ write(*SymtabF, value); // st_value
+ write(*SymtabF, size); // st_size
+ } else {
+ write(*SymtabF, name); // st_name
+ write(*SymtabF, uint32_t(value)); // st_value
+ write(*SymtabF, uint32_t(size)); // st_size
+ write(*SymtabF, info); // st_info
+ write(*SymtabF, other); // st_other
+ write(*SymtabF, Index); // st_shndx
+ }
+
+ ++NumWritten;
+}
+