llvm.org GIT mirror llvm / 5011913
CodeGen: Use PLT relocations for relative references to unnamed_addr functions. The relative vtable ABI (PR26723) needs PLT relocations to refer to virtual functions defined in other DSOs. The unnamed_addr attribute means that the function's address is not significant, so we're allowed to substitute it with the address of a PLT entry. Also includes a bonus feature: addends for COFF image-relative references. Differential Revision: http://reviews.llvm.org/D17938 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@267211 91177308-0d34-0410-b5e6-96231b3b80d8 Peter Collingbourne 4 years ago
14 changed file(s) with 155 addition(s) and 58 deletion(s). Raw diff Collapse all Expand all
2020 #define LLVM_ANALYSIS_CONSTANTFOLDING_H
2121
2222 namespace llvm {
23 class APInt;
24 template class ArrayRef;
2325 class Constant;
2426 class ConstantExpr;
27 class DataLayout;
28 class Function;
29 class GlobalValue;
2530 class Instruction;
26 class DataLayout;
2731 class TargetLibraryInfo;
28 class Function;
2932 class Type;
30 template class ArrayRef;
33
34 /// If this constant is a constant offset from a global, return the global and
35 /// the constant. Because of constantexprs, this function is recursive.
36 bool IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, APInt &Offset,
37 const DataLayout &DL);
3138
3239 /// ConstantFoldInstruction - Try to constant fold the specified instruction.
3340 /// If successful, the constant result is returned, if not, null is returned.
1414 #ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H
1515 #define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H
1616
17 #include "llvm/MC/MCExpr.h"
1718 #include "llvm/MC/SectionKind.h"
1819 #include "llvm/Target/TargetLoweringObjectFile.h"
1920
2122 class MachineModuleInfo;
2223 class Mangler;
2324 class MCAsmInfo;
24 class MCExpr;
2525 class MCSection;
2626 class MCSectionMachO;
2727 class MCSymbol;
3333 class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
3434 bool UseInitArray;
3535 mutable unsigned NextUniqueID = 0;
36
37 protected:
38 MCSymbolRefExpr::VariantKind PLTRelativeVariantKind =
39 MCSymbolRefExpr::VK_None;
3640
3741 public:
3842 TargetLoweringObjectFileELF() : UseInitArray(false) {}
8084 const MCSymbol *KeySym) const override;
8185 MCSection *getStaticDtorSection(unsigned Priority,
8286 const MCSymbol *KeySym) const override;
87
88 const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
89 const GlobalValue *RHS, Mangler &Mang,
90 const TargetMachine &TM) const override;
8391 };
8492
8593
154154 virtual const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const;
155155
156156 virtual const MCExpr *
157 getExecutableRelativeSymbol(const ConstantExpr *CE, Mangler &Mang,
158 const TargetMachine &TM) const {
157 lowerRelativeReference(const GlobalValue *LHS, const GlobalValue *RHS,
158 Mangler &Mang, const TargetMachine &TM) const {
159159 return nullptr;
160160 }
161161
230230 return ConstantVector::get(Result);
231231 }
232232
233 } // end anonymous namespace
234
233235 /// If this constant is a constant offset from a global, return the global and
234236 /// the constant. Because of constantexprs, this function is recursive.
235 bool IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, APInt &Offset,
236 const DataLayout &DL) {
237 bool llvm::IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV,
238 APInt &Offset, const DataLayout &DL) {
237239 // Trivial case, constant is the global.
238240 if ((GV = dyn_cast(C))) {
239241 unsigned BitWidth = DL.getPointerTypeSizeInBits(GV->getType());
269271 Offset = TmpOffset;
270272 return true;
271273 }
274
275 namespace {
272276
273277 /// Recursive helper to read bits out of global. C is the constant being copied
274278 /// out of. ByteOffset is an offset into C. CurPtr is the pointer to copy
17621762 llvm_unreachable("Unknown constant value to lower!");
17631763 }
17641764
1765 if (const MCExpr *RelocExpr
1766 = getObjFileLowering().getExecutableRelativeSymbol(CE, *Mang, TM))
1767 return RelocExpr;
1768
17691765 switch (CE->getOpcode()) {
17701766 default:
17711767 // If the code isn't optimized, there may be outstanding folding
18411837 return MCBinaryExpr::createAnd(OpExpr, MaskExpr, Ctx);
18421838 }
18431839
1840 case Instruction::Sub: {
1841 GlobalValue *LHSGV;
1842 APInt LHSOffset;
1843 if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHSGV, LHSOffset,
1844 getDataLayout())) {
1845 GlobalValue *RHSGV;
1846 APInt RHSOffset;
1847 if (IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset,
1848 getDataLayout())) {
1849 const MCExpr *RelocExpr = getObjFileLowering().lowerRelativeReference(
1850 LHSGV, RHSGV, *Mang, TM);
1851 if (!RelocExpr)
1852 RelocExpr = MCBinaryExpr::createSub(
1853 MCSymbolRefExpr::create(getSymbol(LHSGV), Ctx),
1854 MCSymbolRefExpr::create(getSymbol(RHSGV), Ctx), Ctx);
1855 int64_t Addend = (LHSOffset - RHSOffset).getSExtValue();
1856 if (Addend != 0)
1857 RelocExpr = MCBinaryExpr::createAdd(
1858 RelocExpr, MCConstantExpr::create(Addend, Ctx), Ctx);
1859 return RelocExpr;
1860 }
1861 }
1862 }
1863 // else fallthrough
1864
18441865 // The MC library also has a right-shift operator, but it isn't consistently
18451866 // signed or unsigned between different targets.
18461867 case Instruction::Add:
1847 case Instruction::Sub:
18481868 case Instruction::Mul:
18491869 case Instruction::SDiv:
18501870 case Instruction::SRem:
437437 KeySym);
438438 }
439439
440 const MCExpr *TargetLoweringObjectFileELF::lowerRelativeReference(
441 const GlobalValue *LHS, const GlobalValue *RHS, Mangler &Mang,
442 const TargetMachine &TM) const {
443 // We may only use a PLT-relative relocation to refer to unnamed_addr
444 // functions.
445 if (!LHS->hasUnnamedAddr() || !LHS->getValueType()->isFunctionTy())
446 return nullptr;
447
448 // Basic sanity checks.
449 if (LHS->getType()->getPointerAddressSpace() != 0 ||
450 RHS->getType()->getPointerAddressSpace() != 0 || LHS->isThreadLocal() ||
451 RHS->isThreadLocal())
452 return nullptr;
453
454 return MCBinaryExpr::createSub(
455 MCSymbolRefExpr::create(TM.getSymbol(LHS, Mang), PLTRelativeVariantKind,
456 getContext()),
457 MCSymbolRefExpr::create(TM.getSymbol(RHS, Mang), getContext()),
458 getContext());
459 }
460
440461 void
441462 TargetLoweringObjectFileELF::InitializeELF(bool UseInitArray_) {
442463 UseInitArray = UseInitArray_;
2020 protected:
2121 const MCSection *AttributesSection;
2222 public:
23 ARMElfTargetObjectFile() :
24 TargetLoweringObjectFileELF(),
25 AttributesSection(nullptr)
26 {}
23 ARMElfTargetObjectFile()
24 : TargetLoweringObjectFileELF(), AttributesSection(nullptr) {
25 PLTRelativeVariantKind = MCSymbolRefExpr::VK_ARM_PREL31;
26 }
2727
2828 void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
2929
7272 InitializeELF(TM.Options.UseInitArray);
7373 }
7474
75 const MCExpr *X86WindowsTargetObjectFile::getExecutableRelativeSymbol(
76 const ConstantExpr *CE, Mangler &Mang, const TargetMachine &TM) const {
77 // We are looking for the difference of two symbols, need a subtraction
78 // operation.
79 const SubOperator *Sub = dyn_cast(CE);
80 if (!Sub)
81 return nullptr;
82
83 // Symbols must first be numbers before we can subtract them, we need to see a
84 // ptrtoint on both subtraction operands.
85 const PtrToIntOperator *SubLHS =
86 dyn_cast(Sub->getOperand(0));
87 const PtrToIntOperator *SubRHS =
88 dyn_cast(Sub->getOperand(1));
89 if (!SubLHS || !SubRHS)
90 return nullptr;
91
75 const MCExpr *X86WindowsTargetObjectFile::lowerRelativeReference(
76 const GlobalValue *LHS, const GlobalValue *RHS, Mangler &Mang,
77 const TargetMachine &TM) const {
9278 // Our symbols should exist in address space zero, cowardly no-op if
9379 // otherwise.
94 if (SubLHS->getPointerAddressSpace() != 0 ||
95 SubRHS->getPointerAddressSpace() != 0)
80 if (LHS->getType()->getPointerAddressSpace() != 0 ||
81 RHS->getType()->getPointerAddressSpace() != 0)
9682 return nullptr;
9783
9884 // Both ptrtoint instructions must wrap global objects:
9985 // - Only global variables are eligible for image relative relocations.
10086 // - The subtrahend refers to the special symbol __ImageBase, a GlobalVariable.
101 const auto *GOLHS = dyn_cast(SubLHS->getPointerOperand());
102 const auto *GVRHS = dyn_cast(SubRHS->getPointerOperand());
103 if (!GOLHS || !GVRHS)
104 return nullptr;
105
10687 // We expect __ImageBase to be a global variable without a section, externally
10788 // defined.
10889 //
10990 // It should look something like this: @__ImageBase = external constant i8
110 if (GVRHS->isThreadLocal() || GVRHS->getName() != "__ImageBase" ||
111 !GVRHS->hasExternalLinkage() || GVRHS->hasInitializer() ||
112 GVRHS->hasSection())
91 if (!isa(LHS) || !isa(RHS) ||
92 LHS->isThreadLocal() || RHS->isThreadLocal() ||
93 RHS->getName() != "__ImageBase" || !RHS->hasExternalLinkage() ||
94 cast(RHS)->hasInitializer() || RHS->hasSection())
11395 return nullptr;
11496
115 // An image-relative, thread-local, symbol makes no sense.
116 if (GOLHS->isThreadLocal())
117 return nullptr;
118
119 return MCSymbolRefExpr::create(TM.getSymbol(GOLHS, Mang),
120 MCSymbolRefExpr::VK_COFF_IMGREL32,
121 getContext());
97 return MCSymbolRefExpr::create(
98 TM.getSymbol(LHS, Mang), MCSymbolRefExpr::VK_COFF_IMGREL32, getContext());
12299 }
123100
124101 static std::string APIntToHexString(const APInt &AI) {
3939 /// \brief This implemenatation is used for X86 ELF targets that don't
4040 /// have a further specialization.
4141 class X86ELFTargetObjectFile : public TargetLoweringObjectFileELF {
42 public:
43 X86ELFTargetObjectFile() {
44 PLTRelativeVariantKind = MCSymbolRefExpr::VK_PLT;
45 }
46
4247 /// \brief Describe a TLS variable address within debug info.
4348 const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
4449 };
5257 /// \brief This implementation is used for Windows targets on x86 and x86-64.
5358 class X86WindowsTargetObjectFile : public TargetLoweringObjectFileCOFF {
5459 const MCExpr *
55 getExecutableRelativeSymbol(const ConstantExpr *CE, Mangler &Mang,
56 const TargetMachine &TM) const override;
60 lowerRelativeReference(const GlobalValue *LHS, const GlobalValue *RHS,
61 Mangler &Mang,
62 const TargetMachine &TM) const override;
5763
5864 /// \brief Given a mergeable constant with the specified size and relocation
5965 /// information, return a section that it should be placed in.
0 ; RUN: llc -mtriple=armv7-unknown-linux -o - %s | FileCheck %s
1
2 @vtable = constant [4 x i32] [i32 0,
3 i32 sub (i32 ptrtoint (void ()* @fn1 to i32), i32 ptrtoint (i32* getelementptr ([4 x i32], [4 x i32]* @vtable, i32 0, i32 1) to i32)),
4 i32 sub (i32 ptrtoint (void ()* @fn2 to i32), i32 ptrtoint (i32* getelementptr ([4 x i32], [4 x i32]* @vtable, i32 0, i32 1) to i32)),
5 i32 sub (i32 ptrtoint (void ()* @fn3 to i32), i32 ptrtoint (i32* getelementptr ([4 x i32], [4 x i32]* @vtable, i32 0, i32 1) to i32))
6 ]
7
8 declare void @fn1() unnamed_addr
9 declare void @fn2() unnamed_addr
10 declare void @fn3()
11
12 ; CHECK: .long 0
13 ; CHECK-NEXT: .long (fn1(prel31)-vtable)-4
14 ; CHECK-NEXT: .long (fn2(prel31)-vtable)-4
15 ; CHECK-NEXT: .long (fn3-vtable)-4
0 ; RUN: llc -mtriple=x86_64-unknown-linux -o - %s | FileCheck %s
1
2 @vtable = constant [5 x i32] [i32 0,
3 i32 trunc (i64 sub (i64 ptrtoint (void ()* @fn1 to i64), i64 ptrtoint (i32* getelementptr ([5 x i32], [5 x i32]* @vtable, i32 0, i32 1) to i64)) to i32),
4 i32 trunc (i64 sub (i64 ptrtoint (void ()* @fn2 to i64), i64 ptrtoint (i32* getelementptr ([5 x i32], [5 x i32]* @vtable, i32 0, i32 1) to i64)) to i32),
5 i32 trunc (i64 sub (i64 ptrtoint (void ()* @fn3 to i64), i64 ptrtoint (i32* getelementptr ([5 x i32], [5 x i32]* @vtable, i32 0, i32 1) to i64)) to i32),
6 i32 trunc (i64 sub (i64 ptrtoint (i8* @global4 to i64), i64 ptrtoint (i32* getelementptr ([5 x i32], [5 x i32]* @vtable, i32 0, i32 1) to i64)) to i32)
7 ]
8
9 declare void @fn1() unnamed_addr
10 declare void @fn2() unnamed_addr
11 declare void @fn3()
12 @global4 = external unnamed_addr global i8
13
14 ; CHECK: .long 0
15 ; CHECK-NEXT: .long (fn1@PLT-vtable)-4
16 ; CHECK-NEXT: .long (fn2@PLT-vtable)-4
17 ; CHECK-NEXT: .long (fn3-vtable)-4
18 ; CHECK-NEXT: .long (global4-vtable)-4
0 ; RUN: llc -mtriple=i686-unknown-linux -o - %s | FileCheck %s
1
2 @vtable = constant [4 x i32] [i32 0,
3 i32 sub (i32 ptrtoint (void ()* @fn1 to i32), i32 ptrtoint (i32* getelementptr ([4 x i32], [4 x i32]* @vtable, i32 0, i32 1) to i32)),
4 i32 sub (i32 ptrtoint (void ()* @fn2 to i32), i32 ptrtoint (i32* getelementptr ([4 x i32], [4 x i32]* @vtable, i32 0, i32 1) to i32)),
5 i32 sub (i32 ptrtoint (void ()* @fn3 to i32), i32 ptrtoint (i32* getelementptr ([4 x i32], [4 x i32]* @vtable, i32 0, i32 1) to i32))
6 ]
7
8 declare void @fn1() unnamed_addr
9 declare void @fn2() unnamed_addr
10 declare void @fn3()
11
12 ; CHECK: .long 0
13 ; CHECK-NEXT: .long (fn1@PLT-vtable)-4
14 ; CHECK-NEXT: .long (fn2@PLT-vtable)-4
15 ; CHECK-NEXT: .long (fn3-vtable)-4
2121
2222 ;;;; image base relocation
2323
24 ; CHECK: .long g3@IMGREL
24 ; CHECK: .long g3@IMGREL{{$}}
2525 @t5 = global i32 trunc(i64 sub(i64 ptrtoint(i32* @g3 to i64), i64 ptrtoint(i64** @__ImageBase to i64)) to i32), section ".fix"
26
27 ; CHECK: .long g3@IMGREL+4{{$}}
28 @t6 = global i32 trunc(i64 sub(i64 ptrtoint(i32* getelementptr (i32, i32* @g3, i32 1) to i64), i64 ptrtoint(i64** @__ImageBase to i64)) to i32), section ".fix"
2629
2730 ;;;; cross-section relative with source offset
2831
2932 %struct.EEType = type { [2 x i8], i64, i32}
3033
31 ; CHECK: .long g3-(t6+16)
32 @t6 = global %struct.EEType {
34 ; CHECK: .long (g3-t7)-16
35 @t7 = global %struct.EEType {
3336 [2 x i8] c"\01\02",
3437 i64 256,
35 i32 trunc(i64 sub(i64 ptrtoint(i32* @g3 to i64), i64 ptrtoint(i32* getelementptr inbounds (%struct.EEType, %struct.EEType* @t6, i32 0, i32 2) to i64)) to i32 )
38 i32 trunc(i64 sub(i64 ptrtoint(i32* @g3 to i64), i64 ptrtoint(i32* getelementptr inbounds (%struct.EEType, %struct.EEType* @t7, i32 0, i32 2) to i64)) to i32 )
3639 }, section ".fix"
4848 ; supported on x86-64 but not on ARM64
4949
5050 ; CHECK: .long 5
51 ; CHECK-NEXT: .long (l_extgotequiv-(_table+44))+24
51 ; CHECK-NEXT: .long ((l_extgotequiv-_table)-44)+24
5252 %struct.data { i32 4, %struct.anon { i32 5,
5353 i32 add (i32 trunc (i64 sub (i64 ptrtoint (i32** @extgotequiv to i64),
5454 i64 ptrtoint (i32* getelementptr inbounds ([4 x %struct.data], [4 x %struct.data]* @table, i32 0, i64 3, i32 1, i32 1) to i64))