summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/Support/ELF.h22
-rw-r--r--llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp41
-rw-r--r--llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp26
-rw-r--r--llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp15
-rw-r--r--llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp34
-rw-r--r--llvm/lib/Target/PowerPC/PPCTargetStreamer.h1
-rw-r--r--llvm/test/MC/PowerPC/ppc64-localentry-error1.s11
-rw-r--r--llvm/test/MC/PowerPC/ppc64-localentry-error2.s12
-rw-r--r--llvm/test/MC/PowerPC/ppc64-localentry.s58
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
+
OpenPOWER on IntegriCloud