Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,6 @@ struct Config {
bool gdbIndex;
bool gnuHash = false;
bool gnuUnique;
bool hasDynSymTab;
bool ignoreDataAddressEquality;
bool ignoreFunctionAddressEquality;
bool ltoCSProfileGenerate;
Expand All @@ -306,7 +305,6 @@ struct Config {
bool mipsN32Abi = false;
bool mmapOutputFile;
bool nmagic;
bool noDynamicLinker = false;
bool noinhibitExec;
bool nostdlib;
bool oFormatBinary;
Expand Down
16 changes: 5 additions & 11 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,11 +781,8 @@ static StringRef getDynamicLinker(Ctx &ctx, opt::InputArgList &args) {
auto *arg = args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
if (!arg)
return "";
if (arg->getOption().getID() == OPT_no_dynamic_linker) {
// --no-dynamic-linker suppresses undefined weak symbols in .dynsym
ctx.arg.noDynamicLinker = true;
if (arg->getOption().getID() == OPT_no_dynamic_linker)
return "";
}
return arg->getValue();
}

Expand Down Expand Up @@ -2413,7 +2410,7 @@ static void findKeepUniqueSections(Ctx &ctx, opt::InputArgList &args) {
// or DSOs, so we conservatively mark them as address-significant.
bool icfSafe = ctx.arg.icf == ICFLevel::Safe;
for (Symbol *sym : ctx.symtab->getSymbols())
if (sym->includeInDynsym(ctx))
if (sym->isExported)
markAddrsig(icfSafe, sym);

// Visit the address-significance table in each object file and mark each
Expand Down Expand Up @@ -2554,7 +2551,8 @@ void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
for (Symbol *sym : obj->getGlobalSymbols()) {
if (!sym->isDefined())
continue;
if (ctx.hasDynsym && sym->includeInDynsym(ctx))
if (ctx.hasDynsym && ctx.arg.exportDynamic &&
sym->computeBinding(ctx) != STB_LOCAL)
sym->isExported = true;
if (sym->hasVersionSuffix)
sym->parseSymbolVersion(ctx);
Expand Down Expand Up @@ -2899,12 +2897,8 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {

parseFiles(ctx, files);

// Dynamic linking is used if there is an input DSO,
// or -shared or non-static pie is specified.
ctx.hasDynsym = !ctx.sharedFiles.empty() || ctx.arg.shared ||
(ctx.arg.pie && !ctx.arg.noDynamicLinker);
// Create dynamic sections for dynamic linking and static PIE.
ctx.arg.hasDynSymTab = ctx.hasDynsym || ctx.arg.isPic;
ctx.hasDynsym = !ctx.sharedFiles.empty() || ctx.arg.isPic;

// If an entry symbol is in a static archive, pull out that file now.
if (Symbol *sym = ctx.symtab->find(ctx.arg.entry))
Expand Down
4 changes: 2 additions & 2 deletions lld/ELF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1574,7 +1574,7 @@ template <class ELFT> void SharedFile::parse() {
}
Symbol *s = ctx.symtab->addSymbol(
Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()});
s->exportDynamic = true;
s->isExported = true;
if (sym.getBinding() != STB_WEAK &&
ctx.arg.unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore)
requiredSymbols.push_back(s);
Expand Down Expand Up @@ -1771,7 +1771,7 @@ static void createBitcodeSymbol(Ctx &ctx, Symbol *&sym,
nullptr);
// The definition can be omitted if all bitcode definitions satisfy
// `canBeOmittedFromSymbolTable()` and isUsedInRegularObj is false.
// The latter condition is tested in Symbol::includeInDynsym.
// The latter condition is tested in parseVersionAndComputeIsPreemptible.
sym->ltoCanOmit = objSym.canBeOmittedFromSymbolTable() &&
(!sym->isDefined() || sym->ltoCanOmit);
sym->resolve(ctx, newSym);
Expand Down
8 changes: 3 additions & 5 deletions lld/ELF/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ void SymbolTable::handleDynamicList() {
syms = findByVersion(ver);

for (Symbol *sym : syms)
sym->exportDynamic = sym->inDynamicList = true;
sym->isExported = sym->inDynamicList = true;
}
}

Expand Down Expand Up @@ -350,10 +350,8 @@ void SymbolTable::scanVersionScript() {
assignAsterisk(pat, &v, true);
}

// isPreemptible is false at this point. To correctly compute the binding of a
// Defined (which is used by includeInDynsym(ctx)), we need to know if it is
// VER_NDX_LOCAL or not. Compute symbol versions before handling
// --dynamic-list.
// Handle --dynamic-list. If a specified symbol is also matched by local: in a
// version script, the version script takes precedence.
handleDynamicList();
}

Expand Down
29 changes: 15 additions & 14 deletions lld/ELF/Symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,16 +268,6 @@ uint8_t Symbol::computeBinding(Ctx &ctx) const {
return binding;
}

bool Symbol::includeInDynsym(Ctx &ctx) const {
if (computeBinding(ctx) == STB_LOCAL)
return false;
if (!isDefined() && !isCommon())
return true;

return exportDynamic ||
(ctx.arg.exportDynamic && (isUsedInRegularObj || !ltoCanOmit));
}

// Print out a log message for --trace-symbol.
void elf::printTraceSymbol(const Symbol &sym, StringRef name) {
std::string s;
Expand Down Expand Up @@ -370,13 +360,24 @@ void elf::parseVersionAndComputeIsPreemptible(Ctx &ctx) {
// Symbol themselves might know their versions because symbols
// can contain versions in the form of <name>@<version>.
// Let them parse and update their names to exclude version suffix.
// In addition, compute isExported and isPreemptible.
bool hasDynsym = ctx.hasDynsym;
bool maybePreemptible = ctx.sharedFiles.size() || ctx.arg.shared;
for (Symbol *sym : ctx.symtab->getSymbols()) {
if (sym->hasVersionSuffix)
sym->parseSymbolVersion(ctx);
if (hasDynsym) {
sym->isExported = sym->includeInDynsym(ctx);
sym->isPreemptible = sym->isExported && computeIsPreemptible(ctx, *sym);
if (!hasDynsym)
continue;
if (sym->computeBinding(ctx) == STB_LOCAL) {
sym->isExported = false;
continue;
}
if (!sym->isDefined() && !sym->isCommon()) {
sym->isPreemptible = maybePreemptible && computeIsPreemptible(ctx, *sym);
} else if (ctx.arg.exportDynamic &&
(sym->isUsedInRegularObj || !sym->ltoCanOmit)) {
sym->isExported = true;
sym->isPreemptible = computeIsPreemptible(ctx, *sym);
}
}
}
Expand Down Expand Up @@ -655,7 +656,7 @@ void Symbol::resolve(Ctx &ctx, const LazySymbol &other) {
}

void Symbol::resolve(Ctx &ctx, const SharedSymbol &other) {
exportDynamic = true;
isExported = true;
if (isPlaceholder()) {
other.overwrite(*this);
return;
Expand Down
15 changes: 5 additions & 10 deletions lld/ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ class Symbol {
uint8_t partition;

// True if this symbol is preemptible at load time.
//
// Primarily set in two locations, (a) parseVersionAndComputeIsPreemptible and
// (b) demoteSymbolsAndComputeIsPreemptible.
LLVM_PREFERRED_TYPE(bool)
uint8_t isPreemptible : 1;

Expand All @@ -131,16 +134,9 @@ class Symbol {
// - If -shared or --export-dynamic is specified, any symbol in an object
// file/bitcode sets this property, unless suppressed by LTO
// canBeOmittedFromSymbolTable().
//
// Primarily set in two locations, (a) after parseSymbolVersion and
// (b) during demoteSymbols.
LLVM_PREFERRED_TYPE(bool)
uint8_t isExported : 1;

// Used to compute isExported. Set when defined or referenced by a SharedFile.
LLVM_PREFERRED_TYPE(bool)
uint8_t exportDynamic : 1;

LLVM_PREFERRED_TYPE(bool)
uint8_t ltoCanOmit : 1;

Expand All @@ -159,7 +155,6 @@ class Symbol {
stOther = (stOther & ~3) | visibility;
}

bool includeInDynsym(Ctx &) const;
uint8_t computeBinding(Ctx &) const;
bool isGlobal() const { return binding == llvm::ELF::STB_GLOBAL; }
bool isWeak() const { return binding == llvm::ELF::STB_WEAK; }
Expand Down Expand Up @@ -247,8 +242,8 @@ class Symbol {
Symbol(Kind k, InputFile *file, StringRef name, uint8_t binding,
uint8_t stOther, uint8_t type)
: file(file), nameData(name.data()), nameSize(name.size()), type(type),
binding(binding), stOther(stOther), symbolKind(k), exportDynamic(false),
ltoCanOmit(false), archSpecificBit(false) {}
binding(binding), stOther(stOther), symbolKind(k), ltoCanOmit(false),
archSpecificBit(false) {}

void overwrite(Symbol &sym, Kind k) const {
if (sym.traced)
Expand Down
8 changes: 4 additions & 4 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4740,7 +4740,7 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {

// Add MIPS-specific sections.
if (ctx.arg.emachine == EM_MIPS) {
if (!ctx.arg.shared && ctx.arg.hasDynSymTab) {
if (!ctx.arg.shared && ctx.hasDynsym) {
ctx.in.mipsRldMap = std::make_unique<MipsRldMapSection>(ctx);
add(*ctx.in.mipsRldMap);
}
Expand Down Expand Up @@ -4776,8 +4776,8 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
add(*part.buildId);
}

// dynSymTab is always present to simplify sym->includeInDynsym(ctx) in
// finalizeSections.
// dynSymTab is always present to simplify several finalizeSections
// functions.
part.dynStrTab = std::make_unique<StringTableSection>(ctx, ".dynstr", true);
part.dynSymTab =
std::make_unique<SymbolTableSection<ELFT>>(ctx, *part.dynStrTab);
Expand All @@ -4803,7 +4803,7 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
part.relaDyn = std::make_unique<RelocationSection<ELFT>>(
ctx, relaDynName, ctx.arg.zCombreloc, threadCount);

if (ctx.arg.hasDynSymTab) {
if (ctx.hasDynsym) {
add(*part.dynSymTab);

part.verSym = std::make_unique<VersionTableSection>(ctx);
Expand Down
14 changes: 8 additions & 6 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ static void demoteSymbolsAndComputeIsPreemptible(Ctx &ctx) {
llvm::TimeTraceScope timeScope("Demote symbols");
DenseMap<InputFile *, DenseMap<SectionBase *, size_t>> sectionIndexMap;
bool hasDynsym = ctx.hasDynsym;
bool maybePreemptible = ctx.sharedFiles.size() || ctx.arg.shared;
for (Symbol *sym : ctx.symtab->getSymbols()) {
if (auto *d = dyn_cast<Defined>(sym)) {
if (d->section && !d->section->isLive())
Expand All @@ -296,13 +297,13 @@ static void demoteSymbolsAndComputeIsPreemptible(Ctx &ctx) {
sym->type)
.overwrite(*sym);
sym->versionId = VER_NDX_GLOBAL;
if (hasDynsym && sym->includeInDynsym(ctx))
sym->isExported = true;
}
}

if (hasDynsym)
sym->isPreemptible = sym->isExported && computeIsPreemptible(ctx, *sym);
sym->isPreemptible = maybePreemptible &&
(sym->isUndefined() || sym->isExported) &&
computeIsPreemptible(ctx, *sym);
}
}

Expand Down Expand Up @@ -1841,9 +1842,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {

// If the previous code block defines any non-hidden symbols (e.g.
// __global_pointer$), they may be exported.
if (ctx.hasDynsym)
if (ctx.hasDynsym && ctx.arg.exportDynamic)
for (Symbol *sym : ctx.synthesizedSymbols)
sym->isExported = sym->includeInDynsym(ctx);
if (sym->computeBinding(ctx) != STB_LOCAL)
sym->isExported = true;

demoteSymbolsAndComputeIsPreemptible(ctx);

Expand Down Expand Up @@ -1931,7 +1933,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {

// computeBinding might localize a linker-synthesized hidden symbol
// (e.g. __global_pointer$) that was considered exported.
if (sym->isExported && !sym->isLocal()) {
if ((sym->isExported || sym->isPreemptible) && !sym->isLocal()) {
ctx.partitions[sym->partition - 1].dynSymTab->addSymbol(sym);
if (auto *file = dyn_cast<SharedFile>(sym->file))
if (file->isNeeded && !sym->isUndefined())
Expand Down
6 changes: 4 additions & 2 deletions lld/test/ELF/executable-undefined-ignoreall.s
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# REQUIRES: x86

## --unresolved-symbols=ignore-all behaves similar to -shared:
## In dynamic linking, --unresolved-symbols=ignore-all behaves similar to -shared:
## for PLT relocations to undefined symbols, produce dynamic relocations if we
## emit .dynsym.

# RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/shared.s -o %ta.o
# RUN: ld.lld -shared -soname=ta %ta.o -o %ta.so
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o -o %t --unresolved-symbols=ignore-all -pie
# RUN: ld.lld %t.o %ta.so -o %t --unresolved-symbols=ignore-all -pie
# RUN: llvm-readobj -r %t | FileCheck %s

# CHECK: Relocations [
Expand Down
9 changes: 6 additions & 3 deletions lld/test/ELF/icf-safe.s
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/shared.s -o %ta.o
# RUN: ld.lld -shared -soname=ta %ta.o -o %ta.so

# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
# RUN: llvm-objcopy %t1.o %t1copy.o
# RUN: llvm-objcopy --localize-symbol=h1 %t1.o %t1changed.o
# RUN: ld.lld -r %t1.o -o %t1reloc.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-safe.s -o %t2.o
# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=safe --print-icf-sections | FileCheck %s
# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=safe --print-icf-sections --export-dynamic | FileCheck %s
# RUN: ld.lld %t1copy.o %t2.o -o %t2 --icf=safe --print-icf-sections | FileCheck %s
# RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections -shared | FileCheck --check-prefix=EXPORT %s
# RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections --export-dynamic | FileCheck --check-prefix=EXPORT %s
## Exported symbols are suppressed for ICF when dynamic linking is enabled.
# RUN: ld.lld %t1.o %t2.o %ta.so -o %t3 --icf=safe --print-icf-sections --export-dynamic | FileCheck --check-prefix=EXPORT %s
# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections | FileCheck --check-prefix=ALL %s
# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections --export-dynamic | FileCheck --check-prefix=ALL-EXPORT %s
# RUN: ld.lld %t1.o %t2.o %ta.so -o %t2 --icf=all --print-icf-sections --export-dynamic | FileCheck --check-prefix=ALL-EXPORT %s
# RUN: ld.lld %t1changed.o -o %t4 --icf=safe 2>&1 | FileCheck --check-prefix=SH_LINK_0 %s
# RUN: ld.lld %t1reloc.o -o %t4 --icf=safe 2>&1 | FileCheck --check-prefix=SH_LINK_0 %s

Expand Down
6 changes: 3 additions & 3 deletions lld/test/ELF/ppc32-weak-undef-call.s
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# REQUIRES: ppc
# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
# RUN: ld.lld %t.o -o %t
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=PDE %s
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=STATIC %s
# RUN: ld.lld -pie %t.o -o %t
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=PIC %s
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=STATIC %s
# RUN: ld.lld -shared %t.o -o %t
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=PIC %s

## It does not really matter how we fixup it, but we cannot overflow and
## should not generate a call stub (this would waste space).
# PDE: bl 0x100100b4
# STATIC: bl {{.*}} <.text>

## With -pie or -shared, create a call stub. ld.bfd produces bl .+0
# PIC: bl 0x[[PLT:[0-9a-f]+]]
Expand Down
16 changes: 8 additions & 8 deletions lld/test/ELF/ppc64-undefined-weak.s
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@

# RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o
# RUN: ld.lld %t.o -o %t
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=PDE
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=STATIC
# RUN: ld.lld -pie %t.o -o %t
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=PIC
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=STATIC
# RUN: ld.lld -shared %t.o -o %t.so
# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s --check-prefix=PIC

# RUN: llvm-mc -filetype=obj -triple=powerpc64 %s -o %t.o
# RUN: ld.lld %t.o -o %t
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=PDE
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=STATIC

## Branches to an undefined weak symbol need a thunk iff a dynamic relocation is
## produced. undefweak2 is hidden and does not need a dynamic relocation, so we
## suppress the thunk. undefweak1 needs a thunk iff -pie or -shared.

# PDE-LABEL: <_start>:
# PDE-NEXT: bl {{.*}} <_start>
# PDE-NEXT: nop
# PDE-NEXT: bl {{.*}} <_start+0x8>
# PDE-NEXT: nop
# STATIC-LABEL: <_start>:
# STATIC-NEXT: bl {{.*}} <_start>
# STATIC-NEXT: nop
# STATIC-NEXT: bl {{.*}} <_start+0x8>
# STATIC-NEXT: nop

# PIC-LABEL: <_start>:
# PIC-NEXT: bl {{.*}} <__plt_undefweak1>
Expand Down
13 changes: 8 additions & 5 deletions lld/test/ELF/riscv-gp.s
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@
# SEC32: {{0*}}000039c0 0 NOTYPE GLOBAL DEFAULT [[#SDATA]] __global_pointer$

# SEC64: [ [[#SDATA:]]] .sdata PROGBITS {{0*}}000032e0
# SEC64: '.dynsym'
# SEC64-NOT: __global_pointer$
# SEC64: '.symtab'
# SEC64: {{0*}}00003ae0 0 NOTYPE GLOBAL DEFAULT [[#SDATA]] __global_pointer$

# ERR: error: relocation R_RISCV_PCREL_HI20 cannot be used against symbol '__global_pointer$'; recompile with -fPIC

# RUN: ld.lld -pie --no-dynamic-linker --export-dynamic %t.64.o -o %t.64e
# RUN: llvm-readelf -s %t.64e | FileCheck %s --check-prefix=STATICPIE
# RUN: llvm-readelf -s %t.64e | FileCheck %s --check-prefix=STATICE

# STATICPIE: '.dynsym'
# STATICPIE-NOT: __global_pointer$
# STATICPIE: '.symtab'
# STATICPIE: __global_pointer$
# STATICE: '.dynsym'
# STATICE: __global_pointer$
# STATICE: '.symtab'
# STATICE: __global_pointer$

## -r mode does not define __global_pointer$.
# RUN: ld.lld -r %t.64.o -o %t.64.ro
Expand Down
Loading