diff options
author | Denis Protivensky <dprotivensky@accesssoftek.com> | 2015-10-05 09:43:57 +0000 |
---|---|---|
committer | Denis Protivensky <dprotivensky@accesssoftek.com> | 2015-10-05 09:43:57 +0000 |
commit | 22220d5d5f97c1e3192a42a81dfae76a593bc70b (patch) | |
tree | 790dd013e93b22d2113ed0f2f8877d97664a74ee | |
parent | 6967527441a6daa56027822ab9419dfb882e9780 (diff) | |
download | bcm5719-llvm-22220d5d5f97c1e3192a42a81dfae76a593bc70b.tar.gz bcm5719-llvm-22220d5d5f97c1e3192a42a81dfae76a593bc70b.zip |
[ELF2] Add --undefined option
Add symbol specified with -u as undefined which may cause additional
object files from archives to be linked into the resulting binary.
Differential Revision: http://reviews.llvm.org/D13345
llvm-svn: 249295
-rw-r--r-- | lld/ELF/Driver.cpp | 3 | ||||
-rw-r--r-- | lld/ELF/Options.td | 4 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 25 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.h | 3 | ||||
-rw-r--r-- | lld/ELF/Symbols.h | 10 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 6 | ||||
-rw-r--r-- | lld/test/elf2/undefined-opt.s | 51 |
7 files changed, 96 insertions, 6 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 7375b74565a..078382c0c4b 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -157,6 +157,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { if (Symtab.getObjectFiles().empty()) error("no input files."); + for (auto *Arg : Args.filtered(OPT_undefined)) + Symtab.addUndefinedSym(Arg->getValue()); + // Write the result. const ELFFileBase *FirstObj = Symtab.getFirstELF(); switch (FirstObj->getELFKind()) { diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 284c2abe91e..a9b0cf84d1c 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -61,6 +61,9 @@ def soname : Joined<["-"], "soname=">, def sysroot : Joined<["--"], "sysroot=">, HelpText<"Set the system root">; +def undefined : Joined<["--"], "undefined=">, + HelpText<"Force undefined symbol during linking">; + def whole_archive : Flag<["--"], "whole-archive">, HelpText<"Force load of all members in a static library">; @@ -78,6 +81,7 @@ def alias_l__library : Joined<["--"], "library=">, Alias<l>; def alias_rpath_rpath : Joined<["-"], "rpath=">, Alias<rpath>; def alias_soname_h : Separate<["-"], "h">, Alias<soname>; def alias_soname_soname : Separate<["-"], "soname">, Alias<soname>; +def alias_undefined_u : Separate<["-"], "u">, Alias<undefined>; // Options listed below are silently ignored now. def O3 : Flag<["-"], "O3">; diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 1e527629c5e..14fcb3548a8 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -70,6 +70,29 @@ static TargetInfo *createTarget(uint16_t EMachine) { error("Unknown target machine"); } +void SymbolTable::addUndefinedSym(StringRef Name) { + switch (getFirstELF()->getELFKind()) { + case ELF32LEKind: + addUndefinedSym<ELF32LE>(Name); + break; + case ELF32BEKind: + addUndefinedSym<ELF32BE>(Name); + break; + case ELF64LEKind: + addUndefinedSym<ELF64LE>(Name); + break; + case ELF64BEKind: + addUndefinedSym<ELF64BE>(Name); + break; + } +} + +template <class ELFT> void SymbolTable::addUndefinedSym(StringRef Name) { + Undefined<ELFT>::SyntheticOptional.setVisibility(STV_HIDDEN); + resolve<ELFT>(new (Alloc) + Undefined<ELFT>(Name, Undefined<ELFT>::SyntheticOptional)); +} + template <class ELFT> void SymbolTable::addSyntheticSym(StringRef Name, OutputSection<ELFT> &Section, typename ELFFile<ELFT>::uintX_t Value) { @@ -94,7 +117,7 @@ template <class ELFT> void SymbolTable::init(uint16_t EMachine) { return; EntrySym = new (Alloc) Undefined<ELFT>( Config->Entry.empty() ? Target->getDefaultEntry() : Config->Entry, - Undefined<ELFT>::Synthetic); + Undefined<ELFT>::SyntheticRequired); resolve<ELFT>(EntrySym); // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol is magical diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index c451a2d1b73..b545198e47b 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -61,6 +61,8 @@ public: return EntrySym->getReplacement(); } + void addUndefinedSym(StringRef Name); + template <class ELFT> void addSyntheticSym(StringRef Name, OutputSection<ELFT> &Section, typename llvm::object::ELFFile<ELFT>::uintX_t Value); @@ -73,6 +75,7 @@ private: void addELFFile(ELFFileBase *File); void addLazy(Lazy *New); void addMemberFile(Lazy *Body); + template <class ELFT> void addUndefinedSym(StringRef Name); template <class ELFT> void init(uint16_t EMachine); template <class ELFT> void resolve(SymbolBody *Body); diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index fd928baac6c..39e3d31b4ae 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -53,7 +53,6 @@ public: bool isWeak() const { return IsWeak; } bool isUndefined() const { return SymbolKind == UndefinedKind; } bool isDefined() const { return SymbolKind <= DefinedLast; } - bool isStrongUndefined() const { return !IsWeak && isUndefined(); } bool isCommon() const { return SymbolKind == DefinedCommonKind; } bool isLazy() const { return SymbolKind == LazyKind; } bool isShared() const { return SymbolKind == SharedKind; } @@ -235,7 +234,8 @@ template <class ELFT> class Undefined : public ELFSymbolBody<ELFT> { typedef typename Base::Elf_Sym Elf_Sym; public: - static Elf_Sym Synthetic; + static Elf_Sym SyntheticRequired; + static Elf_Sym SyntheticOptional; Undefined(StringRef N, const Elf_Sym &Sym) : ELFSymbolBody<ELFT>(Base::UndefinedKind, N, Sym) {} @@ -243,10 +243,14 @@ public: static bool classof(const SymbolBody *S) { return S->kind() == Base::UndefinedKind; } + + bool canKeepUndefined() const { return &this->Sym == &SyntheticOptional; } }; template <class ELFT> -typename Undefined<ELFT>::Elf_Sym Undefined<ELFT>::Synthetic; +typename Undefined<ELFT>::Elf_Sym Undefined<ELFT>::SyntheticRequired; +template <class ELFT> +typename Undefined<ELFT>::Elf_Sym Undefined<ELFT>::SyntheticOptional; template <class ELFT> class SharedSymbol : public Defined<ELFT> { typedef Defined<ELFT> Base; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index cd9b760bb23..c7dbafe86ed 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -334,8 +334,10 @@ template <class ELFT> void Writer<ELFT>::createSections() { for (auto &P : Symtab.getSymbols()) { StringRef Name = P.first; SymbolBody *Body = P.second->Body; - if (Body->isStrongUndefined()) - reportUndefined<ELFT>(Symtab, *Body); + if (auto *U = dyn_cast<Undefined<ELFT>>(Body)) { + if (!U->isWeak() && !U->canKeepUndefined()) + reportUndefined<ELFT>(Symtab, *Body); + } if (auto *C = dyn_cast<DefinedCommon<ELFT>>(Body)) CommonSymbols.push_back(C); diff --git a/lld/test/elf2/undefined-opt.s b/lld/test/elf2/undefined-opt.s new file mode 100644 index 00000000000..5fcf6dc3c8c --- /dev/null +++ b/lld/test/elf2/undefined-opt.s @@ -0,0 +1,51 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +# RUN: %p/Inputs/abs.s -o %tabs.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +# RUN: %p/Inputs/shared.s -o %tshared.o +# RUN: rm -f %tar.a +# RUN: llvm-ar rcs %tar.a %tabs.o %tshared.o +# REQUIRES: x86 + +# Symbols from the archive are not in if not needed +# RUN: lld -flavor gnu2 -o %t1 %t.o %tar.a +# RUN: llvm-readobj --symbols %t1 | FileCheck --check-prefix=NO-UNDEFINED %s +# NO-UNDEFINED: Symbols [ +# NO-UNDEFINED-NOT: Name: abs +# NO-UNDEFINED-NOT: Name: big +# NO-UNDEFINED-NOT: Name: bar +# NO-UNDEFINED-NOT: Name: zed +# NO-UNDEFINED: ] + +# Symbols from the archive are in if needed, but only from the +# containing object file +# RUN: lld -flavor gnu2 -o %t2 %t.o %tar.a -u bar +# RUN: llvm-readobj --symbols %t2 | FileCheck --check-prefix=ONE-UNDEFINED %s +# ONE-UNDEFINED: Symbols [ +# ONE-UNDEFINED-NOT: Name: abs +# ONE-UNDEFINED-NOT: Name: big +# ONE-UNDEFINED: Name: bar +# ONE-UNDEFINED: Name: zed +# ONE-UNDEFINED: ] + +# Use the option couple of times, both short and long forms +# RUN: lld -flavor gnu2 -o %t3 %t.o %tar.a -u bar --undefined=abs +# RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TWO-UNDEFINED %s +# TWO-UNDEFINED: Symbols [ +# TWO-UNDEFINED: Name: abs +# TWO-UNDEFINED: Name: big +# TWO-UNDEFINED: Name: bar +# TWO-UNDEFINED: Name: zed +# TWO-UNDEFINED: ] + +# Added undefined symbol may be left undefined without error, but +# shouldn't show up in the dynamic table. +# RUN: lld -flavor gnu2 -shared -o %t4 %t.o %tar.a -u unknown +# RUN: llvm-readobj --dyn-symbols %t4 | \ +# RUN: FileCheck --check-prefix=UNK-UNDEFINED-SO %s +# UNK-UNDEFINED-SO: DynamicSymbols [ +# UNK-UNDEFINED-SO-NOT: Name: unknown +# UNK-UNDEFINED-SO: ] + +.globl _start; +_start: |