forked from OSchip/llvm-project
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:
parent
d77394c5f2
commit
90df1f48d5
|
@ -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.
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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 *>();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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())
|
||||||
|
|
Loading…
Reference in New Issue