(config->exportDynamic || sym->exportDynamic || sym->inDynamicList);
const auto *dr = dyn_cast<Defined>(sym);
r.FinalDefinitionInLinkageUnit =
- (isExec || sym->visibility != STV_DEFAULT) && dr &&
+ (isExec || sym->visibility() != STV_DEFAULT) && dr &&
// Skip absolute symbols from ELF objects, otherwise PC-rel relocations
// will be generated by for them, triggering linker errors.
// Symbol section is always null for bitcode symbols, hence the check
Undefined &sym = *undef.sym;
auto visibility = [&]() -> std::string {
- switch (sym.visibility) {
+ switch (sym.visibility()) {
case STV_INTERNAL:
return "internal ";
case STV_HIDDEN:
if (sym.isWeak())
return false;
- bool canBeExternal = !sym.isLocal() && sym.visibility == STV_DEFAULT;
+ bool canBeExternal = !sym.isLocal() && sym.visibility() == STV_DEFAULT;
if (config->unresolvedSymbols == UnresolvedPolicy::Ignore && canBeExternal)
return false;
// If the symbol has default visibility the symbol defined in the
// executable will preempt it.
// Note that we want the visibility of the shared symbol itself, not
- // the visibility of the symbol in the output file we are producing. That is
- // why we use Sym.stOther.
- if ((sym.stOther & 0x3) == STV_DEFAULT)
+ // the visibility of the symbol in the output file we are producing.
+ if (!sym.dsoProtected)
return true;
// If we are allowed to break address equality of functions, defining
sym->setName(name);
sym->symbolKind = Symbol::PlaceholderKind;
sym->partition = 1;
- sym->visibility = STV_DEFAULT;
+ sym->setVisibility(STV_DEFAULT);
sym->isUsedInRegularObj = false;
sym->exportDynamic = false;
sym->inDynamicList = false;
}
uint8_t Symbol::computeBinding() const {
- if ((visibility != STV_DEFAULT && visibility != STV_PROTECTED) ||
- versionId == VER_NDX_LOCAL)
+ auto v = visibility();
+ if ((v != STV_DEFAULT && v != STV_PROTECTED) || versionId == VER_NDX_LOCAL)
return STB_LOCAL;
if (binding == STB_GNU_UNIQUE && !config->gnuUnique)
return STB_GLOBAL;
// Only symbols with default visibility that appear in dynsym can be
// preempted. Symbols with protected visibility cannot be preempted.
- if (!sym.includeInDynsym() || sym.visibility != STV_DEFAULT)
+ if (!sym.includeInDynsym() || sym.visibility() != STV_DEFAULT)
return false;
// At this point copy relocations have not been created yet, so any
exportDynamic = true;
// DSO symbols do not affect visibility in the output.
- if (!other.isShared() && other.visibility != STV_DEFAULT)
- visibility = visibility == STV_DEFAULT
- ? other.visibility
- : std::min(visibility, other.visibility);
+ if (!other.isShared() && other.visibility() != STV_DEFAULT) {
+ uint8_t v = visibility(), ov = other.visibility();
+ setVisibility(v == STV_DEFAULT ? ov : std::min(v, ov));
+ }
}
void Symbol::resolve(const Symbol &other) {
//
// If this is a non-weak defined symbol in a discarded section, override the
// existing undefined symbol for better error message later.
- if ((isShared() && other.visibility != STV_DEFAULT) ||
+ if ((isShared() && other.visibility() != STV_DEFAULT) ||
(isUndefined() && other.binding != STB_WEAK && other.discardedSecIdx)) {
replace(other);
return;
cast<CommonSymbol>(this)->size = other.size;
return;
}
- if (visibility == STV_DEFAULT && (isUndefined() || isLazy())) {
+ if (visibility() == STV_DEFAULT && (isUndefined() || isLazy())) {
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
uint8_t bind = binding;
// The partition whose dynamic symbol table contains this symbol's definition.
uint8_t partition = 1;
- // Symbol visibility. This is the computed minimum visibility of all
- // observed non-DSO symbols.
- uint8_t visibility : 2;
-
// True if this symbol is preemptible at load time.
uint8_t isPreemptible : 1;
inline void replace(const Symbol &other);
+ // Symbol visibility. This is the computed minimum visibility of all
+ // observed non-DSO symbols.
+ uint8_t visibility() const { return stOther & 3; }
+ void setVisibility(uint8_t visibility) {
+ stOther = (stOther & ~3) | visibility;
+ }
+
bool includeInDynsym() const;
uint8_t computeBinding() const;
bool isGlobal() const { return binding == llvm::ELF::STB_GLOBAL; }
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),
- visibility(stOther & 3), isPreemptible(false),
+ binding(binding), stOther(stOther), symbolKind(k), isPreemptible(false),
isUsedInRegularObj(false), used(false), exportDynamic(false),
inDynamicList(false), referenced(false), referencedAfterWrap(false),
traced(false), hasVersionSuffix(false), isInIplt(false),
gotInIgot(false), folded(false), needsTocRestore(false),
- scriptDefined(false), needsCopy(false), needsGot(false),
- needsPlt(false), needsTlsDesc(false), needsTlsGd(false),
- needsTlsGdToIe(false), needsGotDtprel(false), needsTlsIe(false),
- hasDirectReloc(false) {}
+ scriptDefined(false), dsoProtected(false), needsCopy(false),
+ needsGot(false), needsPlt(false), needsTlsDesc(false),
+ needsTlsGd(false), needsTlsGdToIe(false), needsGotDtprel(false),
+ needsTlsIe(false), hasDirectReloc(false) {}
public:
// True if this symbol is in the Iplt sub-section of the Plt and the Igot
// of the symbol.
uint8_t scriptDefined : 1;
+ // True if defined in a DSO as protected visibility.
+ uint8_t dsoProtected : 1;
+
// True if this symbol needs a canonical PLT entry, or (during
// postScanRelocations) a copy relocation.
uint8_t needsCopy : 1;
: Symbol(SharedKind, &file, name, binding, stOther, type), value(value),
size(size), alignment(alignment) {
exportDynamic = true;
+ dsoProtected = visibility() == llvm::ELF::STV_PROTECTED;
// GNU ifunc is a mechanism to allow user-supplied functions to
// resolve PLT slot values at load-time. This is contrary to the
// regular symbol resolution scheme in which symbols are resolved just
nameData = old.nameData;
nameSize = old.nameSize;
partition = old.partition;
- visibility = old.visibility;
+ setVisibility(old.visibility());
isPreemptible = old.isPreemptible;
isUsedInRegularObj = old.isUsedInRegularObj;
exportDynamic = old.exportDynamic;
// Set st_name, st_info and st_other.
eSym->st_name = ent.strTabOffset;
eSym->setBindingAndType(sym->binding, sym->type);
- eSym->st_other = sym->visibility;
-
- // The 3 most significant bits of st_other are used by OpenPOWER ABI.
- // See getPPC64GlobalEntryToLocalEntryOffset() for more details.
- if (config->emachine == EM_PPC64)
- eSym->st_other |= sym->stOther & 0xe0;
- // The most significant bit of st_other is used by AArch64 ABI for the
- // variant PCS.
- else if (config->emachine == EM_AARCH64)
- eSym->st_other |= sym->stOther & STO_AARCH64_VARIANT_PCS;
+ eSym->st_other = sym->stOther;
if (BssSection *commonSec = getCommonSec(sym)) {
// When -r is specified, a COMMON symbol is not allocated. Its st_shndx
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
-# RUN: not ld.lld -pie %t.o -o /dev/null 2>&1 | FileCheck --check-prefixes=CHECK,PIE %s
-# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck --check-prefixes=CHECK,SHARED %s
+# RUN: not ld.lld -pie %t.o -o /dev/null 2>&1 | FileCheck %s
+# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
## Check we don't create dynamic relocations in a writable section,
## if the number of bits is smaller than the wordsize.
# CHECK: error: relocation R_X86_64_16 cannot be used against local symbol; recompile with -fPIC
# CHECK: error: relocation R_X86_64_32 cannot be used against local symbol; recompile with -fPIC
-# PIE: error: cannot preempt symbol: hidden
-# SHARED: error: relocation R_X86_64_32 cannot be used against symbol 'hidden'; recompile with -fPIC
+# CHECK: error: relocation R_X86_64_32 cannot be used against symbol 'hidden'; recompile with -fPIC
.data
.byte local # R_X86_64_8