diff --git a/elf/input-files.cc b/elf/input-files.cc index 49580a097c..39a92892fa 100644 --- a/elf/input-files.cc +++ b/elf/input-files.cc @@ -324,7 +324,7 @@ void ObjectFile::initialize_sections(Context &ctx) { ctx.has_ctors = true; if (name == ".eh_frame") - eh_frame_section = this->sections[i].get(); + eh_frame_sections.push_back(this->sections[i].get()); if constexpr (is_ppc32) if (name == ".got2") @@ -416,78 +416,75 @@ void ObjectFile::initialize_sections(Context &ctx) { // This function parses an input .eh_frame section. template void ObjectFile::parse_ehframe(Context &ctx) { - if (!eh_frame_section) - return; - - InputSection &isec = *eh_frame_section; - std::span> rels = isec.get_rels(ctx); - i64 cies_begin = cies.size(); - i64 fdes_begin = fdes.size(); + for (InputSection *isec : eh_frame_sections) { + std::span> rels = isec->get_rels(ctx); + i64 cies_begin = cies.size(); + i64 fdes_begin = fdes.size(); + + // Read CIEs and FDEs until empty. + std::string_view contents = this->get_string(ctx, isec->shdr()); + i64 rel_idx = 0; + + for (std::string_view data = contents; !data.empty();) { + i64 size = *(U32 *)data.data(); + if (size == 0) + break; - // Read CIEs and FDEs until empty. - std::string_view contents = this->get_string(ctx, isec.shdr()); - i64 rel_idx = 0; + i64 begin_offset = data.data() - contents.data(); + i64 end_offset = begin_offset + size + 4; + i64 id = *(U32 *)(data.data() + 4); + data = data.substr(size + 4); - for (std::string_view data = contents; !data.empty();) { - i64 size = *(U32 *)data.data(); - if (size == 0) - break; + i64 rel_begin = rel_idx; + while (rel_idx < rels.size() && rels[rel_idx].r_offset < end_offset) + rel_idx++; + assert(rel_idx == rels.size() || begin_offset <= rels[rel_begin].r_offset); - i64 begin_offset = data.data() - contents.data(); - i64 end_offset = begin_offset + size + 4; - i64 id = *(U32 *)(data.data() + 4); - data = data.substr(size + 4); + if (id == 0) { + // This is CIE. + cies.emplace_back(ctx, *this, *isec, begin_offset, rels, rel_begin); + } else { + // This is FDE. + if (rel_begin == rel_idx || rels[rel_begin].r_sym == 0) { + // FDE has no valid relocation, which means FDE is dead from + // the beginning. Compilers usually don't create such FDE, but + // `ld -r` tend to generate such dead FDEs. + continue; + } - i64 rel_begin = rel_idx; - while (rel_idx < rels.size() && rels[rel_idx].r_offset < end_offset) - rel_idx++; - assert(rel_idx == rels.size() || begin_offset <= rels[rel_begin].r_offset); + if (rels[rel_begin].r_offset - begin_offset != 8) + Fatal(ctx) << *isec << ": FDE's first relocation should have offset 8"; - if (id == 0) { - // This is CIE. - cies.emplace_back(ctx, *this, isec, begin_offset, rels, rel_begin); - } else { - // This is FDE. - if (rel_begin == rel_idx || rels[rel_begin].r_sym == 0) { - // FDE has no valid relocation, which means FDE is dead from - // the beginning. Compilers usually don't create such FDE, but - // `ld -r` tend to generate such dead FDEs. - continue; + fdes.emplace_back(begin_offset, rel_begin); } - - if (rels[rel_begin].r_offset - begin_offset != 8) - Fatal(ctx) << isec << ": FDE's first relocation should have offset 8"; - - fdes.emplace_back(begin_offset, rel_begin); } - } - // Associate CIEs to FDEs. - auto find_cie = [&](i64 offset) { - for (i64 i = cies_begin; i < cies.size(); i++) - if (cies[i].input_offset == offset) - return i; - Fatal(ctx) << isec << ": bad FDE pointer"; - }; + // Associate CIEs to FDEs. + auto find_cie = [&](i64 offset) { + for (i64 i = cies_begin; i < cies.size(); i++) + if (cies[i].input_offset == offset) + return i; + Fatal(ctx) << *isec << ": bad FDE pointer"; + }; - for (i64 i = fdes_begin; i < fdes.size(); i++) { - i64 cie_offset = *(I32 *)(contents.data() + fdes[i].input_offset + 4); - fdes[i].cie_idx = find_cie(fdes[i].input_offset + 4 - cie_offset); + for (i64 i = fdes_begin; i < fdes.size(); i++) { + i64 cie_offset = *(I32 *)(contents.data() + fdes[i].input_offset + 4); + fdes[i].cie_idx = find_cie(fdes[i].input_offset + 4 - cie_offset); + } } - auto get_isec = [&](const FdeRecord &fde) -> InputSection * { - return get_section(this->elf_syms[rels[fde.rel_idx].r_sym]); + auto get_isec = [&](const FdeRecord &fde) { + return get_section(this->elf_syms[fde.get_rels(*this)[0].r_sym]); }; // We assume that FDEs for the same input sections are contiguous // in `fdes` vector. - std::stable_sort(fdes.begin() + fdes_begin, fdes.end(), - [&](const FdeRecord &a, const FdeRecord &b) { + sort(fdes, [&](const FdeRecord &a, const FdeRecord &b) { return get_isec(a)->get_priority() < get_isec(b)->get_priority(); }); // Associate FDEs to input sections. - for (i64 i = fdes_begin; i < fdes.size();) { + for (i64 i = 0; i < fdes.size();) { InputSection *isec = get_isec(fdes[i]); assert(isec->fde_begin == -1); isec->fde_begin = i++; diff --git a/elf/mold.h b/elf/mold.h index 86e78dbd22..e4816c4a38 100644 --- a/elf/mold.h +++ b/elf/mold.h @@ -1183,7 +1183,7 @@ class ObjectFile : public InputFile { std::vector> fdes; BitVector has_symver; std::vector> comdat_groups; - InputSection *eh_frame_section = nullptr; + std::vector *> eh_frame_sections; bool exclude_libs = false; std::map gnu_properties; bool is_lto_obj = false; diff --git a/elf/passes.cc b/elf/passes.cc index 7d85a1e461..13fad126bb 100644 --- a/elf/passes.cc +++ b/elf/passes.cc @@ -356,8 +356,8 @@ void kill_eh_frame_sections(Context &ctx) { Timer t(ctx, "kill_eh_frame_sections"); for (ObjectFile *file : ctx.objs) - if (file->eh_frame_section) - file->eh_frame_section->is_alive = false; + for (InputSection *sec : file->eh_frame_sections) + sec->is_alive = false; } template diff --git a/test/elf/exception-multiple-ehframe.sh b/test/elf/exception-multiple-ehframe.sh new file mode 100755 index 0000000000..005538b9cc --- /dev/null +++ b/test/elf/exception-multiple-ehframe.sh @@ -0,0 +1,46 @@ +#!/bin/bash +. $(dirname $0)/common.inc + +[ $MACHINE = m68k ] && skip +[ $MACHINE = sh4 ] && skip + +cat < + +int foo(); +int bar(); + +int main() { + printf("%d %d\n", foo(), bar()); +} +EOF + +$CXX -B. -o $t/exe1 $t/d.o $t/c.o +$QEMU $t/exe1 +$QEMU $t/exe1 | grep -q '^1 3$'