[PATCH 18/23] objtool: cache relocations and function dead end state, do less work

Lorenzo Stoakes (ARM) ljs at kernel.org
Sun Sep 13 13:28:48 PDT 2026


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@kernel.org
>

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



More information about the linux-riscv mailing list