From 618c67a018ec523a2a3116421bd2a690cf696564 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Fri, 6 Mar 2015 13:49:05 +0000 Subject: [PATCH] [AsmPrinter][TLOF] 32-bit MachO support for replacing GOT equivalents Add MachO 32-bit (i.e. arm and x86) support for replacing global GOT equivalent symbol accesses. Unlike 64-bit targets, there's no GOTPCREL relocation, and access through a non_lazy_symbol_pointers section is used instead. -- before _extgotequiv: .long _extfoo _delta: .long _extgotequiv-_delta -- after _delta: .long L_extfoo$non_lazy_ptr-_delta .section __IMPORT,__pointers,non_lazy_symbol_pointers L_extfoo$non_lazy_ptr: .indirect_symbol _extfoo .long 0 llvm-svn: 231475 --- .../llvm/CodeGen/TargetLoweringObjectFileImpl.h | 7 ++ .../include/llvm/Target/TargetLoweringObjectFile.h | 5 +- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 9 +-- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 66 +++++++++++++++++++ .../lib/Target/AArch64/AArch64TargetObjectFile.cpp | 7 +- llvm/lib/Target/AArch64/AArch64TargetObjectFile.h | 7 +- llvm/lib/Target/X86/X86TargetObjectFile.cpp | 12 ++-- llvm/lib/Target/X86/X86TargetObjectFile.h | 9 ++- llvm/test/MC/MachO/cstexpr-gotpcrel-32.ll | 77 ++++++++++++++++++++++ 9 files changed, 177 insertions(+), 22 deletions(-) create mode 100644 llvm/test/MC/MachO/cstexpr-gotpcrel-32.ll diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index 348c634..0ca5365 100644 --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -88,6 +88,7 @@ public: class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile { public: virtual ~TargetLoweringObjectFileMachO() {} + TargetLoweringObjectFileMachO(); /// Extract the dependent library name from a linker option string. Returns /// StringRef() if the option does not specify a library. @@ -122,6 +123,12 @@ public: MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, Mangler &Mang, const TargetMachine &TM, MachineModuleInfo *MMI) const override; + + /// Get MachO PC relative GOT entry relocation + const MCExpr *getIndirectSymViaGOTPCRel(const MCSymbol *Sym, + const MCValue &MV, int64_t Offset, + MachineModuleInfo *MMI, + MCStreamer &Streamer) const override; }; diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h index b121fc6..8093d99 100644 --- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -29,19 +29,20 @@ namespace llvm { class MCSymbol; class MCSymbolRefExpr; class MCStreamer; + class MCValue; class ConstantExpr; class GlobalValue; class TargetMachine; class TargetLoweringObjectFile : public MCObjectFileInfo { MCContext *Ctx; - const DataLayout *DL; TargetLoweringObjectFile( const TargetLoweringObjectFile&) = delete; void operator=(const TargetLoweringObjectFile&) = delete; protected: + const DataLayout *DL; bool SupportIndirectSymViaGOTPCRel; bool SupportGOTPCRelWithOffset; @@ -178,7 +179,9 @@ public: /// \brief Get the target specific PC relative GOT entry relocation virtual const MCExpr *getIndirectSymViaGOTPCRel(const MCSymbol *Sym, + const MCValue &MV, int64_t Offset, + MachineModuleInfo *MMI, MCStreamer &Streamer) const { return nullptr; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 22eae78..6938ed1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2084,7 +2084,9 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME, // // gotpcrelcst := + // - // Only encode if the target supports it. + // If gotpcrelcst is positive it means that we can safely fold the pc rel + // displacement into the GOTPCREL. We can also can have an extra offset + // if the target knows how to encode it. // int64_t GOTPCRelCst = Offset + MV.getConstant(); if (GOTPCRelCst < 0) @@ -2113,9 +2115,8 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME, unsigned NumUses = Result.second; const GlobalValue *FinalGV = dyn_cast(GV->getOperand(0)); const MCSymbol *FinalSym = AP.getSymbol(FinalGV); - *ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel(FinalSym, - GOTPCRelCst, - AP.OutStreamer); + *ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel( + FinalSym, MV, Offset, AP.MMI, AP.OutStreamer); // Update GOT equivalent usage information --NumUses; diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index cb4d3e5..e8ef63a 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -31,6 +31,7 @@ #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" @@ -431,6 +432,11 @@ TargetLoweringObjectFileELF::InitializeELF(bool UseInitArray_) { // MachO //===----------------------------------------------------------------------===// +TargetLoweringObjectFileMachO::TargetLoweringObjectFileMachO() + : TargetLoweringObjectFile() { + SupportIndirectSymViaGOTPCRel = true; +} + /// getDepLibFromLinkerOpt - Extract the dependent library name from a linker /// option string. Returns StringRef() if the option does not specify a library. StringRef TargetLoweringObjectFileMachO:: @@ -705,6 +711,66 @@ MCSymbol *TargetLoweringObjectFileMachO::getCFIPersonalitySymbol( return SSym; } +const MCExpr *TargetLoweringObjectFileMachO::getIndirectSymViaGOTPCRel( + const MCSymbol *Sym, const MCValue &MV, int64_t Offset, + MachineModuleInfo *MMI, MCStreamer &Streamer) const { + // Although MachO 32-bit targets do not explictly have a GOTPCREL relocation + // as 64-bit do, we replace the GOT equivalent by accessing the final symbol + // through a non_lazy_ptr stub instead. One advantage is that it allows the + // computation of deltas to final external symbols. Example: + // + // _extgotequiv: + // .long _extfoo + // + // _delta: + // .long _extgotequiv-_delta + // + // is transformed to: + // + // _delta: + // .long L_extfoo$non_lazy_ptr-(_delta+0) + // + // .section __IMPORT,__pointers,non_lazy_symbol_pointers + // L_extfoo$non_lazy_ptr: + // .indirect_symbol _extfoo + // .long 0 + // + MachineModuleInfoMachO &MachOMMI = + MMI->getObjFileInfo(); + MCContext &Ctx = getContext(); + + // The offset must consider the original displacement from the base symbol + // since 32-bit targets don't have a GOTPCREL to fold the PC displacement. + Offset = -MV.getConstant(); + const MCSymbol *BaseSym = &MV.getSymB()->getSymbol(); + + // Access the final symbol via sym$non_lazy_ptr and generate the appropriated + // non_lazy_ptr stubs. + SmallString<128> Name; + StringRef Suffix = "$non_lazy_ptr"; + Name += DL->getPrivateGlobalPrefix(); + Name += Sym->getName(); + Name += Suffix; + MCSymbol *Stub = Ctx.GetOrCreateSymbol(Name); + + MachineModuleInfoImpl::StubValueTy &StubSym = MachOMMI.getGVStubEntry(Stub); + if (!StubSym.getPointer()) + StubSym = MachineModuleInfoImpl:: + StubValueTy(const_cast(Sym), true /* access indirectly */); + + const MCExpr *BSymExpr = + MCSymbolRefExpr::Create(BaseSym, MCSymbolRefExpr::VK_None, Ctx); + const MCExpr *LHS = + MCSymbolRefExpr::Create(Stub, MCSymbolRefExpr::VK_None, Ctx); + + if (!Offset) + return MCBinaryExpr::CreateSub(LHS, BSymExpr, Ctx); + + const MCExpr *RHS = + MCBinaryExpr::CreateAdd(BSymExpr, MCConstantExpr::Create(Offset, Ctx), Ctx); + return MCBinaryExpr::CreateSub(LHS, RHS, Ctx); +} + //===----------------------------------------------------------------------===// // COFF //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp index 3c0a342..8ff58e9 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp @@ -13,6 +13,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/Dwarf.h" using namespace llvm; using namespace dwarf; @@ -25,7 +26,6 @@ void AArch64_ELFTargetObjectFile::Initialize(MCContext &Ctx, AArch64_MachoTargetObjectFile::AArch64_MachoTargetObjectFile() : TargetLoweringObjectFileMachO() { - SupportIndirectSymViaGOTPCRel = true; SupportGOTPCRelWithOffset = false; } @@ -58,7 +58,10 @@ MCSymbol *AArch64_MachoTargetObjectFile::getCFIPersonalitySymbol( } const MCExpr *AArch64_MachoTargetObjectFile::getIndirectSymViaGOTPCRel( - const MCSymbol *Sym, int64_t Offset, MCStreamer &Streamer) const { + const MCSymbol *Sym, const MCValue &MV, int64_t Offset, + MachineModuleInfo *MMI, MCStreamer &Streamer) const { + assert((Offset+MV.getConstant() == 0) && + "Arch64 does not support GOT PC rel with extra offset"); // On ARM64 Darwin, we can reference symbols with foo@GOT-., which // is an indirect pc-relative reference. const MCExpr *Res = diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h index 067fda5..d41f445 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h +++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h @@ -36,9 +36,10 @@ public: const TargetMachine &TM, MachineModuleInfo *MMI) const override; - const MCExpr * - getIndirectSymViaGOTPCRel(const MCSymbol *Sym, int64_t Offset, - MCStreamer &Streamer) const override; + const MCExpr *getIndirectSymViaGOTPCRel(const MCSymbol *Sym, + const MCValue &MV, int64_t Offset, + MachineModuleInfo *MMI, + MCStreamer &Streamer) const override; }; } // end namespace llvm diff --git a/llvm/lib/Target/X86/X86TargetObjectFile.cpp b/llvm/lib/Target/X86/X86TargetObjectFile.cpp index 15a5fdd..c86a3ee 100644 --- a/llvm/lib/Target/X86/X86TargetObjectFile.cpp +++ b/llvm/lib/Target/X86/X86TargetObjectFile.cpp @@ -15,17 +15,13 @@ #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/Dwarf.h" #include "llvm/Target/TargetLowering.h" using namespace llvm; using namespace dwarf; -X86_64MachoTargetObjectFile::X86_64MachoTargetObjectFile() - : TargetLoweringObjectFileMachO() { - SupportIndirectSymViaGOTPCRel = true; -} - const MCExpr *X86_64MachoTargetObjectFile::getTTypeGlobalReference( const GlobalValue *GV, unsigned Encoding, Mangler &Mang, const TargetMachine &TM, MachineModuleInfo *MMI, @@ -52,13 +48,15 @@ MCSymbol *X86_64MachoTargetObjectFile::getCFIPersonalitySymbol( } const MCExpr *X86_64MachoTargetObjectFile::getIndirectSymViaGOTPCRel( - const MCSymbol *Sym, int64_t Offset, MCStreamer &Streamer) const { + const MCSymbol *Sym, const MCValue &MV, int64_t Offset, + MachineModuleInfo *MMI, MCStreamer &Streamer) const { // On Darwin/X86-64, we need to use foo@GOTPCREL+4 to access the got entry // from a data section. In case there's an additional offset, then use // foo@GOTPCREL+4+. + unsigned FinalOff = Offset+MV.getConstant()+4; const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOTPCREL, getContext()); - const MCExpr *Off = MCConstantExpr::Create(Offset+4, getContext()); + const MCExpr *Off = MCConstantExpr::Create(FinalOff, getContext()); return MCBinaryExpr::CreateAdd(Res, Off, getContext()); } diff --git a/llvm/lib/Target/X86/X86TargetObjectFile.h b/llvm/lib/Target/X86/X86TargetObjectFile.h index 3c7caab..252b277 100644 --- a/llvm/lib/Target/X86/X86TargetObjectFile.h +++ b/llvm/lib/Target/X86/X86TargetObjectFile.h @@ -19,8 +19,6 @@ namespace llvm { /// x86-64. class X86_64MachoTargetObjectFile : public TargetLoweringObjectFileMachO { public: - X86_64MachoTargetObjectFile(); - const MCExpr * getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding, Mangler &Mang, const TargetMachine &TM, @@ -33,9 +31,10 @@ namespace llvm { const TargetMachine &TM, MachineModuleInfo *MMI) const override; - const MCExpr * - getIndirectSymViaGOTPCRel(const MCSymbol *Sym, int64_t Offset, - MCStreamer &Streamer) const override; + const MCExpr *getIndirectSymViaGOTPCRel(const MCSymbol *Sym, + const MCValue &MV, int64_t Offset, + MachineModuleInfo *MMI, + MCStreamer &Streamer) const override; }; /// \brief This implemenatation is used for X86 ELF targets that don't diff --git a/llvm/test/MC/MachO/cstexpr-gotpcrel-32.ll b/llvm/test/MC/MachO/cstexpr-gotpcrel-32.ll new file mode 100644 index 0000000..a28c029 --- /dev/null +++ b/llvm/test/MC/MachO/cstexpr-gotpcrel-32.ll @@ -0,0 +1,77 @@ +; RUN: llc -mtriple=i386-apple-darwin %s -o %t +; RUN: FileCheck %s < %t +; RUN: FileCheck %s -check-prefix=GOT-EQUIV < %t +; RUN: llc -mtriple=arm-apple-darwin %s -o %t +; RUN: FileCheck %s < %t +; RUN: FileCheck %s -check-prefix=GOT-EQUIV < %t + +; GOT equivalent globals references can be replaced by the GOT entry of the +; final symbol instead. + +%struct.data = type { i32, %struct.anon } +%struct.anon = type { i32, i32 } + +; Check that these got equivalent symbols are never emitted or used +; GOT-EQUIV-NOT: _localgotequiv +; GOT-EQUIV-NOT: _extgotequiv +@localfoo = global i32 42 +@localgotequiv = private unnamed_addr constant i32* @localfoo + +@extfoo = external global i32 +@extgotequiv = private unnamed_addr constant i32* @extfoo + +; Don't replace GOT equivalent usage within instructions and emit the GOT +; equivalent since it can't be replaced by the GOT entry. @bargotequiv is +; used by an instruction inside @t0. +; +; CHECK: l_bargotequiv: +; CHECK-NEXT: .long _extbar +@extbar = external global i32 +@bargotequiv = private unnamed_addr constant i32* @extbar + +@table = global [4 x %struct.data] [ +; CHECK-LABEL: _table + %struct.data { i32 1, %struct.anon { i32 2, i32 3 } }, +; Test GOT equivalent usage inside nested constant arrays. +; CHECK: .long 5 +; CHECK-NOT: l_localgotequiv-(_table+20) +; CHECK-NEXT: L_localfoo$non_lazy_ptr-(_table+20) + %struct.data { i32 4, %struct.anon { i32 5, + i32 sub (i32 ptrtoint (i32** @localgotequiv to i32), + i32 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data]* @table, i32 0, i32 1, i32 1, i32 1) to i32))} + }, +; CHECK: .long 5 +; CHECK-NOT: l_extgotequiv-(_table+32) +; CHECK-NEXT: L_extfoo$non_lazy_ptr-(_table+32) + %struct.data { i32 4, %struct.anon { i32 5, + i32 sub (i32 ptrtoint (i32** @extgotequiv to i32), + i32 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data]* @table, i32 0, i32 2, i32 1, i32 1) to i32))} + }, +; Test support for arbitrary constants into the GOTPCREL offset +; CHECK: .long 5 +; CHECK-NOT: (l_extgotequiv-(_table+44))+24 +; CHECK-NEXT: L_extfoo$non_lazy_ptr-(_table+20) + %struct.data { i32 4, %struct.anon { i32 5, + i32 add (i32 sub (i32 ptrtoint (i32** @extgotequiv to i32), + i32 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data]* @table, i32 0, i32 3, i32 1, i32 1) to i32)), + i32 24)} + } +], align 16 + +; Test multiple uses of GOT equivalents. +; CHECK-LABEL: _delta +; CHECK: .long L_extfoo$non_lazy_ptr-_delta +@delta = global i32 sub (i32 ptrtoint (i32** @extgotequiv to i32), + i32 ptrtoint (i32* @delta to i32)) + +; CHECK-LABEL: _deltaplus: +; CHECK: .long L_localfoo$non_lazy_ptr-(_deltaplus-55) +@deltaplus = global i32 add (i32 sub (i32 ptrtoint (i32** @localgotequiv to i32), + i32 ptrtoint (i32* @deltaplus to i32)), + i32 55) + +define i32 @t0(i32 %a) { + %x = add i32 sub (i32 ptrtoint (i32** @bargotequiv to i32), + i32 ptrtoint (i32 (i32)* @t0 to i32)), %a + ret i32 %x +} -- 2.7.4