LTO: Pass SF_Executable flag through to InputFile::Symbol

Summary:
The linker needs to be able to determine whether a symbol is text or data to
handle the case of a common being overridden by a strong definition in an
archive. If the archive contains a text member of the same name as the common,
that function is discarded. However, if the archive contains a data member of
the same name, that strong definition overrides the common. This is a behavior
of ld.bfd, which the Qualcomm linker also supports in LTO.

Here's a test case to illustrate:

####

cat > 1.c << \!
int blah;
!

cat > 2.c << \!
int blah() {
  return 0;
}
!

cat > 3.c << \!
int blah = 20;
!

clang -c 1.c
clang -c 2.c
clang -c 3.c

ar cr lib.a 2.o 3.o
ld 1.o lib.a -t

####

The correct output is:

1.o
(lib.a)3.o

Thanks to Shankar Easwaran and Hemant Kulkarni for the test case!

Reviewers: mehdi_amini, rafael, pcc, davide

Reviewed By: pcc

Subscribers: davide, llvm-commits, inglorion

Differential Revision: https://reviews.llvm.org/D31901

llvm-svn: 300205
This commit is contained in:
Tobias Edler von Koch 2017-04-13 16:24:14 +00:00
parent d77394c5f2
commit 90df1f48d5
5 changed files with 24 additions and 13 deletions

View File

@ -126,6 +126,7 @@ public:
using irsymtab::Symbol::getCommonSize; using irsymtab::Symbol::getCommonSize;
using irsymtab::Symbol::getCommonAlignment; using irsymtab::Symbol::getCommonAlignment;
using irsymtab::Symbol::getCOFFWeakExternalFallback; using irsymtab::Symbol::getCOFFWeakExternalFallback;
using irsymtab::Symbol::isExecutable;
}; };
/// A range over the symbols in this InputFile. /// A range over the symbols in this InputFile.

View File

@ -92,6 +92,7 @@ struct Symbol {
FB_global, FB_global,
FB_format_specific, FB_format_specific,
FB_unnamed_addr, FB_unnamed_addr,
FB_executable,
}; };
/// The index into the Uncommon table, or -1 if this symbol does not have an /// The index into the Uncommon table, or -1 if this symbol does not have an
@ -166,6 +167,7 @@ struct Symbol {
bool isGlobal() const { return (Flags >> S::FB_global) & 1; } bool isGlobal() const { return (Flags >> S::FB_global) & 1; }
bool isFormatSpecific() const { return (Flags >> S::FB_format_specific) & 1; } bool isFormatSpecific() const { return (Flags >> S::FB_format_specific) & 1; }
bool isUnnamedAddr() const { return (Flags >> S::FB_unnamed_addr) & 1; } bool isUnnamedAddr() const { return (Flags >> S::FB_unnamed_addr) & 1; }
bool isExecutable() const { return (Flags >> S::FB_executable) & 1; }
uint64_t getCommonSize() const { uint64_t getCommonSize() const {
assert(isCommon()); assert(isCommon());

View File

@ -125,6 +125,8 @@ Error Builder::addSymbol(ModuleSymbolTable::Symbol Msym) {
Sym.Flags |= 1 << storage::Symbol::FB_global; Sym.Flags |= 1 << storage::Symbol::FB_global;
if (Flags & object::BasicSymbolRef::SF_FormatSpecific) if (Flags & object::BasicSymbolRef::SF_FormatSpecific)
Sym.Flags |= 1 << storage::Symbol::FB_format_specific; Sym.Flags |= 1 << storage::Symbol::FB_format_specific;
if (Flags & object::BasicSymbolRef::SF_Executable)
Sym.Flags |= 1 << storage::Symbol::FB_executable;
Sym.ComdatIndex = -1; Sym.ComdatIndex = -1;
auto *GV = Msym.dyn_cast<GlobalValue *>(); auto *GV = Msym.dyn_cast<GlobalValue *>();

View File

@ -11,37 +11,42 @@ source_filename = "src.c"
!0 = !{i32 6, !"Linker Options", !{!{!"/include:foo"}}} !0 = !{i32 6, !"Linker Options", !{!{!"/include:foo"}}}
!llvm.module.flags = !{ !0 } !llvm.module.flags = !{ !0 }
; CHECK: H------ _g1 ; CHECK: D------X _fun
define i32 @fun() {
ret i32 0
}
; CHECK: H------- _g1
@g1 = hidden global i32 0 @g1 = hidden global i32 0
; CHECK: P------ _g2 ; CHECK: P------- _g2
@g2 = protected global i32 0 @g2 = protected global i32 0
; CHECK: D------ _g3 ; CHECK: D------- _g3
@g3 = global i32 0 @g3 = global i32 0
; CHECK: DU----- _g4 ; CHECK: DU------ _g4
@g4 = external global i32 @g4 = external global i32
; CHECK: D--W--- _g5 ; CHECK: D--W---- _g5
@g5 = weak global i32 0 @g5 = weak global i32 0
; CHECK: D--W-O- _g6 ; CHECK: D--W-O-- _g6
@g6 = linkonce_odr unnamed_addr global i32 0 @g6 = linkonce_odr unnamed_addr global i32 0
; CHECK: D-----T _g7 ; CHECK: D-----T- _g7
@g7 = thread_local global i32 0 @g7 = thread_local global i32 0
; CHECK: D-C---- _g8 ; CHECK: D-C----- _g8
; CHECK-NEXT: size 4 align 8 ; CHECK-NEXT: size 4 align 8
@g8 = common global i32 0, align 8 @g8 = common global i32 0, align 8
; CHECK: D------ _g9 ; CHECK: D------- _g9
; CHECK-NEXT: comdat g9 ; CHECK-NEXT: comdat g9
$g9 = comdat any $g9 = comdat any
@g9 = global i32 0, comdat @g9 = global i32 0, comdat
; CHECK: D--WI-- _g10 ; CHECK: D--WI--- _g10
; CHECK-NEXT: comdat g9 ; CHECK-NEXT: comdat g9
; CHECK-NEXT: fallback _g9 ; CHECK-NEXT: fallback _g9
@g10 = weak alias i32, i32* @g9 @g10 = weak alias i32, i32* @g9

View File

@ -317,6 +317,7 @@ static int dumpSymtab(int argc, char **argv) {
PrintBool('I', Sym.isIndirect()); PrintBool('I', Sym.isIndirect());
PrintBool('O', Sym.canBeOmittedFromSymbolTable()); PrintBool('O', Sym.canBeOmittedFromSymbolTable());
PrintBool('T', Sym.isTLS()); PrintBool('T', Sym.isTLS());
PrintBool('X', Sym.isExecutable());
outs() << ' ' << Sym.getName() << '\n'; outs() << ' ' << Sym.getName() << '\n';
if (Sym.isCommon()) if (Sym.isCommon())