From aa71428378c1cb491ca60041d8ba7aa110bc963d Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Thu, 25 Oct 2012 12:27:42 +0000 Subject: Initial TOC support for PowerPC64 object creation This patch adds initial PPC64 TOC MC object creation using the small mcmodel (a single 64K TOC) adding the some TOC relocations (R_PPC64_TOC, R_PPC64_TOC16, and R_PPC64_TOC16DS). The addition of 'undefinedExplicitRelSym' hook on 'MCELFObjectTargetWriter' is meant to avoid the creation of an unreferenced ".TOC." symbol (used in the .odp creation) as well to set the R_PPC64_TOC relocation target as the temporary ".TOC." symbol. On PPC64 ABI, the R_PPC64_TOC relocation should not point to any symbol. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@166677 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCELFObjectWriter.h | 3 + lib/MC/ELFObjectWriter.cpp | 18 ++++-- lib/MC/MCELFObjectTargetWriter.cpp | 8 +++ lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp | 13 +++- .../PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp | 70 ++++++++++++++++++++-- lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h | 10 ++++ .../PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp | 32 ++++++++-- lib/Target/PowerPC/PPCAsmPrinter.cpp | 8 ++- lib/Target/PowerPC/PPCSubtarget.cpp | 13 +++- test/MC/PowerPC/lit.local.cfg | 5 ++ test/MC/PowerPC/ppc64-relocs-01.ll | 66 ++++++++++++++++++++ 11 files changed, 223 insertions(+), 23 deletions(-) create mode 100644 test/MC/PowerPC/lit.local.cfg create mode 100644 test/MC/PowerPC/ppc64-relocs-01.ll diff --git a/include/llvm/MC/MCELFObjectWriter.h b/include/llvm/MC/MCELFObjectWriter.h index abbe188fe8..4ffea8de15 100644 --- a/include/llvm/MC/MCELFObjectWriter.h +++ b/include/llvm/MC/MCELFObjectWriter.h @@ -85,6 +85,9 @@ public: const MCFragment &F, const MCFixup &Fixup, bool IsPCRel) const; + virtual const MCSymbol *undefinedExplicitRelSym(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const; virtual void adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset); diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index b8b3188ce4..eda062376e 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -133,6 +133,11 @@ class ELFObjectWriter : public MCObjectWriter { bool IsPCRel) const { return TargetObjectWriter->ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); } + const MCSymbol *undefinedExplicitRelSym(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + return TargetObjectWriter->undefinedExplicitRelSym(Target, Fixup, IsPCRel); + } bool is64Bit() const { return TargetObjectWriter->is64Bit(); } bool hasRelocationAddend() const { @@ -639,7 +644,7 @@ const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm, if (ASymbol.isUndefined()) { if (Renamed) return Renamed; - return &ASymbol; + return undefinedExplicitRelSym(Target, Fixup, IsPCRel); } if (SD.isExternal()) { @@ -721,10 +726,13 @@ void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, MCSymbolData &SD = Asm.getSymbolData(ASymbol); MCFragment *F = SD.getFragment(); - Index = F->getParent()->getOrdinal() + 1; - - // Offset of the symbol in the section - Value += Layout.getSymbolOffset(&SD); + if (F) { + Index = F->getParent()->getOrdinal() + 1; + // Offset of the symbol in the section + Value += Layout.getSymbolOffset(&SD); + } else { + Index = 0; + } } else { if (Asm.getSymbolData(Symbol).getFlags() & ELF_Other_Weakref) WeakrefUsedInReloc.insert(RelocSymbol); diff --git a/lib/MC/MCELFObjectTargetWriter.cpp b/lib/MC/MCELFObjectTargetWriter.cpp index 6eb6914f4b..74cd042a0f 100644 --- a/lib/MC/MCELFObjectTargetWriter.cpp +++ b/lib/MC/MCELFObjectTargetWriter.cpp @@ -9,6 +9,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" using namespace llvm; @@ -35,6 +37,12 @@ const MCSymbol *MCELFObjectTargetWriter::ExplicitRelSym(const MCAssembler &Asm, return NULL; } +const MCSymbol *MCELFObjectTargetWriter::undefinedExplicitRelSym(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + return &Symbol.AliasedSymbol(); +} void MCELFObjectTargetWriter::adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset) { diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp index 1744738622..87ecb13a4c 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -29,9 +29,14 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { case FK_Data_1: case FK_Data_2: case FK_Data_4: + case FK_Data_8: + case PPC::fixup_ppc_toc: return Value; + case PPC::fixup_ppc_lo14: + case PPC::fixup_ppc_toc16_ds: + return (Value & 0xffff) << 2; case PPC::fixup_ppc_brcond14: - return Value & 0x3ffc; + return Value & 0xfffc; case PPC::fixup_ppc_br24: return Value & 0x3fffffc; #if 0 @@ -41,6 +46,7 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { case PPC::fixup_ppc_ha16: return ((Value >> 16) + ((Value & 0x8000) ? 1 : 0)) & 0xffff; case PPC::fixup_ppc_lo16: + case PPC::fixup_ppc_toc16: return Value & 0xffff; } } @@ -72,7 +78,10 @@ public: { "fixup_ppc_brcond14", 16, 14, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_ppc_lo16", 16, 16, 0 }, { "fixup_ppc_ha16", 16, 16, 0 }, - { "fixup_ppc_lo14", 16, 14, 0 } + { "fixup_ppc_lo14", 16, 14, 0 }, + { "fixup_ppc_toc", 0, 64, 0 }, + { "fixup_ppc_toc16", 16, 16, 0 }, + { "fixup_ppc_toc16_ds", 16, 14, 0 } }; if (Kind < FirstTargetFixupKind) diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp index a19798157b..de3c3523a9 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp @@ -11,6 +11,8 @@ #include "MCTargetDesc/PPCMCTargetDesc.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" using namespace llvm; @@ -21,9 +23,15 @@ namespace { virtual ~PPCELFObjectWriter(); protected: + virtual unsigned getRelocTypeInner(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const; virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel, bool IsRelocWithSymbol, int64_t Addend) const; + virtual const MCSymbol *undefinedExplicitRelSym(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const; virtual void adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset); }; } @@ -36,11 +44,13 @@ PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI) PPCELFObjectWriter::~PPCELFObjectWriter() { } -unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, - const MCFixup &Fixup, - bool IsPCRel, - bool IsRelocWithSymbol, - int64_t Addend) const { +unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const +{ + MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? + MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); + // determine the type of the relocation unsigned Type; if (IsPCRel) { @@ -61,7 +71,7 @@ unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, Type = ELF::R_PPC_ADDR24; break; case PPC::fixup_ppc_brcond14: - Type = ELF::R_PPC_ADDR14_BRTAKEN; // XXX: or BRNTAKEN?_ + Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_ break; case PPC::fixup_ppc_ha16: Type = ELF::R_PPC_ADDR16_HA; @@ -72,6 +82,26 @@ unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, case PPC::fixup_ppc_lo14: Type = ELF::R_PPC_ADDR14; break; + case PPC::fixup_ppc_toc: + Type = ELF::R_PPC64_TOC; + break; + case PPC::fixup_ppc_toc16: + Type = ELF::R_PPC64_TOC16; + break; + case PPC::fixup_ppc_toc16_ds: + Type = ELF::R_PPC64_TOC16_DS; + break; + case FK_Data_8: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_PPC_TOC: + Type = ELF::R_PPC64_TOC; + break; + case MCSymbolRefExpr::VK_None: + Type = ELF::R_PPC64_ADDR64; + break; + } + break; case FK_Data_4: Type = ELF::R_PPC_ADDR32; break; @@ -83,6 +113,34 @@ unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, return Type; } +unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) const { + return getRelocTypeInner(Target, Fixup, IsPCRel); +} + +const MCSymbol *PPCELFObjectWriter::undefinedExplicitRelSym(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + assert(Target.getSymA() && "SymA cannot be 0"); + const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol(); + + unsigned RelocType = getRelocTypeInner(Target, Fixup, IsPCRel); + + // The .odp creation emits a relocation against the symbol ".TOC." which + // create a R_PPC64_TOC relocation. However the relocation symbol name + // in final object creation should be NULL, since the symbol does not + // really exist, it is just the reference to TOC base for the current + // object file. + bool EmitThisSym = RelocType != ELF::R_PPC64_TOC; + + if (EmitThisSym && !Symbol.isTemporary()) + return &Symbol; + return NULL; +} + void PPCELFObjectWriter:: adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset) { switch ((unsigned)Fixup.getKind()) { diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h b/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h index b3c889e3f8..37b265e7fd 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h +++ b/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h @@ -34,6 +34,16 @@ enum Fixups { /// fixup_ppc_lo14 - A 14-bit fixup corresponding to lo16(_foo) for instrs /// like 'std'. fixup_ppc_lo14, + + /// fixup_ppc_toc - Insert value of TOC base (.TOC.). + fixup_ppc_toc, + + /// fixup_ppc_toc16 - A 16-bit signed fixup relative to the TOC base. + fixup_ppc_toc16, + + /// fixup_ppc_toc16_ds - A 14-bit signed fixup relative to the TOC base with + /// implied 2 zero bits + fixup_ppc_toc16_ds, // Marker LastTargetFixupKind, diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp index 1fba5b8dc3..635d6c80f0 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -15,7 +15,9 @@ #include "MCTargetDesc/PPCBaseInfo.h" #include "MCTargetDesc/PPCFixupKinds.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" @@ -28,13 +30,25 @@ class PPCMCCodeEmitter : public MCCodeEmitter { PPCMCCodeEmitter(const PPCMCCodeEmitter &) LLVM_DELETED_FUNCTION; void operator=(const PPCMCCodeEmitter &) LLVM_DELETED_FUNCTION; + const MCSubtargetInfo &STI; + Triple TT; + public: PPCMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti, - MCContext &ctx) { + MCContext &ctx) + : STI(sti), TT(STI.getTargetTriple()) { } ~PPCMCCodeEmitter() {} + bool is64BitMode() const { + return (STI.getFeatureBits() & PPC::Feature64Bit) != 0; + } + + bool isSVR4ABI() const { + return TT.isMacOSX() == 0; + } + unsigned getDirectBrEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups) const; unsigned getCondBrEncoding(const MCInst &MI, unsigned OpNo, @@ -140,8 +154,12 @@ unsigned PPCMCCodeEmitter::getMemRIEncoding(const MCInst &MI, unsigned OpNo, return (getMachineOpValue(MI, MO, Fixups) & 0xFFFF) | RegBits; // Add a fixup for the displacement field. - Fixups.push_back(MCFixup::Create(0, MO.getExpr(), - (MCFixupKind)PPC::fixup_ppc_lo16)); + if (isSVR4ABI() && is64BitMode()) + Fixups.push_back(MCFixup::Create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_toc16)); + else + Fixups.push_back(MCFixup::Create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_lo16)); return RegBits; } @@ -158,8 +176,12 @@ unsigned PPCMCCodeEmitter::getMemRIXEncoding(const MCInst &MI, unsigned OpNo, return (getMachineOpValue(MI, MO, Fixups) & 0x3FFF) | RegBits; // Add a fixup for the branch target. - Fixups.push_back(MCFixup::Create(0, MO.getExpr(), - (MCFixupKind)PPC::fixup_ppc_lo14)); + if (isSVR4ABI() && is64BitMode()) + Fixups.push_back(MCFixup::Create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_toc16_ds)); + else + Fixups.push_back(MCFixup::Create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_lo14)); return RegBits; } diff --git a/lib/Target/PowerPC/PPCAsmPrinter.cpp b/lib/Target/PowerPC/PPCAsmPrinter.cpp index d8abd9fba0..6941413ed4 100644 --- a/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -420,10 +420,14 @@ void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() { OutStreamer.EmitValueToAlignment(8); MCSymbol *Symbol1 = OutContext.GetOrCreateSymbol(".L." + Twine(CurrentFnSym->getName())); - MCSymbol *Symbol2 = OutContext.GetOrCreateSymbol(StringRef(".TOC.@tocbase")); + // Generates a R_PPC64_ADDR64 (from FK_DATA_8) relocation for the function + // entry point. OutStreamer.EmitValue(MCSymbolRefExpr::Create(Symbol1, OutContext), 8/*size*/, 0/*addrspace*/); - OutStreamer.EmitValue(MCSymbolRefExpr::Create(Symbol2, OutContext), + MCSymbol *Symbol2 = OutContext.GetOrCreateSymbol(StringRef(".TOC.")); + // Generates a R_PPC64_TOC relocation for TOC base insertion. + OutStreamer.EmitValue(MCSymbolRefExpr::Create(Symbol2, + MCSymbolRefExpr::VK_PPC_TOC, OutContext), 8/*size*/, 0/*addrspace*/); // Emit a null environment pointer. OutStreamer.EmitIntValue(0, 8 /* size */, 0 /* addrspace */); diff --git a/lib/Target/PowerPC/PPCSubtarget.cpp b/lib/Target/PowerPC/PPCSubtarget.cpp index 14b8534d1c..9c8cb92cc7 100644 --- a/lib/Target/PowerPC/PPCSubtarget.cpp +++ b/lib/Target/PowerPC/PPCSubtarget.cpp @@ -54,19 +54,26 @@ PPCSubtarget::PPCSubtarget(const std::string &TT, const std::string &CPU, CPUName = sys::getHostCPUName(); #endif - // Parse features string. - ParseSubtargetFeatures(CPUName, FS); - // Initialize scheduling itinerary for the specified CPU. InstrItins = getInstrItineraryForCPU(CPUName); + // Make sure 64-bit features are available when CPUname is generic + std::string FullFS = FS; + // If we are generating code for ppc64, verify that options make sense. if (is64Bit) { Has64BitSupport = true; // Silently force 64-bit register use on ppc64. Use64BitRegs = true; + if (!FullFS.empty()) + FullFS = "+64bit," + FullFS; + else + FullFS = "+64bit"; } + // Parse features string. + ParseSubtargetFeatures(CPUName, FullFS); + // If the user requested use of 64-bit regs, but the cpu selected doesn't // support it, ignore. if (use64BitRegs() && !has64BitSupport()) diff --git a/test/MC/PowerPC/lit.local.cfg b/test/MC/PowerPC/lit.local.cfg new file mode 100644 index 0000000000..88488cdd04 --- /dev/null +++ b/test/MC/PowerPC/lit.local.cfg @@ -0,0 +1,5 @@ +config.suffixes = ['.ll', '.c', '.cpp', '.s'] + +targets = set(config.root.targets_to_build.split()) +if not 'PowerPC' in targets: + config.unsupported = True diff --git a/test/MC/PowerPC/ppc64-relocs-01.ll b/test/MC/PowerPC/ppc64-relocs-01.ll new file mode 100644 index 0000000000..5996af84f4 --- /dev/null +++ b/test/MC/PowerPC/ppc64-relocs-01.ll @@ -0,0 +1,66 @@ +;; RUN: llc -mtriple=powerpc64-unknown-linux-gnu -O3 \ +;; RUN: -filetype=obj %s -o - | \ +;; RUN: elf-dump --dump-section-data | FileCheck %s + +;; FIXME: this file need to be in .s form, change when asm parse is done. + +@number64 = global i64 10, align 8 + +define i64 @access_int64(i64 %a) nounwind readonly { +entry: + %0 = load i64* @number64, align 8 + %cmp = icmp eq i64 %0, %a + %conv1 = zext i1 %cmp to i64 + ret i64 %conv1 +} + +declare double @sin(double) nounwind + +define double @test_branch24 (double %x) nounwind readonly { +entry: + %add = call double @sin(double %x) nounwind + ret double %add +} + +;; The relocations in .rela.text are the 'number64' load using a +;; R_PPC64_TOC16_DS against the .toc and the 'sin' external function +;; address using a R_PPC64_REL24 +;; CHECK: '.rela.text' +;; CHECK: Relocation 0 +;; CHECK-NEXT: 'r_offset', +;; CHECK-NEXT: 'r_sym', 0x00000006 +;; CHECK-NEXT: 'r_type', 0x0000003f +;; CHECK: Relocation 1 +;; CHECK-NEXT: 'r_offset', +;; CHECK-NEXT: 'r_sym', 0x0000000a +;; CHECK-NEXT: 'r_type', 0x0000000a + +;; The .opd entry for the 'access_int64' function creates 2 relocations: +;; 1. A R_PPC64_ADDR64 against the .text segment plus addend (the function +; address itself); +;; 2. And a R_PPC64_TOC against no symbol (the linker will replace for the +;; module's TOC base). +;; CHECK: '.rela.opd' +;; CHECK: Relocation 0 +;; CHECK-NEXT: 'r_offset', +;; CHECK-NEXT: 'r_sym', 0x00000002 +;; CHECK-NEXT: 'r_type', 0x00000026 +;; CHECK: Relocation 1 +;; CHECK-NEXT: 'r_offset', +;; CHECK-NEXT: 'r_sym', 0x00000000 +;; CHECK-NEXT: 'r_type', 0x00000033 + +;; Finally the TOC creates the relocation for the 'number64'. +;; CHECK: '.rela.toc' +;; CHECK: Relocation 0 +;; CHECK-NEXT: 'r_offset', +;; CHECK-NEXT: 'r_sym', 0x00000008 +;; CHECK-NEXT: 'r_type', 0x00000026 + +;; Check if the relocation references are for correct symbols. +;; CHECK: Symbol 7 +;; CHECK-NEXT: 'access_int64' +;; CHECK: Symbol 8 +;; CHECK-NEXT: 'number64' +;; CHECK: Symbol 10 +;; CHECK-NEXT: 'sin' -- cgit v1.2.3-18-g5258