SHF_TLS: This section holds Thread-Local Storage, meaning that each separate execution flow has its own distinct instance of this data. Implementations need not support this flag.
// If all patterns are simple (i.e. not containing any meta- // characters and is not a C++ name), we can simply look up // symbols. auto is_simple = [&] { for (VersionPattern &v : ctx.version_patterns) if (v.is_cpp || v.pattern.find_first_of("*?[") != v.pattern.npos) returnfalse; returntrue; };
if (is_simple()) { for (VersionPattern &v : ctx.version_patterns) { Symbol<E> *sym = get_symbol(ctx, v.pattern);
if (!sym->file && !ctx.arg.undefined_version) Warn(ctx) << v.source << ": cannot assign version `" << v.ver_str << "` to symbol `" << *sym << "`: symbol not found";
if (sym->file && !sym->file->is_dso) sym->ver_idx = v.ver_idx; } return; }
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) { for (Symbol<E> *sym : file->get_global_syms()) { if (sym->file != file) continue;
std::string_view name = sym->name(); i64 match = INT64_MAX;
if (std::optional<u32> idx = matcher.find(name)) match = std::min<i64>(match, *idx);
// Match non-mangled symbols against the C++ pattern as well. // Weird, but required to match other linkers' behavior. if (!cpp_matcher.empty()) { if (std::optional<std::string_view> s = cpp_demangle(name)) name = *s; if (std::optional<u32> idx = cpp_matcher.find(name)) match = std::min<i64>(match, *idx); }
if (match != INT64_MAX) sym->ver_idx = ctx.version_patterns[match].ver_idx; } });
// TODO(cwasser): Actually demangle Symbols on Windows using e.g. // `UnDecorateSymbolName` from Dbghelp, maybe even Itanium symbols? #ifndef _WIN32 if (name.starts_with("_Z")) { int status; char *p = abi::__cxa_demangle(std::string(name).c_str(), buf, &buflen, &status); if (status == 0) { buf = p; return p; } } #endif
return {}; }
obj only
我在读到这里,很好奇为什么只针对的是obj而不考虑dso,看了下相关的命令行参数的介绍才明白过来
-E, –export-dynamic Put symbols in the dynamic symbol table –no-export-dynamic
parse_symbol_version
1 2
// Parse symbol version suffixes (e.g. "foo@ver1"). parse_symbol_version(ctx);
1 2 3 4
template <typename E> voidparse_symbol_version(Context<E> &ctx){ if (!ctx.arg.shared) return;
std::unordered_map<std::string_view, u16> verdefs; for (i64 i = 0; i < ctx.arg.version_definitions.size(); i++) verdefs[ctx.arg.version_definitions[i]] = i + VER_NDX_LAST_RESERVED + 1;
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) { for (i64 i = 0; i < file->elf_syms.size() - file->first_global; i++) { // Match VERSION part of symbol foo@VERSION with version definitions. // The symbols' VERSION parts are in file->symvers. if (!file->symvers[i]) continue;
Use soname as a symbol version and append that version to all symbols.
1 2 3 4 5 6
if (ctx.arg.default_symver) { std::string ver = ctx.arg.soname.empty() ? filepath(ctx.arg.output).filename().string() : std::string(ctx.arg.soname); ctx.arg.version_definitions.push_back(ver); ctx.default_version = VER_NDX_LAST_RESERVED + 1; }
1 2 3 4 5 6 7 8 9
// If both symbol `foo` and `foo@VERSION` are defined, `foo@VERSION` // hides `foo` so that all references to `foo` are resolved to a // versioned symbol. Likewise, if `foo@VERSION` and `foo@@VERSION` are // defined, the default one takes precedence. Symbol<E> *sym2 = get_symbol(ctx, sym->name()); if (sym2->file == file && !file->symvers[sym2->sym_idx - file->first_global]) if (sym2->ver_idx == ctx.default_version || (sym2->ver_idx & ~VERSYM_HIDDEN) == (sym->ver_idx & ~VERSYM_HIDDEN)) sym2->ver_idx = VER_NDX_LOCAL;
// If we are creating an executable, we want to export symbols referenced // by DSOs unless they are explicitly marked as local by a version script. if (!ctx.arg.shared) { tbb::parallel_for_each(ctx.dsos, [&](SharedFile<E> *file) { for (Symbol<E> *sym : file->symbols) { if (sym->file && !sym->file->is_dso && sym->visibility != STV_HIDDEN) { if (sym->ver_idx != VER_NDX_LOCAL || !ctx.default_version_from_version_script) { std::scoped_lock lock(sym->mu); sym->is_exported = true; } } } }); }
// Export symbols that are not hidden or marked as local. // We also want to mark imported symbols as such. tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) { for (Symbol<E> *sym : file->get_global_syms()) { if (!sym->file || sym->visibility == STV_HIDDEN || sym->ver_idx == VER_NDX_LOCAL) continue;
// If we are creating a DSO, all global symbols are exported by default. if (sym->file == file) { std::scoped_lock lock(sym->mu); sym->is_exported = true;