diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 4547924d10904..c521a96d978ea 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -856,11 +856,11 @@ void AArch64BtiPac::writePlt(uint8_t *buf, const Symbol &sym, }; const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop - // needsCopy indicates a non-ifunc canonical PLT entry whose address may + // NEEDS_COPY indicates a non-ifunc canonical PLT entry whose address may // escape to shared objects. isInIplt indicates a non-preemptible ifunc. Its // address may escape if referenced by a direct relocation. The condition is // conservative. - bool hasBti = btiHeader && (sym.needsCopy || sym.isInIplt); + bool hasBti = btiHeader && (sym.hasFlag(NEEDS_COPY) || sym.isInIplt); if (hasBti) { memcpy(buf, btiData, sizeof(btiData)); buf += sizeof(btiData); diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp index 893511929a3a5..ec1c90ee89949 100644 --- a/lld/ELF/MapFile.cpp +++ b/lld/ELF/MapFile.cpp @@ -59,7 +59,7 @@ static std::vector getSymbols() { for (Symbol *b : file->getSymbols()) if (auto *dr = dyn_cast(b)) if (!dr->isSection() && dr->section && dr->section->isLive() && - (dr->file == file || dr->needsCopy || dr->section->bss)) + (dr->file == file || dr->hasFlag(NEEDS_COPY) || dr->section->bss)) v.push_back(dr); return v; } diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index cab39c663f0de..ce819de7eb5fe 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -306,7 +306,8 @@ static void replaceWithDefined(Symbol &sym, SectionBase &sec, uint64_t value, sym.exportDynamic = true; sym.isUsedInRegularObj = true; // A copy relocated alias may need a GOT entry. - sym.needsGot = old.needsGot; + if (old.hasFlag(NEEDS_GOT)) + sym.setFlags(NEEDS_GOT); } // Reserve space in .bss or .bss.rel.ro for copy relocation. @@ -1100,7 +1101,7 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, " against symbol '" + toString(*ss) + "'; recompile with -fPIC or remove '-z nocopyreloc'" + getLocation(*sec, sym, offset)); - sym.needsCopy = true; + sym.setFlags(NEEDS_COPY); } sec->relocations.push_back({expr, type, offset, addend, &sym}); return; @@ -1138,8 +1139,7 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, errorOrWarn("symbol '" + toString(sym) + "' cannot be preempted; recompile with -fPIE" + getLocation(*sec, sym, offset)); - sym.needsCopy = true; - sym.needsPlt = true; + sym.setFlags(NEEDS_COPY | NEEDS_PLT); sec->relocations.push_back({expr, type, offset, addend, &sym}); return; } @@ -1193,7 +1193,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, R_TLSDESC_GOTPLT>(expr) && config->shared) { if (expr != R_TLSDESC_CALL) { - sym.needsTlsDesc = true; + sym.setFlags(NEEDS_TLSDESC); c.relocations.push_back({expr, type, offset, addend, &sym}); } return 1; @@ -1247,7 +1247,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, // Local-Dynamic sequence where offset of tls variable relative to dynamic // thread pointer is stored in the got. This cannot be relaxed to Local-Exec. if (expr == R_TLSLD_GOT_OFF) { - sym.needsGotDtprel = true; + sym.setFlags(NEEDS_GOT_DTPREL); c.relocations.push_back({expr, type, offset, addend, &sym}); return 1; } @@ -1255,7 +1255,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, if (oneof(expr)) { if (!toExecRelax) { - sym.needsTlsGd = true; + sym.setFlags(NEEDS_TLSGD); c.relocations.push_back({expr, type, offset, addend, &sym}); return 1; } @@ -1263,7 +1263,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec // depending on the symbol being locally defined or not. if (sym.isPreemptible) { - sym.needsTlsGdToIe = true; + sym.setFlags(NEEDS_TLSGD_TO_IE); c.relocations.push_back( {target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_IE), type, offset, addend, &sym}); @@ -1283,7 +1283,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, c.relocations.push_back( {R_RELAX_TLS_IE_TO_LE, type, offset, addend, &sym}); } else if (expr != R_TLSIE_HINT) { - sym.needsTlsIe = true; + sym.setFlags(NEEDS_TLSIE); // R_GOT needs a relative relocation for PIC on i386 and Hexagon. if (expr == R_GOT && config->isPic && !target->usesOnlyLowPageBits(type)) addRelativeReloc(c, offset, sym, addend, expr, type); @@ -1438,12 +1438,12 @@ template void RelocationScanner::scanOne(RelTy *&i) { // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf in.mipsGot->addEntry(*sec->file, sym, addend, expr); } else { - sym.needsGot = true; + sym.setFlags(NEEDS_GOT); } } else if (needsPlt(expr)) { - sym.needsPlt = true; + sym.setFlags(NEEDS_PLT); } else if (LLVM_UNLIKELY(isIfunc)) { - sym.hasDirectReloc = true; + sym.setFlags(HAS_DIRECT_RELOC); } processAux(expr, type, offset, sym, addend); @@ -1543,7 +1543,7 @@ template void elf::scanRelocations() { } } -static bool handleNonPreemptibleIfunc(Symbol &sym) { +static bool handleNonPreemptibleIfunc(Symbol &sym, uint16_t flags) { // Handle a reference to a non-preemptible ifunc. These are special in a // few ways: // @@ -1587,7 +1587,7 @@ static bool handleNonPreemptibleIfunc(Symbol &sym) { if (!sym.isGnuIFunc() || sym.isPreemptible || config->zIfuncNoplt) return false; // Skip unreferenced non-preemptible ifunc. - if (!(sym.needsGot || sym.needsPlt || sym.hasDirectReloc)) + if (!(flags & (NEEDS_GOT | NEEDS_PLT | HAS_DIRECT_RELOC))) return true; sym.isInIplt = true; @@ -1603,7 +1603,7 @@ static bool handleNonPreemptibleIfunc(Symbol &sym) { sym.allocateAux(); symAux.back().pltIdx = symAux[directSym->auxIdx].pltIdx; - if (sym.hasDirectReloc) { + if (flags & HAS_DIRECT_RELOC) { // Change the value to the IPLT and redirect all references to it. auto &d = cast(sym); d.section = in.iplt.get(); @@ -1613,9 +1613,9 @@ static bool handleNonPreemptibleIfunc(Symbol &sym) { // don't try to call the PLT as if it were an ifunc resolver. d.type = STT_FUNC; - if (sym.needsGot) + if (flags & NEEDS_GOT) addGotEntry(sym); - } else if (sym.needsGot) { + } else if (flags & NEEDS_GOT) { // Redirect GOT accesses to point to the Igot. sym.gotInIgot = true; } @@ -1624,30 +1624,31 @@ static bool handleNonPreemptibleIfunc(Symbol &sym) { void elf::postScanRelocations() { auto fn = [](Symbol &sym) { - if (handleNonPreemptibleIfunc(sym)) + auto flags = sym.flags; + if (handleNonPreemptibleIfunc(sym, flags)) return; if (!sym.needsDynReloc()) return; sym.allocateAux(); - if (sym.needsGot) + if (flags & NEEDS_GOT) addGotEntry(sym); - if (sym.needsPlt) + if (flags & NEEDS_PLT) addPltEntry(*in.plt, *in.gotPlt, *in.relaPlt, target->pltRel, sym); - if (sym.needsCopy) { + if (flags & NEEDS_COPY) { if (sym.isObject()) { invokeELFT(addCopyRelSymbol, cast(sym)); - // needsCopy is cleared for sym and its aliases so that in later - // iterations aliases won't cause redundant copies. - assert(!sym.needsCopy); + // NEEDS_COPY is cleared for sym and its aliases so that in + // later iterations aliases won't cause redundant copies. + assert(!sym.hasFlag(NEEDS_COPY)); } else { - assert(sym.isFunc() && sym.needsPlt); + assert(sym.isFunc() && sym.hasFlag(NEEDS_PLT)); if (!sym.isDefined()) { replaceWithDefined(sym, *in.plt, target->pltHeaderSize + target->pltEntrySize * sym.getPltIdx(), 0); - sym.needsCopy = true; + sym.setFlags(NEEDS_COPY); if (config->emachine == EM_PPC) { // PPC32 canonical PLT entries are at the beginning of .glink cast(sym).value = in.plt->headerSize; @@ -1662,13 +1663,13 @@ void elf::postScanRelocations() { return; bool isLocalInExecutable = !sym.isPreemptible && !config->shared; - if (sym.needsTlsDesc) { + if (flags & NEEDS_TLSDESC) { in.got->addTlsDescEntry(sym); mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible( target->tlsDescRel, *in.got, in.got->getTlsDescOffset(sym), sym, target->tlsDescRel); } - if (sym.needsTlsGd) { + if (flags & NEEDS_TLSGD) { in.got->addDynTlsEntry(sym); uint64_t off = in.got->getGlobalDynOffset(sym); if (isLocalInExecutable) @@ -1689,18 +1690,18 @@ void elf::postScanRelocations() { in.got->relocations.push_back( {R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym}); } - if (sym.needsTlsGdToIe) { + if (flags & NEEDS_TLSGD_TO_IE) { in.got->addEntry(sym); mainPart->relaDyn->addSymbolReloc(target->tlsGotRel, *in.got, sym.getGotOffset(), sym); } - if (sym.needsGotDtprel) { + if (flags & NEEDS_GOT_DTPREL) { in.got->addEntry(sym); in.got->relocations.push_back( {R_ABS, target->tlsOffsetRel, sym.getGotOffset(), 0, &sym}); } - if (sym.needsTlsIe && !sym.needsTlsGdToIe) + if ((flags & NEEDS_TLSIE) && !(flags & NEEDS_TLSGD_TO_IE)) addTpOffsetGotEntry(sym); }; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 1eb482e690c51..787223bde20c2 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -122,7 +122,7 @@ static uint64_t getSymVA(const Symbol &sym, int64_t addend) { // field etc) do the same trick as compiler uses to mark microMIPS // for CPU - set the less-significant bit. if (config->emachine == EM_MIPS && isMicroMips() && - ((sym.stOther & STO_MIPS_MICROMIPS) || sym.needsCopy)) + ((sym.stOther & STO_MIPS_MICROMIPS) || sym.hasFlag(NEEDS_COPY))) va |= 1; if (d.isTls() && !config->relocatable) { diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 78a94a64b8be8..1c0a5f58d1cc9 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -39,6 +39,20 @@ class Undefined; class LazyObject; class InputFile; +enum { + NEEDS_GOT = 1 << 0, + NEEDS_PLT = 1 << 1, + HAS_DIRECT_RELOC = 1 << 2, + // True if this symbol needs a canonical PLT entry, or (during + // postScanRelocations) a copy relocation. + NEEDS_COPY = 1 << 3, + NEEDS_TLSDESC = 1 << 4, + NEEDS_TLSGD = 1 << 5, + NEEDS_TLSGD_TO_IE = 1 << 6, + NEEDS_GOT_DTPREL = 1 << 7, + NEEDS_TLSIE = 1 << 8, +}; + // Some index properties of a symbol are stored separately in this auxiliary // struct to decrease sizeof(SymbolUnion) in the majority of cases. struct SymbolAux { @@ -252,10 +266,7 @@ class Symbol { inDynamicList(false), referenced(false), referencedAfterWrap(false), traced(false), hasVersionSuffix(false), isInIplt(false), gotInIgot(false), folded(false), needsTocRestore(false), - scriptDefined(false), dsoProtected(false), needsCopy(false), - needsGot(false), needsPlt(false), needsTlsDesc(false), - needsTlsGd(false), needsTlsGdToIe(false), needsGotDtprel(false), - needsTlsIe(false), hasDirectReloc(false) {} + scriptDefined(false), dsoProtected(false) {} public: // True if this symbol is in the Iplt sub-section of the Plt and the Igot @@ -282,20 +293,9 @@ class Symbol { // 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; - // Temporary flags used to communicate which symbol entries need PLT and GOT // entries during postScanRelocations(); - uint8_t needsGot : 1; - uint8_t needsPlt : 1; - uint8_t needsTlsDesc : 1; - uint8_t needsTlsGd : 1; - uint8_t needsTlsGdToIe : 1; - uint8_t needsGotDtprel : 1; - uint8_t needsTlsIe : 1; - uint8_t hasDirectReloc : 1; + uint16_t flags = 0; // A symAux index used to access GOT/PLT entry indexes. This is allocated in // postScanRelocations(). @@ -308,9 +308,18 @@ class Symbol { // Version definition index. uint16_t versionId; + void setFlags(uint16_t bits) { + flags |= bits; + } + bool hasFlag(uint16_t bit) const { + assert(bit && (bit & (bit - 1)) == 0 && "bit must be a power of 2"); + return flags & bit; + } + bool needsDynReloc() const { - return needsCopy || needsGot || needsPlt || needsTlsDesc || needsTlsGd || - needsTlsGdToIe || needsGotDtprel || needsTlsIe; + return flags & + (NEEDS_COPY | NEEDS_GOT | NEEDS_PLT | NEEDS_TLSDESC | NEEDS_TLSGD | + NEEDS_TLSGD_TO_IE | NEEDS_GOT_DTPREL | NEEDS_TLSIE); } void allocateAux() { assert(auxIdx == uint32_t(-1)); diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 4af2de5493a38..afd4038da1a67 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -2175,8 +2175,8 @@ static BssSection *getCommonSec(Symbol *sym) { } static uint32_t getSymSectionIndex(Symbol *sym) { - assert(!(sym->needsCopy && sym->isObject())); - if (!isa(sym) || sym->needsCopy) + assert(!(sym->hasFlag(NEEDS_COPY) && sym->isObject())); + if (!isa(sym) || sym->hasFlag(NEEDS_COPY)) return SHN_UNDEF; if (const OutputSection *os = sym->getOutputSection()) return os->sectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX @@ -2236,7 +2236,7 @@ template void SymbolTableSection::writeTo(uint8_t *buf) { for (SymbolTableEntry &ent : symbols) { Symbol *sym = ent.sym; - if (sym->isInPlt() && sym->needsCopy) + if (sym->isInPlt() && sym->hasFlag(NEEDS_COPY)) eSym->st_other |= STO_MIPS_PLT; if (isMicroMips()) { // We already set the less-significant bit for symbols @@ -2247,7 +2247,7 @@ template void SymbolTableSection::writeTo(uint8_t *buf) { // like `objdump` will be able to deal with a correct // symbol position. if (sym->isDefined() && - ((sym->stOther & STO_MIPS_MICROMIPS) || sym->needsCopy)) { + ((sym->stOther & STO_MIPS_MICROMIPS) || sym->hasFlag(NEEDS_COPY))) { if (!strTabSec.isDynamic()) eSym->st_value &= ~1; eSym->st_other |= STO_MIPS_MICROMIPS;