forked from OSchip/llvm-project
[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
This commit is contained in:
parent
52b1391df6
commit
618c67a018
|
@ -88,6 +88,7 @@ public:
|
||||||
class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile {
|
class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile {
|
||||||
public:
|
public:
|
||||||
virtual ~TargetLoweringObjectFileMachO() {}
|
virtual ~TargetLoweringObjectFileMachO() {}
|
||||||
|
TargetLoweringObjectFileMachO();
|
||||||
|
|
||||||
/// Extract the dependent library name from a linker option string. Returns
|
/// Extract the dependent library name from a linker option string. Returns
|
||||||
/// StringRef() if the option does not specify a library.
|
/// StringRef() if the option does not specify a library.
|
||||||
|
@ -122,6 +123,12 @@ public:
|
||||||
MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, Mangler &Mang,
|
MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, Mangler &Mang,
|
||||||
const TargetMachine &TM,
|
const TargetMachine &TM,
|
||||||
MachineModuleInfo *MMI) const override;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,19 +29,20 @@ namespace llvm {
|
||||||
class MCSymbol;
|
class MCSymbol;
|
||||||
class MCSymbolRefExpr;
|
class MCSymbolRefExpr;
|
||||||
class MCStreamer;
|
class MCStreamer;
|
||||||
|
class MCValue;
|
||||||
class ConstantExpr;
|
class ConstantExpr;
|
||||||
class GlobalValue;
|
class GlobalValue;
|
||||||
class TargetMachine;
|
class TargetMachine;
|
||||||
|
|
||||||
class TargetLoweringObjectFile : public MCObjectFileInfo {
|
class TargetLoweringObjectFile : public MCObjectFileInfo {
|
||||||
MCContext *Ctx;
|
MCContext *Ctx;
|
||||||
const DataLayout *DL;
|
|
||||||
|
|
||||||
TargetLoweringObjectFile(
|
TargetLoweringObjectFile(
|
||||||
const TargetLoweringObjectFile&) = delete;
|
const TargetLoweringObjectFile&) = delete;
|
||||||
void operator=(const TargetLoweringObjectFile&) = delete;
|
void operator=(const TargetLoweringObjectFile&) = delete;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
const DataLayout *DL;
|
||||||
bool SupportIndirectSymViaGOTPCRel;
|
bool SupportIndirectSymViaGOTPCRel;
|
||||||
bool SupportGOTPCRelWithOffset;
|
bool SupportGOTPCRelWithOffset;
|
||||||
|
|
||||||
|
@ -178,7 +179,9 @@ public:
|
||||||
|
|
||||||
/// \brief Get the target specific PC relative GOT entry relocation
|
/// \brief Get the target specific PC relative GOT entry relocation
|
||||||
virtual const MCExpr *getIndirectSymViaGOTPCRel(const MCSymbol *Sym,
|
virtual const MCExpr *getIndirectSymViaGOTPCRel(const MCSymbol *Sym,
|
||||||
|
const MCValue &MV,
|
||||||
int64_t Offset,
|
int64_t Offset,
|
||||||
|
MachineModuleInfo *MMI,
|
||||||
MCStreamer &Streamer) const {
|
MCStreamer &Streamer) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2084,7 +2084,9 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME,
|
||||||
//
|
//
|
||||||
// gotpcrelcst := <offset from @foo base> + <cst>
|
// gotpcrelcst := <offset from @foo base> + <cst>
|
||||||
//
|
//
|
||||||
// Only encode <cst> 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 <cst>
|
||||||
|
// if the target knows how to encode it.
|
||||||
//
|
//
|
||||||
int64_t GOTPCRelCst = Offset + MV.getConstant();
|
int64_t GOTPCRelCst = Offset + MV.getConstant();
|
||||||
if (GOTPCRelCst < 0)
|
if (GOTPCRelCst < 0)
|
||||||
|
@ -2113,9 +2115,8 @@ static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME,
|
||||||
unsigned NumUses = Result.second;
|
unsigned NumUses = Result.second;
|
||||||
const GlobalValue *FinalGV = dyn_cast<GlobalValue>(GV->getOperand(0));
|
const GlobalValue *FinalGV = dyn_cast<GlobalValue>(GV->getOperand(0));
|
||||||
const MCSymbol *FinalSym = AP.getSymbol(FinalGV);
|
const MCSymbol *FinalSym = AP.getSymbol(FinalGV);
|
||||||
*ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel(FinalSym,
|
*ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel(
|
||||||
GOTPCRelCst,
|
FinalSym, MV, Offset, AP.MMI, AP.OutStreamer);
|
||||||
AP.OutStreamer);
|
|
||||||
|
|
||||||
// Update GOT equivalent usage information
|
// Update GOT equivalent usage information
|
||||||
--NumUses;
|
--NumUses;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "llvm/MC/MCSectionMachO.h"
|
#include "llvm/MC/MCSectionMachO.h"
|
||||||
#include "llvm/MC/MCStreamer.h"
|
#include "llvm/MC/MCStreamer.h"
|
||||||
#include "llvm/MC/MCSymbol.h"
|
#include "llvm/MC/MCSymbol.h"
|
||||||
|
#include "llvm/MC/MCValue.h"
|
||||||
#include "llvm/Support/Dwarf.h"
|
#include "llvm/Support/Dwarf.h"
|
||||||
#include "llvm/Support/ELF.h"
|
#include "llvm/Support/ELF.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
|
@ -431,6 +432,11 @@ TargetLoweringObjectFileELF::InitializeELF(bool UseInitArray_) {
|
||||||
// MachO
|
// MachO
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
TargetLoweringObjectFileMachO::TargetLoweringObjectFileMachO()
|
||||||
|
: TargetLoweringObjectFile() {
|
||||||
|
SupportIndirectSymViaGOTPCRel = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// getDepLibFromLinkerOpt - Extract the dependent library name from a linker
|
/// getDepLibFromLinkerOpt - Extract the dependent library name from a linker
|
||||||
/// option string. Returns StringRef() if the option does not specify a library.
|
/// option string. Returns StringRef() if the option does not specify a library.
|
||||||
StringRef TargetLoweringObjectFileMachO::
|
StringRef TargetLoweringObjectFileMachO::
|
||||||
|
@ -705,6 +711,66 @@ MCSymbol *TargetLoweringObjectFileMachO::getCFIPersonalitySymbol(
|
||||||
return SSym;
|
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<MachineModuleInfoMachO>();
|
||||||
|
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<MCSymbol *>(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
|
// COFF
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "llvm/MC/MCContext.h"
|
#include "llvm/MC/MCContext.h"
|
||||||
#include "llvm/MC/MCExpr.h"
|
#include "llvm/MC/MCExpr.h"
|
||||||
#include "llvm/MC/MCStreamer.h"
|
#include "llvm/MC/MCStreamer.h"
|
||||||
|
#include "llvm/MC/MCValue.h"
|
||||||
#include "llvm/Support/Dwarf.h"
|
#include "llvm/Support/Dwarf.h"
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace dwarf;
|
using namespace dwarf;
|
||||||
|
@ -25,7 +26,6 @@ void AArch64_ELFTargetObjectFile::Initialize(MCContext &Ctx,
|
||||||
|
|
||||||
AArch64_MachoTargetObjectFile::AArch64_MachoTargetObjectFile()
|
AArch64_MachoTargetObjectFile::AArch64_MachoTargetObjectFile()
|
||||||
: TargetLoweringObjectFileMachO() {
|
: TargetLoweringObjectFileMachO() {
|
||||||
SupportIndirectSymViaGOTPCRel = true;
|
|
||||||
SupportGOTPCRelWithOffset = false;
|
SupportGOTPCRelWithOffset = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,10 @@ MCSymbol *AArch64_MachoTargetObjectFile::getCFIPersonalitySymbol(
|
||||||
}
|
}
|
||||||
|
|
||||||
const MCExpr *AArch64_MachoTargetObjectFile::getIndirectSymViaGOTPCRel(
|
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
|
// On ARM64 Darwin, we can reference symbols with foo@GOT-., which
|
||||||
// is an indirect pc-relative reference.
|
// is an indirect pc-relative reference.
|
||||||
const MCExpr *Res =
|
const MCExpr *Res =
|
||||||
|
|
|
@ -36,9 +36,10 @@ public:
|
||||||
const TargetMachine &TM,
|
const TargetMachine &TM,
|
||||||
MachineModuleInfo *MMI) const override;
|
MachineModuleInfo *MMI) const override;
|
||||||
|
|
||||||
const MCExpr *
|
const MCExpr *getIndirectSymViaGOTPCRel(const MCSymbol *Sym,
|
||||||
getIndirectSymViaGOTPCRel(const MCSymbol *Sym, int64_t Offset,
|
const MCValue &MV, int64_t Offset,
|
||||||
MCStreamer &Streamer) const override;
|
MachineModuleInfo *MMI,
|
||||||
|
MCStreamer &Streamer) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
|
@ -15,17 +15,13 @@
|
||||||
#include "llvm/MC/MCExpr.h"
|
#include "llvm/MC/MCExpr.h"
|
||||||
#include "llvm/MC/MCSectionCOFF.h"
|
#include "llvm/MC/MCSectionCOFF.h"
|
||||||
#include "llvm/MC/MCSectionELF.h"
|
#include "llvm/MC/MCSectionELF.h"
|
||||||
|
#include "llvm/MC/MCValue.h"
|
||||||
#include "llvm/Support/Dwarf.h"
|
#include "llvm/Support/Dwarf.h"
|
||||||
#include "llvm/Target/TargetLowering.h"
|
#include "llvm/Target/TargetLowering.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace dwarf;
|
using namespace dwarf;
|
||||||
|
|
||||||
X86_64MachoTargetObjectFile::X86_64MachoTargetObjectFile()
|
|
||||||
: TargetLoweringObjectFileMachO() {
|
|
||||||
SupportIndirectSymViaGOTPCRel = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MCExpr *X86_64MachoTargetObjectFile::getTTypeGlobalReference(
|
const MCExpr *X86_64MachoTargetObjectFile::getTTypeGlobalReference(
|
||||||
const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
|
const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
|
||||||
const TargetMachine &TM, MachineModuleInfo *MMI,
|
const TargetMachine &TM, MachineModuleInfo *MMI,
|
||||||
|
@ -52,13 +48,15 @@ MCSymbol *X86_64MachoTargetObjectFile::getCFIPersonalitySymbol(
|
||||||
}
|
}
|
||||||
|
|
||||||
const MCExpr *X86_64MachoTargetObjectFile::getIndirectSymViaGOTPCRel(
|
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
|
// 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
|
// from a data section. In case there's an additional offset, then use
|
||||||
// foo@GOTPCREL+4+<offset>.
|
// foo@GOTPCREL+4+<offset>.
|
||||||
|
unsigned FinalOff = Offset+MV.getConstant()+4;
|
||||||
const MCExpr *Res =
|
const MCExpr *Res =
|
||||||
MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOTPCREL, getContext());
|
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());
|
return MCBinaryExpr::CreateAdd(Res, Off, getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,6 @@ namespace llvm {
|
||||||
/// x86-64.
|
/// x86-64.
|
||||||
class X86_64MachoTargetObjectFile : public TargetLoweringObjectFileMachO {
|
class X86_64MachoTargetObjectFile : public TargetLoweringObjectFileMachO {
|
||||||
public:
|
public:
|
||||||
X86_64MachoTargetObjectFile();
|
|
||||||
|
|
||||||
const MCExpr *
|
const MCExpr *
|
||||||
getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding,
|
getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding,
|
||||||
Mangler &Mang, const TargetMachine &TM,
|
Mangler &Mang, const TargetMachine &TM,
|
||||||
|
@ -33,9 +31,10 @@ namespace llvm {
|
||||||
const TargetMachine &TM,
|
const TargetMachine &TM,
|
||||||
MachineModuleInfo *MMI) const override;
|
MachineModuleInfo *MMI) const override;
|
||||||
|
|
||||||
const MCExpr *
|
const MCExpr *getIndirectSymViaGOTPCRel(const MCSymbol *Sym,
|
||||||
getIndirectSymViaGOTPCRel(const MCSymbol *Sym, int64_t Offset,
|
const MCValue &MV, int64_t Offset,
|
||||||
MCStreamer &Streamer) const override;
|
MachineModuleInfo *MMI,
|
||||||
|
MCStreamer &Streamer) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief This implemenatation is used for X86 ELF targets that don't
|
/// \brief This implemenatation is used for X86 ELF targets that don't
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue