diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -609,9 +609,6 @@ } static DiscardPolicy getDiscard(opt::InputArgList &args) { - if (args.hasArg(OPT_relocatable)) - return DiscardPolicy::None; - auto *arg = args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); if (!arg) diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -560,8 +560,7 @@ // The main function of the writer. template void Writer::run() { - if (config->discard != DiscardPolicy::All) - copyLocalSymbols(); + copyLocalSymbols(); if (config->copyRelocs) addSectionSymbols(); @@ -642,14 +641,16 @@ if (sym.isSection()) return false; - if (config->discard == DiscardPolicy::None) - return true; - - // If -emit-reloc is given, all symbols including local ones need to be + // 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->emitRelocs) + if (config->emitRelocs || config->relocatable) return true; + if (config->discard == DiscardPolicy::None) + return true; + if (config->discard == DiscardPolicy::All) + return false; + // In ELF assembly .L symbols are normally discarded by the assembler. // If the assembler fails to do so, the linker discards them if // * --discard-locals is used. diff --git a/lld/test/ELF/emit-relocs-discard-locals.s b/lld/test/ELF/emit-relocs-discard-locals.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/emit-relocs-discard-locals.s @@ -0,0 +1,50 @@ +# REQUIRES: x86 +## Test that --emit-relocs keeps local symbols and overrides --discard-{locals,all}. + +# 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-readobj -r %tlocal | FileCheck --check-prefix=REL %s +# 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-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-readobj -r %tall | FileCheck --check-prefix=REL %s + +# SYM: NOTYPE LOCAL DEFAULT 2 .Lunused +# SYM-NOGC-NEXT: NOTYPE LOCAL DEFAULT 3 .Lunused_gc +# SYM-NEXT: NOTYPE LOCAL DEFAULT 2 .Lused +# SYM-NEXT: NOTYPE LOCAL DEFAULT 2 unused +# SYM-NOGC-NEXT: NOTYPE LOCAL DEFAULT 3 unused_gc +# SYM-NEXT: NOTYPE LOCAL DEFAULT 2 used +# SYM-NEXT: SECTION LOCAL DEFAULT 1 .text +# SYM-NEXT: SECTION LOCAL DEFAULT 2 text +# SYM-NOGC-NEXT: SECTION LOCAL DEFAULT 3 unreferenced +# SYM-NEXT: SECTION LOCAL DEFAULT {{.*}} .comment +# SYM-NEXT: NOTYPE GLOBAL DEFAULT 1 _start + +# REL: .rela.text { +# REL-NEXT: R_X86_64_PLT32 text 0xFFFFFFFFFFFFFFFC +# REL-NEXT: R_X86_64_PLT32 .Lused 0xFFFFFFFFFFFFFFFC +# REL-NEXT: R_X86_64_PLT32 used 0xFFFFFFFFFFFFFFFC +# REL-NEXT: } + +.globl _start +_start: + call text@plt + jmp .Lused@plt + call used@plt + +.section text,"ax" +.Lunused: +.Lused: +unused: +used: + +.section unreferenced,"ax" +.Lunused_gc: +unused_gc: + ret diff --git a/lld/test/ELF/relocatable-discard-locals.s b/lld/test/ELF/relocatable-discard-locals.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/relocatable-discard-locals.s @@ -0,0 +1,47 @@ +# REQUIRES: x86 +## Test that -r keeps local symbols and overrides --discard-{locals,all}. +## Also see --emit-relocs-discard-locals.s + +# 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-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-readobj -r %tall.ro | FileCheck --check-prefix=REL %s + +# SYM: NOTYPE LOCAL DEFAULT 3 .Lunused +# SYM-NOGC-NEXT: NOTYPE LOCAL DEFAULT 4 .Lunused_gc +# SYM-NEXT: NOTYPE LOCAL DEFAULT 3 .Lused +# SYM-NEXT: NOTYPE LOCAL DEFAULT 3 unused +# SYM-NOGC-NEXT: NOTYPE LOCAL DEFAULT 4 unused_gc +# SYM-NEXT: NOTYPE LOCAL DEFAULT 3 used +# SYM-NEXT: SECTION LOCAL DEFAULT 1 .text +# SYM-NEXT: SECTION LOCAL DEFAULT 3 text +# SYM-NOGC-NEXT: SECTION LOCAL DEFAULT 4 unreferenced +# SYM-NEXT: NOTYPE GLOBAL DEFAULT 1 _start + +# REL: .rela.text { +# REL-NEXT: R_X86_64_PLT32 text 0xFFFFFFFFFFFFFFFC +# REL-NEXT: R_X86_64_PLT32 .Lused 0xFFFFFFFFFFFFFFFC +# REL-NEXT: R_X86_64_PLT32 used 0xFFFFFFFFFFFFFFFC +# REL-NEXT: } + +.globl _start +_start: + call text@plt + jmp .Lused@plt + call used@plt + +.section text,"ax" +.Lunused: +.Lused: +unused: +used: + +.section unreferenced,"ax" +.Lunused_gc: +unused_gc: + ret