diff options
Diffstat (limited to 'lld/ELF')
-rw-r--r-- | lld/ELF/Arch/PPC64.cpp | 114 | ||||
-rw-r--r-- | lld/ELF/InputSection.cpp | 15 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 2 | ||||
-rw-r--r-- | lld/ELF/Relocations.cpp | 12 | ||||
-rw-r--r-- | lld/ELF/Relocations.h | 4 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 15 |
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 |