diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index cbe7a9a2fa85e..53b9c96f0c08e 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -370,10 +370,12 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo { ABI = "elfv1"; } - switch (getTriple().getOS()) { + switch (Triple.getOS()) { case llvm::Triple::FreeBSD: LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + if (Triple.getOSMajorVersion() >= 13) + ABI = "elfv2"; break; default: break; diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index ec70c0a11f70f..4109549a911b1 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -234,6 +234,31 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, } #endif +#if defined(_LIBUNWIND_TARGET_PPC64) +#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1) +#define PPC64_ELFV1_R2_OFFSET 40 +#define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1) +#define PPC64_ELFV2_R2_OFFSET 24 + // If the instruction at return address is a TOC (r2) restore, + // then r2 was saved and needs to be restored. + // ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24, + // while in ELFv1 ABI it is saved at SP + 40. + if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) { + pint_t sp = newRegisters.getRegister(UNW_REG_SP); + pint_t r2 = 0; + switch (addressSpace.get32(returnAddress)) { + case PPC64_ELFV1_R2_LOAD_INST_ENCODING: + r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET); + break; + case PPC64_ELFV2_R2_LOAD_INST_ENCODING: + r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET); + break; + } + if (r2) + newRegisters.setRegister(UNW_PPC64_R2, r2); + } +#endif + // Return address is address after call site instruction, so setting IP to // that does simualates a return. newRegisters.setIP(returnAddress); diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h index 2df930214fae5..70964710b8223 100644 --- a/libunwind/src/assembly.h +++ b/libunwind/src/assembly.h @@ -37,6 +37,20 @@ #define SEPARATOR ; #endif +#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1) +#define PPC64_OPD1 .section .opd,"aw",@progbits SEPARATOR +#define PPC64_OPD2 SEPARATOR \ + .p2align 3 SEPARATOR \ + .quad .Lfunc_begin0 SEPARATOR \ + .quad .TOC.@tocbase SEPARATOR \ + .quad 0 SEPARATOR \ + .text SEPARATOR \ +.Lfunc_begin0: +#else +#define PPC64_OPD1 +#define PPC64_OPD2 +#endif + #define GLUE2(a, b) a ## b #define GLUE(a, b) GLUE2(a, b) #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) @@ -97,13 +111,17 @@ .globl SYMBOL_NAME(name) SEPARATOR \ EXPORT_SYMBOL(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ - SYMBOL_NAME(name): + PPC64_OPD1 \ + SYMBOL_NAME(name): \ + PPC64_OPD2 #define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \ .globl SYMBOL_NAME(name) SEPARATOR \ HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ - SYMBOL_NAME(name): + PPC64_OPD1 \ + SYMBOL_NAME(name): \ + PPC64_OPD2 #if defined(__arm__) #if !defined(__ARM_ARCH) diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp index 8a320c9a4e9ef..5048090f9d29b 100644 --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -123,6 +123,7 @@ class PPC64 final : public TargetInfo { bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, uint8_t StOther) const override; + uint32_t getThunkSectionSpacing() const override; }; } // namespace @@ -925,6 +926,23 @@ bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, return true; } + +uint32_t PPC64::getThunkSectionSpacing() const { + // The placing of pre-created ThunkSections is controlled by the value + // ThunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to + // place the ThunkSection such that all branches from the InputSections + // prior to the ThunkSection can reach a Thunk placed at the end of the + // ThunkSection. Graphically: + // | up to ThunkSectionSpacing .text input sections | + // | ThunkSection | + // | up to ThunkSectionSpacing .text input sections | + // | ThunkSection | + // + // On PowerPC64, we return the PPC64_REL14 relocation range + return 0x8000; +} + + TargetInfo *elf::getPPC64TargetInfo() { static PPC64 Target; return &Target; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index b1a3f8bc70aec..10675588ebe2e 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -2001,6 +2001,11 @@ template void SymbolTableSection::writeTo(uint8_t *Buf) { ESym->setVisibility(Sym->Visibility); } + // The 3 most significant bits of st_other are used by OpenPOWER ABI. + // See getPPC64GlobalEntryToLocalEntryOffset() for more details. + if (Config->EMachine == EM_PPC64) + ESym->st_other |= Sym->StOther & 0xe0; + ESym->st_name = Ent.StrTabOffset; ESym->st_shndx = getSymSectionIndex(Ent.Sym); diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index ade858113a300..1b505776ca19b 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -1271,6 +1271,7 @@ void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, // This is the first place we are able to copy this information. Alias->setExternal(Symbol.isExternal()); Alias->setBinding(Symbol.getBinding()); + Alias->setOther(Symbol.getOther()); if (!Symbol.isUndefined() && !Rest.startswith("@@@")) continue; diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp index a1e4e07b25af4..aaa5dd3fed86c 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -36,6 +36,8 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" +#include + using namespace llvm; #define GET_INSTRINFO_MC_DESC @@ -182,16 +184,35 @@ class PPCTargetELFStreamer : public PPCTargetStreamer { void emitAssignment(MCSymbol *S, const MCExpr *Value) override { auto *Symbol = cast(S); + + auto I = UpdateOther.find(Symbol); + if (I != UpdateOther.end()) + UpdateOther.erase(I); + // When encoding an assignment to set symbol A to symbol B, also copy // the st_other bits encoding the local entry point offset. - if (Value->getKind() != MCExpr::SymbolRef) - return; - const auto &RhsSym = cast( - static_cast(Value)->getSymbol()); - unsigned Other = Symbol->getOther(); + if (copyLocalEntry(Symbol, Value)) + UpdateOther.insert(Symbol); + } + + void finish() override { + for (auto *Sym : UpdateOther) + copyLocalEntry(Sym, Sym->getVariableValue()); + } + +private: + std::set UpdateOther; + + bool copyLocalEntry(MCSymbolELF *D, const MCExpr *S) { + if (S->getKind() != MCExpr::SymbolRef) + return false; + const auto &RhsSym = + cast(static_cast(S)->getSymbol()); + unsigned Other = D->getOther(); Other &= ~ELF::STO_PPC64_LOCAL_MASK; Other |= RhsSym.getOther() & ELF::STO_PPC64_LOCAL_MASK; - Symbol->setOther(Other); + D->setOther(Other); + return true; } }; diff --git a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp index 580d057602f5f..e7358f2971004 100644 --- a/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp +++ b/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp @@ -195,6 +195,20 @@ static PPCTargetMachine::PPCABI computeTargetABI(const Triple &TT, if (TT.isMacOSX()) return PPCTargetMachine::PPC_ABI_UNKNOWN; + if (TT.isOSFreeBSD()) { + switch (TT.getArch()) { + case Triple::ppc64le: + case Triple::ppc64: + if (TT.getOSMajorVersion() >= 13) + return PPCTargetMachine::PPC_ABI_ELFv2; + else + return PPCTargetMachine::PPC_ABI_ELFv1; + case Triple::ppc: + default: + return PPCTargetMachine::PPC_ABI_UNKNOWN; + } + } + switch (TT.getArch()) { case Triple::ppc64le: return PPCTargetMachine::PPC_ABI_ELFv2;