diff options
-rw-r--r-- | lld/ELF/Driver.cpp | 1 | ||||
-rw-r--r-- | lld/ELF/InputFiles.cpp | 8 | ||||
-rw-r--r-- | lld/ELF/InputFiles.h | 3 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 21 | ||||
-rw-r--r-- | lld/ELF/SymbolTable.h | 2 | ||||
-rw-r--r-- | lld/test/elf2/progname.s | 20 |
6 files changed, 51 insertions, 4 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index e0136d25041..346ab44e097 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -227,5 +227,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { Config->OutputFile = "a.out"; // Write the result to the file. + Symtab.finalize(); writeResult<ELFT>(&Symtab); } diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 10f12cd4e9d..b154ac63c2a 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -301,14 +301,14 @@ template <class ELFT> void SharedFile<ELFT>::parse() { uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); SymbolBodies.reserve(NumSymbols); for (const Elf_Sym &Sym : Syms) { - if (Sym.isUndefined()) - continue; - ErrorOr<StringRef> NameOrErr = Sym.getName(this->StringTable); error(NameOrErr.getError()); StringRef Name = *NameOrErr; - SymbolBodies.emplace_back(this, Name, Sym); + if (Sym.isUndefined()) + Undefs.push_back(Name); + else + SymbolBodies.emplace_back(this, Name, Sym); } } diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 86ec5360670..00ab848eddf 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -169,6 +169,7 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> { typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range; std::vector<SharedSymbol<ELFT>> SymbolBodies; + std::vector<StringRef> Undefs; StringRef SoName; public: @@ -177,6 +178,8 @@ public: return SymbolBodies; } + llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; } + static bool classof(const InputFile *F) { return F->kind() == Base::SharedKind; } diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 6818d53db8d..a74913cc5fa 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -181,6 +181,13 @@ template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) { return Sym; } +template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) { + auto It = Symtab.find(Name); + if (It == Symtab.end()) + return nullptr; + return It->second->Body; +} + template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *New) { Symbol *Sym = insert(New); if (Sym->Body == New) @@ -230,6 +237,20 @@ template <class ELFT> void SymbolTable<ELFT>::addMemberFile(Lazy *Body) { addFile(std::move(File)); } +template <class ELFT> void SymbolTable<ELFT>::finalize() { + // This code takes care of the case in which shared libraries depend on + // the user program (not the other way, which is usual). Shared libraries + // may have undefined symbols, expecting that the user program provides + // the definitions for them. An example is BSD's __progname symbol. + // We need to put such symbols to the main program's .dynsym so that + // shared libraries can find them. + for (std::unique_ptr<SharedFile<ELFT>> &File : SharedFiles) + for (StringRef U : File->getUndefinedSymbols()) + if (SymbolBody *Sym = find(U)) + if (Sym->isDefined()) + Sym->setUsedInDynamicReloc(); +} + template class lld::elf2::SymbolTable<ELF32LE>; template class lld::elf2::SymbolTable<ELF32BE>; template class lld::elf2::SymbolTable<ELF64LE>; diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index ddaa9ed842a..a41d8d3b2cd 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -52,6 +52,7 @@ public: void addSyntheticSym(StringRef Name, OutputSection<ELFT> &Section, typename llvm::object::ELFFile<ELFT>::uintX_t Value); void addIgnoredSym(StringRef Name); + void finalize(); private: Symbol *insert(SymbolBody *New); @@ -60,6 +61,7 @@ private: void addMemberFile(Lazy *Body); void checkCompatibility(std::unique_ptr<InputFile> &File); void resolve(SymbolBody *Body); + SymbolBody *find(StringRef Name); void reportConflict(const Twine &Message, const SymbolBody &Old, const SymbolBody &New, bool Warning); diff --git a/lld/test/elf2/progname.s b/lld/test/elf2/progname.s new file mode 100644 index 00000000000..18b1ef7ef96 --- /dev/null +++ b/lld/test/elf2/progname.s @@ -0,0 +1,20 @@ +// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o +// RUN: echo '.global __progname' > %t2.s +// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %t2.s -o %t2.o +// RUN: ld.lld2 -shared %t2.o -o %t2.so +// RUN: ld.lld2 -o %t %t.o %t2.so +// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s + +// CHECK: Name: __progname@ +// CHECK-NEXT: Value: 0x11000 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Global (0x1) +// CHECK-NEXT: Type: None (0x0) +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: .text +// CHECK-NEXT: } + +.global _start, __progname +_start: +__progname: + nop |