diff options
author | Robert Nagy <robert@cvs.openbsd.org> | 2022-11-17 12:24:03 +0000 |
---|---|---|
committer | Robert Nagy <robert@cvs.openbsd.org> | 2022-11-17 12:24:03 +0000 |
commit | 0a96cf0b0a3b31f2ae329f624cabd9295bca7281 (patch) | |
tree | 4c2e43ab72fc3f24c4a87ac3b2e5ed3c1cb0af28 /gnu/llvm | |
parent | 3cb5d42025e6c024c6e514144a5ad1cfb92149a1 (diff) |
add .gnu.warning.SYMBOL support to ld.lld(1) to display the warnings in
these sections like ld.bfd(1)
e.g:
add.c(add.o:(add)): warning: sprintf() is often misused, please use snprintf()
add.c(add.o:(add)): warning: strcpy() is almost always misused, please use strlcpy()
add.c(add.o:(add)): warning: strcat() is almost always misused, please use strlcat()
ok deraadt@
Diffstat (limited to 'gnu/llvm')
-rw-r--r-- | gnu/llvm/lld/ELF/InputFiles.cpp | 31 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/InputFiles.h | 73 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/Relocations.cpp | 14 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/SymbolTable.cpp | 167 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/Symbols.h | 8 |
5 files changed, 217 insertions, 76 deletions
diff --git a/gnu/llvm/lld/ELF/InputFiles.cpp b/gnu/llvm/lld/ELF/InputFiles.cpp index ab65571887d..75652403e1d 100644 --- a/gnu/llvm/lld/ELF/InputFiles.cpp +++ b/gnu/llvm/lld/ELF/InputFiles.cpp @@ -52,6 +52,8 @@ std::vector<SharedFile *> elf::sharedFiles; std::unique_ptr<TarWriter> elf::tar; +DenseMap<StringRef, StringRef> elf::gnuWarnings; + // Returns "<internal>", "foo.a(bar.o)" or "baz.o". std::string lld::toString(const InputFile *f) { if (!f) @@ -66,6 +68,17 @@ std::string lld::toString(const InputFile *f) { return f->toStringCache; } +// .gnu.warning.SYMBOL are treated as warning symbols for the given symbol +void lld::parseGNUWarning(StringRef name, ArrayRef<char> data, size_t size) { + if (!name.empty() && name.startswith(".gnu.warning.")) { + StringRef wsym = name.substr(13); + StringRef s(data.begin()); + StringRef wng(s.substr(0, size)); + symtab->insert(wsym)->gwarn = true; + gnuWarnings.insert({wsym, wng}); + } +} + static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) { unsigned char size; unsigned char endian; @@ -647,6 +660,14 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats) { case SHT_RELA: case SHT_NULL: break; + case SHT_PROGBITS: { + this->sections[i] = createInputSection(sec); + StringRef name = CHECK(obj.getSectionName(sec, this->sectionStringTable), this); + ArrayRef<char> data = + CHECK(obj.template getSectionContentsAsArray<char>(sec), this); + parseGNUWarning(name, data, sec.sh_size); + } + break; default: this->sections[i] = createInputSection(sec); } @@ -1450,6 +1471,9 @@ template <class ELFT> void SharedFile::parse() { const ELFFile<ELFT> obj = this->getObj<ELFT>(); ArrayRef<Elf_Shdr> sections = CHECK(obj.sections(), this); + StringRef sectionStringTable = + CHECK(obj.getSectionStringTable(sections), this); + const Elf_Shdr *versymSec = nullptr; const Elf_Shdr *verdefSec = nullptr; const Elf_Shdr *verneedSec = nullptr; @@ -1472,6 +1496,13 @@ template <class ELFT> void SharedFile::parse() { case SHT_GNU_verneed: verneedSec = &sec; break; + case SHT_PROGBITS: { + StringRef name = CHECK(obj.getSectionName(sec, sectionStringTable), this); + ArrayRef<char> data = + CHECK(obj.template getSectionContentsAsArray<char>(sec), this); + parseGNUWarning(name, data, sec.sh_size); + break; + } } } diff --git a/gnu/llvm/lld/ELF/InputFiles.h b/gnu/llvm/lld/ELF/InputFiles.h index a310ba551bd..4d64a6551d0 100644 --- a/gnu/llvm/lld/ELF/InputFiles.h +++ b/gnu/llvm/lld/ELF/InputFiles.h @@ -37,9 +37,9 @@ class DWARFCache; // Returns "<internal>", "foo.a(bar.o)" or "baz.o". std::string toString(const elf::InputFile *f); +void parseGNUWarning(StringRef name, ArrayRef<char> data, size_t size); + namespace elf { -class InputFile; -class InputSectionBase; using llvm::object::Archive; @@ -94,9 +94,11 @@ public: return symbols; } - // Filename of .a which contained this file. If this file was - // not in an archive file, it is the empty string. We use this - // string for creating error messages. + // Get filename to use for linker script processing. + StringRef getNameForScript() const; + + // If not empty, this stores the name of the archive containing this file. + // We use this string for creating error messages. std::string archiveName; // If this is an architecture-specific file, the following members @@ -130,6 +132,10 @@ public: // [.got, .got + 0xFFFC]. bool ppc64SmallCodeModelTocRelocs = false; + // True if the file has TLSGD/TLSLD GOT relocations without R_PPC64_TLSGD or + // R_PPC64_TLSLD. Disable TLS relaxation to avoid bad code generation. + bool ppc64DisableTLSRelax = false; + // groupId is used for --warn-backrefs which is an optional error // checking feature. All files within the same --{start,end}-group or // --{start,end}-lib get the same group ID. Otherwise, each file gets a new @@ -149,6 +155,9 @@ protected: private: const Kind fileKind; + + // Cache for getNameForScript(). + mutable std::string nameForScriptCache; }; class ELFFileBase : public InputFile { @@ -182,12 +191,7 @@ protected: // .o file. template <class ELFT> class ObjFile : public ELFFileBase { - using Elf_Rel = typename ELFT::Rel; - using Elf_Rela = typename ELFT::Rela; - using Elf_Sym = typename ELFT::Sym; - using Elf_Shdr = typename ELFT::Shdr; - using Elf_Word = typename ELFT::Word; - using Elf_CGProfile = typename ELFT::CGProfile; + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) public: static bool classof(const InputFile *f) { return f->kind() == ObjKind; } @@ -200,7 +204,7 @@ public: ArrayRef<Symbol *> getGlobalSymbols(); ObjFile(MemoryBufferRef m, StringRef archiveName) : ELFFileBase(ObjKind, m) { - this->archiveName = archiveName; + this->archiveName = std::string(archiveName); } void parse(bool ignoreComdats = false); @@ -247,14 +251,17 @@ public: // Pointer to this input file's .llvm_addrsig section, if it has one. const Elf_Shdr *addrsigSec = nullptr; - // SHT_LLVM_CALL_GRAPH_PROFILE table - ArrayRef<Elf_CGProfile> cgProfile; + // SHT_LLVM_CALL_GRAPH_PROFILE section index. + uint32_t cgProfileSectionIndex = 0; + + // Get cached DWARF information. + DWARFCache *getDwarf(); private: void initializeSections(bool ignoreComdats); void initializeSymbols(); void initializeJustSymbols(); - void initializeDwarf(); + InputSectionBase *getRelocTarget(const Elf_Shdr &sec); InputSectionBase *createInputSection(const Elf_Shdr &sec); StringRef getSectionName(const Elf_Shdr &sec); @@ -282,8 +289,8 @@ private: // reporting. Linker may find reasonable number of errors in a // single object file, so we cache debugging information in order to // parse it only once for each object file we link. - DWARFCache *dwarf; - llvm::once_flag initDwarfLine; + std::unique_ptr<DWARFCache> dwarf; + llvm::once_flag initDwarf; }; // LazyObjFile is analogous to ArchiveFile in the sense that @@ -298,7 +305,7 @@ public: LazyObjFile(MemoryBufferRef m, StringRef archiveName, uint64_t offsetInArchive) : InputFile(LazyObjKind, m), offsetInArchive(offsetInArchive) { - this->archiveName = archiveName; + this->archiveName = std::string(archiveName); } static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; } @@ -306,6 +313,12 @@ public: template <class ELFT> void parse(); void fetch(); + // Check if a non-common symbol should be fetched to override a common + // definition. + bool shouldFetchForCommon(const StringRef &name); + + bool fetched = false; + private: uint64_t offsetInArchive; }; @@ -323,6 +336,15 @@ public: // more than once.) void fetch(const Archive::Symbol &sym); + // Check if a non-common symbol should be fetched to override a common + // definition. + bool shouldFetchForCommon(const Archive::Symbol &sym); + + size_t getMemberCount() const; + size_t getFetchedMemberCount() const { return seen.size(); } + + bool parsed = false; + private: std::unique_ptr<Archive> file; llvm::DenseSet<uint64_t> seen; @@ -341,7 +363,7 @@ public: class SharedFile : public ELFFileBase { public: SharedFile(MemoryBufferRef m, StringRef defaultSoName) - : ELFFileBase(SharedKind, m), soName(defaultSoName), + : ELFFileBase(SharedKind, m), soName(std::string(defaultSoName)), isNeeded(!config->asNeeded) {} // This is actually a vector of Elf_Verdef pointers. @@ -361,11 +383,17 @@ public: template <typename ELFT> void parse(); - // Used for --no-allow-shlib-undefined. - bool allNeededIsKnown; - // Used for --as-needed bool isNeeded; + + // Non-weak undefined symbols which are not yet resolved when the SO is + // parsed. Only filled for `--no-allow-shlib-undefined`. + std::vector<Symbol *> requiredSymbols; + +private: + template <typename ELFT> + std::vector<uint32_t> parseVerneed(const llvm::object::ELFFile<ELFT> &obj, + const typename ELFT::Shdr *sec); }; class BinaryFile : public InputFile { @@ -384,6 +412,7 @@ inline bool isBitcode(MemoryBufferRef mb) { std::string replaceThinLTOSuffix(StringRef path); +extern std::vector<ArchiveFile *> archiveFiles; extern std::vector<BinaryFile *> binaryFiles; extern std::vector<BitcodeFile *> bitcodeFiles; extern std::vector<LazyObjFile *> lazyObjFiles; diff --git a/gnu/llvm/lld/ELF/Relocations.cpp b/gnu/llvm/lld/ELF/Relocations.cpp index bf576752c54..114780e0f9a 100644 --- a/gnu/llvm/lld/ELF/Relocations.cpp +++ b/gnu/llvm/lld/ELF/Relocations.cpp @@ -954,6 +954,18 @@ template <class ELFT> void elf::reportUndefinedSymbols() { undefs.clear(); } +static void reportGNUWarning(Symbol &sym, InputSectionBase &sec, + uint64_t offset) { + if (sym.gwarn) { + StringRef gnuWarning = gnuWarnings.lookup(sym.getName()); + // report first occurance only + sym.gwarn = false; + if (!gnuWarning.empty()) + message(sec.getSrcMsg(sym, offset) + "(" + sec.getObjMsg(offset) + + "): warning: " + gnuWarning); + } +} + // Report an undefined symbol if necessary. // Returns true if the undefined symbol will produce an error message. static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec, @@ -1327,6 +1339,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, if (symIndex != 0 && maybeReportUndefined(sym, sec, rel.r_offset)) return; + reportGNUWarning(sym, sec, rel.r_offset); + const uint8_t *relocatedAddr = sec.data().begin() + rel.r_offset; RelExpr expr = target->getRelExpr(type, sym, relocatedAddr); diff --git a/gnu/llvm/lld/ELF/SymbolTable.cpp b/gnu/llvm/lld/ELF/SymbolTable.cpp index f7a8a99cf8f..da1684a91ee 100644 --- a/gnu/llvm/lld/ELF/SymbolTable.cpp +++ b/gnu/llvm/lld/ELF/SymbolTable.cpp @@ -26,10 +26,10 @@ using namespace llvm; using namespace llvm::object; using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; -namespace lld { -namespace elf { -SymbolTable *symtab; +SymbolTable *elf::symtab; void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { // Swap symbols as instructed by -wrap. @@ -40,12 +40,20 @@ void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { idx2 = idx1; idx1 = idx3; - // Now renaming is complete. No one refers Real symbol. We could leave - // Real as-is, but if Real is written to the symbol table, that may - // contain irrelevant values. So, we copy all values from Sym to Real. - StringRef s = real->getName(); + if (real->exportDynamic) + sym->exportDynamic = true; + if (!real->isUsedInRegularObj && sym->isUndefined()) + sym->isUsedInRegularObj = false; + + // Now renaming is complete, and no one refers to real. We drop real from + // .symtab and .dynsym. If real is undefined, it is important that we don't + // leave it in .dynsym, because otherwise it might lead to an undefined symbol + // error in a subsequent link. If real is defined, we could emit real as an + // alias for sym, but that could degrade the user experience of some tools + // that can print out only one symbol for each location: sym is a preferred + // name than real, but they might print out real instead. memcpy(real, sym, sizeof(SymbolUnion)); - real->setName(s); + real->isUsedInRegularObj = false; } // Find an existing symbol or create a new one. @@ -82,13 +90,14 @@ Symbol *SymbolTable::insert(StringRef name) { sym->canInline = true; sym->referenced = false; sym->traced = false; + sym->gwarn = false; sym->scriptDefined = false; sym->partition = 1; return sym; } Symbol *SymbolTable::addSymbol(const Symbol &newSym) { - Symbol *sym = symtab->insert(newSym.getName()); + Symbol *sym = insert(newSym.getName()); sym->resolve(newSym); return sym; } @@ -103,6 +112,13 @@ Symbol *SymbolTable::find(StringRef name) { return sym; } +// A version script/dynamic list is only meaningful for a Defined symbol. +// A CommonSymbol will be converted to a Defined in replaceCommonSymbols(). +// A lazy symbol may be made Defined if an LTO libcall fetches it. +static bool canBeVersioned(const Symbol &sym) { + return sym.isDefined() || sym.isCommon() || sym.isLazy(); +} + // Initialize demangledSyms with a map from demangled symbols to symbol // objects. Used to handle "extern C++" directive in version scripts. // @@ -119,11 +135,20 @@ Symbol *SymbolTable::find(StringRef name) { StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() { if (!demangledSyms) { demangledSyms.emplace(); - for (Symbol *sym : symVector) { - if (!sym->isDefined() && !sym->isCommon()) - continue; - (*demangledSyms)[demangleItanium(sym->getName())].push_back(sym); - } + std::string demangled; + for (Symbol *sym : symVector) + if (canBeVersioned(*sym)) { + StringRef name = sym->getName(); + size_t pos = name.find('@'); + if (pos == std::string::npos) + demangled = demangleItanium(name); + else if (pos + 1 == name.size() || name[pos + 1] == '@') + demangled = demangleItanium(name.substr(0, pos)); + else + demangled = + (demangleItanium(name.substr(0, pos)) + name.substr(pos)).str(); + (*demangledSyms)[demangled].push_back(sym); + } } return *demangledSyms; } @@ -131,25 +156,35 @@ StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() { std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion ver) { if (ver.isExternCpp) return getDemangledSyms().lookup(ver.name); - if (Symbol *b = find(ver.name)) - if (b->isDefined() || b->isCommon()) - return {b}; + if (Symbol *sym = find(ver.name)) + if (canBeVersioned(*sym)) + return {sym}; return {}; } -std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion ver) { +std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion ver, + bool includeNonDefault) { std::vector<Symbol *> res; - StringMatcher m(ver.name); + SingleStringMatcher m(ver.name); + auto check = [&](StringRef name) { + size_t pos = name.find('@'); + if (!includeNonDefault) + return pos == StringRef::npos; + return !(pos + 1 < name.size() && name[pos + 1] == '@'); + }; if (ver.isExternCpp) { for (auto &p : getDemangledSyms()) if (m.match(p.first())) - res.insert(res.end(), p.second.begin(), p.second.end()); + for (Symbol *sym : p.second) + if (check(sym->getName())) + res.push_back(sym); return res; } for (Symbol *sym : symVector) - if ((sym->isDefined() || sym->isCommon()) && m.match(sym->getName())) + if (canBeVersioned(*sym) && check(sym->getName()) && + m.match(sym->getName())) res.push_back(sym); return res; } @@ -159,7 +194,7 @@ void SymbolTable::handleDynamicList() { for (SymbolVersion &ver : config->dynamicList) { std::vector<Symbol *> syms; if (ver.hasWildcard) - syms = findAllByVersion(ver); + syms = findAllByVersion(ver, /*includeNonDefault=*/true); else syms = findByVersion(ver); @@ -168,21 +203,13 @@ void SymbolTable::handleDynamicList() { } } -// Set symbol versions to symbols. This function handles patterns -// containing no wildcard characters. -void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, - StringRef versionName) { - if (ver.hasWildcard) - return; - +// Set symbol versions to symbols. This function handles patterns containing no +// wildcard characters. Return false if no symbol definition matches ver. +bool SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, + StringRef versionName, + bool includeNonDefault) { // Get a list of symbols which we need to assign the version to. std::vector<Symbol *> syms = findByVersion(ver); - if (syms.empty()) { - if (!config->undefinedVersion) - error("version script assignment of '" + versionName + "' to symbol '" + - ver.name + "' failed: symbol not defined"); - return; - } auto getName = [](uint16_t ver) -> std::string { if (ver == VER_NDX_LOCAL) @@ -194,10 +221,11 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, // Assign the version. for (Symbol *sym : syms) { - // Skip symbols containing version info because symbol versions - // specified by symbol names take precedence over version scripts. - // See parseSymbolVersion(). - if (sym->getName().contains('@')) + // For a non-local versionId, skip symbols containing version info because + // symbol versions specified by symbol names take precedence over version + // scripts. See parseSymbolVersion(). + if (!includeNonDefault && versionId != VER_NDX_LOCAL && + sym->getName().contains('@')) continue; // If the version has not been assigned, verdefIndex is -1. Use an arbitrary @@ -212,13 +240,15 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, warn("attempt to reassign symbol '" + ver.name + "' of " + getName(sym->versionId) + " to " + getName(versionId)); } + return !syms.empty(); } -void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId) { +void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId, + bool includeNonDefault) { // Exact matching takes precedence over fuzzy matching, // so we set a version to a symbol only if no version has been assigned // to the symbol. This behavior is compatible with GNU. - for (Symbol *sym : findAllByVersion(ver)) + for (Symbol *sym : findAllByVersion(ver, includeNonDefault)) if (sym->verdefIndex == UINT32_C(-1)) { sym->verdefIndex = 0; sym->versionId = versionId; @@ -231,26 +261,60 @@ void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId) { // script file, the script does not actually define any symbol version, // but just specifies symbols visibilities. void SymbolTable::scanVersionScript() { + SmallString<128> buf; // First, we assign versions to exact matching symbols, // i.e. version definitions not containing any glob meta-characters. - for (VersionDefinition &v : config->versionDefinitions) - for (SymbolVersion &pat : v.patterns) - assignExactVersion(pat, v.id, v.name); + std::vector<Symbol *> syms; + for (VersionDefinition &v : config->versionDefinitions) { + auto assignExact = [&](SymbolVersion pat, uint16_t id, StringRef ver) { + bool found = + assignExactVersion(pat, id, ver, /*includeNonDefault=*/false); + buf.clear(); + found |= assignExactVersion({(pat.name + "@" + v.name).toStringRef(buf), + pat.isExternCpp, /*hasWildCard=*/false}, + id, ver, /*includeNonDefault=*/true); + if (!found && !config->undefinedVersion) + errorOrWarn("version script assignment of '" + ver + "' to symbol '" + + pat.name + "' failed: symbol not defined"); + }; + for (SymbolVersion &pat : v.nonLocalPatterns) + if (!pat.hasWildcard) + assignExact(pat, v.id, v.name); + for (SymbolVersion pat : v.localPatterns) + if (!pat.hasWildcard) + assignExact(pat, VER_NDX_LOCAL, "local"); + } // Next, assign versions to wildcards that are not "*". Note that because the // last match takes precedence over previous matches, we iterate over the // definitions in the reverse order. - for (VersionDefinition &v : llvm::reverse(config->versionDefinitions)) - for (SymbolVersion &pat : v.patterns) + auto assignWildcard = [&](SymbolVersion pat, uint16_t id, StringRef ver) { + assignWildcardVersion(pat, id, /*includeNonDefault=*/false); + buf.clear(); + assignWildcardVersion({(pat.name + "@" + ver).toStringRef(buf), + pat.isExternCpp, /*hasWildCard=*/true}, + id, + /*includeNonDefault=*/true); + }; + for (VersionDefinition &v : llvm::reverse(config->versionDefinitions)) { + for (SymbolVersion &pat : v.nonLocalPatterns) + if (pat.hasWildcard && pat.name != "*") + assignWildcard(pat, v.id, v.name); + for (SymbolVersion &pat : v.localPatterns) if (pat.hasWildcard && pat.name != "*") - assignWildcardVersion(pat, v.id); + assignWildcard(pat, VER_NDX_LOCAL, v.name); + } // Then, assign versions to "*". In GNU linkers they have lower priority than // other wildcards. - for (VersionDefinition &v : config->versionDefinitions) - for (SymbolVersion &pat : v.patterns) + for (VersionDefinition &v : config->versionDefinitions) { + for (SymbolVersion &pat : v.nonLocalPatterns) if (pat.hasWildcard && pat.name == "*") - assignWildcardVersion(pat, v.id); + assignWildcard(pat, v.id, v.name); + for (SymbolVersion &pat : v.localPatterns) + if (pat.hasWildcard && pat.name == "*") + assignWildcard(pat, VER_NDX_LOCAL, v.name); + } // Symbol themselves might know their versions because symbols // can contain versions in the form of <name>@<version>. @@ -264,6 +328,3 @@ void SymbolTable::scanVersionScript() { // --dynamic-list. handleDynamicList(); } - -} // namespace elf -} // namespace lld diff --git a/gnu/llvm/lld/ELF/Symbols.h b/gnu/llvm/lld/ELF/Symbols.h index d4a589ee600..3a4f851a7d4 100644 --- a/gnu/llvm/lld/ELF/Symbols.h +++ b/gnu/llvm/lld/ELF/Symbols.h @@ -142,6 +142,9 @@ public: // True if this symbol is specified by --trace-symbol option. uint8_t traced : 1; + // True if the .gnu.warning.SYMBOL is set for the symbol + uint8_t gwarn : 1; + inline void replace(const Symbol &newSym); bool includeInDynsym() const; @@ -247,7 +250,7 @@ protected: type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3), isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind), exportDynamic(isExportDynamic(k, visibility)), inDynamicList(false), - canInline(false), referenced(false), traced(false), needsPltAddr(false), + canInline(false), referenced(false), traced(false), gwarn(false), needsPltAddr(false), isInIplt(false), gotInIgot(false), isPreemptible(false), used(!config->gcSections), needsTocRestore(false), scriptDefined(false) {} @@ -560,6 +563,7 @@ void Symbol::replace(const Symbol &newSym) { canInline = old.canInline; referenced = old.referenced; traced = old.traced; + gwarn = old.gwarn; isPreemptible = old.isPreemptible; scriptDefined = old.scriptDefined; partition = old.partition; @@ -579,6 +583,8 @@ void maybeWarnUnorderableSymbol(const Symbol *sym); bool computeIsPreemptible(const Symbol &sym); void reportBackrefs(); +extern llvm::DenseMap<StringRef, StringRef> gnuWarnings; + // A mapping from a symbol to an InputFile referencing it backward. Used by // --warn-backrefs. extern llvm::DenseMap<const Symbol *, |