diff options
Diffstat (limited to 'ELF')
-rw-r--r-- | ELF/InputSection.cpp | 57 | ||||
-rw-r--r-- | ELF/InputSection.h | 2 | ||||
-rw-r--r-- | ELF/LinkerScript.cpp | 3 | ||||
-rw-r--r-- | ELF/MapFile.cpp | 18 | ||||
-rw-r--r-- | ELF/MapFile.h | 6 | ||||
-rw-r--r-- | ELF/Relocations.cpp | 4 | ||||
-rw-r--r-- | ELF/Relocations.h | 1 | ||||
-rw-r--r-- | ELF/SyntheticSections.cpp | 31 | ||||
-rw-r--r-- | ELF/SyntheticSections.h | 12 | ||||
-rw-r--r-- | ELF/Target.cpp | 3 | ||||
-rw-r--r-- | ELF/Writer.cpp | 41 |
11 files changed, 103 insertions, 75 deletions
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 87896ec96b294..e8cfd21c4c49d 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -390,14 +390,28 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, } } -template <class ELFT> -static typename ELFT::uint -getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P, - const SymbolBody &Body, RelExpr Expr) { +// ARM SBREL relocations are of the form S + A - B where B is the static base +// The ARM ABI defines base to be "addressing origin of the output segment +// defining the symbol S". We defined the "addressing origin"/static base to be +// the base of the PT_LOAD segment containing the Body. +// The procedure call standard only defines a Read Write Position Independent +// RWPI variant so in practice we should expect the static base to be the base +// of the RW segment. +static uint64_t getARMStaticBase(const SymbolBody &Body) { + OutputSection *OS = Body.getOutputSection(); + if (!OS || !OS->FirstInPtLoad) + fatal("SBREL relocation to " + Body.getName() + " without static base\n"); + return OS->FirstInPtLoad->Addr; +} + +static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, + const SymbolBody &Body, RelExpr Expr) { switch (Expr) { case R_ABS: case R_RELAX_GOT_PC_NOPIC: return Body.getVA(A); + case R_ARM_SBREL: + return Body.getVA(A) - getARMStaticBase(Body); case R_GOT: case R_RELAX_TLS_GD_TO_IE_ABS: return Body.getGotVA() + A; @@ -518,7 +532,7 @@ getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P, case R_NEG_TLS: return Out::TlsPhdr->p_memsz - Body.getVA(A); case R_SIZE: - return Body.getSize<ELFT>() + A; + return A; // Body.getSize was already folded into the addend. case R_TLSDESC: return InX::Got->getGlobalDynAddr(Body) + A; case R_TLSDESC_PAGE: @@ -566,7 +580,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { uint64_t SymVA = 0; if (!Sym.isTls() || Out::TlsPhdr) SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>( - getRelocTargetVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS)); + getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS)); Target->relocateOne(BufLoc, Type, SymVA); } } @@ -577,19 +591,28 @@ template <class ELFT> elf::ObjectFile<ELFT> *InputSectionBase::getFile() const { template <class ELFT> void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { + if (Flags & SHF_ALLOC) + relocateAlloc(Buf, BufEnd); + else + relocateNonAlloc<ELFT>(Buf, BufEnd); +} + +template <class ELFT> +void InputSectionBase::relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd) { // scanReloc function in Writer.cpp constructs Relocations // vector only for SHF_ALLOC'ed sections. For other sections, // we handle relocations directly here. - auto *IS = dyn_cast<InputSection>(this); - if (IS && !(IS->Flags & SHF_ALLOC)) { - if (IS->AreRelocsRela) - IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>()); - else - IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>()); - return; - } + auto *IS = cast<InputSection>(this); + assert(!(IS->Flags & SHF_ALLOC)); + if (IS->AreRelocsRela) + IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>()); + else + IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>()); +} - const unsigned Bits = sizeof(typename ELFT::uint) * 8; +void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { + assert(Flags & SHF_ALLOC); + const unsigned Bits = Config->Wordsize * 8; for (const Relocation &Rel : Relocations) { uint64_t Offset = getOffset(Rel.Offset); uint8_t *BufLoc = Buf + Offset; @@ -597,8 +620,8 @@ void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { uint64_t AddrLoc = getOutputSection()->Addr + Offset; RelExpr Expr = Rel.Expr; - uint64_t TargetVA = SignExtend64<Bits>( - getRelocTargetVA<ELFT>(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr)); + uint64_t TargetVA = SignExtend64( + getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits); switch (Expr) { case R_RELAX_GOT_PC: diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 57458588b6902..303c398b58cd4 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -167,6 +167,8 @@ public: template <class ELFT> std::string getObjMsg(uint64_t Offset); template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd); + void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd); + template <class ELFT> void relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd); std::vector<Relocation> Relocations; diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 161909abf00d0..c303f0524ad44 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -440,9 +440,6 @@ void LinkerScript::fabricateDefaultCommands() { // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections for (OutputSection *Sec : *OutputSections) { - if (!(Sec->Flags & SHF_ALLOC)) - continue; - auto *OSCmd = make<OutputSectionCommand>(Sec->Name); OSCmd->Sec = Sec; SecToCommand[Sec] = OSCmd; diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index 23c63e845c9a7..7b82eceba02a5 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -21,6 +21,8 @@ #include "MapFile.h" #include "InputFiles.h" +#include "LinkerScript.h" +#include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Threads.h" @@ -98,7 +100,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> Syms) { } template <class ELFT> -void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) { +void elf::writeMapFile(llvm::ArrayRef<BaseCommand *> Script) { if (Config->MapFile.empty()) return; @@ -121,7 +123,11 @@ void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) { << " Align Out In Symbol\n"; // Print out file contents. - for (OutputSection *OSec : OutputSections) { + for (BaseCommand *Base : Script) { + auto *Cmd = dyn_cast<OutputSectionCommand>(Base); + if (!Cmd) + continue; + OutputSection *OSec = Cmd->Sec; writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment); OS << OSec->Name << '\n'; @@ -136,7 +142,7 @@ void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) { } } -template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSection *>); -template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSection *>); -template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSection *>); -template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSection *>); +template void elf::writeMapFile<ELF32LE>(ArrayRef<BaseCommand *>); +template void elf::writeMapFile<ELF32BE>(ArrayRef<BaseCommand *>); +template void elf::writeMapFile<ELF64LE>(ArrayRef<BaseCommand *>); +template void elf::writeMapFile<ELF64BE>(ArrayRef<BaseCommand *>); diff --git a/ELF/MapFile.h b/ELF/MapFile.h index 24d636890e53c..f50ef00061ffa 100644 --- a/ELF/MapFile.h +++ b/ELF/MapFile.h @@ -10,12 +10,12 @@ #ifndef LLD_ELF_MAPFILE_H #define LLD_ELF_MAPFILE_H -#include "OutputSections.h" +#include <llvm/ADT/ArrayRef.h> namespace lld { namespace elf { -template <class ELFT> -void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections); +struct BaseCommand; +template <class ELFT> void writeMapFile(llvm::ArrayRef<BaseCommand *> Script); } } diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index c505a14f3c649..5564ea246eeb9 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -935,6 +935,10 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { bool IsConstant = isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, Sec, Rel.r_offset); + // The size is not going to change, so we fold it in here. + if (Expr == R_SIZE) + Addend += Body.getSize<ELFT>(); + // If the output being produced is position independent, the final value // is still not known. In that case we still need some help from the // dynamic linker. We can however do better than just copying the incoming diff --git a/ELF/Relocations.h b/ELF/Relocations.h index f3512e0a89fc0..206f0d9423c95 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -27,6 +27,7 @@ class OutputSection; // doesn't have to know about architecture-specific details. enum RelExpr { R_ABS, + R_ARM_SBREL, R_GOT, R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 5a2c2c37efd8e..599f1441a47fe 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -600,7 +600,7 @@ template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) { } for (EhInputSection *S : Sections) - S->template relocate<ELFT>(Buf, nullptr); + S->relocateAlloc(Buf, nullptr); // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table // to get a FDE from an address to which FDE is applied. So here @@ -617,16 +617,16 @@ template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) { } } -GotBaseSection::GotBaseSection() +GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotEntrySize, ".got") {} -void GotBaseSection::addEntry(SymbolBody &Sym) { +void GotSection::addEntry(SymbolBody &Sym) { Sym.GotIndex = NumEntries; ++NumEntries; } -bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) { +bool GotSection::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = NumEntries; @@ -637,7 +637,7 @@ bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) { // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. -bool GotBaseSection::addTlsIndex() { +bool GotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = NumEntries * Config->Wordsize; @@ -645,27 +645,23 @@ bool GotBaseSection::addTlsIndex() { return true; } -uint64_t GotBaseSection::getGlobalDynAddr(const SymbolBody &B) const { +uint64_t GotSection::getGlobalDynAddr(const SymbolBody &B) const { return this->getVA() + B.GlobalDynIndex * Config->Wordsize; } -uint64_t GotBaseSection::getGlobalDynOffset(const SymbolBody &B) const { +uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const { return B.GlobalDynIndex * Config->Wordsize; } -void GotBaseSection::finalizeContents() { - Size = NumEntries * Config->Wordsize; -} +void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; } -bool GotBaseSection::empty() const { +bool GotSection::empty() const { // If we have a relocation that is relative to GOT (such as GOTOFFREL), // we need to emit a GOT even if it's empty. return NumEntries == 0 && !HasGotOffRel; } -template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) { - this->template relocate<ELFT>(Buf, Buf + Size); -} +void GotSection::writeTo(uint8_t *Buf) { relocateAlloc(Buf, Buf + Size); } MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, @@ -2242,7 +2238,7 @@ StringTableSection *InX::DynStrTab; SymbolTableBaseSection *InX::DynSymTab; InputSection *InX::Interp; GdbIndexSection *InX::GdbIndex; -GotBaseSection *InX::Got; +GotSection *InX::Got; GotPltSection *InX::GotPlt; GnuHashTableSection *InX::GnuHashTab; IgotPltSection *InX::IgotPlt; @@ -2284,11 +2280,6 @@ template class elf::MipsReginfoSection<ELF32BE>; template class elf::MipsReginfoSection<ELF64LE>; template class elf::MipsReginfoSection<ELF64BE>; -template class elf::GotSection<ELF32LE>; -template class elf::GotSection<ELF32BE>; -template class elf::GotSection<ELF64LE>; -template class elf::GotSection<ELF64BE>; - template class elf::DynamicSection<ELF32LE>; template class elf::DynamicSection<ELF32BE>; template class elf::DynamicSection<ELF64LE>; diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index 0477c601a7dfc..c5ffb88c13666 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -104,12 +104,13 @@ private: llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap; }; -class GotBaseSection : public SyntheticSection { +class GotSection : public SyntheticSection { public: - GotBaseSection(); + GotSection(); size_t getSize() const override { return Size; } void finalizeContents() override; bool empty() const override; + void writeTo(uint8_t *Buf) override; void addEntry(SymbolBody &Sym); bool addDynTlsEntry(SymbolBody &Sym); @@ -130,11 +131,6 @@ protected: uint64_t Size = 0; }; -template <class ELFT> class GotSection final : public GotBaseSection { -public: - void writeTo(uint8_t *Buf) override; -}; - // .note.gnu.build-id section. class BuildIdSection : public SyntheticSection { // First 16 bytes are a header. @@ -764,7 +760,7 @@ struct InX { static GnuHashTableSection *GnuHashTab; static InputSection *Interp; static GdbIndexSection *GdbIndex; - static GotBaseSection *Got; + static GotSection *Got; static GotPltSection *GotPlt; static IgotPltSection *IgotPlt; static MipsGotSection *MipsGot; diff --git a/ELF/Target.cpp b/ELF/Target.cpp index 781d7fe3bc3ff..cf7d912ad829a 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -1693,6 +1693,8 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, case R_ARM_TLS_IE32: // GOT(S) + A - P return R_GOT_PC; + case R_ARM_SBREL32: + return R_ARM_SBREL; case R_ARM_TARGET1: return Config->Target1Rel ? R_PC : R_ABS; case R_ARM_TARGET2: @@ -1832,6 +1834,7 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_RELATIVE: + case R_ARM_SBREL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 4be6fe53c18ba..7a21d2b9f13da 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -288,8 +288,13 @@ template <class ELFT> void Writer<ELFT>::run() { if (ErrorCount) return; + // Clear the OutputSections to make sure it is not used anymore. Any + // code from this point on should be using the linker script + // commands. + OutputSections.clear(); + // Handle -Map option. - writeMapFile<ELFT>(OutputSections); + writeMapFile<ELFT>(Script->Opt.Commands); if (ErrorCount) return; @@ -403,7 +408,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { InX::MipsGot = make<MipsGotSection>(); Add(InX::MipsGot); } else { - InX::Got = make<GotSection<ELFT>>(); + InX::Got = make<GotSection>(); Add(InX::Got); } @@ -626,22 +631,22 @@ bool elf::isRelroSection(const OutputSection *Sec) { // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { - RF_NOT_ADDR_SET = 1 << 16, - RF_NOT_INTERP = 1 << 15, - RF_NOT_ALLOC = 1 << 14, - RF_WRITE = 1 << 13, - RF_EXEC = 1 << 12, - RF_NON_TLS_BSS = 1 << 11, - RF_NON_TLS_BSS_RO = 1 << 10, - RF_NOT_TLS = 1 << 9, - RF_BSS = 1 << 8, - RF_PPC_NOT_TOCBSS = 1 << 7, - RF_PPC_OPD = 1 << 6, - RF_PPC_TOCL = 1 << 5, - RF_PPC_TOC = 1 << 4, - RF_PPC_BRANCH_LT = 1 << 3, - RF_MIPS_GPREL = 1 << 2, - RF_MIPS_NOT_GOT = 1 << 1 + RF_NOT_ADDR_SET = 1 << 15, + RF_NOT_INTERP = 1 << 14, + RF_NOT_ALLOC = 1 << 13, + RF_WRITE = 1 << 12, + RF_EXEC = 1 << 11, + RF_NON_TLS_BSS = 1 << 10, + RF_NON_TLS_BSS_RO = 1 << 9, + RF_NOT_TLS = 1 << 8, + RF_BSS = 1 << 7, + RF_PPC_NOT_TOCBSS = 1 << 6, + RF_PPC_OPD = 1 << 5, + RF_PPC_TOCL = 1 << 4, + RF_PPC_TOC = 1 << 3, + RF_PPC_BRANCH_LT = 1 << 2, + RF_MIPS_GPREL = 1 << 1, + RF_MIPS_NOT_GOT = 1 << 0 }; static unsigned getSectionRank(const OutputSection *Sec) { |