diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/Support/ELF.h | 22 | ||||
-rw-r--r-- | llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp | 41 | ||||
-rw-r--r-- | llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp | 26 | ||||
-rw-r--r-- | llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp | 15 | ||||
-rw-r--r-- | llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp | 34 | ||||
-rw-r--r-- | llvm/lib/Target/PowerPC/PPCTargetStreamer.h | 1 | ||||
-rw-r--r-- | llvm/test/MC/PowerPC/ppc64-localentry-error1.s | 11 | ||||
-rw-r--r-- | llvm/test/MC/PowerPC/ppc64-localentry-error2.s | 12 | ||||
-rw-r--r-- | llvm/test/MC/PowerPC/ppc64-localentry.s | 58 |
9 files changed, 220 insertions, 0 deletions
diff --git a/llvm/include/llvm/Support/ELF.h b/llvm/include/llvm/Support/ELF.h index b8ab048a4b3..42abe8906ea 100644 --- a/llvm/include/llvm/Support/ELF.h +++ b/llvm/include/llvm/Support/ELF.h @@ -505,6 +505,28 @@ enum { EF_PPC64_ABI = 3 }; +// Special values for the st_other field in the symbol table entry for PPC64. +enum { + STO_PPC64_LOCAL_BIT = 5, + STO_PPC64_LOCAL_MASK = (7 << STO_PPC64_LOCAL_BIT) +}; +static inline int64_t +decodePPC64LocalEntryOffset(unsigned Other) { + unsigned Val = (Other & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT; + return ((1 << Val) >> 2) << 2; +} +static inline unsigned +encodePPC64LocalEntryOffset(int64_t Offset) { + unsigned Val = (Offset >= 4 * 4 + ? (Offset >= 8 * 4 + ? (Offset >= 16 * 4 ? 6 : 5) + : 4) + : (Offset >= 2 * 4 + ? 3 + : (Offset >= 1 * 4 ? 2 : 0))); + return Val << STO_PPC64_LOCAL_BIT; +} + // ELF Relocation types for PPC64 enum { R_PPC64_NONE = 0, diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp index 7560a7a1831..d7066d58709 100644 --- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" @@ -245,6 +246,7 @@ class PPCAsmParser : public MCTargetAsmParser { bool ParseDirectiveMachine(SMLoc L); bool ParseDarwinDirectiveMachine(SMLoc L); bool ParseDirectiveAbiVersion(SMLoc L); + bool ParseDirectiveLocalEntry(SMLoc L); bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -1415,6 +1417,8 @@ bool PPCAsmParser::ParseDirective(AsmToken DirectiveID) { return ParseDirectiveMachine(DirectiveID.getLoc()); if (IDVal == ".abiversion") return ParseDirectiveAbiVersion(DirectiveID.getLoc()); + if (IDVal == ".localentry") + return ParseDirectiveLocalEntry(DirectiveID.getLoc()); } else { if (IDVal == ".machine") return ParseDarwinDirectiveMachine(DirectiveID.getLoc()); @@ -1558,6 +1562,43 @@ bool PPCAsmParser::ParseDirectiveAbiVersion(SMLoc L) { return false; } +/// ParseDirectiveLocalEntry +/// ::= .localentry symbol, expression +bool PPCAsmParser::ParseDirectiveLocalEntry(SMLoc L) { + StringRef Name; + if (getParser().parseIdentifier(Name)) { + Error(L, "expected identifier in directive"); + return false; + } + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + + if (getLexer().isNot(AsmToken::Comma)) { + Error(L, "unexpected token in directive"); + return false; + } + Lex(); + + const MCExpr *Expr; + if (getParser().parseExpression(Expr)) { + Error(L, "expected expression"); + return false; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Error(L, "unexpected token in directive"); + return false; + } + + PPCTargetStreamer &TStreamer = + *static_cast<PPCTargetStreamer *>( + getParser().getStreamer().getTargetStreamer()); + TStreamer.emitLocalEntry(Sym, Expr); + + return false; +} + + + /// Force static initialization. extern "C" void LLVMInitializePowerPCAsmParser() { RegisterMCAsmParser<PPCAsmParser> A(ThePPC32Target); diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp index 12584bea5a3..c54d5e75bdf 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -9,7 +9,9 @@ #include "MCTargetDesc/PPCMCTargetDesc.h" #include "MCTargetDesc/PPCFixupKinds.h" +#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCELF.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCMachObjectWriter.h" @@ -128,6 +130,30 @@ public: } } + void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFixup &Fixup, const MCFragment *DF, + const MCValue &Target, uint64_t &Value, + bool &IsResolved) override { + switch ((PPC::Fixups)Fixup.getKind()) { + default: break; + case PPC::fixup_ppc_br24: + case PPC::fixup_ppc_br24abs: + // If the target symbol has a local entry point we must not attempt + // to resolve the fixup directly. Emit a relocation and leave + // resolution of the final target address to the linker. + if (const MCSymbolRefExpr *A = Target.getSymA()) { + const MCSymbolData &Data = Asm.getSymbolData(A->getSymbol()); + // The "other" values are stored in the last 6 bits of the second byte. + // The traditional defines for STO values assume the full byte and thus + // the shift to pack it. + unsigned Other = MCELF::getOther(Data) << 2; + if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0) + IsResolved = false; + } + break; + } + } + bool mayNeedRelaxation(const MCInst &Inst) const override { // FIXME. return false; diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp index ffe17e43180..a6fd3dd45fa 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp @@ -30,6 +30,8 @@ namespace { bool IsPCRel) const; unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const override; + + bool needsRelocateWithSymbol(unsigned Type) const override; }; } @@ -387,6 +389,19 @@ unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, return getRelocTypeInner(Target, Fixup, IsPCRel); } +bool PPCELFObjectWriter::needsRelocateWithSymbol(unsigned Type) const { + switch (Type) { + default: + return false; + + case ELF::R_PPC_REL24: + // FIXME: We only need to keep the target symbol of the relocation + // if the symbol uses a local entry point. Unfortunately, we do not + // have access to the symbol here ... + return true; + } +} + MCObjectWriter *llvm::createPPCELFObjectWriter(raw_ostream &OS, bool Is64Bit, bool IsLittleEndian, diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp index fa0e78ab3a7..4c6780ff75a 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -16,7 +16,9 @@ #include "PPCMCAsmInfo.h" #include "PPCTargetStreamer.h" #include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCELF.h" #include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" @@ -130,6 +132,9 @@ public: virtual void emitAbiVersion(int AbiVersion) override { OS << "\t.abiversion " << AbiVersion << '\n'; } + virtual void emitLocalEntry(MCSymbol *S, const MCExpr *LocalOffset) { + OS << "\t.localentry\t" << *S << ", " << *LocalOffset << '\n'; + } }; class PPCTargetELFStreamer : public PPCTargetStreamer { @@ -153,6 +158,32 @@ public: Flags |= (AbiVersion & ELF::EF_PPC64_ABI); MCA.setELFHeaderEFlags(Flags); } + virtual void emitLocalEntry(MCSymbol *S, const MCExpr *LocalOffset) { + MCAssembler &MCA = getStreamer().getAssembler(); + MCSymbolData &Data = getStreamer().getOrCreateSymbolData(S); + + int64_t Res; + if (!LocalOffset->EvaluateAsAbsolute(Res, MCA)) + report_fatal_error(".localentry expression must be absolute."); + + unsigned Encoded = ELF::encodePPC64LocalEntryOffset(Res); + if (Res != ELF::decodePPC64LocalEntryOffset(Encoded)) + report_fatal_error(".localentry expression cannot be encoded."); + + // The "other" values are stored in the last 6 bits of the second byte. + // The traditional defines for STO values assume the full byte and thus + // the shift to pack it. + unsigned Other = MCELF::getOther(Data) << 2; + Other &= ~ELF::STO_PPC64_LOCAL_MASK; + Other |= Encoded; + MCELF::setOther(Data, Other >> 2); + + // For GAS compatibility, unless we already saw a .abiversion directive, + // set e_flags to indicate ELFv2 ABI. + unsigned Flags = MCA.getELFHeaderEFlags(); + if ((Flags & ELF::EF_PPC64_ABI) == 0) + MCA.setELFHeaderEFlags(Flags | 2); + } }; class PPCTargetMachOStreamer : public PPCTargetStreamer { @@ -168,6 +199,9 @@ public: virtual void emitAbiVersion(int AbiVersion) override { llvm_unreachable("Unknown pseudo-op: .abiversion"); } + virtual void emitLocalEntry(MCSymbol *S, const MCExpr *LocalOffset) { + llvm_unreachable("Unknown pseudo-op: .localentry"); + } }; } diff --git a/llvm/lib/Target/PowerPC/PPCTargetStreamer.h b/llvm/lib/Target/PowerPC/PPCTargetStreamer.h index 9baf57d4c72..73fb6910135 100644 --- a/llvm/lib/Target/PowerPC/PPCTargetStreamer.h +++ b/llvm/lib/Target/PowerPC/PPCTargetStreamer.h @@ -20,6 +20,7 @@ public: virtual void emitTCEntry(const MCSymbol &S) = 0; virtual void emitMachine(StringRef CPU) = 0; virtual void emitAbiVersion(int AbiVersion) = 0; + virtual void emitLocalEntry(MCSymbol *S, const MCExpr *LocalOffset) = 0; }; } diff --git a/llvm/test/MC/PowerPC/ppc64-localentry-error1.s b/llvm/test/MC/PowerPC/ppc64-localentry-error1.s new file mode 100644 index 00000000000..e47640fbeb0 --- /dev/null +++ b/llvm/test/MC/PowerPC/ppc64-localentry-error1.s @@ -0,0 +1,11 @@ + +# RUN: not llvm-mc -triple powerpc64-unknown-unknown -filetype=obj < %s 2> %t +# RUN: FileCheck < %t %s +# RUN: not llvm-mc -triple powerpc64le-unknown-unknown -filetype=obj < %s 2> %t +# RUN: FileCheck < %t %s + +sym: + .localentry sym, 123 + +# CHECK: LLVM ERROR: .localentry expression cannot be encoded. + diff --git a/llvm/test/MC/PowerPC/ppc64-localentry-error2.s b/llvm/test/MC/PowerPC/ppc64-localentry-error2.s new file mode 100644 index 00000000000..b05687fe7b6 --- /dev/null +++ b/llvm/test/MC/PowerPC/ppc64-localentry-error2.s @@ -0,0 +1,12 @@ + +# RUN: not llvm-mc -triple powerpc64-unknown-unknown -filetype=obj < %s 2> %t +# RUN: FileCheck < %t %s +# RUN: not llvm-mc -triple powerpc64le-unknown-unknown -filetype=obj < %s 2> %t +# RUN: FileCheck < %t %s + + .globl remote_sym +sym: + .localentry sym, remote_sym + +# CHECK: LLVM ERROR: .localentry expression must be absolute. + diff --git a/llvm/test/MC/PowerPC/ppc64-localentry.s b/llvm/test/MC/PowerPC/ppc64-localentry.s new file mode 100644 index 00000000000..f30b192d5e2 --- /dev/null +++ b/llvm/test/MC/PowerPC/ppc64-localentry.s @@ -0,0 +1,58 @@ + +# RUN: llvm-mc -triple powerpc64-unknown-unknown -filetype=obj %s | \ +# RUN: llvm-readobj -h -r -symbols | FileCheck %s +# RUN: llvm-mc -triple powerpc64le-unknown-unknown -filetype=obj %s | \ +# RUN: llvm-readobj -h -r -symbols | FileCheck %s + + .type callee1, @function +callee1: + nop + nop + .localentry callee1, .-callee1 + nop + nop + .size callee1, .-callee1 + + .type callee2, @function +callee2: + nop + nop + .size callee2, .-callee2 + + .type caller, @function +caller: + bl callee1 + nop + bl callee2 + nop + .size caller, .-caller + +# Verify that use of .localentry implies ABI version 2 +# CHECK: ElfHeader { +# CHECK: Flags [ (0x2) + +# Verify that fixups to local function symbols are performed only +# if the target symbol does not use .localentry +# CHECK: Relocations [ +# CHECK: Section ({{[0-9]*}}) .rela.text { +# CHECK-NEXT: R_PPC64_REL24 callee1 +# CHECK-NEXT: } +# CHECK-NOT: R_PPC64_REL24 callee2 + +# Verify that .localentry is encoded in the Other field. +# CHECK: Symbols [ +# CHECK: Name: callee1 +# CHECK-NEXT: Value: +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: Function +# CHECK-NEXT: Other: 96 +# CHECK-NEXT: Section: .text +# CHECK: Name: callee2 +# CHECK-NEXT: Value: +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: Function +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text + |