summaryrefslogtreecommitdiff
path: root/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'ELF')
-rw-r--r--ELF/InputSection.cpp57
-rw-r--r--ELF/InputSection.h2
-rw-r--r--ELF/LinkerScript.cpp3
-rw-r--r--ELF/MapFile.cpp18
-rw-r--r--ELF/MapFile.h6
-rw-r--r--ELF/Relocations.cpp4
-rw-r--r--ELF/Relocations.h1
-rw-r--r--ELF/SyntheticSections.cpp31
-rw-r--r--ELF/SyntheticSections.h12
-rw-r--r--ELF/Target.cpp3
-rw-r--r--ELF/Writer.cpp41
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) {