Skip to content

Commit

Permalink
[ELF][LTO] Move LTO to the symbol resolution pass
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rui314 committed Feb 17, 2022
1 parent a3f2a5c commit 803547d
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 32 deletions.
6 changes: 0 additions & 6 deletions elf/lto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -538,12 +538,6 @@ void do_lto(Context<E> &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<E> *file : ctx.objs) {
if (file->is_lto_obj)
Expand Down
4 changes: 0 additions & 4 deletions elf/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
66 changes: 44 additions & 22 deletions elf/passes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,39 +77,61 @@ void create_synthetic_sections(Context<E> &ctx) {
}

template <typename E>
void resolve_symbols(Context<E> &ctx) {
Timer t(ctx, "resolve_symbols");

std::vector<InputFile<E> *> files;
append(files, ctx.objs);
append(files, ctx.dsos);

// Register symbols
tbb::parallel_for_each(files, [&](InputFile<E> *file) {
file->resolve_symbols(ctx);
});

// Mark reachable objects to decide which files to include
// into an output.
std::vector<InputFile<E> *> live_set = files;
std::erase_if(live_set, [](InputFile<E> *file) { return !file->is_alive; });

static void mark_live_objects(Context<E> &ctx) {
auto mark_symbol = [&](std::string_view name) {
if (InputFile<E> *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)
mark_symbol(name);
for (std::string_view name : ctx.arg.require_defined)
mark_symbol(name);

tbb::parallel_for_each(live_set, [&](InputFile<E> *file,
tbb::feeder<InputFile<E> *> &feeder) {
file->mark_live_objects(ctx, [&](InputFile<E> *obj) { feeder.add(obj); });
auto mark_file = [&](InputFile<E> *file, tbb::feeder<InputFile<E> *> &feeder) {
if (file->is_alive)
file->mark_live_objects(ctx, [&](InputFile<E> *obj) { feeder.add(obj); });
};

tbb::parallel_for_each(ctx.objs, mark_file);
tbb::parallel_for_each(ctx.dsos, mark_file);
}

template <typename E>
void resolve_symbols(Context<E> &ctx) {
Timer t(ctx, "resolve_symbols");

// Register symbols
tbb::parallel_for_each(ctx.objs, [&](InputFile<E> *file) {
file->resolve_symbols(ctx);
});

tbb::parallel_for_each(ctx.dsos, [&](InputFile<E> *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<InputFile<E> *> files;
append(files, ctx.objs);
append(files, ctx.dsos);

// Remove symbols of eliminated files.
tbb::parallel_for_each(files, [&](InputFile<E> *file) {
if (!file->is_alive)
Expand Down

0 comments on commit 803547d

Please sign in to comment.