Re: [PATCH 18/23] objtool: cache relocations and function dead end state, do less work
From: Lorenzo Stoakes (ARM)
Date: Sun Sep 13 2026 - 16:32:10 EST
On Sat, Sep 12, 2026 at 03:47:33PM -0700, Josh Poimboeuf wrote:
> On Tue, Sep 08, 2026 at 09:55:18PM +0100, Lorenzo Stoakes (ARM) wrote:
> > Whole build, 128-thread Threadripper 9980X, best of N runs:
> >
> > before after delta
> > -------------------------------
> > x86 defconfig, touch mm/vma.c, gcc 8.4s 8.1s -0.28s (-3%)
> > x86 defconfig, touch mm/vma.c, clang 7.5s 7.1s -0.41s (-5%)
> > x86 defconfig, clean, gcc 27.1s 26.8s -0.34s (-1%)
> > x86 defconfig, clean, clang 26.6s 26.2s -0.40s (-1%)
> > x86 allmodconfig, touch mm/vma.c, gcc 30.2s 28.4s -1.8s (-6%)
> > x86 allmodconfig, touch mm/vma.c, clang 28.1s 26.0s -2.1s (-7%)
>
> Nice!
>
> > @@ -305,7 +305,15 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
> >
> > static bool dead_end_function(struct objtool_file *file, struct symbol *func)
> > {
> > - return __dead_end_function(file, func, 0);
> > + if (!func)
> > + return false;
> > +
> > + if (!func->dead_end_known) {
> > + func->dead_end = __dead_end_function(file, func, 0);
> > + func->dead_end_known = 1;
> > + }
> > +
> > + return func->dead_end;
> > }
>
> This bit seems like it should be a separate patch. Though actually, it
> can just be dropped as I have something similar brewing:
>
> https://lore.kernel.org/9d4b8ccfed745ac47a954aa2e1de62a85197122d.1788899473.git.jpoimboe@xxxxxxxxxx
>
Ack, dropped for v2, will reference that seris in the cover.
> > -struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset)
> > +/* Should never be invoked, provided as a backstop. */
> > +static struct reloc *find_reloc_linear(struct section *rsec,
> > + unsigned long offset, unsigned int len)
> > {
> > - return find_reloc_by_dest_range(elf, sec, offset, 1);
> > + struct reloc *reloc, *first = NULL;
> > +
> > + WARN("%s: linear scan for sec %s with %u relocs at offset %lu len %u",
> > + __func__, rsec->name, sec_num_entries(rsec), offset, len);
>
> Won't this be triggered for sections created with
> elf_create_rela_section()? I don't see where they set rsec->hashed.
Good catch thanks, it was triggering for those, e.g. CONFIG_LIVEPATCH, repro'd
locally.
Updated the code to hash these too correctly for v3.
>
> > @@ -1147,6 +1307,28 @@ static int read_relocs(struct elf *elf)
> >
> > rsec->base->rsec = rsec;
> >
> > + /* DWARF relocs are never looked up. */
> > + if (is_dwarf_section(rsec->base))
> > + continue;
> > + if (reloc_sec_in_order(rsec)) {
> > + rsec->sorted = true;
> > + continue;
> > + }
> > +
> > + rsec->hashed = true;
> > + nr_hashed += sec_num_entries(rsec);
> > + }
>
> Hm, I'm not sure whether hashing is even still needed, as compilers
> generally emit sorted relocs.
They do, and anything read from the file in the build does, but this is a
fallback for sections that objtool grows or creates itself which needs the
duplicate check + can be appended out of order.
>
> > @@ -1592,6 +1799,7 @@ static int elf_alloc_reloc(struct elf *elf, struct section *rsec)
> > }
> >
> > rsec->nr_alloc_relocs = nr_alloc;
> > + copy_reloc_cache_to_hash(elf, rsec, nr_relocs_old);
>
> Not all relocation appends go through this allocation code path.
> It can return earlier in this function if the space has already been
> allocated previously. So this call probably belongs in
> elf_create_reloc().
Ack thanks, fixed for v2.
>
> --
> Josh
--
Cheers, Lorenzo