llvm.org GIT mirror llvm / a63ab3c
[LTO] Prevent dead stripping and internalization of symbols with sections Summary: ELF linkers generate __start_<secname> and __stop_<secname> symbols when there is a value in a section <secname> where the name is a valid C identifier. If dead stripping determines that the values declared in section <secname> are dead, and we then internalize (and delete) such a symbol, programs that reference the corresponding start and end section symbols will get undefined reference linking errors. To fix this, add the section name to the IRSymtab entry when a symbol is defined in a specific section. Then use this in the gold-plugin to mark the symbol as external and visible from outside the summary when the section name is a valid C identifier. Reviewers: pcc Subscribers: mehdi_amini, inglorion, eraman, llvm-commits Differential Revision: https://reviews.llvm.org/D35639 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@309009 91177308-0d34-0410-b5e6-96231b3b80d8 Teresa Johnson 3 years ago
8 changed file(s) with 134 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
125125 using irsymtab::Symbol::getCommonSize;
126126 using irsymtab::Symbol::getCommonAlignment;
127127 using irsymtab::Symbol::getCOFFWeakExternalFallback;
128 using irsymtab::Symbol::getSectionName;
128129 using irsymtab::Symbol::isExecutable;
129130 };
130131
120120 /// COFF-specific: the name of the symbol that a weak external resolves to
121121 /// if not defined.
122122 Str COFFWeakExternFallbackName;
123
124 /// Specified section name, if any.
125 Str SectionName;
123126 };
124127
125128 struct Header {
127130 /// when the format changes, but it does not need to be incremented if a
128131 /// change to LLVM would cause it to create a different symbol table.
129132 Word Version;
130 enum { kCurrentVersion = 0 };
133 enum { kCurrentVersion = 1 };
131134
132135 /// The producer's version string (LLVM_VERSION_STRING " " LLVM_REVISION).
133136 /// Consumers should rebuild the symbol table from IR if the producer's
164167 // Copied from storage::Uncommon.
165168 uint32_t CommonSize, CommonAlign;
166169 StringRef COFFWeakExternFallbackName;
170 StringRef SectionName;
167171
168172 /// Returns the mangled symbol name.
169173 StringRef getName() const { return Name; }
214218 assert(isWeak() && isIndirect());
215219 return COFFWeakExternFallbackName;
216220 }
221
222 StringRef getSectionName() const { return SectionName; }
217223 };
218224
219225 /// This class can be used to read a Symtab and Strtab produced by
299305 CommonSize = UncI->CommonSize;
300306 CommonAlign = UncI->CommonAlign;
301307 COFFWeakExternFallbackName = R->str(UncI->COFFWeakExternFallbackName);
302 }
308 SectionName = R->str(UncI->SectionName);
309 } else
310 // Reset this field so it can be queried unconditionally for all symbols.
311 SectionName = "";
303312 }
304313
305314 public:
155155 Unc = &Uncommons.back();
156156 *Unc = {};
157157 setStr(Unc->COFFWeakExternFallbackName, "");
158 setStr(Unc->SectionName, "");
158159 return *Unc;
159160 };
160161
239240 }
240241 }
241242
243 if (!Base->getSection().empty())
244 setStr(Uncommon().SectionName, Saver.save(Base->getSection()));
245
242246 return Error::success();
243247 }
244248
88
99 ; BCA:
1010 ; Version stored at offset 0.
11 ; BCA-NEXT: blob data = '\x00\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00D\x00\x00\x00\x01\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x02\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00'
11 ; BCA-NEXT: blob data = '\x01\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00D\x00\x00\x00\x01\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x02\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00'
1212 ; BCA-NEXT:
1313 ; BCA-NEXT:
1414 ; BCA-NEXT: blob data = 'foobarproducerx86_64-unknown-linux-gnuirsymtab.ll'
1515 ; BCA-NEXT:
1616
17 ; SYMTAB: version: 0
17 ; SYMTAB: version: 1
1818 ; SYMTAB-NEXT: producer: producer
1919 ; SYMTAB-NEXT: target triple: x86_64-unknown-linux-gnu
2020 ; SYMTAB-NEXT: source filename: irsymtab.ll
0 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-unknown-linux-gnu"
2
3 define void @deadfunc2_called_from_section() {
4 ret void
5 }
6
7 define void @deadfunc2_called_from_nonC_section() {
8 ret void
9 }
0 ; Test to ensure we don't internalize or treat as dead a global value
1 ; with a valid C identifier section name. Otherwise, ELF linker generation of
2 ; __start_"sectionname" and __stop_"sectionname" symbols would not occur and
3 ; we can end up with undefined references at link time.
4
5 ; First try RegularLTO
6 ; RUN: opt %s -o %t.o
7 ; RUN: llvm-lto2 dump-symtab %t.o | FileCheck %s --check-prefix=SYMTAB
8 ; RUN: opt %p/Inputs/global_with_section.ll -o %t2.o
9 ; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold.so \
10 ; RUN: --plugin-opt=save-temps \
11 ; RUN: -o %t3.o %t.o %t2.o
12 ; Check results of internalization
13 ; RUN: llvm-dis %t3.o.0.2.internalize.bc -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK2-REGULARLTO
14
15 ; Next try ThinLTO
16 ; RUN: opt -module-summary %s -o %t.o
17 ; RUN: llvm-lto2 dump-symtab %t.o | FileCheck %s --check-prefix=SYMTAB
18 ; RUN: opt -module-summary %p/Inputs/global_with_section.ll -o %t2.o
19 ; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold.so \
20 ; RUN: --plugin-opt=thinlto \
21 ; RUN: --plugin-opt=save-temps \
22 ; RUN: -o %t3.o %t.o %t2.o
23 ; Check results of internalization
24 ; RUN: llvm-dis %t.o.2.internalize.bc -o - | FileCheck %s
25 ; RUN: llvm-dis %t2.o.2.internalize.bc -o - | FileCheck %s --check-prefix=CHECK2-THINLTO
26
27 ; SYMTAB: deadfunc_with_section
28 ; SYMTAB-NEXT: section some_other_section
29 ; SYMTAB-NEXT: deadfunc_with_nonC_section
30 ; SYMTAB-NEXT: section .nonCsection
31 ; SYMTAB-NEXT: deadfunc2_called_from_section
32 ; SYMTAB-NEXT: deadfunc2_called_from_nonC_section
33 ; SYMTAB-NEXT: var_with_section
34 ; SYMTAB-NEXT: section some_section
35 ; SYMTAB-NEXT: var_with_nonC_section
36 ; SYMTAB-NEXT: section .nonCsection
37
38 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
39 target triple = "x86_64-unknown-linux-gnu"
40
41 ; We should not internalize @var_with_section due to section
42 ; CHECK-DAG: @var_with_section = global i32 0, section "some_section"
43 @var_with_section = global i32 0, section "some_section"
44
45 ; Confirm via a variable with a non-C identifier section that we are getting
46 ; the expected internalization.
47 ; CHECK-DAG: @var_with_nonC_section = internal global i32 0, section ".nonCsection"
48 @var_with_nonC_section = global i32 0, section ".nonCsection"
49
50 ; We should not internalize @deadfunc_with_section due to section
51 ; CHECK-DAG: define void @deadfunc_with_section() section "some_other_section"
52 define void @deadfunc_with_section() section "some_other_section" {
53 call void @deadfunc2_called_from_section()
54 ret void
55 }
56
57 ; Confirm via a function with a non-C identifier section that we are getting
58 ; the expected internalization.
59 ; CHECK-DAG: define internal void @deadfunc_with_nonC_section() section ".nonCsection"
60 define void @deadfunc_with_nonC_section() section ".nonCsection" {
61 call void @deadfunc2_called_from_nonC_section()
62 ret void
63 }
64
65 ; In RegularLTO mode, where we have combined all the IR,
66 ; @deadfunc2_called_from_section can be internalized.
67 ; CHECK2-REGULARLTO: define internal void @deadfunc2_called_from_section
68 ; In ThinLTO mode, we can't internalize it as it needs to be preserved
69 ; (due to the access from @deadfunc_with_section which must be preserved), and
70 ; can't be internalized since the reference is from a different module.
71 ; CHECK2-THINLTO: define void @deadfunc2_called_from_section
72 declare void @deadfunc2_called_from_section()
73
74 ; Confirm when called from a function with a non-C identifier section that we
75 ; are getting the expected internalization.
76 ; CHECK2-REGULARLTO: define internal void @deadfunc2_called_from_nonC_section
77 ; CHECK2-THINLTO: define internal void @deadfunc2_called_from_nonC_section
78 declare void @deadfunc2_called_from_nonC_section()
604604 return NewPath.str() + NewSuffix;
605605 }
606606
607 static bool isAlpha(char C) {
608 return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_';
609 }
610
611 static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); }
612
613 // Returns true if S is valid as a C language identifier.
614 static bool isValidCIdentifier(StringRef S) {
615 return !S.empty() && isAlpha(S[0]) &&
616 std::all_of(S.begin() + 1, S.end(), isAlnum);
617 }
618
607619 static void addModule(LTO &Lto, claimed_file &F, const void *View,
608620 StringRef Filename) {
609621 MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize),
615627 toString(ObjOrErr.takeError()).c_str());
616628
617629 unsigned SymNum = 0;
630 std::unique_ptr Input = std::move(ObjOrErr.get());
631 auto InputFileSyms = Input->symbols();
632 assert(InputFileSyms.size() == F.syms.size());
618633 std::vector Resols(F.syms.size());
619634 for (ld_plugin_symbol &Sym : F.syms) {
635 const InputFile::Symbol &InpSym = InputFileSyms[SymNum];
620636 SymbolResolution &R = Resols[SymNum++];
621637
622638 ld_plugin_symbol_resolution Resolution =
652668 break;
653669 }
654670
671 // If the symbol has a C identifier section name, we need to mark
672 // it as visible to a regular object so that LTO will keep it around
673 // to ensure the linker generates special __start_ and
674 // __stop_ symbols which may be used elsewhere.
675 if (isValidCIdentifier(InpSym.getSectionName()))
676 R.VisibleToRegularObj = true;
677
655678 if (Resolution != LDPR_RESOLVED_DYN && Resolution != LDPR_UNDEF &&
656679 (IsExecutable || !Res.DefaultVisibility))
657680 R.FinalDefinitionInLinkageUnit = true;
659682 freeSymName(Sym);
660683 }
661684
662 check(Lto.add(std::move(*ObjOrErr), Resols),
685 check(Lto.add(std::move(Input), Resols),
663686 std::string("Failed to link module ") + F.name);
664687 }
665688
354354
355355 if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect())
356356 outs() << " fallback " << Sym.getCOFFWeakExternalFallback() << '\n';
357
358 if (!Sym.getSectionName().empty())
359 outs() << " section " << Sym.getSectionName() << "\n";
357360 }
358361
359362 outs() << '\n';