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
This commit is contained in:
Rui Ueyama 2015-10-13 16:34:14 +00:00
parent 3014991fcf
commit f8432d97f3
6 changed files with 51 additions and 4 deletions

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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>;

View File

@ -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);

20
lld/test/elf2/progname.s Normal file
View File

@ -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