Skip to content

Commit 82ed93e

Browse files
committed
[ELF] Use stOther to track visibility
This simplifies SymbolTableSection<ELFT>::writeTo. Add dsoProtected to be used in canDefineSymbolInExecutable and get the side benefit that the protected DSO preemption diagnostic is clearer.
1 parent 86c35a5 commit 82ed93e

File tree

7 files changed

+36
-41
lines changed

7 files changed

+36
-41
lines changed

lld/ELF/LTO.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
266266
(config->exportDynamic || sym->exportDynamic || sym->inDynamicList);
267267
const auto *dr = dyn_cast<Defined>(sym);
268268
r.FinalDefinitionInLinkageUnit =
269-
(isExec || sym->visibility != STV_DEFAULT) && dr &&
269+
(isExec || sym->visibility() != STV_DEFAULT) && dr &&
270270
// Skip absolute symbols from ELF objects, otherwise PC-rel relocations
271271
// will be generated by for them, triggering linker errors.
272272
// Symbol section is always null for bitcode symbols, hence the check

lld/ELF/Relocations.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef,
719719
Undefined &sym = *undef.sym;
720720

721721
auto visibility = [&]() -> std::string {
722-
switch (sym.visibility) {
722+
switch (sym.visibility()) {
723723
case STV_INTERNAL:
724724
return "internal ";
725725
case STV_HIDDEN:
@@ -831,7 +831,7 @@ static bool maybeReportUndefined(Undefined &sym, InputSectionBase &sec,
831831
if (sym.isWeak())
832832
return false;
833833

834-
bool canBeExternal = !sym.isLocal() && sym.visibility == STV_DEFAULT;
834+
bool canBeExternal = !sym.isLocal() && sym.visibility() == STV_DEFAULT;
835835
if (config->unresolvedSymbols == UnresolvedPolicy::Ignore && canBeExternal)
836836
return false;
837837

@@ -938,9 +938,8 @@ static bool canDefineSymbolInExecutable(Symbol &sym) {
938938
// If the symbol has default visibility the symbol defined in the
939939
// executable will preempt it.
940940
// Note that we want the visibility of the shared symbol itself, not
941-
// the visibility of the symbol in the output file we are producing. That is
942-
// why we use Sym.stOther.
943-
if ((sym.stOther & 0x3) == STV_DEFAULT)
941+
// the visibility of the symbol in the output file we are producing.
942+
if (!sym.dsoProtected)
944943
return true;
945944

946945
// If we are allowed to break address equality of functions, defining

lld/ELF/SymbolTable.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Symbol *SymbolTable::insert(StringRef name) {
9292
sym->setName(name);
9393
sym->symbolKind = Symbol::PlaceholderKind;
9494
sym->partition = 1;
95-
sym->visibility = STV_DEFAULT;
95+
sym->setVisibility(STV_DEFAULT);
9696
sym->isUsedInRegularObj = false;
9797
sym->exportDynamic = false;
9898
sym->inDynamicList = false;

lld/ELF/Symbols.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ void Symbol::extract() const {
264264
}
265265

266266
uint8_t Symbol::computeBinding() const {
267-
if ((visibility != STV_DEFAULT && visibility != STV_PROTECTED) ||
268-
versionId == VER_NDX_LOCAL)
267+
auto v = visibility();
268+
if ((v != STV_DEFAULT && v != STV_PROTECTED) || versionId == VER_NDX_LOCAL)
269269
return STB_LOCAL;
270270
if (binding == STB_GNU_UNIQUE && !config->gnuUnique)
271271
return STB_GLOBAL;
@@ -344,7 +344,7 @@ bool elf::computeIsPreemptible(const Symbol &sym) {
344344

345345
// Only symbols with default visibility that appear in dynsym can be
346346
// preempted. Symbols with protected visibility cannot be preempted.
347-
if (!sym.includeInDynsym() || sym.visibility != STV_DEFAULT)
347+
if (!sym.includeInDynsym() || sym.visibility() != STV_DEFAULT)
348348
return false;
349349

350350
// At this point copy relocations have not been created yet, so any
@@ -377,10 +377,10 @@ void Symbol::mergeProperties(const Symbol &other) {
377377
exportDynamic = true;
378378

379379
// DSO symbols do not affect visibility in the output.
380-
if (!other.isShared() && other.visibility != STV_DEFAULT)
381-
visibility = visibility == STV_DEFAULT
382-
? other.visibility
383-
: std::min(visibility, other.visibility);
380+
if (!other.isShared() && other.visibility() != STV_DEFAULT) {
381+
uint8_t v = visibility(), ov = other.visibility();
382+
setVisibility(v == STV_DEFAULT ? ov : std::min(v, ov));
383+
}
384384
}
385385

386386
void Symbol::resolve(const Symbol &other) {
@@ -418,7 +418,7 @@ void Symbol::resolveUndefined(const Undefined &other) {
418418
//
419419
// If this is a non-weak defined symbol in a discarded section, override the
420420
// existing undefined symbol for better error message later.
421-
if ((isShared() && other.visibility != STV_DEFAULT) ||
421+
if ((isShared() && other.visibility() != STV_DEFAULT) ||
422422
(isUndefined() && other.binding != STB_WEAK && other.discardedSecIdx)) {
423423
replace(other);
424424
return;
@@ -666,7 +666,7 @@ void Symbol::resolveShared(const SharedSymbol &other) {
666666
cast<CommonSymbol>(this)->size = other.size;
667667
return;
668668
}
669-
if (visibility == STV_DEFAULT && (isUndefined() || isLazy())) {
669+
if (visibility() == STV_DEFAULT && (isUndefined() || isLazy())) {
670670
// An undefined symbol with non default visibility must be satisfied
671671
// in the same DSO.
672672
uint8_t bind = binding;

lld/ELF/Symbols.h

+17-11
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,6 @@ class Symbol {
9393
// The partition whose dynamic symbol table contains this symbol's definition.
9494
uint8_t partition = 1;
9595

96-
// Symbol visibility. This is the computed minimum visibility of all
97-
// observed non-DSO symbols.
98-
uint8_t visibility : 2;
99-
10096
// True if this symbol is preemptible at load time.
10197
uint8_t isPreemptible : 1;
10298

@@ -146,6 +142,13 @@ class Symbol {
146142

147143
inline void replace(const Symbol &other);
148144

145+
// Symbol visibility. This is the computed minimum visibility of all
146+
// observed non-DSO symbols.
147+
uint8_t visibility() const { return stOther & 3; }
148+
void setVisibility(uint8_t visibility) {
149+
stOther = (stOther & ~3) | visibility;
150+
}
151+
149152
bool includeInDynsym() const;
150153
uint8_t computeBinding() const;
151154
bool isGlobal() const { return binding == llvm::ELF::STB_GLOBAL; }
@@ -244,16 +247,15 @@ class Symbol {
244247
Symbol(Kind k, InputFile *file, StringRef name, uint8_t binding,
245248
uint8_t stOther, uint8_t type)
246249
: file(file), nameData(name.data()), nameSize(name.size()), type(type),
247-
binding(binding), stOther(stOther), symbolKind(k),
248-
visibility(stOther & 3), isPreemptible(false),
250+
binding(binding), stOther(stOther), symbolKind(k), isPreemptible(false),
249251
isUsedInRegularObj(false), used(false), exportDynamic(false),
250252
inDynamicList(false), referenced(false), referencedAfterWrap(false),
251253
traced(false), hasVersionSuffix(false), isInIplt(false),
252254
gotInIgot(false), folded(false), needsTocRestore(false),
253-
scriptDefined(false), needsCopy(false), needsGot(false),
254-
needsPlt(false), needsTlsDesc(false), needsTlsGd(false),
255-
needsTlsGdToIe(false), needsGotDtprel(false), needsTlsIe(false),
256-
hasDirectReloc(false) {}
255+
scriptDefined(false), dsoProtected(false), needsCopy(false),
256+
needsGot(false), needsPlt(false), needsTlsDesc(false),
257+
needsTlsGd(false), needsTlsGdToIe(false), needsGotDtprel(false),
258+
needsTlsIe(false), hasDirectReloc(false) {}
257259

258260
public:
259261
// True if this symbol is in the Iplt sub-section of the Plt and the Igot
@@ -277,6 +279,9 @@ class Symbol {
277279
// of the symbol.
278280
uint8_t scriptDefined : 1;
279281

282+
// True if defined in a DSO as protected visibility.
283+
uint8_t dsoProtected : 1;
284+
280285
// True if this symbol needs a canonical PLT entry, or (during
281286
// postScanRelocations) a copy relocation.
282287
uint8_t needsCopy : 1;
@@ -398,6 +403,7 @@ class SharedSymbol : public Symbol {
398403
: Symbol(SharedKind, &file, name, binding, stOther, type), value(value),
399404
size(size), alignment(alignment) {
400405
exportDynamic = true;
406+
dsoProtected = visibility() == llvm::ELF::STV_PROTECTED;
401407
// GNU ifunc is a mechanism to allow user-supplied functions to
402408
// resolve PLT slot values at load-time. This is contrary to the
403409
// regular symbol resolution scheme in which symbols are resolved just
@@ -527,7 +533,7 @@ void Symbol::replace(const Symbol &other) {
527533
nameData = old.nameData;
528534
nameSize = old.nameSize;
529535
partition = old.partition;
530-
visibility = old.visibility;
536+
setVisibility(old.visibility());
531537
isPreemptible = old.isPreemptible;
532538
isUsedInRegularObj = old.isUsedInRegularObj;
533539
exportDynamic = old.exportDynamic;

lld/ELF/SyntheticSections.cpp

+1-10
Original file line numberDiff line numberDiff line change
@@ -2198,16 +2198,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *buf) {
21982198
// Set st_name, st_info and st_other.
21992199
eSym->st_name = ent.strTabOffset;
22002200
eSym->setBindingAndType(sym->binding, sym->type);
2201-
eSym->st_other = sym->visibility;
2202-
2203-
// The 3 most significant bits of st_other are used by OpenPOWER ABI.
2204-
// See getPPC64GlobalEntryToLocalEntryOffset() for more details.
2205-
if (config->emachine == EM_PPC64)
2206-
eSym->st_other |= sym->stOther & 0xe0;
2207-
// The most significant bit of st_other is used by AArch64 ABI for the
2208-
// variant PCS.
2209-
else if (config->emachine == EM_AARCH64)
2210-
eSym->st_other |= sym->stOther & STO_AARCH64_VARIANT_PCS;
2201+
eSym->st_other = sym->stOther;
22112202

22122203
if (BssSection *commonSec = getCommonSec(sym)) {
22132204
// When -r is specified, a COMMON symbol is not allocated. Its st_shndx

lld/test/ELF/x86-64-dyn-rel-error5.s

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# REQUIRES: x86
22
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
3-
# RUN: not ld.lld -pie %t.o -o /dev/null 2>&1 | FileCheck --check-prefixes=CHECK,PIE %s
4-
# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck --check-prefixes=CHECK,SHARED %s
3+
# RUN: not ld.lld -pie %t.o -o /dev/null 2>&1 | FileCheck %s
4+
# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
55

66
## Check we don't create dynamic relocations in a writable section,
77
## if the number of bits is smaller than the wordsize.
@@ -17,8 +17,7 @@ hidden:
1717
# CHECK: error: relocation R_X86_64_16 cannot be used against local symbol; recompile with -fPIC
1818
# CHECK: error: relocation R_X86_64_32 cannot be used against local symbol; recompile with -fPIC
1919

20-
# PIE: error: cannot preempt symbol: hidden
21-
# SHARED: error: relocation R_X86_64_32 cannot be used against symbol 'hidden'; recompile with -fPIC
20+
# CHECK: error: relocation R_X86_64_32 cannot be used against symbol 'hidden'; recompile with -fPIC
2221

2322
.data
2423
.byte local # R_X86_64_8

0 commit comments

Comments
 (0)