diff options
Diffstat (limited to 'contrib/llvm/lib/MC/ELFObjectWriter.cpp')
-rw-r--r-- | contrib/llvm/lib/MC/ELFObjectWriter.cpp | 1014 |
1 files changed, 588 insertions, 426 deletions
diff --git a/contrib/llvm/lib/MC/ELFObjectWriter.cpp b/contrib/llvm/lib/MC/ELFObjectWriter.cpp index 989d4bb4eb9c..db531f75c87c 100644 --- a/contrib/llvm/lib/MC/ELFObjectWriter.cpp +++ b/contrib/llvm/lib/MC/ELFObjectWriter.cpp @@ -43,6 +43,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/StringSaver.h" @@ -68,9 +69,14 @@ namespace { using SectionIndexMapTy = DenseMap<const MCSectionELF *, uint32_t>; class ELFObjectWriter; +struct ELFWriter; + +bool isDwoSection(const MCSectionELF &Sec) { + return Sec.getSectionName().endswith(".dwo"); +} class SymbolTableWriter { - ELFObjectWriter &EWriter; + ELFWriter &EWriter; bool Is64Bit; // indexes we are going to write to .symtab_shndx. @@ -84,7 +90,7 @@ class SymbolTableWriter { template <typename T> void write(T Value); public: - SymbolTableWriter(ELFObjectWriter &EWriter, bool Is64Bit); + SymbolTableWriter(ELFWriter &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); @@ -92,7 +98,16 @@ public: ArrayRef<uint32_t> getShndxIndexes() const { return ShndxIndexes; } }; -class ELFObjectWriter : public MCObjectWriter { +struct ELFWriter { + ELFObjectWriter &OWriter; + support::endian::Writer W; + + enum DwoMode { + AllSections, + NonDwoOnly, + DwoOnly, + } Mode; + static uint64_t SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout); static bool isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, bool Used, bool Renamed); @@ -117,13 +132,6 @@ class ELFObjectWriter : public MCObjectWriter { } }; - /// The target specific ELF writer instance. - std::unique_ptr<MCELFObjectTargetWriter> TargetObjectWriter; - - DenseMap<const MCSymbolELF *, const MCSymbolELF *> Renames; - - DenseMap<const MCSectionELF *, std::vector<ELFRelocationEntry>> Relocations; - /// @} /// @name Symbol Table Data /// @{ @@ -144,14 +152,8 @@ class ELFObjectWriter : public MCObjectWriter { unsigned addToSectionTable(const MCSectionELF *Sec); // TargetObjectWriter wrappers. - bool is64Bit() const { return TargetObjectWriter->is64Bit(); } - bool hasRelocationAddend() const { - return TargetObjectWriter->hasRelocationAddend(); - } - unsigned getRelocType(MCContext &Ctx, const MCValue &Target, - const MCFixup &Fixup, bool IsPCRel) const { - return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); - } + bool is64Bit() const; + bool hasRelocationAddend() const; void align(unsigned Alignment); @@ -160,33 +162,20 @@ class ELFObjectWriter : public MCObjectWriter { bool ZLibStyle, unsigned Alignment); public: - ELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, - raw_pwrite_stream &OS, bool IsLittleEndian) - : MCObjectWriter(OS, IsLittleEndian), - TargetObjectWriter(std::move(MOTW)) {} - - ~ELFObjectWriter() override = default; + ELFWriter(ELFObjectWriter &OWriter, raw_pwrite_stream &OS, + bool IsLittleEndian, DwoMode Mode) + : OWriter(OWriter), + W(OS, IsLittleEndian ? support::little : support::big), Mode(Mode) {} - void reset() override { - Renames.clear(); - Relocations.clear(); - StrTabBuilder.clear(); - SectionTable.clear(); - MCObjectWriter::reset(); - } - - void WriteWord(uint64_t W) { + void WriteWord(uint64_t Word) { if (is64Bit()) - write64(W); + W.write<uint64_t>(Word); else - write32(W); + W.write<uint32_t>(Word); } template <typename T> void write(T Val) { - if (IsLittleEndian) - support::endian::Writer<support::little>(getStream()).write(Val); - else - support::endian::Writer<support::big>(getStream()).write(Val); + W.write(Val); } void writeHeader(const MCAssembler &Asm); @@ -198,15 +187,6 @@ public: using SectionOffsetsTy = std::map<const MCSectionELF *, std::pair<uint64_t, uint64_t>>; - bool shouldRelocateWithSymbol(const MCAssembler &Asm, - const MCSymbolRefExpr *RefA, - const MCSymbol *Sym, uint64_t C, - unsigned Type) const; - - void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCFixup &Fixup, - MCValue Target, uint64_t &FixedValue) override; - // Map from a signature symbol to the group section index using RevGroupMapTy = DenseMap<const MCSymbol *, unsigned>; @@ -220,14 +200,13 @@ public: const RevGroupMapTy &RevGroupMap, SectionOffsetsTy &SectionOffsets); + void writeAddrsigSection(); + MCSectionELF *createRelocationSection(MCContext &Ctx, const MCSectionELF &Sec); const MCSectionELF *createStringTable(MCContext &Ctx); - void executePostLayoutBinding(MCAssembler &Asm, - const MCAsmLayout &Layout) override; - void writeSectionHeader(const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const SectionOffsetsTy &SectionOffsets); @@ -242,26 +221,126 @@ public: void writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec); - using MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl; + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout); + void writeSection(const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, + const MCSectionELF &Section); +}; + +class ELFObjectWriter : public MCObjectWriter { + /// The target specific ELF writer instance. + std::unique_ptr<MCELFObjectTargetWriter> TargetObjectWriter; + + DenseMap<const MCSectionELF *, std::vector<ELFRelocationEntry>> Relocations; + + DenseMap<const MCSymbolELF *, const MCSymbolELF *> Renames; + + bool EmitAddrsigSection = false; + std::vector<const MCSymbol *> AddrsigSyms; + + bool hasRelocationAddend() const; + + bool shouldRelocateWithSymbol(const MCAssembler &Asm, + const MCSymbolRefExpr *RefA, + const MCSymbolELF *Sym, uint64_t C, + unsigned Type) const; + +public: + ELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW) + : TargetObjectWriter(std::move(MOTW)) {} + + void reset() override { + Relocations.clear(); + Renames.clear(); + MCObjectWriter::reset(); + } + bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB, bool InSet, bool IsPCRel) const override; - void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; - void writeSection(const SectionIndexMapTy &SectionIndexMap, - uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, - const MCSectionELF &Section); + virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc, + const MCSectionELF *From, + const MCSectionELF *To) { + return true; + } + + void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue) override; + + void executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) override; + + void emitAddrsigSection() override { EmitAddrsigSection = true; } + void addAddrsigSymbol(const MCSymbol *Sym) override { + AddrsigSyms.push_back(Sym); + } + + friend struct ELFWriter; +}; + +class ELFSingleObjectWriter : public ELFObjectWriter { + raw_pwrite_stream &OS; + bool IsLittleEndian; + +public: + ELFSingleObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, bool IsLittleEndian) + : ELFObjectWriter(std::move(MOTW)), OS(OS), + IsLittleEndian(IsLittleEndian) {} + + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override { + return ELFWriter(*this, OS, IsLittleEndian, ELFWriter::AllSections) + .writeObject(Asm, Layout); + } + + friend struct ELFWriter; +}; + +class ELFDwoObjectWriter : public ELFObjectWriter { + raw_pwrite_stream &OS, &DwoOS; + bool IsLittleEndian; + +public: + ELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS, + bool IsLittleEndian) + : ELFObjectWriter(std::move(MOTW)), OS(OS), DwoOS(DwoOS), + IsLittleEndian(IsLittleEndian) {} + + virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc, + const MCSectionELF *From, + const MCSectionELF *To) override { + if (isDwoSection(*From)) { + Ctx.reportError(Loc, "A dwo section may not contain relocations"); + return false; + } + if (To && isDwoSection(*To)) { + Ctx.reportError(Loc, "A relocation may not refer to a dwo section"); + return false; + } + return true; + } + + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override { + uint64_t Size = ELFWriter(*this, OS, IsLittleEndian, ELFWriter::NonDwoOnly) + .writeObject(Asm, Layout); + Size += ELFWriter(*this, DwoOS, IsLittleEndian, ELFWriter::DwoOnly) + .writeObject(Asm, Layout); + return Size; + } }; } // end anonymous namespace -void ELFObjectWriter::align(unsigned Alignment) { - uint64_t Padding = OffsetToAlignment(getStream().tell(), Alignment); - WriteZeros(Padding); +void ELFWriter::align(unsigned Alignment) { + uint64_t Padding = OffsetToAlignment(W.OS.tell(), Alignment); + W.OS.write_zeros(Padding); } -unsigned ELFObjectWriter::addToSectionTable(const MCSectionELF *Sec) { +unsigned ELFWriter::addToSectionTable(const MCSectionELF *Sec) { SectionTable.push_back(Sec); StrTabBuilder.add(Sec->getSectionName()); return SectionTable.size(); @@ -278,7 +357,7 @@ template <typename T> void SymbolTableWriter::write(T Value) { EWriter.write(Value); } -SymbolTableWriter::SymbolTableWriter(ELFObjectWriter &EWriter, bool Is64Bit) +SymbolTableWriter::SymbolTableWriter(ELFWriter &EWriter, bool Is64Bit) : EWriter(EWriter), Is64Bit(Is64Bit), NumWritten(0) {} void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value, @@ -317,8 +396,16 @@ void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value, ++NumWritten; } +bool ELFWriter::is64Bit() const { + return OWriter.TargetObjectWriter->is64Bit(); +} + +bool ELFWriter::hasRelocationAddend() const { + return OWriter.hasRelocationAddend(); +} + // Emit the ELF header. -void ELFObjectWriter::writeHeader(const MCAssembler &Asm) { +void ELFWriter::writeHeader(const MCAssembler &Asm) { // ELF Header // ---------- // @@ -327,51 +414,54 @@ 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. - writeBytes(ELF::ElfMagic); // e_ident[EI_MAG0] to e_ident[EI_MAG3] + W.OS << ELF::ElfMagic; // e_ident[EI_MAG0] to e_ident[EI_MAG3] - write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] + W.OS << char(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] // e_ident[EI_DATA] - write8(isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); + W.OS << char(W.Endian == support::little ? ELF::ELFDATA2LSB + : ELF::ELFDATA2MSB); - write8(ELF::EV_CURRENT); // e_ident[EI_VERSION] + W.OS << char(ELF::EV_CURRENT); // e_ident[EI_VERSION] // e_ident[EI_OSABI] - write8(TargetObjectWriter->getOSABI()); - write8(0); // e_ident[EI_ABIVERSION] + W.OS << char(OWriter.TargetObjectWriter->getOSABI()); + W.OS << char(0); // e_ident[EI_ABIVERSION] - WriteZeros(ELF::EI_NIDENT - ELF::EI_PAD); + W.OS.write_zeros(ELF::EI_NIDENT - ELF::EI_PAD); - write16(ELF::ET_REL); // e_type + W.write<uint16_t>(ELF::ET_REL); // e_type - write16(TargetObjectWriter->getEMachine()); // e_machine = target + W.write<uint16_t>(OWriter.TargetObjectWriter->getEMachine()); // e_machine = target - write32(ELF::EV_CURRENT); // e_version + W.write<uint32_t>(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(0); // e_shoff = sec hdr table off in bytes // e_flags = whatever the target wants - write32(Asm.getELFHeaderEFlags()); + W.write<uint32_t>(Asm.getELFHeaderEFlags()); // e_ehsize = ELF header size - write16(is64Bit() ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr)); + W.write<uint16_t>(is64Bit() ? sizeof(ELF::Elf64_Ehdr) + : sizeof(ELF::Elf32_Ehdr)); - write16(0); // e_phentsize = prog header entry size - write16(0); // e_phnum = # prog header entries = 0 + W.write<uint16_t>(0); // e_phentsize = prog header entry size + W.write<uint16_t>(0); // e_phnum = # prog header entries = 0 // e_shentsize = Section header entry size - write16(is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); + W.write<uint16_t>(is64Bit() ? sizeof(ELF::Elf64_Shdr) + : sizeof(ELF::Elf32_Shdr)); // e_shnum = # of section header ents - write16(0); + W.write<uint16_t>(0); // e_shstrndx = Section # of '.shstrtab' assert(StringTableIndex < ELF::SHN_LORESERVE); - write16(StringTableIndex); + W.write<uint16_t>(StringTableIndex); } -uint64_t ELFObjectWriter::SymbolValue(const MCSymbol &Sym, - const MCAsmLayout &Layout) { +uint64_t ELFWriter::SymbolValue(const MCSymbol &Sym, + const MCAsmLayout &Layout) { if (Sym.isCommon() && Sym.isExternal()) return Sym.getCommonAlignment(); @@ -385,45 +475,6 @@ uint64_t ELFObjectWriter::SymbolValue(const MCSymbol &Sym, return Res; } -void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, - const MCAsmLayout &Layout) { - // The presence of symbol versions causes undefined symbols and - // versions declared with @@@ to be renamed. - for (const std::pair<StringRef, const MCSymbol *> &P : Asm.Symvers) { - StringRef AliasName = P.first; - const auto &Symbol = cast<MCSymbolELF>(*P.second); - size_t Pos = AliasName.find('@'); - assert(Pos != StringRef::npos); - - StringRef Prefix = AliasName.substr(0, Pos); - StringRef Rest = AliasName.substr(Pos); - StringRef Tail = Rest; - if (Rest.startswith("@@@")) - Tail = Rest.substr(Symbol.isUndefined() ? 2 : 1); - - auto *Alias = - cast<MCSymbolELF>(Asm.getContext().getOrCreateSymbol(Prefix + Tail)); - Asm.registerSymbol(*Alias); - const MCExpr *Value = MCSymbolRefExpr::create(&Symbol, Asm.getContext()); - Alias->setVariableValue(Value); - - // Aliases defined with .symvar copy the binding from the symbol they alias. - // This is the first place we are able to copy this information. - Alias->setExternal(Symbol.isExternal()); - Alias->setBinding(Symbol.getBinding()); - - if (!Symbol.isUndefined() && !Rest.startswith("@@@")) - continue; - - // FIXME: produce a better error message. - if (Symbol.isUndefined() && Rest.startswith("@@") && - !Rest.startswith("@@@")) - report_fatal_error("A @@ version cannot be undefined"); - - Renames.insert(std::make_pair(&Symbol, Alias)); - } -} - static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { uint8_t Type = newType; @@ -459,9 +510,8 @@ static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) { return Type; } -void ELFObjectWriter::writeSymbol(SymbolTableWriter &Writer, - uint32_t StringIndex, ELFSymbolData &MSD, - const MCAsmLayout &Layout) { +void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, + ELFSymbolData &MSD, const MCAsmLayout &Layout) { const auto &Symbol = cast<MCSymbolELF>(*MSD.Symbol); const MCSymbolELF *Base = cast_or_null<MCSymbolELF>(Layout.getBaseSymbol(Symbol)); @@ -502,108 +552,6 @@ void ELFObjectWriter::writeSymbol(SymbolTableWriter &Writer, IsReserved); } -// It is always valid to create a relocation with a symbol. It is preferable -// to use a relocation with a section if that is possible. Using the section -// allows us to omit some local symbols from the symbol table. -bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, - const MCSymbolRefExpr *RefA, - const MCSymbol *S, uint64_t C, - unsigned Type) const { - const auto *Sym = cast_or_null<MCSymbolELF>(S); - // A PCRel relocation to an absolute value has no symbol (or section). We - // represent that with a relocation to a null section. - if (!RefA) - return false; - - MCSymbolRefExpr::VariantKind Kind = RefA->getKind(); - switch (Kind) { - default: - break; - // The .odp creation emits a relocation against the symbol ".TOC." which - // create a R_PPC64_TOC relocation. However the relocation symbol name - // in final object creation should be NULL, since the symbol does not - // really exist, it is just the reference to TOC base for the current - // object file. Since the symbol is undefined, returning false results - // in a relocation with a null section which is the desired result. - case MCSymbolRefExpr::VK_PPC_TOCBASE: - return false; - - // These VariantKind cause the relocation to refer to something other than - // the symbol itself, like a linker generated table. Since the address of - // symbol is not relevant, we cannot replace the symbol with the - // section and patch the difference in the addend. - case MCSymbolRefExpr::VK_GOT: - case MCSymbolRefExpr::VK_PLT: - case MCSymbolRefExpr::VK_GOTPCREL: - case MCSymbolRefExpr::VK_PPC_GOT_LO: - case MCSymbolRefExpr::VK_PPC_GOT_HI: - case MCSymbolRefExpr::VK_PPC_GOT_HA: - return true; - } - - // An undefined symbol is not in any section, so the relocation has to point - // to the symbol itself. - assert(Sym && "Expected a symbol"); - if (Sym->isUndefined()) - return true; - - unsigned Binding = Sym->getBinding(); - switch(Binding) { - default: - llvm_unreachable("Invalid Binding"); - case ELF::STB_LOCAL: - break; - case ELF::STB_WEAK: - // If the symbol is weak, it might be overridden by a symbol in another - // file. The relocation has to point to the symbol so that the linker - // can update it. - return true; - case ELF::STB_GLOBAL: - // Global ELF symbols can be preempted by the dynamic linker. The relocation - // has to point to the symbol for a reason analogous to the STB_WEAK case. - return true; - } - - // If a relocation points to a mergeable section, we have to be careful. - // If the offset is zero, a relocation with the section will encode the - // same information. With a non-zero offset, the situation is different. - // For example, a relocation can point 42 bytes past the end of a string. - // 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. - if (Sym->isInSection()) { - auto &Sec = cast<MCSectionELF>(Sym->getSection()); - unsigned Flags = Sec.getFlags(); - if (Flags & ELF::SHF_MERGE) { - if (C != 0) - return true; - - // It looks like gold has a bug (http://sourceware.org/PR16794) and can - // only handle section relocations to mergeable sections if using RELA. - if (!hasRelocationAddend()) - return true; - } - - // Most TLS relocations use a got, so they need the symbol. Even those that - // are just an offset (@tpoff), require a symbol in gold versions before - // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed - // http://sourceware.org/PR16773. - if (Flags & ELF::SHF_TLS) - return true; - } - - // If the symbol is a thumb function the final relocation must set the lowest - // 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)) - return true; - - if (TargetObjectWriter->needsRelocateWithSymbol(*Sym, Type)) - return true; - return false; -} - // 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. @@ -624,118 +572,8 @@ static bool isWeak(const MCSymbolELF &Sym) { } } -void ELFObjectWriter::recordRelocation(MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { - MCAsmBackend &Backend = Asm.getBackend(); - bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & - MCFixupKindInfo::FKF_IsPCRel; - const MCSectionELF &FixupSection = cast<MCSectionELF>(*Fragment->getParent()); - uint64_t C = Target.getConstant(); - uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); - MCContext &Ctx = Asm.getContext(); - - if (const MCSymbolRefExpr *RefB = Target.getSymB()) { - // Let A, B and C being the components of Target and R be the location of - // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). - // If it is pcrel, we want to compute (A - B + C - R). - - // In general, ELF has no relocations for -B. It can only represent (A + C) - // 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) { - Ctx.reportError( - Fixup.getLoc(), - "No relocation available to represent this relative expression"); - return; - } - - const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol()); - - if (SymB.isUndefined()) { - Ctx.reportError(Fixup.getLoc(), - Twine("symbol '") + SymB.getName() + - "' can not be undefined in a subtraction expression"); - return; - } - - assert(!SymB.isAbsolute() && "Should have been folded"); - const MCSection &SecB = SymB.getSection(); - if (&SecB != &FixupSection) { - Ctx.reportError(Fixup.getLoc(), - "Cannot represent a difference across sections"); - return; - } - - uint64_t SymBOffset = Layout.getSymbolOffset(SymB); - uint64_t K = SymBOffset - FixupOffset; - IsPCRel = true; - C -= K; - } - - // We either rejected the fixup or folded B into C at this point. - const MCSymbolRefExpr *RefA = Target.getSymA(); - const auto *SymA = RefA ? cast<MCSymbolELF>(&RefA->getSymbol()) : nullptr; - - bool ViaWeakRef = false; - if (SymA && SymA->isVariable()) { - const MCExpr *Expr = SymA->getVariableValue(); - if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) { - if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) { - SymA = cast<MCSymbolELF>(&Inner->getSymbol()); - ViaWeakRef = true; - } - } - } - - unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel); - uint64_t OriginalC = C; - bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); - if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) - C += Layout.getSymbolOffset(*SymA); - - uint64_t Addend = 0; - if (hasRelocationAddend()) { - Addend = C; - C = 0; - } - - FixedValue = C; - - if (!RelocateWithSymbol) { - const MCSection *SecA = - (SymA && !SymA->isUndefined()) ? &SymA->getSection() : nullptr; - auto *ELFSec = cast_or_null<MCSectionELF>(SecA); - const auto *SectionSymbol = - ELFSec ? cast<MCSymbolELF>(ELFSec->getBeginSymbol()) : nullptr; - if (SectionSymbol) - SectionSymbol->setUsedInReloc(); - ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, - OriginalC); - Relocations[&FixupSection].push_back(Rec); - return; - } - - const auto *RenamedSymA = SymA; - if (SymA) { - if (const MCSymbolELF *R = Renames.lookup(SymA)) - RenamedSymA = R; - - if (ViaWeakRef) - RenamedSymA->setIsWeakrefUsedInReloc(); - else - RenamedSymA->setUsedInReloc(); - } - ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, - OriginalC); - Relocations[&FixupSection].push_back(Rec); -} - -bool ELFObjectWriter::isInSymtab(const MCAsmLayout &Layout, - const MCSymbolELF &Symbol, bool Used, - bool Renamed) { +bool ELFWriter::isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, + bool Used, bool Renamed) { if (Symbol.isVariable()) { const MCExpr *Expr = Symbol.getVariableValue(); if (const MCSymbolRefExpr *Ref = dyn_cast<MCSymbolRefExpr>(Expr)) { @@ -768,7 +606,7 @@ bool ELFObjectWriter::isInSymtab(const MCAsmLayout &Layout, return true; } -void ELFObjectWriter::computeSymbolTable( +void ELFWriter::computeSymbolTable( MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap, SectionOffsetsTy &SectionOffsets) { @@ -783,7 +621,7 @@ void ELFObjectWriter::computeSymbolTable( SymbolTableIndex = addToSectionTable(SymtabSection); align(SymtabSection->getAlignment()); - uint64_t SecStart = getStream().tell(); + uint64_t SecStart = W.OS.tell(); // The first entry is the undefined symbol entry. Writer.writeSymbol(0, 0, 0, 0, 0, 0, false); @@ -800,7 +638,7 @@ void ELFObjectWriter::computeSymbolTable( bool isSignature = Symbol.isSignature(); if (!isInSymtab(Layout, Symbol, Used || WeakrefUsed || isSignature, - Renames.count(&Symbol))) + OWriter.Renames.count(&Symbol))) continue; if (Symbol.isTemporary() && Symbol.isUndefined()) { @@ -830,6 +668,8 @@ void ELFObjectWriter::computeSymbolTable( } else { const MCSectionELF &Section = static_cast<const MCSectionELF &>(Symbol.getSection()); + if (Mode == NonDwoOnly && isDwoSection(Section)) + continue; MSD.SectionIndex = SectionIndexMap.lookup(&Section); assert(MSD.SectionIndex && "Invalid section index!"); if (MSD.SectionIndex >= ELF::SHN_LORESERVE) @@ -899,7 +739,7 @@ void ELFObjectWriter::computeSymbolTable( assert(MSD.Symbol->getBinding() != ELF::STB_LOCAL); } - uint64_t SecEnd = getStream().tell(); + uint64_t SecEnd = W.OS.tell(); SectionOffsets[SymtabSection] = std::make_pair(SecStart, SecEnd); ArrayRef<uint32_t> ShndxIndexes = Writer.getShndxIndexes(); @@ -909,19 +749,23 @@ void ELFObjectWriter::computeSymbolTable( } assert(SymtabShndxSectionIndex != 0); - SecStart = getStream().tell(); + SecStart = W.OS.tell(); const MCSectionELF *SymtabShndxSection = SectionTable[SymtabShndxSectionIndex - 1]; for (uint32_t Index : ShndxIndexes) write(Index); - SecEnd = getStream().tell(); + SecEnd = W.OS.tell(); SectionOffsets[SymtabShndxSection] = std::make_pair(SecStart, SecEnd); } -MCSectionELF * -ELFObjectWriter::createRelocationSection(MCContext &Ctx, - const MCSectionELF &Sec) { - if (Relocations[&Sec].empty()) +void ELFWriter::writeAddrsigSection() { + for (const MCSymbol *Sym : OWriter.AddrsigSyms) + encodeULEB128(Sym->getIndex(), W.OS); +} + +MCSectionELF *ELFWriter::createRelocationSection(MCContext &Ctx, + const MCSectionELF &Sec) { + if (OWriter.Relocations[&Sec].empty()) return nullptr; const StringRef SectionName = Sec.getSectionName(); @@ -946,7 +790,7 @@ ELFObjectWriter::createRelocationSection(MCContext &Ctx, } // Include the debug info compression header. -bool ELFObjectWriter::maybeWriteCompression( +bool ELFWriter::maybeWriteCompression( uint64_t Size, SmallVectorImpl<char> &CompressedContents, bool ZLibStyle, unsigned Alignment) { if (ZLibStyle) { @@ -975,13 +819,13 @@ bool ELFObjectWriter::maybeWriteCompression( const StringRef Magic = "ZLIB"; if (Size <= Magic.size() + sizeof(Size) + CompressedContents.size()) return false; - write(ArrayRef<char>(Magic.begin(), Magic.size())); - writeBE64(Size); + W.OS << Magic; + support::endian::write(W.OS, Size, support::big); return true; } -void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, - const MCAsmLayout &Layout) { +void ELFWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, + const MCAsmLayout &Layout) { MCSectionELF &Section = static_cast<MCSectionELF &>(Sec); StringRef SectionName = Section.getSectionName(); @@ -995,7 +839,7 @@ void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, MAI->compressDebugSections() != DebugCompressionType::None; if (!CompressionEnabled || !SectionName.startswith(".debug_") || SectionName == ".debug_frame") { - Asm.writeSectionData(&Section, Layout); + Asm.writeSectionData(W.OS, &Section, Layout); return; } @@ -1005,24 +849,21 @@ void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, SmallVector<char, 128> UncompressedData; raw_svector_ostream VecOS(UncompressedData); - raw_pwrite_stream &OldStream = getStream(); - setStream(VecOS); - Asm.writeSectionData(&Section, Layout); - setStream(OldStream); + Asm.writeSectionData(VecOS, &Section, Layout); SmallVector<char, 128> CompressedContents; if (Error E = zlib::compress( StringRef(UncompressedData.data(), UncompressedData.size()), CompressedContents)) { consumeError(std::move(E)); - getStream() << UncompressedData; + W.OS << UncompressedData; return; } bool ZlibStyle = MAI->compressDebugSections() == DebugCompressionType::Z; if (!maybeWriteCompression(UncompressedData.size(), CompressedContents, ZlibStyle, Sec.getAlignment())) { - getStream() << UncompressedData; + W.OS << UncompressedData; return; } @@ -1032,30 +873,28 @@ void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec, else // Add "z" prefix to section name. This is zlib-gnu style. MC.renameELFSection(&Section, (".z" + SectionName.drop_front(1)).str()); - getStream() << CompressedContents; + W.OS << CompressedContents; } -void ELFObjectWriter::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) { - write32(Name); // sh_name: index into string table - write32(Type); // sh_type +void ELFWriter::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) { + W.write<uint32_t>(Name); // sh_name: index into string table + W.write<uint32_t>(Type); // sh_type WriteWord(Flags); // sh_flags WriteWord(Address); // sh_addr WriteWord(Offset); // sh_offset WriteWord(Size); // sh_size - write32(Link); // sh_link - write32(Info); // sh_info + W.write<uint32_t>(Link); // sh_link + W.write<uint32_t>(Info); // sh_info WriteWord(Alignment); // sh_addralign WriteWord(EntrySize); // sh_entsize } -void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, +void ELFWriter::writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec) { - std::vector<ELFRelocationEntry> &Relocs = Relocations[&Sec]; + std::vector<ELFRelocationEntry> &Relocs = OWriter.Relocations[&Sec]; // We record relocations by pushing to the end of a vector. Reverse the vector // to get the relocations in the order they were created. @@ -1064,7 +903,7 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, std::reverse(Relocs.begin(), Relocs.end()); // Sort the relocation entries. MIPS needs this. - TargetObjectWriter->sortRelocs(Asm, Relocs); + OWriter.TargetObjectWriter->sortRelocs(Asm, Relocs); for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { const ELFRelocationEntry &Entry = Relocs[e - i - 1]; @@ -1072,13 +911,13 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, if (is64Bit()) { write(Entry.Offset); - if (TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { + if (OWriter.TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { write(uint32_t(Index)); - write(TargetObjectWriter->getRSsym(Entry.Type)); - write(TargetObjectWriter->getRType3(Entry.Type)); - write(TargetObjectWriter->getRType2(Entry.Type)); - write(TargetObjectWriter->getRType(Entry.Type)); + write(OWriter.TargetObjectWriter->getRSsym(Entry.Type)); + write(OWriter.TargetObjectWriter->getRType3(Entry.Type)); + write(OWriter.TargetObjectWriter->getRType2(Entry.Type)); + write(OWriter.TargetObjectWriter->getRType(Entry.Type)); } else { struct ELF::Elf64_Rela ERE64; ERE64.setSymbolAndType(Index, Entry.Type); @@ -1096,15 +935,17 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, if (hasRelocationAddend()) write(uint32_t(Entry.Addend)); - if (TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { - if (uint32_t RType = TargetObjectWriter->getRType2(Entry.Type)) { + if (OWriter.TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { + if (uint32_t RType = + OWriter.TargetObjectWriter->getRType2(Entry.Type)) { write(uint32_t(Entry.Offset)); ERE32.setSymbolAndType(0, RType); write(ERE32.r_info); write(uint32_t(0)); } - if (uint32_t RType = TargetObjectWriter->getRType3(Entry.Type)) { + if (uint32_t RType = + OWriter.TargetObjectWriter->getRType3(Entry.Type)) { write(uint32_t(Entry.Offset)); ERE32.setSymbolAndType(0, RType); @@ -1116,15 +957,15 @@ void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, } } -const MCSectionELF *ELFObjectWriter::createStringTable(MCContext &Ctx) { +const MCSectionELF *ELFWriter::createStringTable(MCContext &Ctx) { const MCSectionELF *StrtabSection = SectionTable[StringTableIndex - 1]; - StrTabBuilder.write(getStream()); + StrTabBuilder.write(W.OS); return StrtabSection; } -void ELFObjectWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, - uint32_t GroupSymbolIndex, uint64_t Offset, - uint64_t Size, const MCSectionELF &Section) { +void ELFWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, uint64_t Offset, + uint64_t Size, const MCSectionELF &Section) { uint64_t sh_link = 0; uint64_t sh_info = 0; @@ -1146,12 +987,13 @@ void ELFObjectWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, } case ELF::SHT_SYMTAB: - case ELF::SHT_DYNSYM: sh_link = StringTableIndex; sh_info = LastLocalSymbolIndex; break; case ELF::SHT_SYMTAB_SHNDX: + case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: + case ELF::SHT_LLVM_ADDRSIG: sh_link = SymbolTableIndex; break; @@ -1173,7 +1015,7 @@ void ELFObjectWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, Section.getEntrySize()); } -void ELFObjectWriter::writeSectionHeader( +void ELFWriter::writeSectionHeader( const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const SectionOffsetsTy &SectionOffsets) { const unsigned NumSections = SectionTable.size(); @@ -1204,8 +1046,9 @@ void ELFObjectWriter::writeSectionHeader( } } -void ELFObjectWriter::writeObject(MCAssembler &Asm, - const MCAsmLayout &Layout) { +uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { + uint64_t StartOffset = W.OS.tell(); + MCContext &Ctx = Asm.getContext(); MCSectionELF *StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0); @@ -1225,16 +1068,20 @@ void ELFObjectWriter::writeObject(MCAssembler &Asm, std::vector<MCSectionELF *> Relocations; for (MCSection &Sec : Asm) { MCSectionELF &Section = static_cast<MCSectionELF &>(Sec); + if (Mode == NonDwoOnly && isDwoSection(Section)) + continue; + if (Mode == DwoOnly && !isDwoSection(Section)) + continue; align(Section.getAlignment()); // Remember the offset into the file for this section. - uint64_t SecStart = getStream().tell(); + uint64_t SecStart = W.OS.tell(); const MCSymbolELF *SignatureSymbol = Section.getGroup(); writeSectionData(Asm, Section, Layout); - uint64_t SecEnd = getStream().tell(); + uint64_t SecEnd = W.OS.tell(); SectionOffsets[&Section] = std::make_pair(SecStart, SecEnd); MCSectionELF *RelSection = createRelocationSection(Ctx, Section); @@ -1262,11 +1109,19 @@ void ELFObjectWriter::writeObject(MCAssembler &Asm, } } + MCSectionELF *CGProfileSection = nullptr; + if (!Asm.CGProfile.empty()) { + CGProfileSection = Ctx.getELFSection(".llvm.call-graph-profile", + ELF::SHT_LLVM_CALL_GRAPH_PROFILE, + ELF::SHF_EXCLUDE, 16, ""); + SectionIndexMap[CGProfileSection] = addToSectionTable(CGProfileSection); + } + for (MCSectionELF *Group : Groups) { align(Group->getAlignment()); // Remember the offset into the file for this section. - uint64_t SecStart = getStream().tell(); + uint64_t SecStart = W.OS.tell(); const MCSymbol *SignatureSymbol = Group->getGroup(); assert(SignatureSymbol); @@ -1276,65 +1131,364 @@ void ELFObjectWriter::writeObject(MCAssembler &Asm, write(SecIndex); } - uint64_t SecEnd = getStream().tell(); + uint64_t SecEnd = W.OS.tell(); SectionOffsets[Group] = std::make_pair(SecStart, SecEnd); } - // Compute symbol table information. - computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap, SectionOffsets); + if (Mode == DwoOnly) { + // dwo files don't have symbol tables or relocations, but they do have + // string tables. + StrTabBuilder.finalize(); + } else { + MCSectionELF *AddrsigSection; + if (OWriter.EmitAddrsigSection) { + AddrsigSection = Ctx.getELFSection(".llvm_addrsig", ELF::SHT_LLVM_ADDRSIG, + ELF::SHF_EXCLUDE); + addToSectionTable(AddrsigSection); + } + + // Compute symbol table information. + computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap, + SectionOffsets); - for (MCSectionELF *RelSection : Relocations) { - align(RelSection->getAlignment()); + for (MCSectionELF *RelSection : Relocations) { + align(RelSection->getAlignment()); - // Remember the offset into the file for this section. - uint64_t SecStart = getStream().tell(); + // Remember the offset into the file for this section. + uint64_t SecStart = W.OS.tell(); - writeRelocations(Asm, - cast<MCSectionELF>(*RelSection->getAssociatedSection())); + writeRelocations(Asm, + cast<MCSectionELF>(*RelSection->getAssociatedSection())); - uint64_t SecEnd = getStream().tell(); - SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd); + uint64_t SecEnd = W.OS.tell(); + SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd); + } + + if (OWriter.EmitAddrsigSection) { + uint64_t SecStart = W.OS.tell(); + writeAddrsigSection(); + uint64_t SecEnd = W.OS.tell(); + SectionOffsets[AddrsigSection] = std::make_pair(SecStart, SecEnd); + } + } + + if (CGProfileSection) { + uint64_t SecStart = W.OS.tell(); + for (const MCAssembler::CGProfileEntry &CGPE : Asm.CGProfile) { + W.write<uint32_t>(CGPE.From->getSymbol().getIndex()); + W.write<uint32_t>(CGPE.To->getSymbol().getIndex()); + W.write<uint64_t>(CGPE.Count); + } + uint64_t SecEnd = W.OS.tell(); + SectionOffsets[CGProfileSection] = std::make_pair(SecStart, SecEnd); } { - uint64_t SecStart = getStream().tell(); + uint64_t SecStart = W.OS.tell(); const MCSectionELF *Sec = createStringTable(Ctx); - uint64_t SecEnd = getStream().tell(); + uint64_t SecEnd = W.OS.tell(); SectionOffsets[Sec] = std::make_pair(SecStart, SecEnd); } uint64_t NaturalAlignment = is64Bit() ? 8 : 4; align(NaturalAlignment); - const uint64_t SectionHeaderOffset = getStream().tell(); + const uint64_t SectionHeaderOffset = W.OS.tell(); // ... then the section header table ... writeSectionHeader(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); + uint16_t NumSections = support::endian::byte_swap<uint16_t>( + (SectionTable.size() + 1 >= ELF::SHN_LORESERVE) ? (uint16_t)ELF::SHN_UNDEF + : SectionTable.size() + 1, + W.Endian); unsigned NumSectionsOffset; + auto &Stream = static_cast<raw_pwrite_stream &>(W.OS); if (is64Bit()) { - uint64_t Val = SectionHeaderOffset; - if (sys::IsLittleEndianHost != IsLittleEndian) - sys::swapByteOrder(Val); - getStream().pwrite(reinterpret_cast<char *>(&Val), sizeof(Val), - offsetof(ELF::Elf64_Ehdr, e_shoff)); + uint64_t Val = + support::endian::byte_swap<uint64_t>(SectionHeaderOffset, W.Endian); + Stream.pwrite(reinterpret_cast<char *>(&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); - getStream().pwrite(reinterpret_cast<char *>(&Val), sizeof(Val), - offsetof(ELF::Elf32_Ehdr, e_shoff)); + uint32_t Val = + support::endian::byte_swap<uint32_t>(SectionHeaderOffset, W.Endian); + Stream.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val), + offsetof(ELF::Elf32_Ehdr, e_shoff)); NumSectionsOffset = offsetof(ELF::Elf32_Ehdr, e_shnum); } - getStream().pwrite(reinterpret_cast<char *>(&NumSections), - sizeof(NumSections), NumSectionsOffset); + Stream.pwrite(reinterpret_cast<char *>(&NumSections), sizeof(NumSections), + NumSectionsOffset); + + return W.OS.tell() - StartOffset; +} + +bool ELFObjectWriter::hasRelocationAddend() const { + return TargetObjectWriter->hasRelocationAddend(); +} + +void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // The presence of symbol versions causes undefined symbols and + // versions declared with @@@ to be renamed. + for (const std::pair<StringRef, const MCSymbol *> &P : Asm.Symvers) { + StringRef AliasName = P.first; + const auto &Symbol = cast<MCSymbolELF>(*P.second); + size_t Pos = AliasName.find('@'); + assert(Pos != StringRef::npos); + + StringRef Prefix = AliasName.substr(0, Pos); + StringRef Rest = AliasName.substr(Pos); + StringRef Tail = Rest; + if (Rest.startswith("@@@")) + Tail = Rest.substr(Symbol.isUndefined() ? 2 : 1); + + auto *Alias = + cast<MCSymbolELF>(Asm.getContext().getOrCreateSymbol(Prefix + Tail)); + Asm.registerSymbol(*Alias); + const MCExpr *Value = MCSymbolRefExpr::create(&Symbol, Asm.getContext()); + Alias->setVariableValue(Value); + + // Aliases defined with .symvar copy the binding from the symbol they alias. + // This is the first place we are able to copy this information. + Alias->setExternal(Symbol.isExternal()); + Alias->setBinding(Symbol.getBinding()); + + if (!Symbol.isUndefined() && !Rest.startswith("@@@")) + continue; + + // FIXME: produce a better error message. + if (Symbol.isUndefined() && Rest.startswith("@@") && + !Rest.startswith("@@@")) + report_fatal_error("A @@ version cannot be undefined"); + + if (Renames.count(&Symbol) && Renames[&Symbol] != Alias) + report_fatal_error(llvm::Twine("Multiple symbol versions defined for ") + + Symbol.getName()); + + Renames.insert(std::make_pair(&Symbol, Alias)); + } + + for (const MCSymbol *&Sym : AddrsigSyms) { + if (const MCSymbol *R = Renames.lookup(cast<MCSymbolELF>(Sym))) + Sym = R; + Sym->setUsedInReloc(); + } +} + +// It is always valid to create a relocation with a symbol. It is preferable +// to use a relocation with a section if that is possible. Using the section +// allows us to omit some local symbols from the symbol table. +bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm, + const MCSymbolRefExpr *RefA, + const MCSymbolELF *Sym, + uint64_t C, + unsigned Type) const { + // A PCRel relocation to an absolute value has no symbol (or section). We + // represent that with a relocation to a null section. + if (!RefA) + return false; + + MCSymbolRefExpr::VariantKind Kind = RefA->getKind(); + switch (Kind) { + default: + break; + // The .odp creation emits a relocation against the symbol ".TOC." which + // create a R_PPC64_TOC relocation. However the relocation symbol name + // in final object creation should be NULL, since the symbol does not + // really exist, it is just the reference to TOC base for the current + // object file. Since the symbol is undefined, returning false results + // in a relocation with a null section which is the desired result. + case MCSymbolRefExpr::VK_PPC_TOCBASE: + return false; + + // These VariantKind cause the relocation to refer to something other than + // the symbol itself, like a linker generated table. Since the address of + // symbol is not relevant, we cannot replace the symbol with the + // section and patch the difference in the addend. + case MCSymbolRefExpr::VK_GOT: + case MCSymbolRefExpr::VK_PLT: + case MCSymbolRefExpr::VK_GOTPCREL: + case MCSymbolRefExpr::VK_PPC_GOT_LO: + case MCSymbolRefExpr::VK_PPC_GOT_HI: + case MCSymbolRefExpr::VK_PPC_GOT_HA: + return true; + } + + // An undefined symbol is not in any section, so the relocation has to point + // to the symbol itself. + assert(Sym && "Expected a symbol"); + if (Sym->isUndefined()) + return true; + + unsigned Binding = Sym->getBinding(); + switch(Binding) { + default: + llvm_unreachable("Invalid Binding"); + case ELF::STB_LOCAL: + break; + case ELF::STB_WEAK: + // If the symbol is weak, it might be overridden by a symbol in another + // file. The relocation has to point to the symbol so that the linker + // can update it. + return true; + case ELF::STB_GLOBAL: + // Global ELF symbols can be preempted by the dynamic linker. The relocation + // has to point to the symbol for a reason analogous to the STB_WEAK case. + return true; + } + + // If a relocation points to a mergeable section, we have to be careful. + // If the offset is zero, a relocation with the section will encode the + // same information. With a non-zero offset, the situation is different. + // For example, a relocation can point 42 bytes past the end of a string. + // 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. + if (Sym->isInSection()) { + auto &Sec = cast<MCSectionELF>(Sym->getSection()); + unsigned Flags = Sec.getFlags(); + if (Flags & ELF::SHF_MERGE) { + if (C != 0) + return true; + + // It looks like gold has a bug (http://sourceware.org/PR16794) and can + // only handle section relocations to mergeable sections if using RELA. + if (!hasRelocationAddend()) + return true; + } + + // Most TLS relocations use a got, so they need the symbol. Even those that + // are just an offset (@tpoff), require a symbol in gold versions before + // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed + // http://sourceware.org/PR16773. + if (Flags & ELF::SHF_TLS) + return true; + } + + // If the symbol is a thumb function the final relocation must set the lowest + // 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)) + return true; + + if (TargetObjectWriter->needsRelocateWithSymbol(*Sym, Type)) + return true; + return false; +} + +void ELFObjectWriter::recordRelocation(MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + MCAsmBackend &Backend = Asm.getBackend(); + bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsPCRel; + const MCSectionELF &FixupSection = cast<MCSectionELF>(*Fragment->getParent()); + uint64_t C = Target.getConstant(); + uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + MCContext &Ctx = Asm.getContext(); + + if (const MCSymbolRefExpr *RefB = Target.getSymB()) { + // Let A, B and C being the components of Target and R be the location of + // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). + // If it is pcrel, we want to compute (A - B + C - R). + + // In general, ELF has no relocations for -B. It can only represent (A + C) + // 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) { + Ctx.reportError( + Fixup.getLoc(), + "No relocation available to represent this relative expression"); + return; + } + + const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol()); + + if (SymB.isUndefined()) { + Ctx.reportError(Fixup.getLoc(), + Twine("symbol '") + SymB.getName() + + "' can not be undefined in a subtraction expression"); + return; + } + + assert(!SymB.isAbsolute() && "Should have been folded"); + const MCSection &SecB = SymB.getSection(); + if (&SecB != &FixupSection) { + Ctx.reportError(Fixup.getLoc(), + "Cannot represent a difference across sections"); + return; + } + + uint64_t SymBOffset = Layout.getSymbolOffset(SymB); + uint64_t K = SymBOffset - FixupOffset; + IsPCRel = true; + C -= K; + } + + // We either rejected the fixup or folded B into C at this point. + const MCSymbolRefExpr *RefA = Target.getSymA(); + const auto *SymA = RefA ? cast<MCSymbolELF>(&RefA->getSymbol()) : nullptr; + + bool ViaWeakRef = false; + if (SymA && SymA->isVariable()) { + const MCExpr *Expr = SymA->getVariableValue(); + if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) { + if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) { + SymA = cast<MCSymbolELF>(&Inner->getSymbol()); + ViaWeakRef = true; + } + } + } + + unsigned Type = TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); + uint64_t OriginalC = C; + bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); + if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) + C += Layout.getSymbolOffset(*SymA); + + uint64_t Addend = 0; + if (hasRelocationAddend()) { + Addend = C; + C = 0; + } + + FixedValue = C; + + const MCSectionELF *SecA = (SymA && SymA->isInSection()) + ? cast<MCSectionELF>(&SymA->getSection()) + : nullptr; + if (!checkRelocation(Ctx, Fixup.getLoc(), &FixupSection, SecA)) + return; + + if (!RelocateWithSymbol) { + const auto *SectionSymbol = + SecA ? cast<MCSymbolELF>(SecA->getBeginSymbol()) : nullptr; + if (SectionSymbol) + SectionSymbol->setUsedInReloc(); + ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, + OriginalC); + Relocations[&FixupSection].push_back(Rec); + return; + } + + const auto *RenamedSymA = SymA; + if (SymA) { + if (const MCSymbolELF *R = Renames.lookup(SymA)) + RenamedSymA = R; + + if (ViaWeakRef) + RenamedSymA->setIsWeakrefUsedInReloc(); + else + RenamedSymA->setUsedInReloc(); + } + ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, + OriginalC); + Relocations[&FixupSection].push_back(Rec); } bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( @@ -1353,6 +1507,14 @@ bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( std::unique_ptr<MCObjectWriter> llvm::createELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, raw_pwrite_stream &OS, bool IsLittleEndian) { - return llvm::make_unique<ELFObjectWriter>(std::move(MOTW), OS, - IsLittleEndian); + return llvm::make_unique<ELFSingleObjectWriter>(std::move(MOTW), OS, + IsLittleEndian); +} + +std::unique_ptr<MCObjectWriter> +llvm::createELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW, + raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS, + bool IsLittleEndian) { + return llvm::make_unique<ELFDwoObjectWriter>(std::move(MOTW), OS, DwoOS, + IsLittleEndian); } |