From 087d8f9ae33b7328a121f02a63a8ef70742d755a Mon Sep 17 00:00:00 2001 From: Petr Shumilov Date: Wed, 27 Nov 2024 15:47:17 +0300 Subject: [PATCH] Add stats collecting for relative relocations --- src/arch-arm32.cc | 5 +++++ src/arch-arm64.cc | 10 ++++++++++ src/arch-i386.cc | 10 ++++++++++ src/arch-loongarch.cc | 5 +++++ src/arch-m68k.cc | 5 +++++ src/arch-ppc64v1.cc | 10 ++++++++++ src/arch-ppc64v2.cc | 5 +++++ src/arch-riscv.cc | 5 +++++ src/arch-s390x.cc | 10 ++++++++++ src/arch-sparc64.cc | 10 ++++++++++ src/arch-x86-64.cc | 10 ++++++++++ src/mold.h | 45 +++++++++++++++++++++++++++++++++++++++++++ src/passes.cc | 14 ++++++++++++++ 13 files changed, 144 insertions(+) diff --git a/src/arch-arm32.cc b/src/arch-arm32.cc index 043cf0ce88..64688b1965 100644 --- a/src/arch-arm32.cc +++ b/src/arch-arm32.cc @@ -253,6 +253,7 @@ static bool is_jump_reachable(i64 val) { template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; auto get_tls_trampoline_addr = [&, i = 0](u64 addr) mutable { for (; i < output_section->thunks.size(); i++) { @@ -273,6 +274,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -532,6 +535,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 541a251112..1ef47ba8eb 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]; @@ -156,6 +157,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -434,11 +437,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]; @@ -449,6 +455,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -481,6 +489,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 008faaf014..99ec485f18 100644 --- a/src/arch-i386.cc +++ b/src/arch-i386.cc @@ -285,6 +285,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) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -435,11 +438,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]; @@ -450,6 +456,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -509,6 +517,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 dda138e99a..1cae6eb3ff 100644 --- a/src/arch-loongarch.cc +++ b/src/arch-loongarch.cc @@ -265,6 +265,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; auto get_r_delta = [&](i64 idx) { return extra.r_deltas.empty() ? 0 : extra.r_deltas[idx]; @@ -284,6 +285,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u8 *loc = base + r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -657,6 +660,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 edffe04801..67284ca542 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]; @@ -87,6 +88,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -207,6 +210,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 e3ec1c5557..535487b451 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]; @@ -163,6 +164,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -279,11 +282,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]; @@ -294,6 +300,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -328,6 +336,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 fdb5d568c1..492558912b 100644 --- a/src/arch-ppc64v2.cc +++ b/src/arch-ppc64v2.cc @@ -344,6 +344,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]; @@ -354,6 +355,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -388,6 +391,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 b69c988aa7..943663f14e 100644 --- a/src/arch-riscv.cc +++ b/src/arch-riscv.cc @@ -208,6 +208,7 @@ static inline bool is_hi20(const ElfRel &rel) { template <> void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { std::span> rels = get_rels(ctx); + RelocationsStats rels_stats; u64 GP = ctx.__global_pointer ? ctx.__global_pointer->get_addr(ctx) : 0; auto get_r_delta = [&](i64 idx) { @@ -225,6 +226,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u8 *loc = base + r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -620,6 +623,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 dedc607c76..a0590168f5 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]; @@ -125,6 +126,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -323,11 +326,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]; @@ -338,6 +344,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -372,6 +380,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 b04bb3011a..773eec3600 100644 --- a/src/arch-sparc64.cc +++ b/src/arch-sparc64.cc @@ -141,6 +141,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]; @@ -151,6 +152,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -452,11 +455,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]; @@ -467,6 +473,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -505,6 +513,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 4e0b5f9353..3fc7a94b4b 100644 --- a/src/arch-x86-64.cc +++ b/src/arch-x86-64.cc @@ -367,6 +367,7 @@ static void relax_ld_to_le(u8 *loc, 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]; @@ -377,6 +378,8 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -589,6 +592,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 @@ -606,6 +611,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]; @@ -616,6 +622,8 @@ void InputSection::apply_reloc_nonalloc(Context &ctx, u8 *base) { u8 *loc = base + rel.r_offset; auto check = [&](i64 val, i64 lo, i64 hi) { + if (ctx.arg.stats) + update_relocation_stats(rels_stats, i, val, lo, hi); if (val < lo || hi <= val) Error(ctx) << *this << ": relocation " << rel << " against " << sym << " out of range: " << val << " is not in [" @@ -693,6 +701,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 ce74a26e48..64f246fc53 100644 --- a/src/mold.h +++ b/src/mold.h @@ -310,6 +310,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: @@ -329,6 +335,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 // @@ -2148,6 +2187,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 aeac428db2..5cdc8b76b6 100644 --- a/src/passes.cc +++ b/src/passes.cc @@ -3214,10 +3214,24 @@ void show_stats(Context &ctx) { thunk_bytes += thunk->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;