for (i64 i = 0; i < ctx.arg.defsyms.size(); i++) { std::pair<Symbol<E> *, std::variant<Symbol<E> *, u64>> &defsym = ctx.arg.defsyms[i]; add(defsym.first);
if (std::holds_alternative<Symbol<E> *>(defsym.second)) { // Add an undefined symbol to keep a reference to the defsym target. // This prevents elimination by e.g. LTO or gc-sections. // The undefined symbol will never make to the final object file; we // double-check that the defsym target is not undefined in // fix_synthetic_symbols. auto sym = std::get<Symbol<E> *>(defsym.second); add_undef(sym); } }
处理完defsym后再从命令行参数中读取的SectionOrder的符号
1 2 3
for (SectionOrder &ord : ctx.arg.section_order) if (ord.type == SectionOrder::SYMBOL) add(get_symbol(ctx, ord.name));
关于SectionOrder的定义
1 2 3 4 5
structSectionOrder { enum { NONE, SECTION, GROUP, ADDR, ALIGN, SYMBOL } type = NONE; std::string name; u64 value = 0; };
auto add = [&](Symbol<E> *sym) { obj->symbols.push_back(sym);
// An actual value will be set to a linker-synthesized symbol by // fix_synthetic_symbols(). Until then, `value` doesn't have a valid // value. 0xdeadbeef is a unique dummy value to make debugging easier // if the field is accidentally used before it gets a valid one. sym->value = 0xdeadbeef;
// Mark reachable objects to decide which files to include into an output. // This also merges symbol visibility. mark_live_objects(ctx);
// Cleanup. The rule used for archive extraction isn't accurate for the // general case of symbol extraction, so reset the resolution to be redone // later. for_each_file([](InputFile<E> *file) { file->clear_symbols(); });
// Now that the symbol references are gone, remove the eliminated files from // the file list. std::erase_if(ctx.objs, [](InputFile<E> *file) { return !file->is_alive; }); std::erase_if(ctx.dsos, [](InputFile<E> *file) { return !file->is_alive; }); }
// An optimized "mark" operation for parallel mark-and-sweep algorithms. // Returns true if `visited` was false and updated to true. inlineboolfast_mark(std::atomic<bool> &visited){ // A relaxed load + branch (assuming miss) takes only around 20 cycles, // while an atomic RMW can easily take hundreds on x86. We note that it's // common that another thread beat us in marking, so doing an optimistic // early test tends to improve performance in the ~20% ballpark. return !visited.load(std::memory_order_relaxed) && !visited.exchange(true, std::memory_order_relaxed); }
template <typename E> void ObjectFile<E>::eliminate_duplicate_comdat_groups() { for (ComdatGroupRef<E> &ref : comdat_groups) if (ref.group->owner != this->priority) for (u32 i : ref.members) if (sections[i]) sections[i]->kill(); }
template <typename E> inlinevoid InputSection<E>::kill() { if (is_alive.exchange(false)) for (FdeRecord<E> &fde : get_fdes()) fde.is_alive = false; }
// Symbols with higher priorities overwrites symbols with lower priorities. // Here is the list of priorities, from the highest to the lowest. // // 1. Strong defined symbol // 2. Weak defined symbol // 3. Strong defined symbol in a DSO/archive // 4. Weak Defined symbol in a DSO/archive // 5. Common symbol // 6. Common symbol in an archive // 7. Unclaimed (nonexistent) symbol // // Ties are broken by file priority. template <typename E> static u64 get_rank(InputFile<E> *file, const ElfSym<E> &esym, bool is_lazy){ if (esym.is_common()) { assert(!file->is_dso); if (is_lazy) return (6 << 24) + file->priority; return (5 << 24) + file->priority; }
if (ctx.has_lto_object) { // Do link-time optimization. We pass all IR object files to the // compiler backend to compile them into a few ELF object files. // // The compiler backend needs to know how symbols are resolved, // so compute symbol visibility, import/export bits, etc early. mark_live_objects(ctx); apply_version_script(ctx); parse_symbol_version(ctx); compute_import_export(ctx);
// Do LTO. It compiles IR object files into a few big ELF files. std::vector<ObjectFile<E> *> lto_objs = do_lto(ctx);
// do_resolve_symbols() have removed unreferenced files. Restore the // original files here because some of them may have to be resurrected // because they are referenced by the ELF files returned from do_lto(). ctx.objs = objs; ctx.dsos = dsos;
append(ctx.objs, lto_objs);
// Redo name resolution from scratch. tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) { file->clear_symbols(); file->is_alive = !file->is_in_lib; });