From 8f0acbf413463592adfcb7f4d7f58848fb8c7324 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 17 Feb 2022 14:22:06 +0900 Subject: [PATCH] [ELF][LTO] Move LTO to the symbol resolution pass ELF object files returned by do_lto() may contain unforeseen undefined symbols, so we can't call that function after the symbol resolution pass because it can cause undefined symbol errors. --- elf/lto.cc | 7 ------ elf/main.cc | 4 ---- elf/passes.cc | 66 ++++++++++++++++++++++++++++++++++----------------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/elf/lto.cc b/elf/lto.cc index 11048cd949..c35c379052 100644 --- a/elf/lto.cc +++ b/elf/lto.cc @@ -163,7 +163,6 @@ static PluginStatus add_input_file(const char *path) { file->is_alive = true; file->parse(ctx); file->resolve_symbols(ctx); - file->mark_live_objects(ctx, [](InputFile *) { unreachable(); }); return LDPS_OK; } @@ -538,12 +537,6 @@ void do_lto(Context &ctx) { assert(phase == 1); phase = 2; - // Compute import/export information early because `get_symbols` - // function needs them. - apply_version_script(ctx); - parse_symbol_version(ctx); - compute_import_export(ctx); - // Set `referenced_by_regular_obj` bit. for (ObjectFile *file : ctx.objs) { if (file->is_lto_obj) diff --git a/elf/main.cc b/elf/main.cc index 9b80cd49f0..103206ad91 100644 --- a/elf/main.cc +++ b/elf/main.cc @@ -469,10 +469,6 @@ static int elf_main(int argc, char **argv) { // included to the final output. resolve_symbols(ctx); - // Do LTO - if (ctx.has_lto_object) - do_lto(ctx); - // Resolve mergeable section pieces to merge them. register_section_pieces(ctx); diff --git a/elf/passes.cc b/elf/passes.cc index 03ed7496a8..3a14808d0b 100644 --- a/elf/passes.cc +++ b/elf/passes.cc @@ -77,27 +77,10 @@ void create_synthetic_sections(Context &ctx) { } template -void resolve_symbols(Context &ctx) { - Timer t(ctx, "resolve_symbols"); - - std::vector *> files; - append(files, ctx.objs); - append(files, ctx.dsos); - - // Register symbols - tbb::parallel_for_each(files, [&](InputFile *file) { - file->resolve_symbols(ctx); - }); - - // Mark reachable objects to decide which files to include - // into an output. - std::vector *> live_set = files; - std::erase_if(live_set, [](InputFile *file) { return !file->is_alive; }); - +static void mark_live_objects(Context &ctx) { auto mark_symbol = [&](std::string_view name) { if (InputFile *file = get_symbol(ctx, name)->file) - if (!file->is_alive.exchange(true)) - live_set.push_back(file); + file->is_alive = true; }; for (std::string_view name : ctx.arg.undefined) @@ -105,11 +88,50 @@ void resolve_symbols(Context &ctx) { for (std::string_view name : ctx.arg.require_defined) mark_symbol(name); - tbb::parallel_for_each(live_set, [&](InputFile *file, - tbb::feeder *> &feeder) { - file->mark_live_objects(ctx, [&](InputFile *obj) { feeder.add(obj); }); + auto mark_file = [&](InputFile *file, tbb::feeder *> &feeder) { + if (file->is_alive) + file->mark_live_objects(ctx, [&](InputFile *obj) { feeder.add(obj); }); + }; + + tbb::parallel_for_each(ctx.objs, mark_file); + tbb::parallel_for_each(ctx.dsos, mark_file); +} + +template +void resolve_symbols(Context &ctx) { + Timer t(ctx, "resolve_symbols"); + + // Register symbols + tbb::parallel_for_each(ctx.objs, [&](InputFile *file) { + file->resolve_symbols(ctx); }); + tbb::parallel_for_each(ctx.dsos, [&](InputFile *file) { + file->resolve_symbols(ctx); + }); + + // Do link-time optimization. We pass all IR object files to the + // compiler backend to compile them into a few ELF object files. + if (ctx.has_lto_object) { + Timer t(ctx, "do_lto"); + + // The compiler backend needs to know how symbols are resolved, + // so compute symbolvisibility, import/export bits, etc early. + mark_live_objects(ctx); + apply_version_script(ctx); + parse_symbol_version(ctx); + compute_import_export(ctx); + do_lto(ctx); + } + + // Mark reachable objects to decide which files to include into an output. + // This also merges symbol visibility. + mark_live_objects(ctx); + + std::vector *> files; + append(files, ctx.objs); + append(files, ctx.dsos); + // Remove symbols of eliminated files. tbb::parallel_for_each(files, [&](InputFile *file) { if (!file->is_alive)