diff options
| author | Fangrui Song <maskray@google.com> | 2019-02-01 02:25:05 +0000 |
|---|---|---|
| committer | Fangrui Song <maskray@google.com> | 2019-02-01 02:25:05 +0000 |
| commit | b4744d306c0a21933d4339fa4fb497866a36ee49 (patch) | |
| tree | 67a14e57521744701f1cdfc7911c61e3dddd6f2b /lld/ELF/InputFiles.cpp | |
| parent | dfbd19033bd5675b7dcc4c54603bbfe29d551082 (diff) | |
[ELF] Support --{,no-}allow-shlib-undefined
Summary:
In ld.bfd/gold, --no-allow-shlib-undefined is the default when linking
an executable. This patch implements a check to error on undefined
symbols in a shared object, if all of its DT_NEEDED entries are seen.
Our approach resembles the one used in gold, achieves a good balance to
be useful but not too smart (ld.bfd traces all DSOs and emulates the
behavior of a dynamic linker to catch more cases).
The error is issued based on the symbol table, different from undefined
reference errors issued for relocations. It is most effective when there
are DSOs that were not linked with -z defs (e.g. when static sanitizers
runtime is used).
gold has a comment that some system libraries on GNU/Linux may have
spurious undefined references and thus system libraries should be
excluded (https://sourceware.org/bugzilla/show_bug.cgi?id=6811). The
story may have changed now but we make --allow-shlib-undefined the
default for now. Its interaction with -shared can be discussed in the
future.
Reviewers: ruiu, grimar, pcc, espindola
Reviewed By: ruiu
Subscribers: joerg, emaste, arichardson, llvm-commits
Differential Revision: https://reviews.llvm.org/D57385
llvm-svn: 352826
Diffstat (limited to 'lld/ELF/InputFiles.cpp')
| -rw-r--r-- | lld/ELF/InputFiles.cpp | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 030a375ecb4f..c3e5b2f4878a 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -862,7 +862,7 @@ SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) // Partially parse the shared object file so that we can call // getSoName on this object. -template <class ELFT> void SharedFile<ELFT>::parseSoName() { +template <class ELFT> void SharedFile<ELFT>::parseDynamic() { const Elf_Shdr *DynamicSec = nullptr; const ELFFile<ELFT> Obj = this->getObj(); ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this); @@ -899,12 +899,16 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { ArrayRef<Elf_Dyn> Arr = CHECK(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec), this); for (const Elf_Dyn &Dyn : Arr) { - if (Dyn.d_tag == DT_SONAME) { + if (Dyn.d_tag == DT_NEEDED) { + uint64_t Val = Dyn.getVal(); + if (Val >= this->StringTable.size()) + fatal(toString(this) + ": invalid DT_NEEDED entry"); + DtNeeded.push_back(this->StringTable.data() + Val); + } else if (Dyn.d_tag == DT_SONAME) { uint64_t Val = Dyn.getVal(); if (Val >= this->StringTable.size()) fatal(toString(this) + ": invalid DT_SONAME entry"); SoName = this->StringTable.data() + Val; - return; } } } @@ -972,7 +976,7 @@ uint32_t SharedFile<ELFT>::getAlignment(ArrayRef<Elf_Shdr> Sections, return (Ret > UINT32_MAX) ? 0 : Ret; } -// Fully parse the shared object file. This must be called after parseSoName(). +// Fully parse the shared object file. This must be called after parseDynamic(). // // This function parses symbol versions. If a DSO has version information, // the file has a ".gnu.version_d" section which contains symbol version |
