diff --git a/src/arch-arm32.cc b/src/arch-arm32.cc index 6d68f67744..da4d92e0a3 100644 --- a/src/arch-arm32.cc +++ b/src/arch-arm32.cc @@ -288,6 +288,7 @@ static Thunk &get_reachable_thunk(OutputSection &osec, u64 addr) { template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -305,6 +306,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u64 GOT = ctx.got->shdr.sh_addr; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -549,6 +552,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { Error(ctx) << *this << ": unknown relocation: " << rel; } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-arm64.cc b/src/arch-arm64.cc index ec25657d6c..e5e10c4c0d 100644 --- a/src/arch-arm64.cc +++ b/src/arch-arm64.cc @@ -146,6 +146,7 @@ static bool is_add(u8 *loc) { template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -154,7 +155,6 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { Symbol &sym = *file.symbols[rel.r_sym]; u8 *loc = base + rel.r_offset; - u64 S = sym.get_addr(ctx); u64 A = rel.r_addend; u64 P = get_addr() + rel.r_offset; @@ -162,6 +162,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u64 GOT = ctx.got->shdr.sh_addr; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -431,11 +433,14 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -453,6 +458,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u64 A = frag ? frag_addend : (i64)rel.r_addend; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, val, i, lo, hi); }; @@ -473,6 +480,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { break; } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-i386.cc b/src/arch-i386.cc index 931d2d03dc..13a79c6bbe 100644 --- a/src/arch-i386.cc +++ b/src/arch-i386.cc @@ -279,6 +279,7 @@ static u32 relax_tlsdesc_to_le(u8 *loc) { template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -295,6 +296,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u64 GOT = ctx.got->shdr.sh_addr; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -430,11 +433,14 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -453,6 +459,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u64 GOT = ctx.got->shdr.sh_addr; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, val, i, lo, hi); }; @@ -501,6 +509,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-loongarch.cc b/src/arch-loongarch.cc index 78facfc06b..7e8563679d 100644 --- a/src/arch-loongarch.cc +++ b/src/arch-loongarch.cc @@ -273,6 +273,7 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span deltas = extra.r_deltas; i64 k = 0; u8 *buf = (u8 *)contents.data(); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -326,6 +327,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { }; auto check_branch = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check(val, lo, hi); if (val & 0b11) Error(ctx) << *this << ": misaligned symbol " << sym @@ -652,6 +655,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-m68k.cc b/src/arch-m68k.cc index 9be51968f8..d5851e5e9f 100644 --- a/src/arch-m68k.cc +++ b/src/arch-m68k.cc @@ -77,6 +77,7 @@ void EhFrameSection::apply_eh_reloc(Context &ctx, const ElfRel &rel, template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -93,6 +94,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u64 GOT = ctx.got->shdr.sh_addr; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -204,6 +207,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-ppc64v1.cc b/src/arch-ppc64v1.cc index 255fa9869c..316b1ff2a2 100644 --- a/src/arch-ppc64v1.cc +++ b/src/arch-ppc64v1.cc @@ -153,6 +153,7 @@ void EhFrameSection::apply_eh_reloc(Context &ctx, const ElfRel &rel, template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -170,6 +171,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u64 TOC = ctx.extra.TOC->value; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -276,11 +279,14 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -298,6 +304,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u64 A = frag ? frag_addend : (i64)rel.r_addend; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, val, i, lo, hi); }; @@ -320,6 +328,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { << rel; } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-ppc64v2.cc b/src/arch-ppc64v2.cc index 1f52c63517..7b675e2bc0 100644 --- a/src/arch-ppc64v2.cc +++ b/src/arch-ppc64v2.cc @@ -345,6 +345,7 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { template <> void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -362,6 +363,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u64 A = frag ? frag_addend : (i64)rel.r_addend; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -384,6 +387,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { << rel; } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-riscv.cc b/src/arch-riscv.cc index 333c523994..9141f619ac 100644 --- a/src/arch-riscv.cc +++ b/src/arch-riscv.cc @@ -269,6 +269,7 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span deltas = extra.r_deltas; i64 k = 0; u8 *buf = (u8 *)contents.data(); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -298,6 +299,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u64 GOT = ctx.got->shdr.sh_addr; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -642,6 +645,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-s390x.cc b/src/arch-s390x.cc index ba850c3a25..baad36fa30 100644 --- a/src/arch-s390x.cc +++ b/src/arch-s390x.cc @@ -115,6 +115,7 @@ void EhFrameSection::apply_eh_reloc(Context &ctx, const ElfRel &rel, template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -131,6 +132,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u64 GOT = ctx.got->shdr.sh_addr; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -330,11 +333,14 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -352,6 +358,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u64 A = frag ? frag_addend : (i64)rel.r_addend; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, val, i, lo, hi); }; @@ -376,6 +384,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { Fatal(ctx) << *this << ": apply_reloc_nonalloc: " << rel; } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-sparc64.cc b/src/arch-sparc64.cc index 35cecaeaf5..660f888db2 100644 --- a/src/arch-sparc64.cc +++ b/src/arch-sparc64.cc @@ -138,6 +138,7 @@ void EhFrameSection::apply_eh_reloc(Context &ctx, const ElfRel &rel, template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -154,6 +155,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u64 GOT = ctx.got->shdr.sh_addr; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -446,11 +449,14 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -468,6 +474,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u64 A = frag ? frag_addend : (i64)rel.r_addend; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, val, i, lo, hi); }; @@ -494,6 +502,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { Fatal(ctx) << *this << ": apply_reloc_nonalloc: " << rel; } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } template <> diff --git a/src/arch-x86-64.cc b/src/arch-x86-64.cc index 36663972ae..8649b45584 100644 --- a/src/arch-x86-64.cc +++ b/src/arch-x86-64.cc @@ -433,6 +433,7 @@ static void relax_ld_to_le(u8 *loc, const ElfRel &rel, i64 tls_size) { template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -449,6 +450,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u64 GOT = ctx.gotplt->shdr.sh_addr; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -640,6 +643,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { unreachable(); } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } // This function is responsible for applying relocations against @@ -657,6 +662,7 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { template <> void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; for (i64 i = 0; i < rels.size(); i++) { const ElfRel &rel = rels[i]; @@ -674,6 +680,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u64 A = frag ? frag_addend : (i64)rel.r_addend; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); check_range(ctx, i, val, lo, hi); }; @@ -741,6 +749,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { break; } } + if (ctx.arg.stats) + save_relocation_stats(ctx, *this, rels_stats); } // Linker has to create data structures in an output file to apply diff --git a/src/mold.h b/src/mold.h index 1cf9c5ba51..b8497afb93 100644 --- a/src/mold.h +++ b/src/mold.h @@ -354,6 +354,12 @@ class __attribute__((aligned(4))) InputSection { bool icf_eligible = false; bool icf_leaf = false; + // For stats recovering + struct { + Atomic relative_relocations_offset_supremum = -1; + Atomic relative_relocations_offset_infimum = -1; + } stats; + [[no_unique_address]] InputSectionExtras extra; private: @@ -371,6 +377,39 @@ class __attribute__((aligned(4))) InputSection { std::optional get_tombstone(Symbol &sym, SectionFragment *frag); }; +struct RelocationsStats { + i64 min_offset_lower_bound {std::numeric_limits::max()}; + i64 min_offset_upper_bound {std::numeric_limits::max()}; + i64 min_offset_lower_bound_rel_idx {-1}; + i64 min_offset_upper_bound_rel_idx {-1}; +}; + +inline void update_relocation_stats(RelocationsStats &stats, const i64 i, const i64 val, const i64 lo, const i64 hi) { + const auto to_lo = std::abs(lo - val); + const auto to_hi = std::abs(hi - val); + if (to_lo < stats.min_offset_lower_bound) { + stats.min_offset_lower_bound = to_lo; + stats.min_offset_lower_bound_rel_idx = i; + } + if (to_hi < stats.min_offset_upper_bound) { + stats.min_offset_upper_bound = to_hi; + stats.min_offset_upper_bound_rel_idx = i; + } +} + +template +inline void save_relocation_stats(Context &ctx, InputSection &isec, const RelocationsStats &stats) { + if (stats.min_offset_lower_bound < ctx.stats.relative_relocations_offset_infimum) { + ctx.stats.relative_relocations_offset_infimum = stats.min_offset_lower_bound; + isec.stats.relative_relocations_offset_infimum = stats.min_offset_lower_bound; + } + if (stats.min_offset_upper_bound < ctx.stats.relative_relocations_offset_supremum) { + ctx.stats.relative_relocations_offset_supremum = stats.min_offset_upper_bound; + isec.stats.relative_relocations_offset_supremum = stats.min_offset_upper_bound; + } +} + + // // tls.cc // @@ -2208,6 +2247,12 @@ struct Context { Symbol *end = nullptr; Symbol *etext = nullptr; + struct { + // Extra statistic for "free space" observation in output binary + Atomic relative_relocations_offset_infimum = std::numeric_limits::max(); + Atomic relative_relocations_offset_supremum = std::numeric_limits::max(); + } stats; + [[no_unique_address]] ContextExtras extra; }; diff --git a/src/passes.cc b/src/passes.cc index edb893ea1b..826f2db962 100644 --- a/src/passes.cc +++ b/src/passes.cc @@ -3361,10 +3361,24 @@ void show_stats(Context &ctx) { num_rels += isec->extra.r_deltas.size(); } + static Counter alloc_dist_to_lower_limit("rel_reloc_offset_infimum", ctx.stats.relative_relocations_offset_infimum); + static Counter alloc_dist_to_upper_limit("rel_reloc_offset_supremum", ctx.stats.relative_relocations_offset_supremum); + Counter::print(); for (std::unique_ptr> &sec : ctx.merged_sections) sec->print_stats(ctx); + + for (ObjectFile *obj : ctx.objs) { + for (std::unique_ptr> &sec : obj->sections) { + if (!sec || !sec->is_alive) + continue; + if (ctx.stats.relative_relocations_offset_infimum == sec->stats.relative_relocations_offset_infimum) + Out(ctx) << "'rel_reloc_offset_infimum' is relevant for " << *sec; + if (ctx.stats.relative_relocations_offset_supremum == sec->stats.relative_relocations_offset_supremum) + Out(ctx) << "'rel_reloc_offset_supremum' is relevant for " << *sec; + } + } } using E = MOLD_TARGET;