57 changes: 45 additions & 12 deletions llvm/lib/Target/PowerPC/PPCISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1491,10 +1491,9 @@ static bool GetLabelAccessInfo(const TargetMachine &TM, unsigned &HiOpFlags,
HiOpFlags = PPCII::MO_HA;
LoOpFlags = PPCII::MO_LO;

// Don't use the pic base if not in PIC relocation model. Or if we are on a
// non-darwin platform. We don't support PIC on other platforms yet.
bool isPIC = TM.getRelocationModel() == Reloc::PIC_ &&
TM.getSubtarget<PPCSubtarget>().isDarwin();
// Don't use the pic base if not in PIC relocation model.
bool isPIC = TM.getRelocationModel() == Reloc::PIC_;

if (isPIC) {
HiOpFlags |= PPCII::MO_PIC_FLAG;
LoOpFlags |= PPCII::MO_PIC_FLAG;
Expand Down Expand Up @@ -1550,6 +1549,15 @@ SDValue PPCTargetLowering::LowerConstantPool(SDValue Op,

unsigned MOHiFlag, MOLoFlag;
bool isPIC = GetLabelAccessInfo(DAG.getTarget(), MOHiFlag, MOLoFlag);

if (isPIC && Subtarget.isSVR4ABI()) {
SDValue GA = DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment(),
PPCII::MO_PIC_FLAG);
SDLoc DL(CP);
return DAG.getNode(PPCISD::TOC_ENTRY, DL, MVT::i32, GA,
DAG.getNode(PPCISD::GlobalBaseReg, DL, PtrVT));
}

SDValue CPIHi =
DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment(), 0, MOHiFlag);
SDValue CPILo =
Expand All @@ -1571,6 +1579,15 @@ SDValue PPCTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const {

unsigned MOHiFlag, MOLoFlag;
bool isPIC = GetLabelAccessInfo(DAG.getTarget(), MOHiFlag, MOLoFlag);

if (isPIC && Subtarget.isSVR4ABI()) {
SDValue GA = DAG.getTargetJumpTable(JT->getIndex(), PtrVT,
PPCII::MO_PIC_FLAG);
SDLoc DL(GA);
return DAG.getNode(PPCISD::TOC_ENTRY, SDLoc(JT), PtrVT, GA,
DAG.getNode(PPCISD::GlobalBaseReg, DL, PtrVT));
}

SDValue JTIHi = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, MOHiFlag);
SDValue JTILo = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, MOLoFlag);
return LowerLabelRef(JTIHi, JTILo, isPIC, DAG);
Expand Down Expand Up @@ -1700,6 +1717,14 @@ SDValue PPCTargetLowering::LowerGlobalAddress(SDValue Op,
unsigned MOHiFlag, MOLoFlag;
bool isPIC = GetLabelAccessInfo(DAG.getTarget(), MOHiFlag, MOLoFlag, GV);

if (isPIC && Subtarget.isSVR4ABI()) {
SDValue GA = DAG.getTargetGlobalAddress(GV, DL, PtrVT,
GSDN->getOffset(),
PPCII::MO_PIC_FLAG);
return DAG.getNode(PPCISD::TOC_ENTRY, DL, MVT::i32, GA,
DAG.getNode(PPCISD::GlobalBaseReg, DL, MVT::i32));
}

SDValue GAHi =
DAG.getTargetGlobalAddress(GV, DL, PtrVT, GSDN->getOffset(), MOHiFlag);
SDValue GALo =
Expand Down Expand Up @@ -3357,15 +3382,18 @@ unsigned PrepareCall(SelectionDAG &DAG, SDValue &Callee, SDValue &InFlag,
// far-call stubs may be outside relocation limits for a BL instruction.
if (!DAG.getTarget().getSubtarget<PPCSubtarget>().isJITCodeModel()) {
unsigned OpFlags = 0;
if (DAG.getTarget().getRelocationModel() != Reloc::Static &&
if ((DAG.getTarget().getRelocationModel() != Reloc::Static &&
(Subtarget.getTargetTriple().isMacOSX() &&
Subtarget.getTargetTriple().isMacOSXVersionLT(10, 5)) &&
(G->getGlobal()->isDeclaration() ||
G->getGlobal()->isWeakForLinker())) {
G->getGlobal()->isWeakForLinker())) ||
(Subtarget.isTargetELF() && !isPPC64 &&
!G->getGlobal()->hasLocalLinkage() &&
DAG.getTarget().getRelocationModel() == Reloc::PIC_)) {
// PC-relative references to external symbols should go through $stub,
// unless we're building with the leopard linker or later, which
// automatically synthesizes these stubs.
OpFlags = PPCII::MO_DARWIN_STUB;
OpFlags = PPCII::MO_PLT_OR_STUB;
}

// If the callee is a GlobalAddress/ExternalSymbol node (quite common,
Expand All @@ -3381,13 +3409,15 @@ unsigned PrepareCall(SelectionDAG &DAG, SDValue &Callee, SDValue &InFlag,
if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
unsigned char OpFlags = 0;

if (DAG.getTarget().getRelocationModel() != Reloc::Static &&
(Subtarget.getTargetTriple().isMacOSX() &&
Subtarget.getTargetTriple().isMacOSXVersionLT(10, 5))) {
if ((DAG.getTarget().getRelocationModel() != Reloc::Static &&
(Subtarget.getTargetTriple().isMacOSX() &&
Subtarget.getTargetTriple().isMacOSXVersionLT(10, 5))) ||
(Subtarget.isTargetELF() && !isPPC64 &&
DAG.getTarget().getRelocationModel() == Reloc::PIC_) ) {
// PC-relative references to external symbols should go through $stub,
// unless we're building with the leopard linker or later, which
// automatically synthesizes these stubs.
OpFlags = PPCII::MO_DARWIN_STUB;
OpFlags = PPCII::MO_PLT_OR_STUB;
}

Callee = DAG.getTargetExternalSymbol(S->getSymbol(), Callee.getValueType(),
Expand Down Expand Up @@ -6613,7 +6643,10 @@ PPCTargetLowering::emitEHSjLjLongJmp(MachineInstr *MI,
// Since FP is only updated here but NOT referenced, it's treated as GPR.
unsigned FP = (PVT == MVT::i64) ? PPC::X31 : PPC::R31;
unsigned SP = (PVT == MVT::i64) ? PPC::X1 : PPC::R1;
unsigned BP = (PVT == MVT::i64) ? PPC::X30 : PPC::R30;
unsigned BP = (PVT == MVT::i64) ? PPC::X30 :
(Subtarget.isSVR4ABI() &&
MF->getTarget().getRelocationModel() == Reloc::PIC_ ?
PPC::R29 : PPC::R30);

MachineInstrBuilder MIB;

Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Target/PowerPC/PPCInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ def SDT_PPCTC_ret : SDTypeProfile<0, 2, [
SDTCisPtrTy<0>, SDTCisVT<1, i32>
]>;

def tocentry32 : Operand<iPTR> {
let MIOperandInfo = (ops i32imm:$imm);
}

//===----------------------------------------------------------------------===//
// PowerPC specific DAG Nodes.
Expand Down Expand Up @@ -2400,6 +2403,18 @@ def LDgotTprelL32: Pseudo<(outs gprc:$rD), (ins s16imm:$disp, gprc_nor0:$reg),
def : Pat<(PPCaddTls i32:$in, tglobaltlsaddr:$g),
(ADD4TLS $in, tglobaltlsaddr:$g)>;

// Support for Position-independent code
def LWZtoc: Pseudo<(outs gprc:$rD), (ins tocentry32:$disp, gprc:$reg),
"#LWZtoc",
[(set i32:$rD,
(PPCtoc_entry tglobaladdr:$disp, i32:$reg))]>;
// Get Global (GOT) Base Register offset, from the word immediately preceding
// the function label.
def GetGBRO: Pseudo<(outs gprc:$rT), (ins gprc:$rI), "#GetGBRO", []>;
// Update the Global(GOT) Base Register with the above offset.
def UpdateGBR: Pseudo<(outs gprc:$rT), (ins gprc:$rI), "#UpdateGBR", []>;


// Standard shifts. These are represented separately from the real shifts above
// so that we can distinguish between shifts that allow 5-bit and 6-bit shift
// amounts.
Expand Down
14 changes: 10 additions & 4 deletions llvm/lib/Target/PowerPC/PPCMCInstLower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//

#include "PPC.h"
#include "PPCSubtarget.h"
#include "MCTargetDesc/PPCMCExpr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
Expand All @@ -39,12 +40,14 @@ static MCSymbol *GetSymbolFromOperand(const MachineOperand &MO, AsmPrinter &AP){
Mangler *Mang = AP.Mang;
const DataLayout *DL = TM.getDataLayout();
MCContext &Ctx = AP.OutContext;
bool isDarwin = TM.getSubtarget<PPCSubtarget>().isDarwin();

SmallString<128> Name;
StringRef Suffix;
if (MO.getTargetFlags() == PPCII::MO_DARWIN_STUB)
Suffix = "$stub";
else if (MO.getTargetFlags() & PPCII::MO_NLP_FLAG)
if (MO.getTargetFlags() == PPCII::MO_PLT_OR_STUB) {
if (isDarwin)
Suffix = "$stub";
} else if (MO.getTargetFlags() & PPCII::MO_NLP_FLAG)
Suffix = "$non_lazy_ptr";

if (!Suffix.empty())
Expand All @@ -68,7 +71,7 @@ static MCSymbol *GetSymbolFromOperand(const MachineOperand &MO, AsmPrinter &AP){

// If the target flags on the operand changes the name of the symbol, do that
// before we return the symbol.
if (MO.getTargetFlags() == PPCII::MO_DARWIN_STUB) {
if (MO.getTargetFlags() == PPCII::MO_PLT_OR_STUB && isDarwin) {
MachineModuleInfoImpl::StubValueTy &StubSym =
getMachOMMI(AP).getFnStubEntry(Sym);
if (StubSym.getPointer())
Expand Down Expand Up @@ -136,6 +139,9 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol,
break;
}

if (MO.getTargetFlags() == PPCII::MO_PLT_OR_STUB && !isDarwin)
RefKind = MCSymbolRefExpr::VK_PLT;

const MCExpr *Expr = MCSymbolRefExpr::Create(Symbol, RefKind, Ctx);

if (!MO.isJTI() && MO.getOffset())
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@
//===----------------------------------------------------------------------===//

#include "PPCMachineFunctionInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCContext.h"
#include "llvm/Target/TargetMachine.h"

using namespace llvm;

void PPCFunctionInfo::anchor() { }

MCSymbol *PPCFunctionInfo::getPICOffsetSymbol() const {
const DataLayout *DL = MF.getTarget().getDataLayout();
return MF.getContext().GetOrCreateSymbol(Twine(DL->getPrivateGlobalPrefix())+
Twine(MF.getFunctionNumber())+"$poff");
}
15 changes: 14 additions & 1 deletion llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ class PPCFunctionInfo : public MachineFunctionInfo {
/// 64-bit SVR4 ABI.
SmallVector<unsigned, 3> MustSaveCRs;

/// Hold onto our MachineFunction context.
MachineFunction &MF;

/// Whether this uses the PIC Base register or not.
bool UsesPICBase;

public:
explicit PPCFunctionInfo(MachineFunction &MF)
: FramePointerSaveIndex(0),
Expand All @@ -109,7 +115,9 @@ class PPCFunctionInfo : public MachineFunctionInfo {
VarArgsStackOffset(0),
VarArgsNumGPR(0),
VarArgsNumFPR(0),
CRSpillFrameIndex(0) {}
CRSpillFrameIndex(0),
MF(MF),
UsesPICBase(0) {}

int getFramePointerSaveIndex() const { return FramePointerSaveIndex; }
void setFramePointerSaveIndex(int Idx) { FramePointerSaveIndex = Idx; }
Expand Down Expand Up @@ -170,6 +178,11 @@ class PPCFunctionInfo : public MachineFunctionInfo {
const SmallVectorImpl<unsigned> &
getMustSaveCRs() const { return MustSaveCRs; }
void addMustSaveCR(unsigned Reg) { MustSaveCRs.push_back(Reg); }

void setUsesPICBase(bool uses) { UsesPICBase = uses; }
bool usesPICBase() const { return UsesPICBase; }

MCSymbol *getPICOffsetSymbol() const;
};

} // end of namespace llvm
Expand Down
20 changes: 18 additions & 2 deletions llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,16 @@ BitVector PPCRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
if (PPCFI->needsFP(MF))
Reserved.set(PPC::R31);

if (hasBasePointer(MF))
if (hasBasePointer(MF)) {
if (Subtarget.isSVR4ABI() && !Subtarget.isPPC64() &&
MF.getTarget().getRelocationModel() == Reloc::PIC_)
Reserved.set(PPC::R29);
else
Reserved.set(PPC::R30);
}

if (Subtarget.isSVR4ABI() && !Subtarget.isPPC64() &&
MF.getTarget().getRelocationModel() == Reloc::PIC_)
Reserved.set(PPC::R30);

// Reserve Altivec registers when Altivec is unavailable.
Expand Down Expand Up @@ -843,7 +852,14 @@ unsigned PPCRegisterInfo::getBaseRegister(const MachineFunction &MF) const {
if (!hasBasePointer(MF))
return getFrameRegister(MF);

return Subtarget.isPPC64() ? PPC::X30 : PPC::R30;
if (Subtarget.isPPC64())
return PPC::X30;

if (Subtarget.isSVR4ABI() &&
MF.getTarget().getRelocationModel() == Reloc::PIC_)
return PPC::R29;

return PPC::R30;
}

bool PPCRegisterInfo::hasBasePointer(const MachineFunction &MF) const {
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/PowerPC/PPCSubtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ class PPCSubtarget : public PPCGenSubtargetInfo {
/// isBGQ - True if this is a BG/Q platform.
bool isBGQ() const { return TargetTriple.getVendor() == Triple::BGQ; }

bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
bool isTargetMachO() const { return TargetTriple.isOSBinFormatMachO(); }

bool isDarwinABI() const { return isDarwin(); }
bool isSVR4ABI() const { return !isDarwin(); }

Expand Down
9 changes: 7 additions & 2 deletions llvm/test/CodeGen/PowerPC/available-externally.ll
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
; RUN: llc < %s -relocation-model=static | FileCheck %s -check-prefix=STATIC
; RUN: llc < %s -relocation-model=pic | FileCheck %s -check-prefix=PIC
; RUN: llc < %s -relocation-model=pic -mtriple=powerpc-apple-darwin8 | FileCheck %s -check-prefix=PIC
; RUN: llc < %s -relocation-model=pic -mtriple=powerpc-unknown-linux | FileCheck %s -check-prefix=PICELF
; RUN: llc < %s -relocation-model=pic -mtriple=powerpc64-apple-darwin8 | FileCheck %s -check-prefix=PIC64
; RUN: llc < %s -relocation-model=dynamic-no-pic | FileCheck %s -check-prefix=DYNAMIC
; RUN: llc < %s -relocation-model=dynamic-no-pic -mtriple=powerpc-apple-darwin8 | FileCheck %s -check-prefix=DYNAMIC
; RUN: llc < %s -relocation-model=dynamic-no-pic -mtriple=powerpc64-apple-darwin8 | FileCheck %s -check-prefix=DYNAMIC64
; PR4482
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
Expand All @@ -18,6 +19,10 @@ entry:
; PIC: bl L_exact_log2$stub
; PIC: blr

; PICELF: foo:
; PICELF: bl exact_log2@PLT
; PICELF: blr

; PIC64: _foo:
; PIC64: bl L_exact_log2$stub
; PIC64: blr
Expand Down
21 changes: 21 additions & 0 deletions llvm/test/CodeGen/PowerPC/ppc32-pic.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
; RUN: llc < %s -mtriple=powerpc-unknown-linux-gnu -relocation-model=pic | FileCheck %s
@foobar = common global i32 0, align 4

define i32 @foo() {
entry:
%0 = load i32* @foobar, align 4
ret i32 %0
}

; CHECK: [[POFF:\.L[0-9]+\$poff]]:
; CHECK-NEXT: .long .L.TOC.-[[PB:\.L[0-9]+\$pb]]
; CHECK-NEXT: foo:
; CHECK: bl [[PB]]
; CHECK-NEXT: [[PB]]:
; CHECK: mflr 30
; CHECK: lwz [[REG:[0-9]+]], [[POFF]]-[[PB]](30)
; CHECK-NEXT: add 30, [[REG]], 30
; CHECK: lwz [[VREG:[0-9]+]], [[VREF:\.LC[0-9]+]]-.L.TOC.(30)
; CHECK: lwz {{[0-9]+}}, 0([[VREG]])
; CHECK: [[VREF]]:
; CHECK-NEXT: .long foobar
4 changes: 4 additions & 0 deletions llvm/test/CodeGen/PowerPC/sections.ll
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
; Test to make sure that bss sections are printed with '.section' directive.
; RUN: llc < %s -mtriple=powerpc-unknown-linux-gnu | FileCheck %s
; RUN: llc < %s -mtriple=powerpc-unknown-linux-gnu -relocation-model=pic | FileCheck %s -check-prefix=PIC

@A = global i32 0

; CHECK: .section .bss,"aw",@nobits
; CHECK: .globl A

; PIC: .section .got2,"aw",@progbits
; PIC: .section .bss,"aw",@nobits
; PIC: .globl A
53 changes: 52 additions & 1 deletion llvm/test/CodeGen/PowerPC/stack-realign.ll
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
; RUN: llc -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 < %s | FileCheck %s
; RUN: llc -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 -disable-fp-elim < %s | FileCheck -check-prefix=CHECK-FP %s
; RUN: llc -mtriple=powerpc-unknown-linux-gnu -disable-fp-elim < %s | FileCheck -check-prefix=CHECK-32 %s
; RUN: llc -mtriple=powerpc-unknown-linux-gnu -disable-fp-elim -relocation-model=pic < %s | FileCheck -check-prefix=CHECK-32-PIC %s
target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-v128:128:128-n32:64"
target triple = "powerpc64-unknown-linux-gnu"

%struct.s = type { i32, i32 }

declare void @bar(i32*)

@barbaz = external global i32

define void @goo(%struct.s* byval nocapture readonly %a) {
entry:
%x = alloca [2 x i32], align 32
Expand All @@ -16,8 +20,9 @@ entry:
store i32 %0, i32* %arrayidx, align 32
%b = getelementptr inbounds %struct.s* %a, i64 0, i32 1
%1 = load i32* %b, align 4
%2 = load i32* @barbaz, align 4
%arrayidx2 = getelementptr inbounds [2 x i32]* %x, i64 0, i64 1
store i32 %1, i32* %arrayidx2, align 4
store i32 %2, i32* %arrayidx2, align 4
call void @bar(i32* %arrayidx)
ret void
}
Expand Down Expand Up @@ -69,6 +74,24 @@ entry:
; CHECK-FP-DAG: mtlr 0
; CHECK-FP: blr

; CHECK-32-LABEL: @goo
; CHECK-32-DAG: mflr 0
; CHECK-32-DAG: rlwinm [[REG:[0-9]+]], 1, 0, 27, 31
; CHECK-32-DAG: stw 30, -8(1)
; CHECK-32-DAG: mr 30, 1
; CHECK-32-DAG: stw 0, 4(1)
; CHECK-32-DAG: subfic 0, [[REG]], -64
; CHECK-32: stwux 1, 1, 0

; CHECK-32-PIC-LABEL: @goo
; CHECK-32-PIC-DAG: mflr 0
; CHECK-32-PIC-DAG: rlwinm [[REG:[0-9]+]], 1, 0, 27, 31
; CHECK-32-PIC-DAG: stw 29, -12(1)
; CHECK-32-PIC-DAG: mr 29, 1
; CHECK-32-PIC-DAG: stw 0, 4(1)
; CHECK-32-PIC-DAG: subfic 0, [[REG]], -64
; CHECK-32-PIC: stwux 1, 1, 0

; The large-frame-size case.
define void @hoo(%struct.s* byval nocapture readonly %a) {
entry:
Expand Down Expand Up @@ -99,6 +122,34 @@ entry:

; CHECK: blr

; CHECK-32-LABEL: @hoo

; CHECK-32-DAG: lis [[REG1:[0-9]+]], -13
; CHECK-32-DAG: rlwinm [[REG3:[0-9]+]], 1, 0, 27, 31
; CHECK-32-DAG: mflr 0
; CHECK-32-DAG: ori [[REG2:[0-9]+]], [[REG1]], 51904
; CHECK-32-DAG: stw 30, -8(1)
; CHECK-32-DAG: mr 30, 1
; CHECK-32-DAG: stw 0, 4(1)
; CHECK-32-DAG: subfc 0, [[REG3]], [[REG2]]
; CHECK-32: stwux 1, 1, 0

; CHECK-32: blr

; CHECK-32-PIC-LABEL: @hoo

; CHECK-32-PIC-DAG: lis [[REG1:[0-9]+]], -13
; CHECK-32-PIC-DAG: rlwinm [[REG3:[0-9]+]], 1, 0, 27, 31
; CHECK-32-PIC-DAG: mflr 0
; CHECK-32-PIC-DAG: ori [[REG2:[0-9]+]], [[REG1]], 51904
; CHECK-32-PIC-DAG: stw 29, -12(1)
; CHECK-32-PIC-DAG: mr 29, 1
; CHECK-32-PIC-DAG: stw 0, 4(1)
; CHECK-32-PIC-DAG: subfc 0, [[REG3]], [[REG2]]
; CHECK-32: stwux 1, 1, 0

; CHECK-32: blr

; Make sure that the FP save area is still allocated correctly relative to
; where r30 is saved.
define void @loo(%struct.s* byval nocapture readonly %a) {
Expand Down
17 changes: 17 additions & 0 deletions llvm/test/MC/PowerPC/ppc-reloc.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# RUN: llvm-mc -triple=powerpc-unknown-linux-gnu -filetype=obj %s | \
# RUN: llvm-readobj -r | FileCheck %s
.section .text

.globl foo
.type foo,@function
.align 2
foo:
bl printf@plt
.LC1:
.size foo, . - foo

# CHECK: Relocations [
# CHECK-NEXT: Section (2) .rela.text {
# CHECK-NEXT: 0x0 R_PPC_PLTREL24 printf 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]