summaryrefslogtreecommitdiffstats
path: root/lld/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF')
-rw-r--r--lld/ELF/Arch/PPC64.cpp114
-rw-r--r--lld/ELF/InputSection.cpp15
-rw-r--r--lld/ELF/OutputSections.cpp2
-rw-r--r--lld/ELF/OutputSections.h2
-rw-r--r--lld/ELF/Relocations.cpp12
-rw-r--r--lld/ELF/Relocations.h4
-rw-r--r--lld/ELF/Writer.cpp15
7 files changed, 62 insertions, 102 deletions
diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index 8c03379f172..22392db1a2d 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -72,13 +72,9 @@ PPC64::PPC64() {
GotBaseSymInGotPlt = false;
GotBaseSymOff = 0x8000;
- if (Config->EKind == ELF64LEKind) {
- GotHeaderEntriesNum = 1;
- GotPltHeaderEntriesNum = 2;
- PltRel = R_PPC64_JMP_SLOT;
- } else {
- PltRel = R_PPC64_GLOB_DAT;
- }
+ GotHeaderEntriesNum = 1;
+ GotPltHeaderEntriesNum = 2;
+ PltRel = R_PPC64_JMP_SLOT;
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
@@ -99,39 +95,46 @@ PPC64::PPC64() {
}
static uint32_t getEFlags(InputFile *File) {
- // Get the e_flag from the input file and if it is unspecified, then set it to
- // the e_flag appropriate for the ABI.
+ // Get the e_flag from the input file and issue an error if incompatible
+ // e_flag encountered.
- // We are currently handling both ELF64LE and ELF64BE but eventually will
- // remove BE support once v2 ABI support is complete.
- switch (Config->EKind) {
- case ELF64BEKind:
- if (uint32_t EFlags =
- cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags)
- return EFlags;
- return 1;
- case ELF64LEKind:
- if (uint32_t EFlags =
- cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags)
- return EFlags;
- return 2;
- default:
- llvm_unreachable("unknown Config->EKind");
+ uint32_t EFlags = Config->IsLE ?
+ cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags :
+ cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags;
+ if (EFlags > 2) {
+ error("incompatible e_flags: " + toString(File));
+ return 0;
}
+ return EFlags;
}
uint32_t PPC64::calcEFlags() const {
assert(!ObjectFiles.empty());
- uint32_t Ret = getEFlags(ObjectFiles[0]);
- // Verify that all input files have the same e_flags.
- for (InputFile *F : makeArrayRef(ObjectFiles).slice(1)) {
- if (Ret == getEFlags(F))
+ uint32_t NonZeroFlag;
+ for (InputFile *F : makeArrayRef(ObjectFiles)) {
+ NonZeroFlag = getEFlags(F);
+ if (NonZeroFlag)
+ break;
+ }
+
+ // Verify that all input files have either the same e_flags, or zero.
+ for (InputFile *F : makeArrayRef(ObjectFiles)) {
+ uint32_t Flag = getEFlags(F);
+ if (Flag == 0 || Flag == NonZeroFlag)
continue;
- error("incompatible e_flags: " + toString(F));
+ error(toString(F) + ": ABI version " + Twine(Flag) +
+ " is not compatible with ABI version " + Twine(NonZeroFlag) +
+ " output");
return 0;
}
- return Ret;
+
+ if (NonZeroFlag == 1) {
+ error("PPC64 V1 ABI not supported");
+ return 0;
+ }
+
+ return 2;
}
RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
@@ -147,7 +150,7 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
case R_PPC64_TOC:
return R_PPC_TOC;
case R_PPC64_REL24:
- return R_PPC_PLT_OPD;
+ return R_PPC_CALL_PLT;
case R_PPC64_REL16_LO:
case R_PPC64_REL16_HA:
return R_PC;
@@ -157,8 +160,7 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
}
void PPC64::writeGotHeader(uint8_t *Buf) const {
- if (Config->EKind == ELF64LEKind)
- write64(Buf, getPPC64TocBase());
+ write64(Buf, getPPC64TocBase());
}
void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
@@ -166,37 +168,21 @@ void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
unsigned RelOff) const {
uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
- if (Config->EKind == ELF64LEKind) {
- // The most-common form of the plt stub. This assumes that the toc-pointer
- // register is properly initalized, and that the stub must save the toc
- // pointer value to the stack-save slot reserved for it (sp + 24).
- // There are 2 other variants but we don't have to emit those until we add
- // support for R_PPC64_REL24_NOTOC and R_PPC64_TOCSAVE relocations.
- // We are missing a super simple optimization, where if the upper 16 bits of
- // the offset are zero, then we can omit the addis instruction, and load
- // r2 + lo-offset directly into r12. I decided to leave this out in the
- // spirit of keeping it simple until we can link actual non-trivial
- // programs.
- write32(Buf + 0, 0xf8410018); // std r2,24(r1)
- write32(Buf + 4, 0x3d820000 | applyPPCHa(Off)); // addis r12,r2, X@plt@to@ha
- write32(Buf + 8, 0xe98c0000 | applyPPCLo(Off)); // ld r12,X@plt@toc@l(r12)
- write32(Buf + 12, 0x7d8903a6); // mtctr r12
- write32(Buf + 16, 0x4e800420); // bctr
- } else {
- // FIXME: What we should do, in theory, is get the offset of the function
- // descriptor in the .opd section, and use that as the offset from %r2 (the
- // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
- // be a pointer to the function descriptor in the .opd section. Using
- // this scheme is simpler, but requires an extra indirection per PLT dispatch.
- write32(Buf, 0xf8410028); // std %r2, 40(%r1)
- write32(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
- write32(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
- write32(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
- write32(Buf + 16, 0x7d6903a6); // mtctr %r11
- write32(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
- write32(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
- write32(Buf + 28, 0x4e800420); // bctr
- }
+ // The most-common form of the plt stub. This assumes that the toc-pointer
+ // register is properly initalized, and that the stub must save the toc
+ // pointer value to the stack-save slot reserved for it (sp + 24).
+ // There are 2 other variants but we don't have to emit those until we add
+ // support for R_PPC64_REL24_NOTOC and R_PPC64_TOCSAVE relocations.
+ // We are missing a super simple optimization, where if the upper 16 bits of
+ // the offset are zero, then we can omit the addis instruction, and load
+ // r2 + lo-offset directly into r12. I decided to leave this out in the
+ // spirit of keeping it simple until we can link actual non-trivial
+ // programs.
+ write32(Buf + 0, 0xf8410018); // std r2,24(r1)
+ write32(Buf + 4, 0x3d820000 | applyPPCHa(Off)); // addis r12,r2, X@plt@to@ha
+ write32(Buf + 8, 0xe98c0000 | applyPPCLo(Off)); // ld r12,X@plt@toc@l(r12)
+ write32(Buf + 12, 0x7d8903a6); // mtctr r12
+ write32(Buf + 16, 0x4e800420); // bctr
}
static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 77a50b6579d..48a385b6992 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -566,24 +566,15 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
case R_PLT:
return Sym.getPltVA() + A;
case R_PLT_PC:
- case R_PPC_PLT_OPD:
+ case R_PPC_CALL_PLT:
return Sym.getPltVA() + A - P;
- case R_PPC_OPD: {
+ case R_PPC_CALL: {
uint64_t SymVA = Sym.getVA(A);
// If we have an undefined weak symbol, we might get here with a symbol
// address of zero. That could overflow, but the code must be unreachable,
// so don't bother doing anything at all.
if (!SymVA)
return 0;
- if (Out::Opd) {
- // If this is a local call, and we currently have the address of a
- // function-descriptor, get the underlying code address instead.
- uint64_t OpdStart = Out::Opd->Addr;
- uint64_t OpdEnd = OpdStart + Out::Opd->Size;
- bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
- if (InOpd)
- SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]);
- }
// PPC64 V2 ABI describes two entry points to a function. The global entry
// point sets up the TOC base pointer. When calling a local function, the
@@ -749,7 +740,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
case R_RELAX_TLS_GD_TO_IE_END:
Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
break;
- case R_PPC_PLT_OPD:
+ case R_PPC_CALL_PLT:
// Patch a nop (0x60000000) to a ld.
if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) {
error(getErrorLocation(BufLoc) + "call lacks nop, can't restore toc");
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 325b5be4238..31e1d196db4 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -31,8 +31,6 @@ using namespace lld;
using namespace lld::elf;
uint8_t Out::First;
-OutputSection *Out::Opd;
-uint8_t *Out::OpdBuf;
PhdrEntry *Out::TlsPhdr;
OutputSection *Out::DebugInfo;
OutputSection *Out::ElfHeader;
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 514b9dafa8b..9720aab0e14 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -128,8 +128,6 @@ std::vector<InputSection *> getInputSections(OutputSection* OS);
// until Writer is initialized.
struct Out {
static uint8_t First;
- static OutputSection *Opd;
- static uint8_t *OpdBuf;
static PhdrEntry *TlsPhdr;
static OutputSection *DebugInfo;
static OutputSection *ElfHeader;
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 5f7e0083824..7463129fd07 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -312,7 +312,7 @@ static bool isAbsoluteValue(const Symbol &Sym) {
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
@@ -347,7 +347,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32,
R_MIPS_GOT_GP_PC, R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC,
R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC,
- R_TLSGD, R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE,
+ R_TLSGD, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE,
R_HINT>(E))
return true;
@@ -395,8 +395,8 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
static RelExpr toPlt(RelExpr Expr) {
switch (Expr) {
- case R_PPC_OPD:
- return R_PPC_PLT_OPD;
+ case R_PPC_CALL:
+ return R_PPC_CALL_PLT;
case R_PC:
return R_PLT_PC;
case R_PAGE_PC:
@@ -414,8 +414,8 @@ static RelExpr fromPlt(RelExpr Expr) {
switch (Expr) {
case R_PLT_PC:
return R_PC;
- case R_PPC_PLT_OPD:
- return R_PPC_OPD;
+ case R_PPC_CALL_PLT:
+ return R_PPC_CALL;
case R_PLT:
return R_ABS;
default:
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 69afe31ddfe..b139f4b3f16 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -59,8 +59,8 @@ enum RelExpr {
R_PLT,
R_PLT_PAGE_PC,
R_PLT_PC,
- R_PPC_OPD,
- R_PPC_PLT_OPD,
+ R_PPC_CALL,
+ R_PPC_CALL_PLT,
R_PPC_TOC,
R_RELAX_GOT_PC,
R_RELAX_GOT_PC_NOPIC,
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index c4ae8c78a67..bb5b39b4785 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -689,7 +689,6 @@ enum RankFlags {
RF_BSS = 1 << 8,
RF_NOTE = 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,
@@ -794,9 +793,6 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (Name != ".tocbss")
Rank |= RF_PPC_NOT_TOCBSS;
- if (Name == ".opd")
- Rank |= RF_PPC_OPD;
-
if (Name == ".toc1")
Rank |= RF_PPC_TOCL;
@@ -2295,14 +2291,6 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
- // PPC64 needs to process relocations in the .opd section
- // before processing relocations in code-containing sections.
- if (auto *OpdCmd = findSection(".opd")) {
- Out::Opd = OpdCmd;
- Out::OpdBuf = Buf + Out::Opd->Offset;
- OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
- }
-
OutputSection *EhFrameHdr = nullptr;
if (InX::EhFrameHdr && !InX::EhFrameHdr->empty())
EhFrameHdr = InX::EhFrameHdr->getParent();
@@ -2315,8 +2303,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
Sec->writeTo<ELFT>(Buf + Sec->Offset);
for (OutputSection *Sec : OutputSections)
- if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
- Sec->Type != SHT_RELA)
+ if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
OpenPOWER on IntegriCloud