[lld] 66e4eb9 - [LLD][ELF] Implement --discard-* for cases when -r or --emit-relocs are used.

Igor Kudrin via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 25 05:00:09 PDT 2020


Author: Igor Kudrin
Date: 2020-04-25T18:59:41+07:00
New Revision: 66e4eb9c1bbd1cc571393a88787157a8ae6abdc1

URL: https://github.com/llvm/llvm-project/commit/66e4eb9c1bbd1cc571393a88787157a8ae6abdc1
DIFF: https://github.com/llvm/llvm-project/commit/66e4eb9c1bbd1cc571393a88787157a8ae6abdc1.diff

LOG: [LLD][ELF] Implement --discard-* for cases when -r or --emit-relocs are used.

When discarding local symbols with --discard-all or --discard-locals,
the ones which are used in relocations should be preserved. LLD used
the simplest approach and just ignored those switches when -r or
--emit-relocs was specified.

The patch implements handling the --discard-* switches for the cases
when relocations are kept by identifying used local symbols and allowing
removing only unused ones. This makes the behavior of LLD compatible
with GNU linkers.

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

Added: 
    

Modified: 
    lld/ELF/Symbols.h
    lld/ELF/Writer.cpp
    lld/test/ELF/emit-relocs-discard-locals.s
    lld/test/ELF/relocatable-discard-locals.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index a36669e893aa..b69d263153d2 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -258,6 +258,9 @@ class Symbol {
   uint8_t isPreemptible : 1;
 
   // True if an undefined or shared symbol is used from a live section.
+  //
+  // NOTE: In Writer.cpp the field is used to mark local defined symbols
+  // which are referenced by relocations when -r or --emit-relocs is given.
   uint8_t used : 1;
 
   // True if a call to this symbol needs to be followed by a restore of the

diff  --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index a9dd643f85c6..03fe0fe92aa0 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -637,13 +637,48 @@ template <class ELFT> void Writer<ELFT>::run() {
     error("failed to write to the output file: " + toString(std::move(e)));
 }
 
+template <class ELFT, class RelTy>
+static void markUsedLocalSymbolsImpl(ObjFile<ELFT> *file,
+                                     llvm::ArrayRef<RelTy> rels) {
+  for (const RelTy &rel : rels) {
+    Symbol &sym = file->getRelocTargetSym(rel);
+    if (sym.isLocal())
+      sym.used = true;
+  }
+}
+
+// The function ensures that the "used" field of local symbols reflects the fact
+// that the symbol is used in a relocation from a live section.
+template <class ELFT> static void markUsedLocalSymbols() {
+  // With --gc-sections, the field is already filled.
+  // See MarkLive<ELFT>::resolveReloc().
+  if (config->gcSections)
+    return;
+  // Without --gc-sections, the field is initialized with "true".
+  // Drop the flag first and then rise for symbols referenced in relocations.
+  for (InputFile *file : objectFiles) {
+    ObjFile<ELFT> *f = cast<ObjFile<ELFT>>(file);
+    for (Symbol *b : f->getLocalSymbols())
+      b->used = false;
+    for (InputSectionBase *s : f->getSections()) {
+      InputSection *isec = dyn_cast_or_null<InputSection>(s);
+      if (!isec)
+        continue;
+      if (isec->type == SHT_REL)
+        markUsedLocalSymbolsImpl(f, isec->getDataAs<typename ELFT::Rel>());
+      else if (isec->type == SHT_RELA)
+        markUsedLocalSymbolsImpl(f, isec->getDataAs<typename ELFT::Rela>());
+    }
+  }
+}
+
 static bool shouldKeepInSymtab(const Defined &sym) {
   if (sym.isSection())
     return false;
 
-  // If --emit-reloc or -r is given, all symbols including local ones need to be
-  // copied because they may be referenced by relocations.
-  if (config->copyRelocs)
+  // If --emit-reloc or -r is given, preserve symbols referenced by relocations
+  // from live sections.
+  if (config->copyRelocs && sym.used)
     return true;
 
   if (config->discard == DiscardPolicy::None)
@@ -696,6 +731,8 @@ static bool includeInSymtab(const Symbol &b) {
 template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
   if (!in.symTab)
     return;
+  if (config->copyRelocs && config->discard != DiscardPolicy::None)
+    markUsedLocalSymbols<ELFT>();
   for (InputFile *file : objectFiles) {
     ObjFile<ELFT> *f = cast<ObjFile<ELFT>>(file);
     for (Symbol *b : f->getLocalSymbols()) {

diff  --git a/lld/test/ELF/emit-relocs-discard-locals.s b/lld/test/ELF/emit-relocs-discard-locals.s
index 39d1aa56dc37..baf31503a67d 100644
--- a/lld/test/ELF/emit-relocs-discard-locals.s
+++ b/lld/test/ELF/emit-relocs-discard-locals.s
@@ -1,31 +1,50 @@
 # REQUIRES: x86
-## Test that --emit-relocs keeps local symbols and overrides --discard-{locals,all}.
+## Test that --emit-relocs keeps local symbols which are used in relocations
+## even when --discard-{locals,all} is given.
+
+## There are two separate code paths that mark used local symbols when
+## --gc-sections is specified and when is not. The test checks both.
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64 -save-temp-labels %s -o %t.o
 
 # RUN: ld.lld --emit-relocs --discard-locals %t.o -o %tlocal
-# RUN: llvm-readelf -s %tlocal | FileCheck --check-prefixes=SYM,SYM-NOGC %s
+# RUN: llvm-readelf -s %tlocal | FileCheck --check-prefixes=DISCARD-LOCALS,DISCARD-LOCALS-NOGC %s
 # RUN: llvm-readobj -r %tlocal | FileCheck --check-prefix=REL %s
+
 ## --gc-sections can discard symbols relative to GCed sections (including STT_SECTION).
 # RUN: ld.lld --emit-relocs --discard-locals --gc-sections %t.o -o %tlocal.gc
-# RUN: llvm-readelf -s %tlocal.gc | FileCheck --check-prefix=SYM %s
+# RUN: llvm-readelf -s %tlocal.gc | FileCheck --check-prefix=DISCARD-LOCALS %s
 # RUN: llvm-readobj -r %tlocal | FileCheck --check-prefix=REL %s
 
 # RUN: ld.lld --emit-relocs --discard-all %t.o -o %tall
-# RUN: llvm-readelf -s %tall | FileCheck --check-prefixes=SYM,SYM-NOGC %s
+# RUN: llvm-readelf -s %tall | FileCheck --check-prefixes=DISCARD-ALL,DISCARD-ALL-NOGC %s
 # RUN: llvm-readobj -r %tall | FileCheck --check-prefix=REL %s
 
-# SYM:           NOTYPE  LOCAL  DEFAULT {{.*}} .Lunused
-# SYM-NOGC-NEXT: NOTYPE  LOCAL  DEFAULT {{.*}} .Lunused_gc
-# SYM-NEXT:      NOTYPE  LOCAL  DEFAULT {{.*}} .Lused
-# SYM-NEXT:      NOTYPE  LOCAL  DEFAULT {{.*}} unused
-# SYM-NOGC-NEXT: NOTYPE  LOCAL  DEFAULT {{.*}} unused_gc
-# SYM-NEXT:      NOTYPE  LOCAL  DEFAULT {{.*}} used
-# SYM-NEXT:      SECTION LOCAL  DEFAULT {{.*}} .text
-# SYM-NEXT:      SECTION LOCAL  DEFAULT {{.*}} text
-# SYM-NOGC-NEXT: SECTION LOCAL  DEFAULT {{.*}} gc
-# SYM-NEXT:      SECTION LOCAL  DEFAULT {{.*}} .comment
-# SYM-NEXT:      NOTYPE  GLOBAL DEFAULT {{.*}} _start
+# RUN: ld.lld --emit-relocs --discard-all --gc-sections %t.o -o %tall.gc
+# RUN: llvm-readelf -s %tall.gc | FileCheck --check-prefix=DISCARD-ALL %s
+# RUN: llvm-readobj -r %tall.gc | FileCheck --check-prefix=REL %s
+
+## --discard-locals removes unused local symbols which start with ".L"
+# DISCARD-LOCALS:    0: {{0+}} 0 NOTYPE  LOCAL  DEFAULT UND
+# DISCARD-LOCALS-NEXT:           NOTYPE  LOCAL  DEFAULT {{.*}} .Lused
+# DISCARD-LOCALS-NEXT:           NOTYPE  LOCAL  DEFAULT {{.*}} unused
+# DISCARD-LOCALS-NOGC-NEXT:      NOTYPE  LOCAL  DEFAULT {{.*}} unused_gc
+# DISCARD-LOCALS-NEXT:           NOTYPE  LOCAL  DEFAULT {{.*}} used
+# DISCARD-LOCALS-NEXT:           SECTION LOCAL  DEFAULT {{.*}} .text
+# DISCARD-LOCALS-NEXT:           SECTION LOCAL  DEFAULT {{.*}} text
+# DISCARD-LOCALS-NOGC-NEXT:      SECTION LOCAL  DEFAULT {{.*}} gc
+# DISCARD-LOCALS-NEXT:           SECTION LOCAL  DEFAULT {{.*}} .comment
+# DISCARD-LOCALS-NEXT:           NOTYPE  GLOBAL DEFAULT {{.*}} _start
+
+## --discard-all removes all unused regular local symbols.
+# DISCARD-ALL:       0: {{0+}} 0 NOTYPE  LOCAL  DEFAULT UND
+# DISCARD-ALL-NEXT:              NOTYPE  LOCAL  DEFAULT {{.*}} .Lused
+# DISCARD-ALL-NEXT:              NOTYPE  LOCAL  DEFAULT {{.*}} used
+# DISCARD-ALL-NEXT:              SECTION LOCAL  DEFAULT {{.*}} .text
+# DISCARD-ALL-NEXT:              SECTION LOCAL  DEFAULT {{.*}} text
+# DISCARD-ALL-NOGC-NEXT:         SECTION LOCAL  DEFAULT {{.*}} gc
+# DISCARD-ALL-NEXT:              SECTION LOCAL  DEFAULT {{.*}} .comment
+# DISCARD-ALL-NEXT:              NOTYPE  GLOBAL DEFAULT {{.*}} _start
 
 # REL:      .rela.text {
 # REL-NEXT:   R_X86_64_PLT32 text 0xFFFFFFFFFFFFFFFC

diff  --git a/lld/test/ELF/relocatable-discard-locals.s b/lld/test/ELF/relocatable-discard-locals.s
index c1e06bda8b64..298590def5f1 100644
--- a/lld/test/ELF/relocatable-discard-locals.s
+++ b/lld/test/ELF/relocatable-discard-locals.s
@@ -1,27 +1,36 @@
 # REQUIRES: x86
-## Test that -r keeps local symbols and overrides --discard-{locals,all}.
-## Also see emit-relocs-discard-locals.s
+## Test that -r keeps local symbols which are used in relocations even when
+## --discard-{locals,all} is given.
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64 -save-temp-labels %s -o %t.o
 
 # RUN: ld.lld -r --discard-locals %t.o -o %tlocal.ro
-# RUN: llvm-readelf -s %tlocal.ro | FileCheck --check-prefixes=SYM,SYM-NOGC %s
+# RUN: llvm-readelf -s %tlocal.ro | FileCheck --check-prefix=DISCARD-LOCALS %s
 # RUN: llvm-readobj -r %tlocal.ro | FileCheck --check-prefix=REL %s
 
 # RUN: ld.lld -r --discard-all %t.o -o %tall.ro
-# RUN: llvm-readelf -s %tall.ro | FileCheck --check-prefixes=SYM,SYM-NOGC %s
+# RUN: llvm-readelf -s %tall.ro | FileCheck --check-prefix=DISCARD-ALL %s
 # RUN: llvm-readobj -r %tall.ro | FileCheck --check-prefix=REL %s
 
-# SYM:           NOTYPE  LOCAL  DEFAULT {{.*}} .Lunused
-# SYM-NOGC-NEXT: NOTYPE  LOCAL  DEFAULT {{.*}} .Lunused_gc
-# SYM-NEXT:      NOTYPE  LOCAL  DEFAULT {{.*}} .Lused
-# SYM-NEXT:      NOTYPE  LOCAL  DEFAULT {{.*}} unused
-# SYM-NOGC-NEXT: NOTYPE  LOCAL  DEFAULT {{.*}} unused_gc
-# SYM-NEXT:      NOTYPE  LOCAL  DEFAULT {{.*}} used
-# SYM-NEXT:      SECTION LOCAL  DEFAULT {{.*}} .text
-# SYM-NEXT:      SECTION LOCAL  DEFAULT {{.*}} text
-# SYM-NOGC-NEXT: SECTION LOCAL  DEFAULT {{.*}} gc
-# SYM-NEXT:      NOTYPE  GLOBAL DEFAULT {{.*}} _start
+## --discard-locals removes unused local symbols which start with ".L"
+# DISCARD-LOCALS:    0: {{0+}} 0 NOTYPE  LOCAL  DEFAULT UND
+# DISCARD-LOCALS-NEXT:           NOTYPE  LOCAL  DEFAULT {{.*}} .Lused
+# DISCARD-LOCALS-NEXT:           NOTYPE  LOCAL  DEFAULT {{.*}} unused
+# DISCARD-LOCALS-NEXT:           NOTYPE  LOCAL  DEFAULT {{.*}} unused_gc
+# DISCARD-LOCALS-NEXT:           NOTYPE  LOCAL  DEFAULT {{.*}} used
+# DISCARD-LOCALS-NEXT:           SECTION LOCAL  DEFAULT {{.*}} .text
+# DISCARD-LOCALS-NEXT:           SECTION LOCAL  DEFAULT {{.*}} text
+# DISCARD-LOCALS-NEXT:           SECTION LOCAL  DEFAULT {{.*}} gc
+# DISCARD-LOCALS-NEXT:           NOTYPE  GLOBAL DEFAULT {{.*}} _start
+
+## --discard-all removes all unused regular local symbols.
+# DISCARD-ALL:    0: {{0+}} 0 NOTYPE  LOCAL  DEFAULT UND
+# DISCARD-ALL-NEXT:           NOTYPE  LOCAL  DEFAULT {{.*}} .Lused
+# DISCARD-ALL-NEXT:           NOTYPE  LOCAL  DEFAULT {{.*}} used
+# DISCARD-ALL-NEXT:           SECTION LOCAL  DEFAULT {{.*}} .text
+# DISCARD-ALL-NEXT:           SECTION LOCAL  DEFAULT {{.*}} text
+# DISCARD-ALL-NEXT:           SECTION LOCAL  DEFAULT {{.*}} gc
+# DISCARD-ALL-NEXT:           NOTYPE  GLOBAL DEFAULT {{.*}} _start
 
 # REL:      .rela.text {
 # REL-NEXT:   R_X86_64_PLT32 text 0xFFFFFFFFFFFFFFFC


        


More information about the llvm-commits mailing list