ELF2: Fix BSD's __progname symbol issue.
BSD's DSO files have undefined symbol "__progname" which is defined
in crt1.o. On that system, both user programs and system shared
libraries depend on each other.
In general, we need to put symbols defined by user programs which are
referenced by shared libraries to user program's .dynsym.
http://reviews.llvm.org/D13637
llvm-svn: 250176
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index e0136d2..346ab44 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -227,5 +227,6 @@
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 10f12cd..b154ac6 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -301,14 +301,14 @@
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 86ec536..00ab848 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -169,6 +169,7 @@
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 @@
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 6818d53..a74913c 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -181,6 +181,13 @@
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 @@
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 ddaa9ed..a41d8d3 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -52,6 +52,7 @@
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 @@
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);