[PATCH 04/23] kallsyms: output binary data to speed output and kallsyms assembly

David Laight david.laight.linux at gmail.com
Thu Sep 10 02:29:03 PDT 2026


On Tue, 08 Sep 2026 21:55:04 +0100
"Lorenzo Stoakes (ARM)" <ljs at kernel.org> wrote:

> kallsyms generates an assembly file that consists mostly of .byte entries
> containing compressed names, token strings and name-sorted sequence
> numbers.
> 
> For an x86-64 build with 158k symbols that is a 37 MiB .S file which takes
> 0.57s to assemble each of the two to three times it is built over a kernel
> build.
> 
> Each time it is generated it also takes kallsyms a similar amount of time
> to output it.
> 
> Avoid this overhead by instead outputting this data as binary and importing
> it into the assembly using the .incbin directive.
> 
> Tables that are wider than a byte remain part of the assembly to ensure
> endianness and relative relocations are performed correctly.
> 
> With this change, the output assembly file shrinks from 37 MiB to 9.8 MiB,
> with a 2.6 MiB binary data file alongside it, and the object remains
> identical.
> 
> The generated binary file is deleted correctly on build clean along with
> all other ephemeral data.
> 
> On an x86-64 system with CONFIG_KALLSYMS_ALL set:
> 
>                        before   after    delta
>   scripts/kallsyms     0.24s    0.18s    0.06s
>   assemble             0.57s    0.16s    0.41s
> 
> Per kallsyms invocation/assembly, for a total of 0.47s time saving upon
> invocation.
> 
> An incremental build on the same system was reduced from 11.15s to 9.65s,
> indicating a total of 1.5 seconds saved over the build.
> 
> The kallsyms runs and their assembly are on the serial tail of every build
> that links vmlinux, no-op builds are unchanged.
> 
> Whole build, 128-thread Threadripper 9980X, best of N runs:
> 
>                                          before   after     delta
>                                          -------------------------------
>   x86 defconfig, touch mm/vma.c, gcc       10.8s     9.9s    -0.92s (-8%)
>   x86 defconfig, touch mm/vma.c, clang     10.7s     9.5s     -1.2s (-11%)
>   x86 defconfig, clean, gcc                29.5s    28.7s    -0.81s (-3%)
>   x86 defconfig, clean, clang              29.7s    28.6s     -1.1s (-4%)
>   x86 allmodconfig, touch mm/vma.c, gcc    45.3s    44.0s     -1.3s (-3%)
>   x86 allmodconfig, touch mm/vma.c, clang  42.9s    40.2s     -2.7s (-6%)
> 
> Assisted-by: LLM
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs at kernel.org>
> ---
>  scripts/kallsyms.c      | 97 ++++++++++++++++++++++++++++++++++++++-----------
>  scripts/link-vmlinux.sh |  2 +-
>  2 files changed, 77 insertions(+), 22 deletions(-)
> 
> diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
> index 350d118c3b9e..61c5eb537ed4 100644
> --- a/scripts/kallsyms.c
> +++ b/scripts/kallsyms.c
> @@ -5,7 +5,10 @@
>   * This software may be used and distributed according to the terms
>   * of the GNU General Public License, incorporated herein by reference.
>   *
> - * Usage: kallsyms [--all-symbols] in.map > out.S
> + * Usage: kallsyms [--all-symbols] [--pc-relative] in.map out.bin > out.S
> + *
> + *      The byte tables go to out.bin and are pulled into out.S with .incbin;
> + *  wider tables stay assembler source for endianness and relocations.
>   *
>   *      Table compression uses all the unused char codes on the symbols and
>   *  maps these to the most used substrings (tokens). For instance, it might
> @@ -102,7 +105,7 @@ static void sym_arr_free(struct sym_arr *arr)
>  
>  static void usage(void)
>  {
> -	fprintf(stderr, "Usage: kallsyms [--all-symbols] in.map > out.S\n");
> +	fprintf(stderr, "Usage: kallsyms [--all-symbols] [--pc-relative] in.map out.bin > out.S\n");
>  	exit(1);
>  }
>  
> @@ -319,6 +322,40 @@ static void output_label(const char *label)
>  	printf("%s:\n", label);
>  }
>  
> +static void write_bin(FILE *file, const void *data, size_t len)
> +{
> +	if (fwrite(data, 1, len, file) == len)
> +		return;
> +
> +	perror("kallsyms: write");
> +	exit(EXIT_FAILURE);
> +}

It is pretty pointless checking the return value from fwrite().
Most of the time it is just doing a memcpy().
Instead call fflush() and the ferror() prior to the fclose().
(Or just rely on fclose() giving you that error status.)

David



More information about the linux-riscv mailing list