diff options
author | Peter Smith <peter.smith@linaro.org> | 2018-05-15 08:57:21 +0000 |
---|---|---|
committer | Peter Smith <peter.smith@linaro.org> | 2018-05-15 08:57:21 +0000 |
commit | dbef8cc67c9918334c22f03e23e2dfa84ade464b (patch) | |
tree | b5fdfd07c8936ada276396dbbcbfb7284194b919 | |
parent | 559d1e34df710a0c88dc775b014413c8f80804f7 (diff) | |
download | bcm5719-llvm-dbef8cc67c9918334c22f03e23e2dfa84ade464b.tar.gz bcm5719-llvm-dbef8cc67c9918334c22f03e23e2dfa84ade464b.zip |
[ELF] Implement --keep-unique option
The --keep-unique <symbol> option is taken from gold. The intention is that
<symbol> will be prevented from being folded by ICF. Although not
specifically mentioned in the documentation <symbol> only matches
global symbols, with a warning if the symbol is not found.
The implementation finds the Section defining <symbol> and removes it from
the set of sections considered for ICF.
Differential Revision: https://reviews.llvm.org/D46755
llvm-svn: 332332
-rw-r--r-- | lld/ELF/Driver.cpp | 16 | ||||
-rw-r--r-- | lld/ELF/ICF.cpp | 3 | ||||
-rw-r--r-- | lld/ELF/InputSection.h | 7 | ||||
-rw-r--r-- | lld/ELF/Options.td | 2 | ||||
-rw-r--r-- | lld/test/ELF/icf-keep-unique.s | 43 |
5 files changed, 67 insertions, 4 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 0d6602b767e..c81efb3905d 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1163,6 +1163,18 @@ template <class ELFT> static void demoteSymbols() { } } +// Record sections that define symbols mentioned in --keep-unique <symbol> +// these sections are inelligible for ICF. +static void findKeepUniqueSections(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered(OPT_keep_unique)) { + StringRef Name = Arg->getValue(); + if (auto *Sym = dyn_cast_or_null<Defined>(Symtab->find(Name))) + Sym->Section->KeepUnique = true; + else + warn("could not find symbol " + Name + " to keep unique"); + } +} + // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { @@ -1335,8 +1347,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { markLive<ELFT>(); demoteSymbols<ELFT>(); mergeSections(); - if (Config->ICF) + if (Config->ICF) { + findKeepUniqueSections(Args); doIcf<ELFT>(); + } // Read the callgraph now that we know what was gced or icfed if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file)) diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp index f98a859991a..d4e490c08d4 100644 --- a/lld/ELF/ICF.cpp +++ b/lld/ELF/ICF.cpp @@ -162,7 +162,8 @@ template <class ELFT> static uint32_t getHash(InputSection *S) { // Returns true if section S is subject of ICF. static bool isEligible(InputSection *S) { - if (!S->Live || !(S->Flags & SHF_ALLOC) || (S->Flags & SHF_WRITE)) + if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC) || + (S->Flags & SHF_WRITE)) return false; // Don't merge read only data sections unless diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 50ca557a634..bc70baf8ba3 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -61,6 +61,9 @@ public: unsigned Bss : 1; + // Set for sections that should not be folded by ICF. + unsigned KeepUnique : 1; + // These corresponds to the fields in Elf_Shdr. uint32_t Alignment; uint64_t Flags; @@ -85,8 +88,8 @@ protected: uint64_t Entsize, uint64_t Alignment, uint32_t Type, uint32_t Info, uint32_t Link) : Name(Name), Repl(this), SectionKind(SectionKind), Live(false), - Bss(false), Alignment(Alignment), Flags(Flags), Entsize(Entsize), - Type(Type), Link(Link), Info(Info) {} + Bss(false), KeepUnique(false), Alignment(Alignment), Flags(Flags), + Entsize(Entsize), Type(Type), Link(Link), Info(Info) {} }; // This corresponds to a section of an input file. diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index b71804e7bb0..580f1731469 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -192,6 +192,8 @@ defm init: Eq<"init">, HelpText<"Specify an initializer function">, defm just_symbols: Eq<"just-symbols">, HelpText<"Just link symbols">; +defm keep_unique: Eq<"keep-unique">, HelpText<"Do not fold this symbol during ICF">; + defm library: Eq<"library">, HelpText<"Root name of library to use">, MetaVarName<"<libName>">; diff --git a/lld/test/ELF/icf-keep-unique.s b/lld/test/ELF/icf-keep-unique.s new file mode 100644 index 00000000000..a6f883fc7b2 --- /dev/null +++ b/lld/test/ELF/icf-keep-unique.s @@ -0,0 +1,43 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections | FileCheck %s +# RUN: ld.lld %t -o %t2 --keep-unique f2 --keep-unique f4 --keep-unique f5 --icf=all --print-icf-sections 2>&1 | FileCheck %s -check-prefix=CHECK-KEEP + +// Base case, expect only .text.f1 to be kept +// CHECK: selected section {{.*}}:(.text.f1) +// CHECK-NEXT: removing identical section {{.*}}:(.text.f2) +// CHECK-NEXT: removing identical section {{.*}}:(.text.f3) +// CHECK-NEXT: removing identical section {{.*}}:(.text.f4) +// CHECK-NEXT: removing identical section {{.*}}:(.text.f5) + +// With --keep-unique f2, f4 and f5 we expect only f3 and f5 to be removed. +// f5 is not matched by --keep-unique as it is a local symbol. +// CHECK-KEEP: warning: could not find symbol f5 to keep unique +// CHECK-KEEP: selected section {{.*}}:(.text.f1) +// CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f3) +// CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f5) + .globl _start, f1, f2, f3, f4 +_start: + ret + + .section .text.f1, "ax" +f1: + nop + + .section .text.f2, "ax" +f2: + nop + +.section .text.f3, "ax" +f3: + nop + +.section .text.f4, "ax" +f4: + nop + +# f5 is local, not found by --keep-unique f5 +.section .text.f5, "ax" +f5: + nop |