diff options
author | Rui Ueyama <ruiu@google.com> | 2015-10-11 20:59:12 +0000 |
---|---|---|
committer | Rui Ueyama <ruiu@google.com> | 2015-10-11 20:59:12 +0000 |
commit | 35da9b6e1ca4db99f0471b0634deace6fdf630ef (patch) | |
tree | deb6a11b1700e01b07dc9c7d39bcd62838fc8af7 | |
parent | 78ed9b43fdfe966dd4c3e8d581a83a693693380d (diff) | |
download | bcm5719-llvm-35da9b6e1ca4db99f0471b0634deace6fdf630ef.tar.gz bcm5719-llvm-35da9b6e1ca4db99f0471b0634deace6fdf630ef.zip |
ELF2: Implement --as-needed.
This patch adds AsNeeded and IsUsed bool fields to SharedFile. AsNeeded bit
is set if the DSO is enclosed with --as-needed and --no-as-needed. IsUsed
bit is off by default. When we adds a symbol to the symbol table for dynamic
linking, we set its SharedFile's IsUsed bit.
If AsNeeded is set but IsUsed is not set, we don't want to write that
file's SO name to DT_NEEDED field.
http://reviews.llvm.org/D13579
llvm-svn: 249998
-rw-r--r-- | lld/ELF/Config.h | 1 | ||||
-rw-r--r-- | lld/ELF/Driver.cpp | 13 | ||||
-rw-r--r-- | lld/ELF/InputFiles.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/InputFiles.h | 7 | ||||
-rw-r--r-- | lld/ELF/InputSection.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/LinkerScript.cpp | 5 | ||||
-rw-r--r-- | lld/ELF/Options.td | 6 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 9 | ||||
-rw-r--r-- | lld/ELF/Symbols.h | 7 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 19 | ||||
-rw-r--r-- | lld/test/elf2/Inputs/shared2.s | 6 | ||||
-rw-r--r-- | lld/test/elf2/Inputs/shared3.s | 3 | ||||
-rw-r--r-- | lld/test/elf2/as-needed.s | 43 |
13 files changed, 106 insertions, 17 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index c19d136ffce..b740579221f 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -43,6 +43,7 @@ struct Configuration { std::string RPath; std::vector<llvm::StringRef> SearchPaths; bool AllowMultipleDefinition; + bool AsNeeded = false; bool DiscardAll; bool DiscardLocals; bool DiscardNone; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index aa37656b598..0e081d18dda 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -100,9 +100,12 @@ void LinkerDriver::addFile(StringRef Path) { } Files.push_back(make_unique<ArchiveFile>(MBRef)); return; - case file_magic::elf_shared_object: - Files.push_back(createELFFile<SharedFile>(MBRef)); + case file_magic::elf_shared_object: { + std::unique_ptr<ELFFileBase> File = createELFFile<SharedFile>(MBRef); + cast<SharedFileBase>(File.get())->AsNeeded = Config->AsNeeded; + Files.push_back(std::move(File)); return; + } default: Files.push_back(createELFFile<ObjectFile>(MBRef)); } @@ -187,6 +190,12 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { case OPT_script: addFile(Arg->getValue()); break; + case OPT_as_needed: + Config->AsNeeded = true; + break; + case OPT_no_as_needed: + Config->AsNeeded = false; + break; case OPT_Bstatic: Config->Static = true; break; diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 78aaa8f4b67..b0a5b16c57b 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -329,7 +329,7 @@ template <class ELFT> void SharedFile<ELFT>::parse() { error(NameOrErr.getError()); StringRef Name = *NameOrErr; - SymbolBodies.emplace_back(Name, Sym); + SymbolBodies.emplace_back(this, Name, Sym); } } diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 488a7608941..288f1364cc3 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -146,7 +146,7 @@ public: uint32_t FirstNonLocal = this->Symtab->sh_info; if (SymbolIndex < FirstNonLocal) return nullptr; - return SymbolBodies[SymbolIndex - FirstNonLocal]->repl(); + return SymbolBodies[SymbolIndex - FirstNonLocal]; } Elf_Sym_Range getLocalSymbols(); @@ -198,6 +198,11 @@ public: StringRef getSoName() const { return SoName; } virtual void parseSoName() = 0; virtual void parse() = 0; + + // Used for --as-needed + bool AsNeeded = false; + bool IsUsed = false; + bool isNeeded() const { return !AsNeeded || IsUsed; } }; template <class ELFT> diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 35b61487508..fd186b11da9 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -46,7 +46,7 @@ void InputSection<ELFT>::relocate( continue; SymVA = getLocalSymVA(Sym, File); } else { - SymbolBody &Body = *File.getSymbolBody(SymIndex); + SymbolBody &Body = *File.getSymbolBody(SymIndex)->repl(); SymVA = getSymVA<ELFT>(Body); if (Target->relocNeedsPlt(Type, Body)) { SymVA = Out<ELFT>::Plt->getEntryAddr(Body); diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index e1c26417ba0..933b6becb32 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -155,12 +155,15 @@ void LinkerScript::addFile(StringRef S) { void LinkerScript::readAsNeeded() { expect("("); + bool Orig = Config->AsNeeded; + Config->AsNeeded = true; for (;;) { StringRef Tok = next(); if (Tok == ")") - return; + break; addFile(Tok); } + Config->AsNeeded = Orig; } void LinkerScript::readEntry() { diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 82e5922fcab..20f34acab27 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -14,6 +14,8 @@ def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">, def allow_shlib_undefined : Flag<["--", "-"], "allow-shlib-undefined">; +def as_needed : Flag<["--"], "as-needed">; + def disable_new_dtags : Flag<["--"], "disable-new-dtags">, HelpText<"Disable new dynamic tags">; @@ -52,6 +54,8 @@ def m : Separate<["-"], "m">, def no_allow_shlib_undefined : Flag<["--"], "no-allow-shlib-undefined">; +def no_as_needed : Flag<["--"], "no-as-needed">; + def no_whole_archive : Flag<["--"], "no-whole-archive">, HelpText<"Restores the default behavior of loading archive members">; @@ -111,14 +115,12 @@ def alias_undefined_u : Separate<["-"], "u">, Alias<undefined>; // Options listed below are silently ignored now. def O3 : Flag<["-"], "O3">; -def as_needed : Flag<["--"], "as-needed">; def build_id : Flag<["--"], "build-id">; def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">; def end_group : Flag<["--"], "end-group">; def gc_sections : Flag<["--"], "gc-sections">; def hash_style : Joined<["--"], "hash-style=">; def no_add_needed : Flag<["--"], "no-add-needed">; -def no_as_needed : Flag<["--"], "no-as-needed">; def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">; def start_group : Flag<["--"], "start-group">; def strip_all : Flag<["--"], "strip-all">; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 16261d76529..e7e9400d87e 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -116,8 +116,10 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { OutputSection<ELFT> *OutSec = C.getOutputSection(); uint32_t SymIndex = RI.getSymbol(IsMips64EL); const ObjectFile<ELFT> &File = *C.getFile(); - const SymbolBody *Body = File.getSymbolBody(SymIndex); + SymbolBody *Body = File.getSymbolBody(SymIndex); const ELFFile<ELFT> &Obj = File.getObj(); + if (Body) + Body = Body->repl(); uint32_t Type = RI.getType(IsMips64EL); @@ -279,6 +281,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { NumEntries += 2; for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles()) { + if (!F->isNeeded()) + continue; Out<ELFT>::DynStrTab->add(F->getSoName()); ++NumEntries; } @@ -356,7 +360,8 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { WriteArray(DT_FINI_ARRAY, DT_FINI_ARRAYSZ, FiniArraySec); for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles()) - WriteVal(DT_NEEDED, Out<ELFT>::DynStrTab->getFileOff(F->getSoName())); + if (F->isNeeded()) + WriteVal(DT_NEEDED, Out<ELFT>::DynStrTab->getFileOff(F->getSoName())); if (InitSym) WritePtr(DT_INIT, getSymVA<ELFT>(*InitSym)); diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 0e8c005a359..f53d956bd8f 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -24,6 +24,7 @@ class InputFile; class SymbolBody; template <class ELFT> class ObjectFile; template <class ELFT> class OutputSection; +template <class ELFT> class SharedFile; // Initializes global objects defined in this file. // Called at the beginning of main(). @@ -263,8 +264,10 @@ public: return S->kind() == Base::SharedKind; } - SharedSymbol(StringRef Name, const Elf_Sym &Sym) - : Defined<ELFT>(Base::SharedKind, Name, Sym) {} + SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym) + : Defined<ELFT>(Base::SharedKind, Name, Sym), File(F) {} + + SharedFile<ELFT> *File; }; // This class represents a symbol defined in an archive file. It is diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index bfb5dce8b91..bb3cd1aeb3c 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -174,6 +174,14 @@ void Writer<ELFT>::scanRelocs( uint32_t SymIndex = RI.getSymbol(IsMips64EL); SymbolBody *Body = File.getSymbolBody(SymIndex); uint32_t Type = RI.getType(IsMips64EL); + + // Set "used" bit for --as-needed. + if (Body && Body->isUndefined() && !Body->isWeak()) + if (auto *S = dyn_cast<SharedSymbol<ELFT>>(Body->repl())) + S->File->IsUsed = true; + + if (Body) + Body = Body->repl(); if (Body) { if (Target->relocNeedsPlt(Type, *Body)) { if (Body->isInPlt()) @@ -186,12 +194,13 @@ void Writer<ELFT>::scanRelocs( Out<ELFT>::Got->addEntry(Body); } } - if (canBePreempted(Body)) { + + bool CBP = canBePreempted(Body); + if (!CBP && (!Config->Shared || Target->isRelRelative(Type))) + continue; + if (CBP) Body->setUsedInDynamicReloc(); - Out<ELFT>::RelaDyn->addReloc({C, RI}); - } else if (Config->Shared && !Target->isRelRelative(Type)) { - Out<ELFT>::RelaDyn->addReloc({C, RI}); - } + Out<ELFT>::RelaDyn->addReloc({C, RI}); } } diff --git a/lld/test/elf2/Inputs/shared2.s b/lld/test/elf2/Inputs/shared2.s new file mode 100644 index 00000000000..a723902e890 --- /dev/null +++ b/lld/test/elf2/Inputs/shared2.s @@ -0,0 +1,6 @@ +.global bar2 +.type bar2, @function +bar2: + +.global zed2 +zed2: diff --git a/lld/test/elf2/Inputs/shared3.s b/lld/test/elf2/Inputs/shared3.s new file mode 100644 index 00000000000..d1f6ffea133 --- /dev/null +++ b/lld/test/elf2/Inputs/shared3.s @@ -0,0 +1,3 @@ +.global baz +.type barz, @function +baz: diff --git a/lld/test/elf2/as-needed.s b/lld/test/elf2/as-needed.s new file mode 100644 index 00000000000..2a3786f9d7a --- /dev/null +++ b/lld/test/elf2/as-needed.s @@ -0,0 +1,43 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared2.s -o %t3.o +// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared3.s -o %t4.o +// RUN: ld.lld2 -shared %t2.o -soname shared1 -o %t2.so +// RUN: ld.lld2 -shared %t3.o -soname shared2 -o %t3.so +// RUN: ld.lld2 -shared %t4.o -soname shared3 -o %t4.so + +/// Check if --as-needed actually works. + +// RUN: ld.lld2 %t.o %t2.so %t3.so %t4.so -o %t2 +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s + +// RUN: ld.lld2 --as-needed %t.o %t2.so %t3.so %t4.so -o %t2 +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s + +// RUN: ld.lld2 --as-needed %t.o %t2.so --no-as-needed %t3.so %t4.so -o %t2 +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s + +/// GROUP directive is the same as --as-needed. + +// RUN: echo "GROUP(" %t2.so %t3.so %t4.so ")" > %t.script +// RUN: ld.lld2 %t.o %t.script -o %t2 +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s + +// RUN: echo "GROUP(AS_NEEDED(" %t2.so %t3.so %t4.so "))" > %t.script +// RUN: ld.lld2 %t.o %t.script -o %t2 +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s + +// CHECK: NEEDED SharedLibrary (shared1) +// CHECK: NEEDED SharedLibrary (shared2) +// CHECK: NEEDED SharedLibrary (shared3) + +// CHECK2: NEEDED SharedLibrary (shared1) +// CHECK2-NOT: NEEDED SharedLibrary (shared2) +// CHECK2-NOT: NEEDED SharedLibrary (shared3) + +.global _start +_start: +.long bar +.long zed +.weak baz |