X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FMC%2FELFObjectWriter.cpp;h=8afd00fb7e315cee0211c832b839a0396fb1dfa4;hb=ad7c1174c70a26e547f7dc6f852664b1141f7453;hp=983e7b0b5b910738f873a8689d41a8cf4534f010;hpb=872266937b2110656db675f388d5470c53d8862a;p=oota-llvm.git diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 983e7b0b5b9..8afd00fb7e3 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -41,94 +41,53 @@ using namespace llvm; #define DEBUG_TYPE "reloc-info" namespace { -class FragmentWriter { - bool IsLittleEndian; - -public: - FragmentWriter(bool IsLittleEndian); - template void write(MCDataFragment &F, T Val); -}; typedef DenseMap SectionIndexMapTy; +class ELFObjectWriter; + class SymbolTableWriter { - MCAssembler &Asm; - FragmentWriter &FWriter; + ELFObjectWriter &EWriter; bool Is64Bit; - SectionIndexMapTy &SectionIndexMap; - // The symbol .symtab fragment we are writting to. - MCDataFragment *SymtabF; - - // .symtab_shndx fragment we are writting to. - MCDataFragment *ShndxF; + // indexes we are going to write to .symtab_shndx. + std::vector ShndxIndexes; // The numbel of symbols written so far. unsigned NumWritten; void createSymtabShndx(); - template void write(MCDataFragment &F, T Value); + template void write(T Value); public: - SymbolTableWriter(MCAssembler &Asm, FragmentWriter &FWriter, bool Is64Bit, - SectionIndexMapTy &SectionIndexMap, - MCDataFragment *SymtabF); + SymbolTableWriter(ELFObjectWriter &EWriter, bool Is64Bit); 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. - const MCSymbol *Symbol; // The symbol 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), Symbol(Symbol), Type(Type), Addend(Addend) {} + ArrayRef getShndxIndexes() const { return ShndxIndexes; } }; 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, + static uint64_t SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout); + static bool isInSymtab(const MCAsmLayout &Layout, const MCSymbol &Symbol, 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. + static bool isLocal(const MCSymbol &Symbol, bool isUsedInReloc); + + /// Helper struct for containing some precomputed information on symbols. struct ELFSymbolData { - MCSymbolData *SymbolData; + const MCSymbol *Symbol; uint64_t StringIndex; uint32_t SectionIndex; StringRef Name; // Support lexicographic sorting. bool operator<(const ELFSymbolData &RHS) const { - unsigned LHSType = MCELF::GetType(*SymbolData); - unsigned RHSType = MCELF::GetType(*RHS.SymbolData); + unsigned LHSType = MCELF::GetType(Symbol->getData()); + unsigned RHSType = MCELF::GetType(RHS.Symbol->getData()); if (LHSType == ELF::STT_SECTION && RHSType != ELF::STT_SECTION) return false; if (LHSType != ELF::STT_SECTION && RHSType == ELF::STT_SECTION) @@ -146,8 +105,8 @@ class ELFObjectWriter : public MCObjectWriter { SmallPtrSet WeakrefUsedInReloc; DenseMap Renames; - llvm::DenseMap> - Relocations; + llvm::DenseMap> + Relocations; StringTableBuilder ShStrTabBuilder; /// @} @@ -173,6 +132,9 @@ class ELFObjectWriter : public MCObjectWriter { unsigned ShstrtabIndex; + // Sections in the order they are to be output in the section table. + std::vector SectionTable; + unsigned addToSectionTable(MCSectionELF *Sec); // TargetObjectWriter wrappers. bool is64Bit() const { return TargetObjectWriter->is64Bit(); } @@ -185,10 +147,10 @@ class ELFObjectWriter : public MCObjectWriter { } public: - ELFObjectWriter(MCELFObjectTargetWriter *MOTW, raw_ostream &OS, + ELFObjectWriter(MCELFObjectTargetWriter *MOTW, raw_pwrite_stream &OS, bool IsLittleEndian) - : MCObjectWriter(OS, IsLittleEndian), FWriter(IsLittleEndian), - TargetObjectWriter(MOTW), NeedsGOT(false) {} + : MCObjectWriter(OS, IsLittleEndian), TargetObjectWriter(MOTW), + NeedsGOT(false) {} void reset() override { UsedInReloc.clear(); @@ -201,10 +163,12 @@ class ELFObjectWriter : public MCObjectWriter { LocalSymbolData.clear(); ExternalSymbolData.clear(); UndefinedSymbolData.clear(); + NeedsGOT = false; + SectionTable.clear(); MCObjectWriter::reset(); } - virtual ~ELFObjectWriter(); + ~ELFObjectWriter() override; void WriteWord(uint64_t W) { if (is64Bit()) @@ -213,24 +177,28 @@ class ELFObjectWriter : public MCObjectWriter { Write32(W); } - template void write(MCDataFragment &F, T Value) { - FWriter.write(F, Value); + template void write(T Val) { + if (IsLittleEndian) + support::endian::Writer(OS).write(Val); + else + support::endian::Writer(OS).write(Val); } - void WriteHeader(const MCAssembler &Asm, - uint64_t SectionHeaderOffset, - unsigned NumberOfSections); + void writeHeader(const MCAssembler &Asm); void WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD, const MCAsmLayout &Layout); - void WriteSymbolTable(MCDataFragment *SymtabF, MCAssembler &Asm, - const MCAsmLayout &Layout, - SectionIndexMapTy &SectionIndexMap); + // Start and end offset of each section + typedef std::map> + SectionOffsetsTy; + + void WriteSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout, + SectionOffsetsTy &SectionOffsets); bool shouldRelocateWithSymbol(const MCAssembler &Asm, const MCSymbolRefExpr *RefA, - const MCSymbolData *SD, uint64_t C, + const MCSymbol *Sym, uint64_t C, unsigned Type) const; void RecordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, @@ -241,122 +209,76 @@ class ELFObjectWriter : public MCObjectWriter { uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, const MCSymbol *S); - // Map from a group section to the signature symbol - typedef DenseMap GroupMapTy; - // Map from a signature symbol to the group section - typedef DenseMap RevGroupMapTy; - // Map from a section to its offset - typedef DenseMap SectionOffsetMapTy; + // Map from a signature symbol to the group section index + typedef DenseMap RevGroupMapTy; /// 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, const RevGroupMapTy &RevGroupMap); - void computeIndexMap(MCAssembler &Asm, SectionIndexMapTy &SectionIndexMap); - - MCSectionData *createRelocationSection(MCAssembler &Asm, - const MCSectionData &SD); + MCSectionELF *createRelocationSection(MCAssembler &Asm, + const MCSectionELF &Sec); - void CompressDebugSections(MCAssembler &Asm, MCAsmLayout &Layout); - - void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout); - - void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout, - SectionIndexMapTy &SectionIndexMap); - - // 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 MCSectionELF *createSectionHeaderStringTable(); + const MCSectionELF *createStringTable(MCContext &Ctx); void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) override; - void writeSectionHeader(MCAssembler &Asm, const GroupMapTy &GroupMap, - const MCAsmLayout &Layout, + void writeSectionHeader(MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, - const SectionOffsetMapTy &SectionOffsetMap); + const SectionOffsetsTy &SectionOffsets); - void ComputeSectionOrder(MCAssembler &Asm, - std::vector &Sections); + void writeSectionData(const MCAssembler &Asm, const MCSectionData &SD, + const MCAsmLayout &Layout); 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); + 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); + void writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec); - bool - IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, - const MCSymbolData &DataA, - const MCSymbolData *DataB, - const MCFragment &FB, - bool InSet, - bool IsPCRel) const override; + bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbol &SymA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const override; - bool isWeak(const MCSymbolData &SD) const override; + bool isWeak(const MCSymbol &Sym) 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, + uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, const MCSectionELF &Section); }; } -FragmentWriter::FragmentWriter(bool IsLittleEndian) - : IsLittleEndian(IsLittleEndian) {} - -template void FragmentWriter::write(MCDataFragment &F, T Val) { - if (IsLittleEndian) - Val = support::endian::byte_swap(Val); - else - Val = support::endian::byte_swap(Val); - const char *Start = (const char *)&Val; - F.getContents().append(Start, Start + sizeof(T)); +unsigned ELFObjectWriter::addToSectionTable(MCSectionELF *Sec) { + SectionTable.push_back(Sec); + ShStrTabBuilder.add(Sec->getSectionName()); + return SectionTable.size(); } void SymbolTableWriter::createSymtabShndx() { - if (ShndxF) + if (!ShndxIndexes.empty()) return; - MCContext &Ctx = Asm.getContext(); - const MCSectionELF *SymtabShndxSection = - Ctx.getELFSection(".symtab_shndxr", ELF::SHT_SYMTAB_SHNDX, 0, 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)); + ShndxIndexes.resize(NumWritten); } -template -void SymbolTableWriter::write(MCDataFragment &F, T Value) { - FWriter.write(F, Value); +template void SymbolTableWriter::write(T Value) { + EWriter.write(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) {} +SymbolTableWriter::SymbolTableWriter(ELFObjectWriter &EWriter, bool Is64Bit) + : EWriter(EWriter), Is64Bit(Is64Bit), NumWritten(0) {} void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value, uint64_t size, uint8_t other, @@ -366,31 +288,29 @@ void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value, if (LargeIndex) createSymtabShndx(); - if (ShndxF) { + if (!ShndxIndexes.empty()) { if (LargeIndex) - write(*ShndxF, shndx); + ShndxIndexes.push_back(shndx); else - write(*ShndxF, uint32_t(0)); + ShndxIndexes.push_back(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 + write(name); // st_name + write(info); // st_info + write(other); // st_other + write(Index); // st_shndx + write(value); // st_value + write(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 + write(name); // st_name + write(uint32_t(value)); // st_value + write(uint32_t(size)); // st_size + write(info); // st_info + write(other); // st_other + write(Index); // st_shndx } ++NumWritten; @@ -428,9 +348,7 @@ ELFObjectWriter::~ELFObjectWriter() {} // Emit the ELF header. -void ELFObjectWriter::WriteHeader(const MCAssembler &Asm, - uint64_t SectionHeaderOffset, - unsigned NumberOfSections) { +void ELFObjectWriter::writeHeader(const MCAssembler &Asm) { // ELF Header // ---------- // @@ -439,10 +357,7 @@ void ELFObjectWriter::WriteHeader(const MCAssembler &Asm, // emitWord method behaves differently for ELF32 and ELF64, writing // 4 bytes in the former and 8 in the latter. - Write8(0x7f); // e_ident[EI_MAG0] - Write8('E'); // e_ident[EI_MAG1] - Write8('L'); // e_ident[EI_MAG2] - Write8('F'); // e_ident[EI_MAG3] + WriteBytes(ELF::ElfMagic); // e_ident[EI_MAG0] to e_ident[EI_MAG3] Write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] @@ -463,7 +378,7 @@ void ELFObjectWriter::WriteHeader(const MCAssembler &Asm, Write32(ELF::EV_CURRENT); // e_version WriteWord(0); // e_entry, no entry point in .o file WriteWord(0); // e_phoff, no program header for .o - WriteWord(SectionHeaderOffset); // e_shoff = sec hdr table off in bytes + WriteWord(0); // e_shoff = sec hdr table off in bytes // e_flags = whatever the target wants Write32(Asm.getELFHeaderEFlags()); @@ -478,28 +393,24 @@ void ELFObjectWriter::WriteHeader(const MCAssembler &Asm, Write16(is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); // e_shnum = # of section header ents - if (NumberOfSections >= ELF::SHN_LORESERVE) - Write16(ELF::SHN_UNDEF); - else - Write16(NumberOfSections); + Write16(0); // e_shstrndx = Section # of '.shstrtab' - if (ShstrtabIndex >= ELF::SHN_LORESERVE) - Write16(ELF::SHN_XINDEX); - else - Write16(ShstrtabIndex); + assert(ShstrtabIndex < ELF::SHN_LORESERVE); + Write16(ShstrtabIndex); } -uint64_t ELFObjectWriter::SymbolValue(MCSymbolData &Data, +uint64_t ELFObjectWriter::SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout) { + MCSymbolData &Data = Sym.getData(); if (Data.isCommon() && Data.isExternal()) return Data.getCommonAlignment(); uint64_t Res; - if (!Layout.getSymbolOffset(&Data, Res)) + if (!Layout.getSymbolOffset(Sym, Res)) return 0; - if (Layout.getAssembler().isThumbFunc(&Data.getSymbol())) + if (Layout.getAssembler().isThumbFunc(&Sym)) Res |= 1; return Res; @@ -510,8 +421,8 @@ void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, // The presence of symbol versions causes undefined symbols and // versions declared with @@@ to be renamed. - for (MCSymbolData &OriginalData : Asm.symbols()) { - const MCSymbol &Alias = OriginalData.getSymbol(); + for (const MCSymbol &Alias : Asm.symbols()) { + MCSymbolData &OriginalData = Alias.getData(); // Not an alias. if (!Alias.isVariable()) @@ -582,12 +493,12 @@ static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { void ELFObjectWriter::WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD, const MCAsmLayout &Layout) { - MCSymbolData &OrigData = *MSD.SymbolData; + MCSymbolData &OrigData = MSD.Symbol->getData(); assert((!OrigData.getFragment() || (&OrigData.getFragment()->getParent()->getSection() == - &OrigData.getSymbol().getSection())) && + &MSD.Symbol->getSection())) && "The symbol's section doesn't match the fragment's symbol"); - const MCSymbol *Base = Layout.getBaseSymbol(OrigData.getSymbol()); + const MCSymbol *Base = Layout.getBaseSymbol(*MSD.Symbol); // This has to be in sync with when computeSymbolTable uses SHN_ABS or // SHN_COMMON. @@ -609,7 +520,7 @@ void ELFObjectWriter::WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD, uint8_t Other = MCELF::getOther(OrigData) << (ELF_STO_Shift - ELF_STV_Shift); Other |= Visibility; - uint64_t Value = SymbolValue(OrigData, Layout); + uint64_t Value = SymbolValue(*MSD.Symbol, Layout); uint64_t Size = 0; const MCExpr *ESize = OrigData.getSize(); @@ -628,16 +539,30 @@ void ELFObjectWriter::WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD, MSD.SectionIndex, IsReserved); } -void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, - MCAssembler &Asm, +void ELFObjectWriter::WriteSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout, - SectionIndexMapTy &SectionIndexMap) { + SectionOffsetsTy &SectionOffsets) { + + MCContext &Ctx = Asm.getContext(); + + unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; + + // Symbol table + MCSectionELF *SymtabSection = + Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, EntrySize, ""); + MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection); + SymtabSD.setAlignment(is64Bit() ? 8 : 4); + SymbolTableIndex = addToSectionTable(SymtabSection); + // The string table must be emitted first because we need the index // into the string table for all the symbol names. - // FIXME: Make sure the start of the symbol table is aligned. + SymbolTableWriter Writer(*this, is64Bit()); - SymbolTableWriter Writer(Asm, FWriter, is64Bit(), SectionIndexMap, SymtabF); + uint64_t Padding = OffsetToAlignment(OS.tell(), SymtabSD.getAlignment()); + WriteZeros(Padding); + + uint64_t SecStart = OS.tell(); // The first entry is the undefined symbol entry. Writer.writeSymbol(0, 0, 0, 0, 0, 0, false); @@ -657,7 +582,7 @@ void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) { ELFSymbolData &MSD = ExternalSymbolData[i]; - MCSymbolData &Data = *MSD.SymbolData; + MCSymbolData &Data = MSD.Symbol->getData(); assert(((Data.getFlags() & ELF_STB_Global) || (Data.getFlags() & ELF_STB_Weak)) && "External symbol requires STB_GLOBAL or STB_WEAK flag"); @@ -668,11 +593,30 @@ void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) { ELFSymbolData &MSD = UndefinedSymbolData[i]; - MCSymbolData &Data = *MSD.SymbolData; + MCSymbolData &Data = MSD.Symbol->getData(); WriteSymbol(Writer, MSD, Layout); if (MCELF::GetBinding(Data) == ELF::STB_LOCAL) LastLocalSymbolIndex++; } + + uint64_t SecEnd = OS.tell(); + SectionOffsets[SymtabSection] = std::make_pair(SecStart, SecEnd); + + ArrayRef ShndxIndexes = Writer.getShndxIndexes(); + if (ShndxIndexes.empty()) + return; + + SecStart = OS.tell(); + MCSectionELF *SymtabShndxSection = + Ctx.getELFSection(".symtab_shndxr", ELF::SHT_SYMTAB_SHNDX, 0, 4, ""); + addToSectionTable(SymtabShndxSection); + MCSectionData *SymtabShndxSD = + &Asm.getOrCreateSectionData(*SymtabShndxSection); + SymtabShndxSD->setAlignment(4); + for (uint32_t Index : ShndxIndexes) + write(Index); + SecEnd = OS.tell(); + SectionOffsets[SymtabShndxSection] = std::make_pair(SecStart, SecEnd); } // It is always valid to create a relocation with a symbol. It is preferable @@ -680,9 +624,10 @@ void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, // allows us to omit some local symbols from the symbol table. bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, const MCSymbolRefExpr *RefA, - const MCSymbolData *SD, - uint64_t C, + const MCSymbol *Sym, uint64_t C, unsigned Type) const { + MCSymbolData *SD = Sym ? &Sym->getData() : nullptr; + // A PCRel relocation to an absolute value has no symbol (or section). We // represent that with a relocation to a null section. if (!RefA) @@ -717,8 +662,8 @@ bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, // An undefined symbol is not in any section, so the relocation has to point // to the symbol itself. - const MCSymbol &Sym = SD->getSymbol(); - if (Sym.isUndefined()) + assert(Sym && "Expected a symbol"); + if (Sym->isUndefined()) return true; unsigned Binding = MCELF::GetBinding(*SD); @@ -745,7 +690,7 @@ bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, // If we change such a relocation to use the section, the linker would think // that it pointed to another string and subtracting 42 at runtime will // produce the wrong value. - auto &Sec = cast(Sym.getSection()); + auto &Sec = cast(Sym->getSection()); unsigned Flags = Sec.getFlags(); if (Flags & ELF::SHF_MERGE) { if (C != 0) @@ -768,7 +713,7 @@ bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, // bit. With a symbol that is done by just having the symbol have that bit // set, so we would lose the bit if we relocated with the section. // FIXME: We could use the section but add the bit to the relocation value. - if (Asm.isThumbFunc(&Sym)) + if (Asm.isThumbFunc(Sym)) return true; if (TargetObjectWriter->needsRelocateWithSymbol(*SD, Type)) @@ -795,8 +740,24 @@ static const MCSymbol *getWeakRef(const MCSymbolRefExpr &Ref) { return nullptr; } +// True if the assembler knows nothing about the final value of the symbol. +// This doesn't cover the comdat issues, since in those cases the assembler +// can at least know that all symbols in the section will move together. static bool isWeak(const MCSymbolData &D) { - return D.getFlags() & ELF_STB_Weak || MCELF::GetType(D) == ELF::STT_GNU_IFUNC; + if (MCELF::GetType(D) == ELF::STT_GNU_IFUNC) + return true; + + switch (MCELF::GetBinding(D)) { + default: + llvm_unreachable("Unknown binding"); + case ELF::STB_LOCAL: + return false; + case ELF::STB_GLOBAL: + return false; + case ELF::STB_WEAK: + case ELF::STB_GNU_UNIQUE: + return true; + } } void ELFObjectWriter::RecordRelocation(MCAssembler &Asm, @@ -804,7 +765,9 @@ void ELFObjectWriter::RecordRelocation(MCAssembler &Asm, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, bool &IsPCRel, uint64_t &FixedValue) { - const MCSectionData *FixupSection = Fragment->getParent(); + const MCSectionData *FixupSectionD = Fragment->getParent(); + const MCSectionELF &FixupSection = + cast(FixupSectionD->getSection()); uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); @@ -820,30 +783,29 @@ void ELFObjectWriter::RecordRelocation(MCAssembler &Asm, // or (A + C - R). If B = R + K and the relocation is not pcrel, we can // replace B to implement it: (A - R - K + C) if (IsPCRel) - Asm.getContext().FatalError( + Asm.getContext().reportFatalError( Fixup.getLoc(), "No relocation available to represent this relative expression"); const MCSymbol &SymB = RefB->getSymbol(); if (SymB.isUndefined()) - Asm.getContext().FatalError( + Asm.getContext().reportFatalError( Fixup.getLoc(), Twine("symbol '") + SymB.getName() + "' can not be undefined in a subtraction expression"); assert(!SymB.isAbsolute() && "Should have been folded"); const MCSection &SecB = SymB.getSection(); - if (&SecB != &FixupSection->getSection()) - Asm.getContext().FatalError( + if (&SecB != &FixupSection) + Asm.getContext().reportFatalError( Fixup.getLoc(), "Cannot represent a difference across sections"); - const MCSymbolData &SymBD = Asm.getSymbolData(SymB); - if (::isWeak(SymBD)) - Asm.getContext().FatalError( + if (::isWeak(SymB.getData())) + Asm.getContext().reportFatalError( Fixup.getLoc(), "Cannot represent a subtraction with a weak symbol"); - uint64_t SymBOffset = Layout.getSymbolOffset(&SymBD); + uint64_t SymBOffset = Layout.getSymbolOffset(SymB); uint64_t K = SymBOffset - FixupOffset; IsPCRel = true; C -= K; @@ -852,12 +814,11 @@ void ELFObjectWriter::RecordRelocation(MCAssembler &Asm, // We either rejected the fixup or folded B into C at this point. const MCSymbolRefExpr *RefA = Target.getSymA(); const MCSymbol *SymA = RefA ? &RefA->getSymbol() : nullptr; - const MCSymbolData *SymAD = SymA ? &Asm.getSymbolData(*SymA) : nullptr; unsigned Type = GetRelocType(Target, Fixup, IsPCRel); - bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymAD, C, Type); + bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) - C += Layout.getSymbolOffset(SymAD); + C += Layout.getSymbolOffset(*SymA); uint64_t Addend = 0; if (hasRelocationAddend()) { @@ -881,7 +842,7 @@ void ELFObjectWriter::RecordRelocation(MCAssembler &Asm, ELFSec ? Asm.getContext().getOrCreateSectionSymbol(*ELFSec) : nullptr; ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend); - Relocations[FixupSection].push_back(Rec); + Relocations[&FixupSection].push_back(Rec); return; } @@ -895,7 +856,7 @@ void ELFObjectWriter::RecordRelocation(MCAssembler &Asm, UsedInReloc.insert(SymA); } ELFRelocationEntry Rec(FixupOffset, SymA, Type, Addend); - Relocations[FixupSection].push_back(Rec); + Relocations[&FixupSection].push_back(Rec); return; } @@ -908,9 +869,9 @@ ELFObjectWriter::getSymbolIndexInSymbolTable(const MCAssembler &Asm, } bool ELFObjectWriter::isInSymtab(const MCAsmLayout &Layout, - const MCSymbolData &Data, bool Used, + const MCSymbol &Symbol, bool Used, bool Renamed) { - const MCSymbol &Symbol = Data.getSymbol(); + const MCSymbolData &Data = Symbol.getData(); if (Symbol.isVariable()) { const MCExpr *Expr = Symbol.getVariableValue(); if (const MCSymbolRefExpr *Ref = dyn_cast(Expr)) { @@ -944,11 +905,11 @@ bool ELFObjectWriter::isInSymtab(const MCAsmLayout &Layout, return true; } -bool ELFObjectWriter::isLocal(const MCSymbolData &Data, bool isUsedInReloc) { +bool ELFObjectWriter::isLocal(const MCSymbol &Symbol, bool isUsedInReloc) { + const MCSymbolData &Data = Symbol.getData(); if (Data.isExternal()) return false; - const MCSymbol &Symbol = Data.getSymbol(); if (Symbol.isDefined()) return true; @@ -958,36 +919,6 @@ bool ELFObjectWriter::isLocal(const MCSymbolData &Data, bool isUsedInReloc) { return true; } -void ELFObjectWriter::computeIndexMap(MCAssembler &Asm, - SectionIndexMapTy &SectionIndexMap) { - unsigned Index = 1; - for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionELF &Section = - static_cast(it->getSection()); - if (Section.getType() != ELF::SHT_GROUP) - continue; - SectionIndexMap[&Section] = Index++; - } - - for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionData &SD = *it; - const MCSectionELF &Section = - static_cast(SD.getSection()); - if (Section.getType() == ELF::SHT_GROUP || - Section.getType() == ELF::SHT_REL || - Section.getType() == ELF::SHT_RELA) - continue; - SectionIndexMap[&Section] = Index++; - if (MCSectionData *RelSD = createRelocationSection(Asm, SD)) { - const MCSectionELF *RelSection = - static_cast(&RelSD->getSection()); - SectionIndexMap[RelSection] = Index++; - } - } -} - void ELFObjectWriter::computeSymbolTable( MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, @@ -996,32 +927,31 @@ void ELFObjectWriter::computeSymbolTable( // FIXME: Why is an undefined reference to _GLOBAL_OFFSET_TABLE_ needed? if (NeedsGOT) { StringRef Name = "_GLOBAL_OFFSET_TABLE_"; - MCSymbol *Sym = Asm.getContext().GetOrCreateSymbol(Name); + MCSymbol *Sym = Asm.getContext().getOrCreateSymbol(Name); MCSymbolData &Data = Asm.getOrCreateSymbolData(*Sym); Data.setExternal(true); MCELF::SetBinding(Data, ELF::STB_GLOBAL); } // Add the data for the symbols. - for (MCSymbolData &SD : Asm.symbols()) { - const MCSymbol &Symbol = SD.getSymbol(); + for (const MCSymbol &Symbol : Asm.symbols()) { + MCSymbolData &SD = Symbol.getData(); bool Used = UsedInReloc.count(&Symbol); bool WeakrefUsed = WeakrefUsedInReloc.count(&Symbol); bool isSignature = RevGroupMap.count(&Symbol); - if (!isInSymtab(Layout, SD, - Used || WeakrefUsed || isSignature, + if (!isInSymtab(Layout, Symbol, Used || WeakrefUsed || isSignature, Renames.count(&Symbol))) continue; ELFSymbolData MSD; - MSD.SymbolData = &SD; + MSD.Symbol = &Symbol; const MCSymbol *BaseSymbol = Layout.getBaseSymbol(Symbol); // Undefined symbols are global, but this is the first place we // are able to set it. - bool Local = isLocal(SD, Used); + bool Local = isLocal(Symbol, Used); if (!Local && MCELF::GetBinding(SD) == ELF::STB_LOCAL) { assert(BaseSymbol); MCSymbolData &BaseData = Asm.getSymbolData(*BaseSymbol); @@ -1036,7 +966,7 @@ void ELFObjectWriter::computeSymbolTable( MSD.SectionIndex = ELF::SHN_COMMON; } else if (BaseSymbol->isUndefined()) { if (isSignature && !Used) - MSD.SectionIndex = SectionIndexMap.lookup(RevGroupMap.lookup(&Symbol)); + MSD.SectionIndex = RevGroupMap.lookup(&Symbol); else MSD.SectionIndex = ELF::SHN_UNDEF; if (!Used && WeakrefUsed) @@ -1108,7 +1038,7 @@ void ELFObjectWriter::computeSymbolTable( FileSymbolData.push_back(StrTabBuilder.getOffset(*i)); for (ELFSymbolData &MSD : LocalSymbolData) - MSD.StringIndex = MCELF::GetType(*MSD.SymbolData) == ELF::STT_SECTION + MSD.StringIndex = MCELF::GetType(MSD.Symbol->getData()) == ELF::STT_SECTION ? 0 : StrTabBuilder.getOffset(MSD.Name); for (ELFSymbolData &MSD : ExternalSymbolData) @@ -1125,25 +1055,22 @@ void ELFObjectWriter::computeSymbolTable( // symbols with non-local bindings. unsigned Index = FileSymbolData.size() + 1; for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) - LocalSymbolData[i].SymbolData->setIndex(Index++); + LocalSymbolData[i].Symbol->getData().setIndex(Index++); for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) - ExternalSymbolData[i].SymbolData->setIndex(Index++); + ExternalSymbolData[i].Symbol->getData().setIndex(Index++); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) - UndefinedSymbolData[i].SymbolData->setIndex(Index++); + UndefinedSymbolData[i].Symbol->getData().setIndex(Index++); } -MCSectionData * +MCSectionELF * ELFObjectWriter::createRelocationSection(MCAssembler &Asm, - const MCSectionData &SD) { - if (Relocations[&SD].empty()) + const MCSectionELF &Sec) { + if (Relocations[&Sec].empty()) return nullptr; MCContext &Ctx = Asm.getContext(); - const MCSectionELF &Section = - static_cast(SD.getSection()); - - const StringRef SectionName = Section.getSectionName(); + const StringRef SectionName = Sec.getSectionName(); std::string RelaSectionName = hasRelocationAddend() ? ".rela" : ".rel"; RelaSectionName += SectionName; @@ -1154,18 +1081,20 @@ ELFObjectWriter::createRelocationSection(MCAssembler &Asm, EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); unsigned Flags = 0; - if (Section.getFlags() & ELF::SHF_GROUP) + if (Sec.getFlags() & ELF::SHF_GROUP) Flags = ELF::SHF_GROUP; - const MCSectionELF *RelaSection = Ctx.createELFRelSection( + MCSectionELF *RelaSection = Ctx.createELFRelSection( RelaSectionName, hasRelocationAddend() ? ELF::SHT_RELA : ELF::SHT_REL, - Flags, EntrySize, Section.getGroup(), &Section); - return &Asm.getOrCreateSectionData(*RelaSection); + Flags, EntrySize, Sec.getGroup(), &Sec); + MCSectionData &RelSD = Asm.getOrCreateSectionData(*RelaSection); + RelSD.setAlignment(is64Bit() ? 8 : 4); + return RelaSection; } static SmallVector -getUncompressedData(MCAsmLayout &Layout, - MCSectionData::FragmentListType &Fragments) { +getUncompressedData(const MCAsmLayout &Layout, + const MCSectionData::FragmentListType &Fragments) { SmallVector UncompressedData; for (const MCFragment &F : Fragments) { const SmallVectorImpl *Contents; @@ -1208,123 +1137,42 @@ prependCompressionHeader(uint64_t Size, return true; } -// Return a single fragment containing the compressed contents of the whole -// section. Null if the section was not compressed for any reason. -static std::unique_ptr -getCompressedFragment(MCAsmLayout &Layout, - MCSectionData::FragmentListType &Fragments) { - std::unique_ptr CompressedFragment(new MCDataFragment()); +void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, + const MCSectionData &SD, + const MCAsmLayout &Layout) { + MCSectionELF &Section = static_cast(SD.getSection()); + StringRef SectionName = Section.getSectionName(); - // Gather the uncompressed data from all the fragments, recording the - // alignment fragment, if seen, and any fixups. + // Compressing debug_frame requires handling alignment fragments which is + // more work (possibly generalizing MCAssembler.cpp:writeFragment to allow + // for writing to arbitrary buffers) for little benefit. + if (!Asm.getContext().getAsmInfo()->compressDebugSections() || + !SectionName.startswith(".debug_") || SectionName == ".debug_frame") { + Asm.writeSectionData(&SD, Layout); + return; + } + + // Gather the uncompressed data from all the fragments. + const MCSectionData::FragmentListType &Fragments = SD.getFragmentList(); SmallVector UncompressedData = getUncompressedData(Layout, Fragments); - SmallVectorImpl &CompressedContents = CompressedFragment->getContents(); - + SmallVector CompressedContents; zlib::Status Success = zlib::compress( StringRef(UncompressedData.data(), UncompressedData.size()), CompressedContents); - if (Success != zlib::StatusOK) - return nullptr; - - if (!prependCompressionHeader(UncompressedData.size(), CompressedContents)) - return nullptr; - - return CompressedFragment; -} - -typedef DenseMap> -DefiningSymbolMap; - -static void UpdateSymbols(const MCAsmLayout &Layout, - const std::vector &Symbols, - MCFragment &NewFragment) { - for (MCSymbolData *Sym : Symbols) { - Sym->setOffset(Sym->getOffset() + - Layout.getFragmentOffset(Sym->getFragment())); - Sym->setFragment(&NewFragment); + if (Success != zlib::StatusOK) { + Asm.writeSectionData(&SD, Layout); + return; } -} - -static void CompressDebugSection(MCAssembler &Asm, MCAsmLayout &Layout, - const DefiningSymbolMap &DefiningSymbols, - const MCSectionELF &Section, - MCSectionData &SD) { - StringRef SectionName = Section.getSectionName(); - MCSectionData::FragmentListType &Fragments = SD.getFragmentList(); - - std::unique_ptr CompressedFragment = - getCompressedFragment(Layout, Fragments); - // Leave the section as-is if the fragments could not be compressed. - if (!CompressedFragment) + if (!prependCompressionHeader(UncompressedData.size(), CompressedContents)) { + Asm.writeSectionData(&SD, Layout); return; - - // Update the fragment+offsets of any symbols referring to fragments in this - // section to refer to the new fragment. - auto I = DefiningSymbols.find(&SD); - if (I != DefiningSymbols.end()) - UpdateSymbols(Layout, I->second, *CompressedFragment); - - // Invalidate the layout for the whole section since it will have new and - // different fragments now. - Layout.invalidateFragmentsFrom(&Fragments.front()); - Fragments.clear(); - - // Complete the initialization of the new fragment - CompressedFragment->setParent(&SD); - CompressedFragment->setLayoutOrder(0); - Fragments.push_back(CompressedFragment.release()); - - // Rename from .debug_* to .zdebug_* + } Asm.getContext().renameELFSection(&Section, (".z" + SectionName.drop_front(1)).str()); -} - -void ELFObjectWriter::CompressDebugSections(MCAssembler &Asm, - MCAsmLayout &Layout) { - if (!Asm.getContext().getAsmInfo()->compressDebugSections()) - return; - - DefiningSymbolMap DefiningSymbols; - - for (MCSymbolData &SD : Asm.symbols()) - if (MCFragment *F = SD.getFragment()) - DefiningSymbols[F->getParent()].push_back(&SD); - - for (MCSectionData &SD : Asm) { - const MCSectionELF &Section = - static_cast(SD.getSection()); - StringRef SectionName = Section.getSectionName(); - - // Compressing debug_frame requires handling alignment fragments which is - // more work (possibly generalizing MCAssembler.cpp:writeFragment to allow - // for writing to arbitrary buffers) for little benefit. - if (!SectionName.startswith(".debug_") || SectionName == ".debug_frame") - continue; - - CompressDebugSection(Asm, Layout, DefiningSymbols, Section, SD); - } -} - -void ELFObjectWriter::WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) { - for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { - MCSectionData &RelSD = *it; - const MCSectionELF &RelSection = - static_cast(RelSD.getSection()); - - unsigned Type = RelSection.getType(); - if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA) - continue; - - const MCSectionELF *Section = RelSection.getAssociatedSection(); - MCSectionData &SD = Asm.getOrCreateSectionData(*Section); - RelSD.setAlignment(is64Bit() ? 8 : 4); - - MCDataFragment *F = new MCDataFragment(&RelSD); - WriteRelocationsFragment(Asm, F, &SD); - } + OS << CompressedContents; } void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, @@ -1345,31 +1193,13 @@ void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, WriteWord(EntrySize); // sh_entsize } -// ELF doesn't require relocations to be in any order. We sort by the r_offset, -// just to match gnu as for easier comparison. The use type is an arbitrary way -// of making the sort deterministic. -static int cmpRel(const ELFRelocationEntry *AP, const ELFRelocationEntry *BP) { - const ELFRelocationEntry &A = *AP; - const ELFRelocationEntry &B = *BP; - if (A.Offset != B.Offset) - return B.Offset - A.Offset; - if (B.Type != A.Type) - return A.Type - B.Type; - //llvm_unreachable("ELFRelocs might be unstable!"); - return 0; -} - -static void sortRelocs(const MCAssembler &Asm, - std::vector &Relocs) { - array_pod_sort(Relocs.begin(), Relocs.end(), cmpRel); -} +void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, + const MCSectionELF &Sec) { + std::vector &Relocs = Relocations[&Sec]; -void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm, - MCDataFragment *F, - const MCSectionData *SD) { - std::vector &Relocs = Relocations[SD]; - - sortRelocs(Asm, Relocs); + // Sort the relocation entries. Most targets just sort by Offset, but some + // (e.g., MIPS) have additional constraints. + TargetObjectWriter->sortRelocs(Asm, Relocs); for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { const ELFRelocationEntry &Entry = Relocs[e - i - 1]; @@ -1377,134 +1207,53 @@ void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm, Entry.Symbol ? getSymbolIndexInSymbolTable(Asm, Entry.Symbol) : 0; if (is64Bit()) { - write(*F, Entry.Offset); + write(Entry.Offset); if (TargetObjectWriter->isN64()) { - write(*F, uint32_t(Index)); + write(uint32_t(Index)); - write(*F, TargetObjectWriter->getRSsym(Entry.Type)); - write(*F, TargetObjectWriter->getRType3(Entry.Type)); - write(*F, TargetObjectWriter->getRType2(Entry.Type)); - write(*F, TargetObjectWriter->getRType(Entry.Type)); + write(TargetObjectWriter->getRSsym(Entry.Type)); + write(TargetObjectWriter->getRType3(Entry.Type)); + write(TargetObjectWriter->getRType2(Entry.Type)); + write(TargetObjectWriter->getRType(Entry.Type)); } else { struct ELF::Elf64_Rela ERE64; ERE64.setSymbolAndType(Index, Entry.Type); - write(*F, ERE64.r_info); + write(ERE64.r_info); } if (hasRelocationAddend()) - write(*F, Entry.Addend); + write(Entry.Addend); } else { - write(*F, uint32_t(Entry.Offset)); + write(uint32_t(Entry.Offset)); struct ELF::Elf32_Rela ERE32; ERE32.setSymbolAndType(Index, Entry.Type); - write(*F, ERE32.r_info); + write(ERE32.r_info); if (hasRelocationAddend()) - write(*F, uint32_t(Entry.Addend)); + write(uint32_t(Entry.Addend)); } } } -void ELFObjectWriter::CreateMetadataSections( - MCAssembler &Asm, MCAsmLayout &Layout, SectionIndexMapTy &SectionIndexMap) { - MCContext &Ctx = Asm.getContext(); - MCDataFragment *F; - - unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; - - // We construct .shstrtab, .symtab and .strtab in this order to match gnu as. - const MCSectionELF *ShstrtabSection = - Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0); - MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); - ShstrtabSD.setAlignment(1); - ShstrtabIndex = SectionIndexMap.size() + 1; - SectionIndexMap[ShstrtabSection] = ShstrtabIndex; - - const MCSectionELF *SymtabSection = - Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, - EntrySize, ""); - MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection); - SymtabSD.setAlignment(is64Bit() ? 8 : 4); - SymbolTableIndex = SectionIndexMap.size() + 1; - SectionIndexMap[SymtabSection] = SymbolTableIndex; - - const MCSectionELF *StrtabSection; - StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0); - MCSectionData &StrtabSD = Asm.getOrCreateSectionData(*StrtabSection); - StrtabSD.setAlignment(1); - StringTableIndex = SectionIndexMap.size() + 1; - SectionIndexMap[StrtabSection] = StringTableIndex; - - // Symbol table - F = new MCDataFragment(&SymtabSD); - WriteSymbolTable(F, Asm, Layout, SectionIndexMap); - - F = new MCDataFragment(&StrtabSD); - F->getContents().append(StrTabBuilder.data().begin(), - StrTabBuilder.data().end()); - - F = new MCDataFragment(&ShstrtabSD); - - // Section header string table. - for (auto it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { - const MCSectionELF &Section = - static_cast(it->getSection()); - ShStrTabBuilder.add(Section.getSectionName()); - } +const MCSectionELF *ELFObjectWriter::createSectionHeaderStringTable() { + const MCSectionELF *ShstrtabSection = SectionTable[ShstrtabIndex - 1]; ShStrTabBuilder.finalize(StringTableBuilder::ELF); - F->getContents().append(ShStrTabBuilder.data().begin(), - ShStrTabBuilder.data().end()); + OS << ShStrTabBuilder.data(); + return ShstrtabSection; } -void ELFObjectWriter::createIndexedSections( - MCAssembler &Asm, MCAsmLayout &Layout, GroupMapTy &GroupMap, - RevGroupMapTy &RevGroupMap, SectionIndexMapTy &SectionIndexMap) { - MCContext &Ctx = Asm.getContext(); - - // Build the groups - for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); - it != ie; ++it) { - const MCSectionELF &Section = - static_cast(it->getSection()); - if (!(Section.getFlags() & ELF::SHF_GROUP)) - continue; - - const MCSymbol *SignatureSymbol = Section.getGroup(); - Asm.getOrCreateSymbolData(*SignatureSymbol); - const MCSectionELF *&Group = RevGroupMap[SignatureSymbol]; - if (!Group) { - Group = Ctx.CreateELFGroupSection(); - MCSectionData &Data = Asm.getOrCreateSectionData(*Group); - Data.setAlignment(4); - MCDataFragment *F = new MCDataFragment(&Data); - write(*F, uint32_t(ELF::GRP_COMDAT)); - } - GroupMap[Group] = SignatureSymbol; - } - - computeIndexMap(Asm, SectionIndexMap); - - // Add sections to the groups - for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); - it != ie; ++it) { - const MCSectionELF &Section = - static_cast(it->getSection()); - if (!(Section.getFlags() & ELF::SHF_GROUP)) - continue; - const MCSectionELF *Group = RevGroupMap[Section.getGroup()]; - MCSectionData &Data = Asm.getOrCreateSectionData(*Group); - // FIXME: we could use the previous fragment - MCDataFragment *F = new MCDataFragment(&Data); - uint32_t Index = SectionIndexMap.lookup(&Section); - write(*F, Index); - } +const MCSectionELF *ELFObjectWriter::createStringTable(MCContext &Ctx) { + MCSectionELF *StrtabSection = + Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0); + StringTableIndex = addToSectionTable(StrtabSection); + OS << StrTabBuilder.data(); + return StrtabSection; } void ELFObjectWriter::writeSection(MCAssembler &Asm, const SectionIndexMapTy &SectionIndexMap, uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, - uint64_t Alignment, const MCSectionELF &Section) { uint64_t sh_link = 0; uint64_t sh_info = 0; @@ -1515,8 +1264,7 @@ void ELFObjectWriter::writeSection(MCAssembler &Asm, break; case ELF::SHT_DYNAMIC: - sh_link = ShStrTabBuilder.getOffset(Section.getSectionName()); - break; + llvm_unreachable("SHT_DYNAMIC in a relocatable object"); case ELF::SHT_REL: case ELF::SHT_RELA: { @@ -1548,230 +1296,207 @@ void ELFObjectWriter::writeSection(MCAssembler &Asm, sh_link = SectionIndexMap.lookup(Section.getAssociatedSection()); WriteSecHdrEntry(ShStrTabBuilder.getOffset(Section.getSectionName()), - Section.getType(), - Section.getFlags(), 0, Offset, Size, sh_link, sh_info, - Alignment, Section.getEntrySize()); -} - -bool ELFObjectWriter::IsELFMetaDataSection(const MCSectionData &SD) { - return SD.getOrdinal() == ~UINT32_C(0) && - !SD.getSection().isVirtualSection(); -} - -uint64_t ELFObjectWriter::DataSectionSize(const MCSectionData &SD) { - uint64_t Ret = 0; - for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; - ++i) { - const MCFragment &F = *i; - assert(F.getKind() == MCFragment::FT_Data); - Ret += cast(F).getContents().size(); - } - return Ret; -} - -uint64_t ELFObjectWriter::GetSectionFileSize(const MCAsmLayout &Layout, - const MCSectionData &SD) { - if (IsELFMetaDataSection(SD)) - return DataSectionSize(SD); - return Layout.getSectionFileSize(&SD); -} - -uint64_t ELFObjectWriter::GetSectionAddressSize(const MCAsmLayout &Layout, - const MCSectionData &SD) { - if (IsELFMetaDataSection(SD)) - return DataSectionSize(SD); - return Layout.getSectionAddressSize(&SD); -} - -void ELFObjectWriter::WriteDataSectionData(MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCSectionELF &Section) { - const MCSectionData &SD = Asm.getOrCreateSectionData(Section); - - uint64_t Padding = OffsetToAlignment(OS.tell(), SD.getAlignment()); - WriteZeros(Padding); - - if (IsELFMetaDataSection(SD)) { - for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; - ++i) { - const MCFragment &F = *i; - assert(F.getKind() == MCFragment::FT_Data); - WriteBytes(cast(F).getContents()); - } - } else { - Asm.writeSectionData(&SD, Layout); - } + Section.getType(), Section.getFlags(), 0, Offset, Size, + sh_link, sh_info, Section.getAlignment(), + Section.getEntrySize()); } void ELFObjectWriter::writeSectionHeader( - MCAssembler &Asm, const GroupMapTy &GroupMap, const MCAsmLayout &Layout, + MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, - const SectionOffsetMapTy &SectionOffsetMap) { - const unsigned NumSections = Asm.size() + 1; - - std::vector Sections; - Sections.resize(NumSections - 1); - - for (SectionIndexMapTy::const_iterator i= - SectionIndexMap.begin(), e = SectionIndexMap.end(); i != e; ++i) { - const std::pair &p = *i; - Sections[p.second - 1] = p.first; - } + const SectionOffsetsTy &SectionOffsets) { + const unsigned NumSections = SectionTable.size(); // Null section first. uint64_t FirstSectionSize = - NumSections >= ELF::SHN_LORESERVE ? NumSections : 0; - uint32_t FirstSectionLink = - ShstrtabIndex >= ELF::SHN_LORESERVE ? ShstrtabIndex : 0; - WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, FirstSectionLink, 0, 0, 0); - - for (unsigned i = 0; i < NumSections - 1; ++i) { - const MCSectionELF &Section = *Sections[i]; - const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + (NumSections + 1) >= ELF::SHN_LORESERVE ? NumSections + 1 : 0; + WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, 0, 0, 0, 0); + + for (MCSectionELF *Section : SectionTable) { + const MCSectionData &SD = Asm.getOrCreateSectionData(*Section); uint32_t GroupSymbolIndex; - if (Section.getType() != ELF::SHT_GROUP) + unsigned Type = Section->getType(); + if (Type != ELF::SHT_GROUP) GroupSymbolIndex = 0; else - GroupSymbolIndex = getSymbolIndexInSymbolTable(Asm, - GroupMap.lookup(&Section)); + GroupSymbolIndex = getSymbolIndexInSymbolTable(Asm, Section->getGroup()); - uint64_t Size = GetSectionAddressSize(Layout, SD); + const std::pair &Offsets = + SectionOffsets.find(Section)->second; + uint64_t Size = Type == ELF::SHT_NOBITS ? Layout.getSectionAddressSize(&SD) + : Offsets.second - Offsets.first; - writeSection(Asm, SectionIndexMap, GroupSymbolIndex, - SectionOffsetMap.lookup(&Section), Size, SD.getAlignment(), - Section); - } -} - -void ELFObjectWriter::ComputeSectionOrder(MCAssembler &Asm, - std::vector &Sections) { - for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionELF &Section = - static_cast(it->getSection()); - if (Section.getType() == ELF::SHT_GROUP) - Sections.push_back(&Section); - } - - for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionELF &Section = - static_cast(it->getSection()); - if (Section.getType() != ELF::SHT_GROUP && - Section.getType() != ELF::SHT_REL && - Section.getType() != ELF::SHT_RELA) - Sections.push_back(&Section); - } - - for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionELF &Section = - static_cast(it->getSection()); - if (Section.getType() == ELF::SHT_REL || - Section.getType() == ELF::SHT_RELA) - Sections.push_back(&Section); + writeSection(Asm, SectionIndexMap, GroupSymbolIndex, Offsets.first, Size, + *Section); } } void ELFObjectWriter::WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { - GroupMapTy GroupMap; + MCContext &Ctx = Asm.getContext(); + MCSectionELF *ShstrtabSection = + Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0); + ShstrtabIndex = addToSectionTable(ShstrtabSection); + RevGroupMapTy RevGroupMap; SectionIndexMapTy SectionIndexMap; - CompressDebugSections(Asm, const_cast(Layout)); - createIndexedSections(Asm, const_cast(Layout), GroupMap, - RevGroupMap, SectionIndexMap); - - unsigned NumRegularSections = Asm.size(); - - // Compute symbol table information. - computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap); + std::map> GroupMembers; - WriteRelocations(Asm, const_cast(Layout)); - - CreateMetadataSections(const_cast(Asm), - const_cast(Layout), - SectionIndexMap); - - uint64_t NaturalAlignment = is64Bit() ? 8 : 4; - uint64_t HeaderSize = is64Bit() ? sizeof(ELF::Elf64_Ehdr) : - sizeof(ELF::Elf32_Ehdr); - uint64_t FileOff = HeaderSize; + // Write out the ELF header ... + writeHeader(Asm); - std::vector Sections; - ComputeSectionOrder(Asm, Sections); - unsigned NumSections = Sections.size(); - SectionOffsetMapTy SectionOffsetMap; - for (unsigned i = 0; i < NumRegularSections + 1; ++i) { - const MCSectionELF &Section = *Sections[i]; - const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + // ... then the sections ... + SectionOffsetsTy SectionOffsets; + bool ComputedSymtab = false; + for (const MCSectionData &SD : Asm) { + MCSectionELF &Section = static_cast(SD.getSection()); - FileOff = RoundUpToAlignment(FileOff, SD.getAlignment()); + uint64_t Padding = OffsetToAlignment(OS.tell(), SD.getAlignment()); + WriteZeros(Padding); // Remember the offset into the file for this section. - SectionOffsetMap[&Section] = FileOff; - - // Get the size of the section in the output file (including padding). - FileOff += GetSectionFileSize(Layout, SD); - } + uint64_t SecStart = OS.tell(); - FileOff = RoundUpToAlignment(FileOff, NaturalAlignment); + const MCSymbol *SignatureSymbol = Section.getGroup(); + unsigned Type = Section.getType(); + if (Type == ELF::SHT_GROUP) { + assert(SignatureSymbol); + write(uint32_t(ELF::GRP_COMDAT)); + for (const MCSectionELF *Member : GroupMembers[SignatureSymbol]) { + uint32_t SecIndex = SectionIndexMap.lookup(Member); + write(SecIndex); + } + } else if (Type == ELF::SHT_REL || Type == ELF::SHT_RELA) { + if (!ComputedSymtab) { + // Compute symbol table information. + computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap); + ComputedSymtab = true; + } + writeRelocations(Asm, *Section.getAssociatedSection()); + } else { + writeSectionData(Asm, SD, Layout); + } - const unsigned SectionHeaderOffset = FileOff; + uint64_t SecEnd = OS.tell(); + SectionOffsets[&Section] = std::make_pair(SecStart, SecEnd); - uint64_t SectionHeaderEntrySize = is64Bit() ? - sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr); - FileOff += (NumSections + 1) * SectionHeaderEntrySize; + if (Type == ELF::SHT_GROUP || Type == ELF::SHT_REL || Type == ELF::SHT_RELA) + continue; - for (unsigned i = NumRegularSections + 1; i < NumSections; ++i) { - const MCSectionELF &Section = *Sections[i]; - const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + MCSectionELF *RelSection = createRelocationSection(Asm, Section); - FileOff = RoundUpToAlignment(FileOff, SD.getAlignment()); + if (SignatureSymbol) { + Asm.getOrCreateSymbolData(*SignatureSymbol); + unsigned &GroupIdx = RevGroupMap[SignatureSymbol]; + if (!GroupIdx) { + MCSectionELF *Group = Ctx.createELFGroupSection(SignatureSymbol); + GroupIdx = addToSectionTable(Group); + MCSectionData *GroupD = &Asm.getOrCreateSectionData(*Group); + GroupD->setAlignment(4); + } + GroupMembers[SignatureSymbol].push_back(&Section); + if (RelSection) + GroupMembers[SignatureSymbol].push_back(RelSection); + } - // Remember the offset into the file for this section. - SectionOffsetMap[&Section] = FileOff; + SectionIndexMap[&Section] = addToSectionTable(&Section); + if (RelSection) + SectionIndexMap[RelSection] = addToSectionTable(RelSection); + } - // Get the size of the section in the output file (including padding). - FileOff += GetSectionFileSize(Layout, SD); + if (!ComputedSymtab) { + // Compute symbol table information. + computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap); + ComputedSymtab = true; } - // Write out the ELF header ... - WriteHeader(Asm, SectionHeaderOffset, NumSections + 1); + WriteSymbolTable(Asm, Layout, SectionOffsets); + + { + uint64_t SecStart = OS.tell(); + const MCSectionELF *Sec = createStringTable(Ctx); + uint64_t SecEnd = OS.tell(); + SectionOffsets[Sec] = std::make_pair(SecStart, SecEnd); + } - // ... then the regular sections ... - // + because of .shstrtab - for (unsigned i = 0; i < NumRegularSections + 1; ++i) - WriteDataSectionData(Asm, Layout, *Sections[i]); + { + uint64_t SecStart = OS.tell(); + const MCSectionELF *Sec = createSectionHeaderStringTable(); + uint64_t SecEnd = OS.tell(); + SectionOffsets[Sec] = std::make_pair(SecStart, SecEnd); + } + uint64_t NaturalAlignment = is64Bit() ? 8 : 4; uint64_t Padding = OffsetToAlignment(OS.tell(), NaturalAlignment); WriteZeros(Padding); - // ... then the section header table ... - writeSectionHeader(Asm, GroupMap, Layout, SectionIndexMap, SectionOffsetMap); + const unsigned SectionHeaderOffset = OS.tell(); - // ... and then the remaining sections ... - for (unsigned i = NumRegularSections + 1; i < NumSections; ++i) - WriteDataSectionData(Asm, Layout, *Sections[i]); + // ... then the section header table ... + writeSectionHeader(Asm, Layout, SectionIndexMap, SectionOffsets); + + uint16_t NumSections = (SectionTable.size() + 1 >= ELF::SHN_LORESERVE) + ? (uint16_t)ELF::SHN_UNDEF + : SectionTable.size() + 1; + if (sys::IsLittleEndianHost != IsLittleEndian) + sys::swapByteOrder(NumSections); + unsigned NumSectionsOffset; + + if (is64Bit()) { + uint64_t Val = SectionHeaderOffset; + if (sys::IsLittleEndianHost != IsLittleEndian) + sys::swapByteOrder(Val); + OS.pwrite(reinterpret_cast(&Val), sizeof(Val), + offsetof(ELF::Elf64_Ehdr, e_shoff)); + NumSectionsOffset = offsetof(ELF::Elf64_Ehdr, e_shnum); + } else { + uint32_t Val = SectionHeaderOffset; + if (sys::IsLittleEndianHost != IsLittleEndian) + sys::swapByteOrder(Val); + OS.pwrite(reinterpret_cast(&Val), sizeof(Val), + offsetof(ELF::Elf32_Ehdr, e_shoff)); + NumSectionsOffset = offsetof(ELF::Elf32_Ehdr, e_shnum); + } + OS.pwrite(reinterpret_cast(&NumSections), sizeof(NumSections), + NumSectionsOffset); } bool ELFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl( - const MCAssembler &Asm, const MCSymbolData &DataA, - const MCSymbolData *DataB, const MCFragment &FB, bool InSet, - bool IsPCRel) const { - if (!InSet && (::isWeak(DataA) || (DataB && ::isWeak(*DataB)))) - return false; - return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl( - Asm, DataA, DataB, FB, InSet, IsPCRel); + const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB, + bool InSet, bool IsPCRel) const { + if (IsPCRel) { + assert(!InSet); + if (::isWeak(SymA.getData())) + return false; + } + return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB, + InSet, IsPCRel); } -bool ELFObjectWriter::isWeak(const MCSymbolData &SD) const { - return ::isWeak(SD); +bool ELFObjectWriter::isWeak(const MCSymbol &Sym) const { + const MCSymbolData &SD = Sym.getData(); + if (::isWeak(SD)) + return true; + + // It is invalid to replace a reference to a global in a comdat + // with a reference to a local since out of comdat references + // to a local are forbidden. + // We could try to return false for more cases, like the reference + // being in the same comdat or Sym being an alias to another global, + // but it is not clear if it is worth the effort. + if (MCELF::GetBinding(SD) != ELF::STB_GLOBAL) + return false; + + if (!Sym.isInSection()) + return false; + + const auto &Sec = cast(Sym.getSection()); + return Sec.getGroup(); } MCObjectWriter *llvm::createELFObjectWriter(MCELFObjectTargetWriter *MOTW, - raw_ostream &OS, + raw_pwrite_stream &OS, bool IsLittleEndian) { return new ELFObjectWriter(MOTW, OS, IsLittleEndian); }