Path: blob/main/contrib/llvm-project/lld/ELF/SymbolTable.cpp
34878 views
//===- SymbolTable.cpp ----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Symbol table is a bag of all known symbols. We put all symbols of9// all input files to the symbol table. The symbol table is basically10// a hash table with the logic to resolve symbol name conflicts using11// the symbol types.12//13//===----------------------------------------------------------------------===//1415#include "SymbolTable.h"16#include "Config.h"17#include "InputFiles.h"18#include "Symbols.h"19#include "lld/Common/ErrorHandler.h"20#include "lld/Common/Memory.h"21#include "lld/Common/Strings.h"22#include "llvm/ADT/STLExtras.h"23#include "llvm/Demangle/Demangle.h"2425using namespace llvm;26using namespace llvm::object;27using namespace llvm::ELF;28using namespace lld;29using namespace lld::elf;3031SymbolTable elf::symtab;3233void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {34// Redirect __real_foo to the original foo and foo to the original __wrap_foo.35int &idx1 = symMap[CachedHashStringRef(sym->getName())];36int &idx2 = symMap[CachedHashStringRef(real->getName())];37int &idx3 = symMap[CachedHashStringRef(wrap->getName())];3839idx2 = idx1;40idx1 = idx3;4142// Propagate symbol usage information to the redirected symbols.43if (sym->isUsedInRegularObj)44wrap->isUsedInRegularObj = true;45if (real->isUsedInRegularObj)46sym->isUsedInRegularObj = true;47else if (!sym->isDefined())48// Now that all references to sym have been redirected to wrap, if there are49// no references to real (which has been redirected to sym), we only need to50// keep sym if it was defined, otherwise it's unused and can be dropped.51sym->isUsedInRegularObj = false;5253// Now renaming is complete, and no one refers to real. We drop real from54// .symtab and .dynsym. If real is undefined, it is important that we don't55// leave it in .dynsym, because otherwise it might lead to an undefined symbol56// error in a subsequent link. If real is defined, we could emit real as an57// alias for sym, but that could degrade the user experience of some tools58// that can print out only one symbol for each location: sym is a preferred59// name than real, but they might print out real instead.60memcpy(real, sym, sizeof(SymbolUnion));61real->isUsedInRegularObj = false;62}6364// Find an existing symbol or create a new one.65Symbol *SymbolTable::insert(StringRef name) {66// <name>@@<version> means the symbol is the default version. In that67// case <name>@@<version> will be used to resolve references to <name>.68//69// Since this is a hot path, the following string search code is70// optimized for speed. StringRef::find(char) is much faster than71// StringRef::find(StringRef).72StringRef stem = name;73size_t pos = name.find('@');74if (pos != StringRef::npos && pos + 1 < name.size() && name[pos + 1] == '@')75stem = name.take_front(pos);7677auto p = symMap.insert({CachedHashStringRef(stem), (int)symVector.size()});78if (!p.second) {79Symbol *sym = symVector[p.first->second];80if (stem.size() != name.size()) {81sym->setName(name);82sym->hasVersionSuffix = true;83}84return sym;85}8687Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());88symVector.push_back(sym);8990// *sym was not initialized by a constructor. Initialize all Symbol fields.91memset(sym, 0, sizeof(Symbol));92sym->setName(name);93sym->partition = 1;94sym->versionId = VER_NDX_GLOBAL;95if (pos != StringRef::npos)96sym->hasVersionSuffix = true;97return sym;98}99100// This variant of addSymbol is used by BinaryFile::parse to check duplicate101// symbol errors.102Symbol *SymbolTable::addAndCheckDuplicate(const Defined &newSym) {103Symbol *sym = insert(newSym.getName());104if (sym->isDefined())105sym->checkDuplicate(newSym);106sym->resolve(newSym);107sym->isUsedInRegularObj = true;108return sym;109}110111Symbol *SymbolTable::find(StringRef name) {112auto it = symMap.find(CachedHashStringRef(name));113if (it == symMap.end())114return nullptr;115return symVector[it->second];116}117118// A version script/dynamic list is only meaningful for a Defined symbol.119// A CommonSymbol will be converted to a Defined in replaceCommonSymbols().120// A lazy symbol may be made Defined if an LTO libcall extracts it.121static bool canBeVersioned(const Symbol &sym) {122return sym.isDefined() || sym.isCommon() || sym.isLazy();123}124125// Initialize demangledSyms with a map from demangled symbols to symbol126// objects. Used to handle "extern C++" directive in version scripts.127//128// The map will contain all demangled symbols. That can be very large,129// and in LLD we generally want to avoid do anything for each symbol.130// Then, why are we doing this? Here's why.131//132// Users can use "extern C++ {}" directive to match against demangled133// C++ symbols. For example, you can write a pattern such as134// "llvm::*::foo(int, ?)". Obviously, there's no way to handle this135// other than trying to match a pattern against all demangled symbols.136// So, if "extern C++" feature is used, we need to demangle all known137// symbols.138StringMap<SmallVector<Symbol *, 0>> &SymbolTable::getDemangledSyms() {139if (!demangledSyms) {140demangledSyms.emplace();141std::string demangled;142for (Symbol *sym : symVector)143if (canBeVersioned(*sym)) {144StringRef name = sym->getName();145size_t pos = name.find('@');146std::string substr;147if (pos == std::string::npos)148demangled = demangle(name);149else if (pos + 1 == name.size() || name[pos + 1] == '@') {150substr = name.substr(0, pos);151demangled = demangle(substr);152} else {153substr = name.substr(0, pos);154demangled = (demangle(substr) + name.substr(pos)).str();155}156(*demangledSyms)[demangled].push_back(sym);157}158}159return *demangledSyms;160}161162SmallVector<Symbol *, 0> SymbolTable::findByVersion(SymbolVersion ver) {163if (ver.isExternCpp)164return getDemangledSyms().lookup(ver.name);165if (Symbol *sym = find(ver.name))166if (canBeVersioned(*sym))167return {sym};168return {};169}170171SmallVector<Symbol *, 0> SymbolTable::findAllByVersion(SymbolVersion ver,172bool includeNonDefault) {173SmallVector<Symbol *, 0> res;174SingleStringMatcher m(ver.name);175auto check = [&](const Symbol &sym) -> bool {176if (!includeNonDefault)177return !sym.hasVersionSuffix;178StringRef name = sym.getName();179size_t pos = name.find('@');180return !(pos + 1 < name.size() && name[pos + 1] == '@');181};182183if (ver.isExternCpp) {184for (auto &p : getDemangledSyms())185if (m.match(p.first()))186for (Symbol *sym : p.second)187if (check(*sym))188res.push_back(sym);189return res;190}191192for (Symbol *sym : symVector)193if (canBeVersioned(*sym) && check(*sym) && m.match(sym->getName()))194res.push_back(sym);195return res;196}197198void SymbolTable::handleDynamicList() {199SmallVector<Symbol *, 0> syms;200for (SymbolVersion &ver : config->dynamicList) {201if (ver.hasWildcard)202syms = findAllByVersion(ver, /*includeNonDefault=*/true);203else204syms = findByVersion(ver);205206for (Symbol *sym : syms)207sym->inDynamicList = true;208}209}210211// Set symbol versions to symbols. This function handles patterns containing no212// wildcard characters. Return false if no symbol definition matches ver.213bool SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,214StringRef versionName,215bool includeNonDefault) {216// Get a list of symbols which we need to assign the version to.217SmallVector<Symbol *, 0> syms = findByVersion(ver);218219auto getName = [](uint16_t ver) -> std::string {220if (ver == VER_NDX_LOCAL)221return "VER_NDX_LOCAL";222if (ver == VER_NDX_GLOBAL)223return "VER_NDX_GLOBAL";224return ("version '" + config->versionDefinitions[ver].name + "'").str();225};226227// Assign the version.228for (Symbol *sym : syms) {229// For a non-local versionId, skip symbols containing version info because230// symbol versions specified by symbol names take precedence over version231// scripts. See parseSymbolVersion().232if (!includeNonDefault && versionId != VER_NDX_LOCAL &&233sym->getName().contains('@'))234continue;235236// If the version has not been assigned, assign versionId to the symbol.237if (!sym->versionScriptAssigned) {238sym->versionScriptAssigned = true;239sym->versionId = versionId;240}241if (sym->versionId == versionId)242continue;243244warn("attempt to reassign symbol '" + ver.name + "' of " +245getName(sym->versionId) + " to " + getName(versionId));246}247return !syms.empty();248}249250void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId,251bool includeNonDefault) {252// Exact matching takes precedence over fuzzy matching,253// so we set a version to a symbol only if no version has been assigned254// to the symbol. This behavior is compatible with GNU.255for (Symbol *sym : findAllByVersion(ver, includeNonDefault))256if (!sym->versionScriptAssigned) {257sym->versionScriptAssigned = true;258sym->versionId = versionId;259}260}261262// This function processes version scripts by updating the versionId263// member of symbols.264// If there's only one anonymous version definition in a version265// script file, the script does not actually define any symbol version,266// but just specifies symbols visibilities.267void SymbolTable::scanVersionScript() {268SmallString<128> buf;269// First, we assign versions to exact matching symbols,270// i.e. version definitions not containing any glob meta-characters.271for (VersionDefinition &v : config->versionDefinitions) {272auto assignExact = [&](SymbolVersion pat, uint16_t id, StringRef ver) {273bool found =274assignExactVersion(pat, id, ver, /*includeNonDefault=*/false);275buf.clear();276found |= assignExactVersion({(pat.name + "@" + v.name).toStringRef(buf),277pat.isExternCpp, /*hasWildCard=*/false},278id, ver, /*includeNonDefault=*/true);279if (!found && !config->undefinedVersion)280errorOrWarn("version script assignment of '" + ver + "' to symbol '" +281pat.name + "' failed: symbol not defined");282};283for (SymbolVersion &pat : v.nonLocalPatterns)284if (!pat.hasWildcard)285assignExact(pat, v.id, v.name);286for (SymbolVersion pat : v.localPatterns)287if (!pat.hasWildcard)288assignExact(pat, VER_NDX_LOCAL, "local");289}290291// Next, assign versions to wildcards that are not "*". Note that because the292// last match takes precedence over previous matches, we iterate over the293// definitions in the reverse order.294auto assignWildcard = [&](SymbolVersion pat, uint16_t id, StringRef ver) {295assignWildcardVersion(pat, id, /*includeNonDefault=*/false);296buf.clear();297assignWildcardVersion({(pat.name + "@" + ver).toStringRef(buf),298pat.isExternCpp, /*hasWildCard=*/true},299id,300/*includeNonDefault=*/true);301};302for (VersionDefinition &v : llvm::reverse(config->versionDefinitions)) {303for (SymbolVersion &pat : v.nonLocalPatterns)304if (pat.hasWildcard && pat.name != "*")305assignWildcard(pat, v.id, v.name);306for (SymbolVersion &pat : v.localPatterns)307if (pat.hasWildcard && pat.name != "*")308assignWildcard(pat, VER_NDX_LOCAL, v.name);309}310311// Then, assign versions to "*". In GNU linkers they have lower priority than312// other wildcards.313for (VersionDefinition &v : llvm::reverse(config->versionDefinitions)) {314for (SymbolVersion &pat : v.nonLocalPatterns)315if (pat.hasWildcard && pat.name == "*")316assignWildcard(pat, v.id, v.name);317for (SymbolVersion &pat : v.localPatterns)318if (pat.hasWildcard && pat.name == "*")319assignWildcard(pat, VER_NDX_LOCAL, v.name);320}321322// Symbol themselves might know their versions because symbols323// can contain versions in the form of <name>@<version>.324// Let them parse and update their names to exclude version suffix.325for (Symbol *sym : symVector)326if (sym->hasVersionSuffix)327sym->parseSymbolVersion();328329// isPreemptible is false at this point. To correctly compute the binding of a330// Defined (which is used by includeInDynsym()), we need to know if it is331// VER_NDX_LOCAL or not. Compute symbol versions before handling332// --dynamic-list.333handleDynamicList();334}335336Symbol *SymbolTable::addUnusedUndefined(StringRef name, uint8_t binding) {337return addSymbol(Undefined{ctx.internalFile, name, binding, STV_DEFAULT, 0});338}339340341