summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Chancellor <nathan@kernel.org>2026-10-11 01:22:02 +0100
committerNathan Chancellor <nathan@kernel.org>2026-10-11 01:22:02 +0100
commitfd26cc1da1ec4dbe4ca19d0c94f802ff4300a788 (patch)
treef343bf7e191d0567d77f8f352fdd53111b75e8e1
parent185b2c6a021ac46c62342fa814e5e2393f8396c5 (diff)
parentae5f6044c4cdffe2b3361b15c1d6fc67b339f2a4 (diff)
downloadlinux-next-fd26cc1da1ec4dbe4ca19d0c94f802ff4300a788.tar.gz
linux-next-fd26cc1da1ec4dbe4ca19d0c94f802ff4300a788.zip
Merge branch 'kbuild-next-speedups' into kbuild-for-next
* kbuild-next-speedups: kbuild: Mark the initcall ordering recipe as recursive kbuild: Mark the gzip recipes as recursive kconfig: Improve ergonomics around disabling warnings with cc-option scripts/Kconfig.toolchain: Drop compiler symbols from dependencies kbuild: keep .modinfo when vmlinux is linked with --gc-sections kbuild: compress the kernel with pigz if available kbuild: avoid re-running compiler and linker probes kbuild: move the toolchain checks into scripts/Kconfig.toolchain kallsyms: reimplement mksysmap in C elf-parse: add section flags, symbol binding and mapping helpers kbuild: only emit vmlinux relocations when required kbuild: do not sort nm output where the order is irrelevant sorttable: parse nm output correctly kallsyms: output binary data to speed output and kallsyms assembly kallsyms: index symbols by token to speed up table compression kbuild: do not allocate .modinfo in vmlinux Signed-off-by: Nathan Chancellor <nathan@kernel.org>
-rw-r--r--Documentation/kbuild/kbuild.rst17
-rw-r--r--Documentation/kbuild/makefiles.rst7
-rw-r--r--Documentation/process/changes.rst8
-rw-r--r--MAINTAINERS1
-rw-r--r--Makefile31
-rw-r--r--arch/alpha/boot/Makefile4
-rw-r--r--arch/arc/boot/Makefile2
-rw-r--r--arch/arm/boot/compressed/Makefile2
-rw-r--r--arch/arm64/boot/Makefile2
-rw-r--r--arch/arm64/kernel/pi/Makefile2
-rw-r--r--arch/csky/boot/Makefile2
-rw-r--r--arch/microblaze/boot/Makefile2
-rw-r--r--arch/mips/boot/Makefile2
-rw-r--r--arch/mips/boot/compressed/Makefile2
-rw-r--r--arch/nios2/boot/Makefile2
-rw-r--r--arch/parisc/boot/compressed/Makefile2
-rw-r--r--arch/riscv/boot/Makefile2
-rw-r--r--arch/riscv/kernel/pi/Makefile2
-rw-r--r--arch/s390/boot/Makefile2
-rw-r--r--arch/sh/boot/Makefile2
-rw-r--r--arch/sh/boot/compressed/Makefile2
-rw-r--r--arch/sparc/boot/Makefile4
-rw-r--r--arch/x86/Kconfig17
-rw-r--r--arch/x86/Makefile12
-rw-r--r--arch/x86/boot/Makefile2
-rw-r--r--arch/x86/boot/compressed/Makefile4
-rw-r--r--arch/xtensa/boot/Makefile2
-rw-r--r--drivers/firmware/efi/libstub/Makefile2
-rw-r--r--drivers/firmware/efi/libstub/Makefile.zboot2
-rw-r--r--include/asm-generic/vmlinux.lds.h2
-rw-r--r--init/Kconfig197
-rw-r--r--kernel/Makefile6
-rw-r--r--scripts/Kconfig.include2
-rw-r--r--scripts/Kconfig.toolchain272
-rw-r--r--scripts/Makefile5
-rw-r--r--scripts/Makefile.lib4
-rw-r--r--scripts/Makefile.vmlinux10
-rw-r--r--scripts/Makefile.vmlinux_o2
-rw-r--r--scripts/Makefile.warn28
-rwxr-xr-xscripts/check-function-names.sh3
-rw-r--r--scripts/elf-parse.c103
-rw-r--r--scripts/elf-parse.h54
-rwxr-xr-xscripts/jobserver-exec3
-rw-r--r--scripts/kallsyms-sysmap.c248
-rw-r--r--scripts/kallsyms.c379
-rw-r--r--scripts/kallsyms.h44
-rwxr-xr-xscripts/link-vmlinux.sh24
-rwxr-xr-xscripts/mksysmap94
-rw-r--r--scripts/sorttable.c15
-rwxr-xr-xscripts/ver_linux1
-rwxr-xr-xtools/lib/python/jobserver.py13
-rw-r--r--usr/Makefile2
52 files changed, 1162 insertions, 492 deletions
diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst
index 5a9013bacfb7..e71a692a559a 100644
--- a/Documentation/kbuild/kbuild.rst
+++ b/Documentation/kbuild/kbuild.rst
@@ -110,6 +110,23 @@ HOSTLDLIBS
----------
Additional libraries to link against when building host programs.
+KGZIP
+-----
+The gzip program used for compressed modules, packaging and the embedded
+kernel configuration. Defaults to gzip.
+
+KPGZIP
+------
+The gzip program used for the compressed kernel image. Defaults to pigz (a
+parallel implementation of gzip), run under scripts/jobserver-exec so that it
+uses the job slots make has free, if pigz is installed, otherwise to
+``KGZIP``. Set ``KPGZIP=`` on the make command line to use another program.
+
+KBZIP2, KLZOP, LZMA, LZ4, XZ, ZSTD
+----------------------------------
+The compressor programs for the other formats. Each defaults to the program
+of the same name.
+
.. _userkbuildflags:
USERCFLAGS
diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst
index 7521cae7d56f..535d30eef59a 100644
--- a/Documentation/kbuild/makefiles.rst
+++ b/Documentation/kbuild/makefiles.rst
@@ -1452,13 +1452,16 @@ objcopy
OBJCOPYFLAGS_$@ may be used to set additional options.
gzip
- Compress target. Use maximum compression to compress target.
+ Compress target. Use maximum compression to compress target. Prefix the
+ recipe line with '+' so that GNU Make passes it the jobserver, which
+ scripts/jobserver-exec needs to run pigz (if available) on the free job
+ slots.
Example::
#arch/x86/boot/compressed/Makefile
$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
dtc
Create flattened device tree blob object suitable for linking
diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst
index 0aa232b117b5..28f2ca63318e 100644
--- a/Documentation/process/changes.rst
+++ b/Documentation/process/changes.rst
@@ -55,6 +55,7 @@ nfs-utils 1.0.5 showmount --version
openssl & libcrypto 1.0.0 openssl version
pahole 1.26 pahole --version
pcmciautils 004 pccardctl -V
+pigz (optional) 2.4 pigz --version
PPP 2.4.0 pppd --version
procps 3.2.0 ps --version
Python 3.9.x python3 --version
@@ -206,6 +207,13 @@ GNU AWK
GNU AWK is needed if you want kernel builds to generate address range data for
builtin modules (CONFIG_BUILTIN_MODULE_RANGES).
+pigz (optional)
+---------------
+
+pigz is a parallel implementation of gzip. If it is installed the compressed
+kernel image is produced with it rather than with gzip, see ``KPGZIP`` in
+Documentation/kbuild/kbuild.rst.
+
System utilities
****************
diff --git a/MAINTAINERS b/MAINTAINERS
index 7704147dd975..a2f62c6a7038 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14057,6 +14057,7 @@ Q: https://patchwork.kernel.org/project/linux-kbuild/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git
F: Documentation/kbuild/kconfig*
F: scripts/Kconfig.include
+F: scripts/Kconfig.toolchain
F: scripts/kconfig/
KCORE
diff --git a/Makefile b/Makefile
index 28502178746f..8d23af898d44 100644
--- a/Makefile
+++ b/Makefile
@@ -569,6 +569,9 @@ LZMA = lzma
LZ4 = lz4
XZ = xz
ZSTD = zstd
+# The kernel image is compressed with pigz, on the job slots make has free,
+# if it is installed. Everything else uses KGZIP.
+KPGZIP := $(if $(shell command -v pigz 2>/dev/null),$(PYTHON3) $(abs_srctree)/scripts/jobserver-exec pigz -p %PARALLELISM%,$(KGZIP))
TAR = tar
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
@@ -649,7 +652,7 @@ export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN LLVM_
export HOSTRUSTC KBUILD_HOSTRUSTFLAGS
export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
-export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD TAR
+export KGZIP KPGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD TAR
export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS KBUILD_PROCMACROLDFLAGS LDFLAGS_MODULE
export KBUILD_USERCFLAGS KBUILD_USERLDFLAGS
@@ -947,8 +950,8 @@ KBUILD_RUSTFLAGS += -Coverflow-checks=$(if $(CONFIG_RUST_OVERFLOW_CHECKS),y,n)
ifdef CONFIG_CC_IS_GCC
# gcc-10 renamed --param=allow-store-data-races=0 to
# -fno-allow-store-data-races.
-KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0)
-KBUILD_CFLAGS += $(call cc-option,-fno-allow-store-data-races)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_ALLOW_STORE_DATA_RACES_PARAM)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_NO_ALLOW_STORE_DATA_RACES)
endif
ifdef CONFIG_READABLE_ASM
@@ -1012,18 +1015,20 @@ endif
endif
# Explicitly clear padding bits during variable initialization
-KBUILD_CFLAGS += $(call cc-option,-fzero-init-padding-bits=all)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_ZERO_INIT_PADDING_BITS)
# While VLAs have been removed, GCC produces unreachable stack probes
# for the randomize_kstack_offset feature. Disable it for all compilers.
+# Probed here rather than in Kconfig as clang only accepts it for some
+# sub-targets, so the architecture's flags matter.
KBUILD_CFLAGS += $(call cc-option, -fno-stack-clash-protection)
# Get details on warnings generated due to GCC value tracking.
-KBUILD_CFLAGS += $(call cc-option, -fdiagnostics-show-context=2)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_DIAGNOSTICS_SHOW_CONTEXT)
# Show inlining notes for __attribute__((warning/error)) call chains.
# GCC supports this unconditionally while Clang 23+ provides a flag.
-KBUILD_CFLAGS += $(call cc-option, -fdiagnostics-show-inlining-chain)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_DIAGNOSTICS_SHOW_INLINING_CHAIN)
# Clear used registers at func exit (to reduce data lifetime and ROP gadgets).
ifdef CONFIG_ZERO_CALL_USED_REGS
@@ -1034,7 +1039,7 @@ ifdef CONFIG_FUNCTION_TRACER
ifdef CONFIG_FTRACE_MCOUNT_USE_CC
CC_FLAGS_FTRACE += -mrecord-mcount
ifdef CONFIG_HAVE_NOP_MCOUNT
- ifeq ($(call cc-option-yn, -mnop-mcount),y)
+ ifdef CONFIG_CC_HAS_MNOP_MCOUNT
CC_FLAGS_FTRACE += -mnop-mcount
CC_FLAGS_USING += -DCC_USING_NOP_MCOUNT
endif
@@ -1052,8 +1057,7 @@ ifdef CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
endif
endif
ifdef CONFIG_HAVE_FENTRY
- # s390-linux-gnu-gcc did not support -mfentry until gcc-9.
- ifeq ($(call cc-option-yn, -mfentry),y)
+ ifdef CONFIG_CC_HAS_MFENTRY
CC_FLAGS_FTRACE += -mfentry
CC_FLAGS_USING += -DCC_USING_FENTRY
endif
@@ -1161,7 +1165,7 @@ NOSTDINC_FLAGS += -nostdinc
# the kernel uses only C99 flexible arrays for dynamically sized trailing
# arrays. Enforce this for everything that may examine structure sizes and
# perform bounds checking.
-KBUILD_CFLAGS += $(call cc-option, -fstrict-flex-arrays=3)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_STRICT_FLEX_ARRAYS)
# disable invalid "can't wrap" optimizations for signed / pointers
KBUILD_CFLAGS += -fno-strict-overflow
@@ -1244,11 +1248,11 @@ LDFLAGS_vmlinux += --build-id=sha1
# COMDAT-deduplicated sections. Use --force-group-allocation to resolve these
# groups when linking modules. The option is available from ld.bfd 2.29 and
# ld.lld 19.1.0.
-KBUILD_LDFLAGS_MODULE += $(call ld-option,--force-group-allocation)
+KBUILD_LDFLAGS_MODULE += $(CONFIG_LD_OPT_FORCE_GROUP_ALLOCATION)
KBUILD_LDFLAGS += -z noexecstack
ifeq ($(CONFIG_LD_IS_BFD),y)
-KBUILD_LDFLAGS += $(call ld-option,--no-warn-rwx-segments)
+KBUILD_LDFLAGS += $(CONFIG_LD_OPT_NO_WARN_RWX_SEGMENTS)
endif
ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
@@ -1266,8 +1270,9 @@ ifdef CONFIG_LD_ORPHAN_WARN
LDFLAGS_vmlinux += --orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL)
endif
+# --emit-relocs is added by scripts/link-vmlinux.sh, for the final link only.
ifneq ($(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS),)
-LDFLAGS_vmlinux += --emit-relocs --discard-none
+LDFLAGS_vmlinux += --discard-none
endif
# Align the architecture of userspace programs with the kernel
diff --git a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile
index d8dba85e606c..b050753e9015 100644
--- a/arch/alpha/boot/Makefile
+++ b/arch/alpha/boot/Makefile
@@ -40,7 +40,7 @@ endif
# Compressed kernel image
$(obj)/vmlinux.gz: $(obj)/vmlinux FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
@echo ' Kernel $@ is ready'
$(obj)/main.o: $(obj)/ksize.h
@@ -85,7 +85,7 @@ $(obj)/vmlinux.nh: vmlinux $(OBJSTRIP) FORCE
$(call if_changed,objstrip)
$(obj)/vmlinux.nh.gz: $(obj)/vmlinux.nh FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/tools/lxboot: $(obj)/bootloader $(OBJSTRIP) FORCE
$(call if_changed,objstrip)
diff --git a/arch/arc/boot/Makefile b/arch/arc/boot/Makefile
index 5a8550124b73..8a44c3e7ff3e 100644
--- a/arch/arc/boot/Makefile
+++ b/arch/arc/boot/Makefile
@@ -23,7 +23,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
$(call if_changed,lzma)
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index e3f550d62857..5f0a1a2e915a 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -153,7 +153,7 @@ $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \
@$(check_for_bad_syms)
$(obj)/piggy_data: $(obj)/../Image FORCE
- $(call if_changed,$(compress-y))
+ +$(call if_changed,$(compress-y))
$(obj)/piggy.o: $(obj)/piggy_data
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index b5a08333bc57..d42d07667822 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -26,7 +26,7 @@ $(obj)/Image.bz2: $(obj)/Image FORCE
$(call if_changed,bzip2)
$(obj)/Image.gz: $(obj)/Image FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/Image.lz4: $(obj)/Image FORCE
$(call if_changed,lz4)
diff --git a/arch/arm64/kernel/pi/Makefile b/arch/arm64/kernel/pi/Makefile
index be92d73c25b2..4a0cbedfdcd6 100644
--- a/arch/arm64/kernel/pi/Makefile
+++ b/arch/arm64/kernel/pi/Makefile
@@ -9,7 +9,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \
-include $(srctree)/include/linux/hidden.h \
-D__DISABLE_EXPORTS -ffreestanding -D__NO_FORTIFY \
-fno-asynchronous-unwind-tables -fno-unwind-tables \
- $(call cc-option,-fno-addrsig)
+ $(CONFIG_CC_OPT_NO_ADDRSIG)
# this code may run with the MMU off so disable unaligned accesses
CFLAGS_map_range.o += -mstrict-align
diff --git a/arch/csky/boot/Makefile b/arch/csky/boot/Makefile
index c3cfde28f8e6..5d88dc31877b 100644
--- a/arch/csky/boot/Makefile
+++ b/arch/csky/boot/Makefile
@@ -12,7 +12,7 @@ compress-$(CONFIG_KERNEL_XZ) = xzkern
compress-$(CONFIG_KERNEL_LZ4) = lz4
$(obj)/zImage: $(obj)/Image FORCE
- $(call if_changed,$(compress-y))
+ +$(call if_changed,$(compress-y))
@echo ' Kernel: $@ is ready'
UIMAGE_ARCH = sandbox
diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile
index 2b42c370d574..e3df3a64808a 100644
--- a/arch/microblaze/boot/Makefile
+++ b/arch/microblaze/boot/Makefile
@@ -14,7 +14,7 @@ $(obj)/linux.bin.ub: $(obj)/linux.bin FORCE
$(call if_changed,uimage)
$(obj)/linux.bin.gz: $(obj)/linux.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
quiet_cmd_strip = STRIP $< $@$2
cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
index 8473c4671702..996bf41b78de 100644
--- a/arch/mips/boot/Makefile
+++ b/arch/mips/boot/Makefile
@@ -63,7 +63,7 @@ $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
$(call if_changed,bzip2)
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
$(call if_changed,lzma)
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
index e0b8ec9a9516..2684540758a8 100644
--- a/arch/mips/boot/compressed/Makefile
+++ b/arch/mips/boot/compressed/Makefile
@@ -69,7 +69,7 @@ tool_$(CONFIG_KERNEL_ZSTD) = zstd22_with_size
targets += vmlinux.bin.z
$(obj)/vmlinux.bin.z: $(obj)/vmlinux.bin FORCE
- $(call if_changed,$(tool_y))
+ +$(call if_changed,$(tool_y))
targets += piggy.o dummy.o
diff --git a/arch/nios2/boot/Makefile b/arch/nios2/boot/Makefile
index 29c11a06b750..1381e6e428a8 100644
--- a/arch/nios2/boot/Makefile
+++ b/arch/nios2/boot/Makefile
@@ -18,7 +18,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/vmImage: $(obj)/vmlinux.gz FORCE
$(call if_changed,uimage)
diff --git a/arch/parisc/boot/compressed/Makefile b/arch/parisc/boot/compressed/Makefile
index 14eefb5ed5d1..a7fc7d424c00 100644
--- a/arch/parisc/boot/compressed/Makefile
+++ b/arch/parisc/boot/compressed/Makefile
@@ -55,7 +55,7 @@ suffix-$(CONFIG_KERNEL_LZO) := lzo
suffix-$(CONFIG_KERNEL_XZ) := xz
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
$(call if_changed,bzip2_with_size)
$(obj)/vmlinux.bin.lz4: $(obj)/vmlinux.bin FORCE
diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile
index 4a2d75b7e42d..b80a077a8e8f 100644
--- a/arch/riscv/boot/Makefile
+++ b/arch/riscv/boot/Makefile
@@ -23,7 +23,7 @@ $(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/Image.gz: $(obj)/Image FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/loader.o: $(src)/loader.S $(obj)/Image
diff --git a/arch/riscv/kernel/pi/Makefile b/arch/riscv/kernel/pi/Makefile
index bc098edac898..4c8e52b3f176 100644
--- a/arch/riscv/kernel/pi/Makefile
+++ b/arch/riscv/kernel/pi/Makefile
@@ -8,7 +8,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \
-include $(srctree)/include/linux/hidden.h \
-D__DISABLE_EXPORTS -ffreestanding \
-fno-asynchronous-unwind-tables -fno-unwind-tables \
- $(call cc-option,-fno-addrsig)
+ $(CONFIG_CC_OPT_NO_ADDRSIG)
# Disable LTO
KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS))
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index 10b75e053a6f..e8e43ae80dd5 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -117,7 +117,7 @@ suffix-$(CONFIG_KERNEL_XZ) := .xz
suffix-$(CONFIG_KERNEL_ZSTD) := .zst
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
$(call if_changed,bzip2_with_size)
$(obj)/vmlinux.bin.lz4: $(obj)/vmlinux.bin FORCE
diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
index 1f5d2df3c7e0..cf63e319b786 100644
--- a/arch/sh/boot/Makefile
+++ b/arch/sh/boot/Makefile
@@ -66,7 +66,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
$(call if_changed,bzip2)
diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
index 58df491778b2..b85aa5f0d616 100644
--- a/arch/sh/boot/compressed/Makefile
+++ b/arch/sh/boot/compressed/Makefile
@@ -39,7 +39,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
$(call if_changed,bzip2_with_size)
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
index 339c42d35089..b53cf596611e 100644
--- a/arch/sparc/boot/Makefile
+++ b/arch/sparc/boot/Makefile
@@ -23,7 +23,7 @@ ifeq ($(CONFIG_SPARC64),y)
# Actual linking
$(obj)/zImage: $(obj)/image FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
@$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')'
$(obj)/vmlinux.aout: vmlinux FORCE
@@ -45,7 +45,7 @@ $(obj)/image.bin: $(obj)/image FORCE
$(call if_changed,objcopy)
$(obj)/image.gz: $(obj)/image.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
UIMAGE_LOADADDR = $(CONFIG_UBOOT_LOAD_ADDR)
UIMAGE_ENTRYADDR = $(CONFIG_UBOOT_ENTRY_ADDR)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 15fd9ec5ecac..0fea2fc4ba1d 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2364,6 +2364,23 @@ config CC_HAS_KCFI_ARITY
def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
depends on CC_IS_CLANG && !RUST
+config CC_OPT_INDIRECT_BRANCH_CS_PREFIX
+ def_string "$(cc-option-str,-mindirect-branch-cs-prefix)"
+
+config CC_OPT_CF_PROTECTION_NONE
+ def_string "$(cc-option-str,-fcf-protection=none)"
+
+# with jump tables off: the compilers use NOTRACK for them, which kernel IBT
+# does not allow
+config CC_OPT_CF_PROTECTION_BRANCH
+ def_string "$(cc-option-str,-fcf-protection=branch -fno-jump-tables)"
+
+config CC_OPT_FALIGN_JUMPS
+ def_string "$(cc-option-str,-falign-jumps=1)"
+
+config CC_OPT_FALIGN_LOOPS
+ def_string "$(cc-option-str,-falign-loops=1)"
+
config FUNCTION_PADDING_CFI
int
default 59 if FUNCTION_ALIGNMENT_64B
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 598f178102ee..aac30ba51b2f 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -20,7 +20,7 @@ ifdef CONFIG_CC_IS_CLANG
RETPOLINE_CFLAGS := -mretpoline-external-thunk
RETPOLINE_VDSO_CFLAGS := -mretpoline
endif
-RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch-cs-prefix)
+RETPOLINE_CFLAGS += $(CONFIG_CC_OPT_INDIRECT_BRANCH_CS_PREFIX)
ifdef CONFIG_MITIGATION_RETHUNK
RETHUNK_CFLAGS := -mfunction-return=thunk-extern
@@ -52,7 +52,7 @@ REALMODE_CFLAGS := $(CC_FLAGS_DIALECT) -m16 -g -Os \
-DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS \
-Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
-fno-strict-aliasing -fomit-frame-pointer -fno-pic \
- -mno-mmx -mno-sse $(call cc-option,-fcf-protection=none)
+ -mno-mmx -mno-sse $(CONFIG_CC_OPT_CF_PROTECTION_NONE)
REALMODE_CFLAGS += -ffreestanding
REALMODE_CFLAGS += -fno-stack-protector
@@ -99,10 +99,10 @@ ifeq ($(CONFIG_X86_KERNEL_IBT),y)
#
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104816
#
-KBUILD_CFLAGS += $(call cc-option,-fcf-protection=branch -fno-jump-tables)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_CF_PROTECTION_BRANCH)
KBUILD_RUSTFLAGS += -Zcf-protection=branch $(if $(call rustc-min-version,109300),-Cjump-tables=n,-Zno-jump-tables)
else
-KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_CF_PROTECTION_NONE)
endif
ifeq ($(CONFIG_X86_32),y)
@@ -138,10 +138,10 @@ else
KBUILD_CFLAGS += -m64
# Align jump targets to 1 byte, not the default 16 bytes:
- KBUILD_CFLAGS += $(call cc-option,-falign-jumps=1)
+ KBUILD_CFLAGS += $(CONFIG_CC_OPT_FALIGN_JUMPS)
# Pack loops tightly as well:
- KBUILD_CFLAGS += $(call cc-option,-falign-loops=1)
+ KBUILD_CFLAGS += $(CONFIG_CC_OPT_FALIGN_LOOPS)
# Don't autogenerate traditional x87 instructions
KBUILD_CFLAGS += -mno-80387
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 3f9fb3698d66..4a9bce32586d 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -74,7 +74,7 @@ SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|efi.._stub_entry\|efi\(32\)\?_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|_e\?data\|_e\?sbat\|z_.*\)$$/\#define ZO_\2 0x\1/p'
quiet_cmd_zoffset = ZOFFSET $@
- cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
+ cmd_zoffset = $(NM) -p $< | sed -n $(sed-zoffset) > $@
targets += zoffset.h
$(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 06934f9691d6..680ad803cba7 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -76,7 +76,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include
sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABbCDGRSTtVW] \(_text\|__start_rodata\|_sinittext\|__inittext_end\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p'
quiet_cmd_voffset = VOFFSET $@
- cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@
+ cmd_voffset = $(NM) -p $< | sed -n $(sed-voffset) > $@
targets += ../voffset.h
@@ -133,7 +133,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin
vmlinux.bin.all-$(CONFIG_X86_NEED_RELOCS) += $(obj)/vmlinux.relocs
$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
$(call if_changed,bzip2_with_size)
$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
diff --git a/arch/xtensa/boot/Makefile b/arch/xtensa/boot/Makefile
index d8b0fadf429a..934f9015b15f 100644
--- a/arch/xtensa/boot/Makefile
+++ b/arch/xtensa/boot/Makefile
@@ -36,7 +36,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,gzip)
+ +$(call if_changed,gzip)
boot-elf: $(obj)/vmlinux.bin
boot-redboot: $(obj)/vmlinux.bin.gz
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 77a2b2d74f3f..415f63105b48 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -40,7 +40,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(cflags-y)) \
-D__NO_FORTIFY \
-ffreestanding \
-fno-stack-protector \
- $(call cc-option,-fno-addrsig) \
+ $(CONFIG_CC_OPT_NO_ADDRSIG) \
-D__DISABLE_EXPORTS
#
diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot
index 832deee36e48..52baacf3e9d9 100644
--- a/drivers/firmware/efi/libstub/Makefile.zboot
+++ b/drivers/firmware/efi/libstub/Makefile.zboot
@@ -24,7 +24,7 @@ zboot-method-$(CONFIG_KERNEL_ZSTD) := zstd22_with_size
zboot-size-len-$(CONFIG_KERNEL_ZSTD) := 4
$(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,$(zboot-method-y))
+ +$(call if_changed,$(zboot-method-y))
# avoid eager evaluation to prevent references to non-existent build artifacts
OBJCOPYFLAGS_vmlinuz.o = -I binary -O $(EFI_ZBOOT_BFD_TARGET) $(EFI_ZBOOT_OBJCOPY_FLAGS) \
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 26201821ea7f..7a3e9f00d628 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -855,7 +855,7 @@
KLP_SYMID
#define MODINFO \
- .modinfo : { *(.modinfo) }
+ .modinfo (INFO) : { KEEP(*(.modinfo)) }
#ifdef CONFIG_GENERIC_BUG
#define BUG_TABLE \
diff --git a/init/Kconfig b/init/Kconfig
index 8583d9f06c52..352601b44b5c 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1,201 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
-config CC_VERSION_TEXT
- string
- default "$(CC_VERSION_TEXT)"
- help
- This is used in unclear ways:
-
- - Re-run Kconfig when the compiler is updated
- The 'default' property references the environment variable,
- CC_VERSION_TEXT so it is recorded in include/config/auto.conf.cmd.
- When the compiler is updated, Kconfig will be invoked.
-
- - Ensure full rebuild when the compiler is updated
- include/linux/compiler-version.h contains this option in the comment
- line so fixdep adds include/config/CC_VERSION_TEXT into the
- auto-generated dependency. When the compiler is updated, syncconfig
- will touch it and then every file will be rebuilt.
-
-config CC_IS_GCC
- def_bool $(success,test "$(cc-name)" = GCC)
-
-config GCC_VERSION
- int
- default $(cc-version) if CC_IS_GCC
- default 0
-
-config CC_IS_CLANG
- def_bool $(success,test "$(cc-name)" = Clang)
-
-config CLANG_VERSION
- int
- default $(cc-version) if CC_IS_CLANG
- default 0
-
-config AS_IS_GNU
- def_bool $(success,test "$(as-name)" = GNU)
-
-config AS_IS_LLVM
- def_bool $(success,test "$(as-name)" = LLVM)
-
-config AS_VERSION
- int
- # Use clang version if this is the integrated assembler
- default CLANG_VERSION if AS_IS_LLVM
- default $(as-version)
-
-config LD_IS_BFD
- def_bool $(success,test "$(ld-name)" = BFD)
-
-config LD_VERSION
- int
- default $(ld-version) if LD_IS_BFD
- default 0
-
-config LD_IS_LLD
- def_bool $(success,test "$(ld-name)" = LLD)
-
-config LLD_VERSION
- int
- default $(ld-version) if LD_IS_LLD
- default 0
-
-config RUSTC_VERSION
- int
- default $(rustc-version)
- help
- It does not depend on `RUST` since that one may need to use the version
- in a `depends on`.
-
-config RUST_IS_AVAILABLE
- def_bool $(success,$(srctree)/scripts/rust_is_available.sh)
- help
- This shows whether a suitable Rust toolchain is available (found).
-
- Please see Documentation/rust/quick-start.rst for instructions on how
- to satisfy the build requirements of Rust support.
-
- In particular, the Makefile target 'rustavailable' is useful to check
- why the Rust toolchain is not being detected.
-
-config RUSTC_LLVM_VERSION
- int
- default $(rustc-llvm-version)
-
-config RUSTC_LLVM_MAJOR_VERSION
- int
- default $(shell,expr $(rustc-llvm-version) / 10000)
-config RUSTC_CLANG_LLVM_COMPATIBLE
- bool
- default y if CC_IS_CLANG && RUSTC_LLVM_MAJOR_VERSION = $(shell,expr $(cc-version) / 10000)
- help
- This indicates whether Rust and Clang use LLVM of the same major
- version.
-
- Operations involving handling LLVM IR or bitcode (e.g. cross-language
- LTO) require the same LLVM major version to work properly. For best
- compatibility it is recommended that the exact same LLVM is used.
-
-config ARCH_HAS_CC_CAN_LINK
- bool
-
-config CC_CAN_LINK
- bool
- default ARCH_CC_CAN_LINK if ARCH_HAS_CC_CAN_LINK
- default $(cc_can_link_user,$(m64-flag)) if 64BIT
- default $(cc_can_link_user,$(m32-flag))
-
-# Fixed in GCC 14, 13.3, 12.4 and 11.5
-# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921
-config GCC_ASM_GOTO_OUTPUT_BROKEN
- bool
- depends on CC_IS_GCC
- default y if GCC_VERSION < 110500
- default y if GCC_VERSION >= 120000 && GCC_VERSION < 120400
- default y if GCC_VERSION >= 130000 && GCC_VERSION < 130300
-
-config CC_HAS_ASM_GOTO_OUTPUT
- def_bool y
- depends on !GCC_ASM_GOTO_OUTPUT_BROKEN
- depends on $(success,echo 'int foo(int x) { asm goto ("": "=r"(x) ::: bar); return x; bar: return 0; }' | $(CC) -x c - -c -o /dev/null)
-
-config CC_HAS_ASM_GOTO_TIED_OUTPUT
- depends on CC_HAS_ASM_GOTO_OUTPUT
- # Detect buggy gcc and clang, fixed in gcc-11 clang-14.
- def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null)
-
-config TOOLS_SUPPORT_RELR
- def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
-
-config CC_HAS_ASM_INLINE
- def_bool $(success,echo 'void foo(void) { asm inline (""); }' | $(CC) -x c - -c -o /dev/null)
-
-config CC_HAS_ASSUME
- bool
- # clang needs to be at least 19.1.0 since the meaning of the assume
- # attribute changed:
- # https://github.com/llvm/llvm-project/commit/c44fa3e8a9a44c2e9a575768a3c185354b9f6c17
- default y if CC_IS_CLANG && CLANG_VERSION >= 190100
- # supported since gcc 13.1.0
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106654
- default y if CC_IS_GCC && GCC_VERSION >= 130100
-
-config CC_HAS_NO_PROFILE_FN_ATTR
- def_bool $(success,echo '__attribute__((no_profile_instrument_function)) int x();' | $(CC) -x c - -c -o /dev/null -Werror)
-
-config CC_HAS_COUNTED_BY
- bool
- # clang needs to be at least 20.1.0 to avoid potential crashes
- # when building structures that contain __counted_by
- # https://github.com/ClangBuiltLinux/linux/issues/2114
- # https://github.com/llvm/llvm-project/commit/160fb1121cdf703c3ef5e61fb26c5659eb581489
- default y if CC_IS_CLANG && CLANG_VERSION >= 200100
- # supported since gcc 15.1.0
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
- default y if CC_IS_GCC && GCC_VERSION >= 150100
-
-config CC_HAS_COUNTED_BY_PTR
- bool
- # supported since clang 22
- default y if CC_IS_CLANG && CLANG_VERSION >= 220100
- # supported since gcc 16.0.0
- default y if CC_IS_GCC && GCC_VERSION >= 160000
-
-config CC_HAS_BROKEN_COUNTED_BY_REF
- bool
- # https://github.com/llvm/llvm-project/issues/182575
- default y if CC_IS_CLANG && CLANG_VERSION < 220100
-
-config CC_HAS_ALLOC_TOKEN
- def_bool $(cc-option,-falloc-token-max=123)
-
-config CC_HAS_MULTIDIMENSIONAL_NONSTRING
- def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror)
-
-config LD_CAN_USE_KEEP_IN_OVERLAY
- # ld.lld prior to 21.0.0 did not support KEEP within an overlay description
- # https://github.com/llvm/llvm-project/pull/130661
- def_bool LD_IS_BFD || LLD_VERSION >= 210000
-
-config RUSTC_HAS_SPAN_FILE
- def_bool RUSTC_VERSION >= 108800
-
-config RUSTC_HAS_UNNECESSARY_TRANSMUTES
- def_bool RUSTC_VERSION >= 108800
-
-config RUSTC_HAS_FILE_WITH_NUL
- def_bool RUSTC_VERSION >= 108900
-
-config RUSTC_HAS_FILE_AS_C_STR
- def_bool RUSTC_VERSION >= 109100
-
-config RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS
- def_bool RUSTC_VERSION >= 109800
-
-config PAHOLE_VERSION
- int
- default "$(PAHOLE_VERSION)"
+source "scripts/Kconfig.toolchain"
config CONSTRUCTORS
bool
diff --git a/kernel/Makefile b/kernel/Makefile
index 1e1a31673577..c64c82c96b40 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -153,9 +153,13 @@ obj-$(CONFIG_SCF_TORTURE_TEST) += scftorture.o
$(obj)/configs.o: $(obj)/config_data.gz
+# .config is small, so it is compressed with gzip rather than the image compressor.
+quiet_cmd_gzip_config = GZIP $@
+ cmd_gzip_config = cat $(real-prereqs) | $(KGZIP) -n -f -9 > $@
+
targets += config_data config_data.gz
$(obj)/config_data.gz: $(obj)/config_data FORCE
- $(call if_changed,gzip)
+ $(call if_changed,gzip_config)
filechk_cat = cat $<
diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include
index 622d21e6953f..a7d9201acfcc 100644
--- a/scripts/Kconfig.include
+++ b/scripts/Kconfig.include
@@ -26,7 +26,7 @@ failure = $(if-success,$(1),n,y)
# $(cc-probe,<flag>)
# The command $(cc-option) and $(cc-option-str) test <flag> with. Not meant
# to be called directly; use one of those two instead.
-cc-probe = trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$/tmp.o
+cc-probe = trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(CC) -Werror $(CLANG_FLAGS) $(shell,echo $(1) | sed "s;^-Wno-;-W;") -c -x c /dev/null -o .tmp_$$/tmp.o
# $(cc-option,<flag>)
# Return y if the compiler supports <flag>, n otherwise
diff --git a/scripts/Kconfig.toolchain b/scripts/Kconfig.toolchain
new file mode 100644
index 000000000000..254393d4f98a
--- /dev/null
+++ b/scripts/Kconfig.toolchain
@@ -0,0 +1,272 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config CC_VERSION_TEXT
+ string
+ default "$(CC_VERSION_TEXT)"
+ help
+ This is used in unclear ways:
+
+ - Re-run Kconfig when the compiler is updated
+ The 'default' property references the environment variable,
+ CC_VERSION_TEXT so it is recorded in include/config/auto.conf.cmd.
+ When the compiler is updated, Kconfig will be invoked.
+
+ - Ensure full rebuild when the compiler is updated
+ include/linux/compiler-version.h contains this option in the comment
+ line so fixdep adds include/config/CC_VERSION_TEXT into the
+ auto-generated dependency. When the compiler is updated, syncconfig
+ will touch it and then every file will be rebuilt.
+
+config CC_IS_GCC
+ def_bool $(success,test "$(cc-name)" = GCC)
+
+config GCC_VERSION
+ int
+ default $(cc-version) if CC_IS_GCC
+ default 0
+
+config CC_IS_CLANG
+ def_bool $(success,test "$(cc-name)" = Clang)
+
+config CLANG_VERSION
+ int
+ default $(cc-version) if CC_IS_CLANG
+ default 0
+
+config AS_IS_GNU
+ def_bool $(success,test "$(as-name)" = GNU)
+
+config AS_IS_LLVM
+ def_bool $(success,test "$(as-name)" = LLVM)
+
+config AS_VERSION
+ int
+ # Use clang version if this is the integrated assembler
+ default CLANG_VERSION if AS_IS_LLVM
+ default $(as-version)
+
+config LD_IS_BFD
+ def_bool $(success,test "$(ld-name)" = BFD)
+
+config LD_VERSION
+ int
+ default $(ld-version) if LD_IS_BFD
+ default 0
+
+config LD_IS_LLD
+ def_bool $(success,test "$(ld-name)" = LLD)
+
+config LLD_VERSION
+ int
+ default $(ld-version) if LD_IS_LLD
+ default 0
+
+config RUSTC_VERSION
+ int
+ default $(rustc-version)
+ help
+ It does not depend on `RUST` since that one may need to use the version
+ in a `depends on`.
+
+config RUST_IS_AVAILABLE
+ def_bool $(success,$(srctree)/scripts/rust_is_available.sh)
+ help
+ This shows whether a suitable Rust toolchain is available (found).
+
+ Please see Documentation/rust/quick-start.rst for instructions on how
+ to satisfy the build requirements of Rust support.
+
+ In particular, the Makefile target 'rustavailable' is useful to check
+ why the Rust toolchain is not being detected.
+
+config RUSTC_LLVM_VERSION
+ int
+ default $(rustc-llvm-version)
+
+config RUSTC_LLVM_MAJOR_VERSION
+ int
+ default $(shell,expr $(rustc-llvm-version) / 10000)
+
+config RUSTC_CLANG_LLVM_COMPATIBLE
+ bool
+ default y if CC_IS_CLANG && RUSTC_LLVM_MAJOR_VERSION = $(shell,expr $(cc-version) / 10000)
+ help
+ This indicates whether Rust and Clang use LLVM of the same major
+ version.
+
+ Operations involving handling LLVM IR or bitcode (e.g. cross-language
+ LTO) require the same LLVM major version to work properly. For best
+ compatibility it is recommended that the exact same LLVM is used.
+
+config ARCH_HAS_CC_CAN_LINK
+ bool
+
+config CC_CAN_LINK
+ bool
+ default ARCH_CC_CAN_LINK if ARCH_HAS_CC_CAN_LINK
+ default $(cc_can_link_user,$(m64-flag)) if 64BIT
+ default $(cc_can_link_user,$(m32-flag))
+
+# Fixed in GCC 14, 13.3, 12.4 and 11.5
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921
+config GCC_ASM_GOTO_OUTPUT_BROKEN
+ bool
+ depends on CC_IS_GCC
+ default y if GCC_VERSION < 110500
+ default y if GCC_VERSION >= 120000 && GCC_VERSION < 120400
+ default y if GCC_VERSION >= 130000 && GCC_VERSION < 130300
+
+config CC_HAS_ASM_GOTO_OUTPUT
+ def_bool y
+ depends on !GCC_ASM_GOTO_OUTPUT_BROKEN
+ depends on $(success,echo 'int foo(int x) { asm goto ("": "=r"(x) ::: bar); return x; bar: return 0; }' | $(CC) -x c - -c -o /dev/null)
+
+config CC_HAS_ASM_GOTO_TIED_OUTPUT
+ depends on CC_HAS_ASM_GOTO_OUTPUT
+ # Detect buggy gcc and clang, fixed in gcc-11 clang-14.
+ def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null)
+
+config TOOLS_SUPPORT_RELR
+ def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
+
+config CC_HAS_ASM_INLINE
+ def_bool $(success,echo 'void foo(void) { asm inline (""); }' | $(CC) -x c - -c -o /dev/null)
+
+config CC_HAS_ASSUME
+ bool
+ # clang needs to be at least 19.1.0 since the meaning of the assume
+ # attribute changed:
+ # https://github.com/llvm/llvm-project/commit/c44fa3e8a9a44c2e9a575768a3c185354b9f6c17
+ default y if CC_IS_CLANG && CLANG_VERSION >= 190100
+ # supported since gcc 13.1.0
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106654
+ default y if CC_IS_GCC && GCC_VERSION >= 130100
+
+config CC_HAS_NO_PROFILE_FN_ATTR
+ def_bool $(success,echo '__attribute__((no_profile_instrument_function)) int x();' | $(CC) -x c - -c -o /dev/null -Werror)
+
+config CC_OPT_ZERO_INIT_PADDING_BITS
+ def_string "$(cc-option-str,-fzero-init-padding-bits=all)"
+
+config CC_OPT_NO_ADDRSIG
+ def_string "$(cc-option-str,-fno-addrsig)"
+
+config CC_OPT_DIAGNOSTICS_SHOW_CONTEXT
+ def_string "$(cc-option-str,-fdiagnostics-show-context=2)"
+
+config CC_OPT_DIAGNOSTICS_SHOW_INLINING_CHAIN
+ def_string "$(cc-option-str,-fdiagnostics-show-inlining-chain)"
+
+config CC_OPT_STRICT_FLEX_ARRAYS
+ def_string "$(cc-option-str,-fstrict-flex-arrays=3)"
+
+# gcc-10 renamed --param=allow-store-data-races=0 to -fno-allow-store-data-races
+config CC_OPT_ALLOW_STORE_DATA_RACES_PARAM
+ def_string "$(cc-option-str,--param=allow-store-data-races=0)"
+
+config CC_OPT_NO_ALLOW_STORE_DATA_RACES
+ def_string "$(cc-option-str,-fno-allow-store-data-races)"
+
+config CC_HAS_MNOP_MCOUNT
+ def_bool $(cc-option,-mnop-mcount)
+
+# s390-linux-gnu-gcc did not support -mfentry until gcc-9.
+config CC_HAS_MFENTRY
+ def_bool $(cc-option,-mfentry)
+
+config LD_OPT_FORCE_GROUP_ALLOCATION
+ def_string "$(ld-option-str,--force-group-allocation)"
+
+config LD_OPT_NO_WARN_RWX_SEGMENTS
+ def_string "$(ld-option-str,--no-warn-rwx-segments)"
+
+config CC_OPT_WNO_ADDRESS_OF_PACKED_MEMBER
+ def_string "$(cc-option-str,-Wno-address-of-packed-member)"
+
+config CC_OPT_WNO_FORMAT_OVERFLOW_NON_KPRINTF
+ def_string "$(cc-option-str,-Wno-format-overflow-non-kprintf)"
+
+config CC_OPT_WNO_FORMAT_TRUNCATION_NON_KPRINTF
+ def_string "$(cc-option-str,-Wno-format-truncation-non-kprintf)"
+
+config CC_OPT_WNO_DEFAULT_CONST_INIT_UNSAFE
+ def_string "$(cc-option-str,-Wno-default-const-init-unsafe)"
+
+config CC_OPT_WNO_DANGLING_POINTER
+ def_string "$(cc-option-str,-Wno-dangling-pointer)"
+
+config CC_OPT_WVLA_LARGER_THAN
+ def_string "$(cc-option-str,-Wvla-larger-than=1)"
+
+config CC_HAS_WSTRINGOP_OVERFLOW
+ def_bool $(cc-option,-Wstringop-overflow)
+
+config CC_OPT_WNO_UNTERMINATED_STRING_INITIALIZATION
+ def_string "$(cc-option-str,-Wno-unterminated-string-initialization)"
+
+config CC_OPT_WERROR_DESIGNATED_INIT
+ def_string "$(cc-option-str,-Werror=designated-init)"
+
+config CC_OPT_WENUM_CONVERSION
+ def_string "$(cc-option-str,-Wenum-conversion)"
+
+config CC_OPT_WNO_PACKED_NOT_ALIGNED
+ def_string "$(cc-option-str,-Wno-packed-not-aligned)"
+
+config CC_OPT_WNO_FORMAT_OVERFLOW
+ def_string "$(cc-option-str,-Wno-format-overflow)"
+
+config CC_OPT_WNO_STRINGOP_TRUNCATION
+ def_string "$(cc-option-str,-Wno-stringop-truncation)"
+
+config CC_HAS_COUNTED_BY
+ bool
+ # clang needs to be at least 20.1.0 to avoid potential crashes
+ # when building structures that contain __counted_by
+ # https://github.com/ClangBuiltLinux/linux/issues/2114
+ # https://github.com/llvm/llvm-project/commit/160fb1121cdf703c3ef5e61fb26c5659eb581489
+ default y if CC_IS_CLANG && CLANG_VERSION >= 200100
+ # supported since gcc 15.1.0
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
+ default y if CC_IS_GCC && GCC_VERSION >= 150100
+
+config CC_HAS_COUNTED_BY_PTR
+ bool
+ # supported since clang 22
+ default y if CC_IS_CLANG && CLANG_VERSION >= 220100
+ # supported since gcc 16.0.0
+ default y if CC_IS_GCC && GCC_VERSION >= 160000
+
+config CC_HAS_BROKEN_COUNTED_BY_REF
+ bool
+ # https://github.com/llvm/llvm-project/issues/182575
+ default y if CC_IS_CLANG && CLANG_VERSION < 220100
+
+config CC_HAS_ALLOC_TOKEN
+ def_bool $(cc-option,-falloc-token-max=123)
+
+config CC_HAS_MULTIDIMENSIONAL_NONSTRING
+ def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror)
+
+config LD_CAN_USE_KEEP_IN_OVERLAY
+ # ld.lld prior to 21.0.0 did not support KEEP within an overlay description
+ # https://github.com/llvm/llvm-project/pull/130661
+ def_bool LD_IS_BFD || LLD_VERSION >= 210000
+
+config RUSTC_HAS_SPAN_FILE
+ def_bool RUSTC_VERSION >= 108800
+
+config RUSTC_HAS_UNNECESSARY_TRANSMUTES
+ def_bool RUSTC_VERSION >= 108800
+
+config RUSTC_HAS_FILE_WITH_NUL
+ def_bool RUSTC_VERSION >= 108900
+
+config RUSTC_HAS_FILE_AS_C_STR
+ def_bool RUSTC_VERSION >= 109100
+
+config RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS
+ def_bool RUSTC_VERSION >= 109800
+
+config PAHOLE_VERSION
+ int
+ default "$(PAHOLE_VERSION)"
diff --git a/scripts/Makefile b/scripts/Makefile
index 3d50805b0885..d7fbb7ca098b 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -3,7 +3,7 @@
# scripts contains sources for various helper programs used throughout
# the kernel for the build process.
-hostprogs-always-$(CONFIG_KALLSYMS) += kallsyms
+hostprogs-always-y += kallsyms
hostprogs-always-$(BUILD_C_RECORDMCOUNT) += recordmcount
hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable
hostprogs-always-$(CONFIG_ASN1) += asn1_compiler
@@ -13,6 +13,7 @@ hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder
hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen
hostprogs-always-$(CONFIG_TRACEPOINTS) += tracepoint-update
+kallsyms-objs := kallsyms.o kallsyms-sysmap.o elf-parse.o
sorttable-objs := sorttable.o elf-parse.o
tracepoint-update-objs := tracepoint-update.o elf-parse.o
@@ -30,6 +31,8 @@ rustdoc_test_builder-rust := y
rustdoc_test_gen-rust := y
HOSTCFLAGS_tracepoint-update.o = -I$(srctree)/tools/include
+HOSTCFLAGS_kallsyms.o = -I$(srctree)/tools/include
+HOSTCFLAGS_kallsyms-sysmap.o = -I$(srctree)/tools/include
HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include
HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
HOSTLDLIBS_sorttable = -lpthread
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 0a4fdd8bd975..19e96b30a122 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -333,11 +333,11 @@ quiet_cmd_ar = AR $@
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
-# Gzip
+# Gzip, for the kernel image
# ---------------------------------------------------------------------------
quiet_cmd_gzip = GZIP $@
- cmd_gzip = cat $(real-prereqs) | $(KGZIP) -n -f -9 > $@
+ cmd_gzip = cat $(real-prereqs) | $(KPGZIP) -n -f -9 > $@
# Bzip2
# ---------------------------------------------------------------------------
diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
index 6833b517cacb..95b523fe4f9e 100644
--- a/scripts/Makefile.vmlinux
+++ b/scripts/Makefile.vmlinux
@@ -89,11 +89,8 @@ remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel.*'
remove-symbols := -w --strip-unneeded-symbol='__mod_device_table__*'
-# To avoid warnings: "empty loadable segment detected at ..." from GNU objcopy,
-# it is necessary to remove the PT_LOAD flag from the segment.
quiet_cmd_strip_relocs = OBJCOPY $@
- cmd_strip_relocs = $(OBJCOPY) $(patsubst %,--set-section-flags %=noload,$(remove-section-y)) $< $@; \
- $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $@
+ cmd_strip_relocs = $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $< $@
targets += vmlinux
vmlinux: vmlinux.unstripped FORCE
@@ -103,10 +100,7 @@ vmlinux: vmlinux.unstripped FORCE
# ---------------------------------------------------------------------------
quiet_cmd_modules_builtin_modinfo = GEN $@
- cmd_modules_builtin_modinfo = $(cmd_objcopy); \
- chmod -x $@
-
-OBJCOPYFLAGS_modules.builtin.modinfo := -j .modinfo -O binary
+ cmd_modules_builtin_modinfo = $(OBJCOPY) -O binary -j .modinfo --dump-section .modinfo=$@ $< /dev/null
targets += modules.builtin.modinfo
modules.builtin.modinfo: vmlinux.unstripped FORCE
diff --git a/scripts/Makefile.vmlinux_o b/scripts/Makefile.vmlinux_o
index 24a3a4fd271c..0b37bd5dc3a4 100644
--- a/scripts/Makefile.vmlinux_o
+++ b/scripts/Makefile.vmlinux_o
@@ -19,7 +19,7 @@ quiet_cmd_gen_initcalls_lds = GEN $@
.tmp_initcalls.lds: $(srctree)/scripts/generate_initcall_order.pl \
vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
- $(call if_changed,gen_initcalls_lds)
+ +$(call if_changed,gen_initcalls_lds)
targets := .tmp_initcalls.lds
diff --git a/scripts/Makefile.warn b/scripts/Makefile.warn
index 35af7d6c6d18..556fa249ca07 100644
--- a/scripts/Makefile.warn
+++ b/scripts/Makefile.warn
@@ -17,7 +17,7 @@ KBUILD_CFLAGS += -Werror=strict-prototypes
KBUILD_CFLAGS += -Wno-format-security
KBUILD_CFLAGS += -Wno-trigraphs
KBUILD_CFLAGS += -Wno-frame-address
-KBUILD_CFLAGS += $(call cc-option, -Wno-address-of-packed-member)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_ADDRESS_OF_PACKED_MEMBER)
KBUILD_CFLAGS += -Wmissing-declarations
KBUILD_CFLAGS += -Wmissing-prototypes
@@ -30,8 +30,8 @@ KBUILD_CFLAGS-$(CONFIG_CC_NO_ARRAY_BOUNDS) += -Wno-array-bounds
ifdef CONFIG_CC_IS_CLANG
# Clang checks for overflow/truncation with '%p', while GCC does not:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111219
-KBUILD_CFLAGS += $(call cc-option, -Wno-format-overflow-non-kprintf)
-KBUILD_CFLAGS += $(call cc-option, -Wno-format-truncation-non-kprintf)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_FORMAT_OVERFLOW_NON_KPRINTF)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_FORMAT_TRUNCATION_NON_KPRINTF)
# Clang may emit a warning when a const variable, such as the dummy variables
# in typecheck(), or const member of an aggregate type are not initialized,
@@ -43,7 +43,7 @@ KBUILD_CFLAGS += $(call cc-option, -Wno-format-truncation-non-kprintf)
# disabled with this same switch, there should not be too much coverage lost
# because -Wuninitialized will still flag when an uninitialized const variable
# is used.
-KBUILD_CFLAGS += $(call cc-option, -Wno-default-const-init-unsafe)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_DEFAULT_CONST_INIT_UNSAFE)
else
# gcc inanely warns about local variables called 'main'
@@ -54,7 +54,7 @@ endif
KBUILD_CFLAGS += -Wno-type-limits
# These result in bogus false positives
-KBUILD_CFLAGS += $(call cc-option, -Wno-dangling-pointer)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_DANGLING_POINTER)
# Stack Variable Length Arrays (VLAs) must not be used in the kernel.
# Function array parameters should, however, be usable, but -Wvla will
@@ -62,7 +62,7 @@ KBUILD_CFLAGS += $(call cc-option, -Wno-dangling-pointer)
# types, so depend on GCC for now to keep stack VLAs out of the tree.
# https://github.com/llvm/llvm-project/issues/57098
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98217
-KBUILD_CFLAGS += $(call cc-option,-Wvla-larger-than=1)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WVLA_LARGER_THAN)
# disable pointer signed / unsigned warnings in gcc 4.0
KBUILD_CFLAGS += -Wno-pointer-sign
@@ -73,11 +73,11 @@ KBUILD_CFLAGS += -Wno-pointer-sign
KBUILD_CFLAGS += -Wcast-function-type
# Currently, disable -Wstringop-overflow for GCC 11, globally.
-KBUILD_CFLAGS-$(CONFIG_CC_NO_STRINGOP_OVERFLOW) += $(call cc-option, -Wno-stringop-overflow)
-KBUILD_CFLAGS-$(CONFIG_CC_STRINGOP_OVERFLOW) += $(call cc-option, -Wstringop-overflow)
+KBUILD_CFLAGS-$(CONFIG_CC_NO_STRINGOP_OVERFLOW) += $(if $(CONFIG_CC_HAS_WSTRINGOP_OVERFLOW),-Wno-stringop-overflow)
+KBUILD_CFLAGS-$(CONFIG_CC_STRINGOP_OVERFLOW) += $(if $(CONFIG_CC_HAS_WSTRINGOP_OVERFLOW),-Wstringop-overflow)
# Currently, disable -Wunterminated-string-initialization as broken
-KBUILD_CFLAGS += $(call cc-option, -Wno-unterminated-string-initialization)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_UNTERMINATED_STRING_INITIALIZATION)
# The allocators already balk at large sizes, so silence the compiler
# warnings for bounds checks involving those possible values. While
@@ -100,10 +100,10 @@ KBUILD_CFLAGS += -Werror=date-time
KBUILD_CFLAGS += -Werror=incompatible-pointer-types
# Require designated initializers for all marked structures
-KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WERROR_DESIGNATED_INIT)
# Warn if there is an enum types mismatch
-KBUILD_CFLAGS += $(call cc-option,-Wenum-conversion)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WENUM_CONVERSION)
KBUILD_CFLAGS += -Wunused
@@ -125,12 +125,12 @@ else
# Suppress them by using -Wno... except for W=1.
KBUILD_CFLAGS += -Wno-unused-but-set-variable
KBUILD_CFLAGS += -Wno-unused-const-variable
-KBUILD_CFLAGS += $(call cc-option, -Wno-packed-not-aligned)
-KBUILD_CFLAGS += $(call cc-option, -Wno-format-overflow)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_PACKED_NOT_ALIGNED)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_FORMAT_OVERFLOW)
ifdef CONFIG_CC_IS_GCC
KBUILD_CFLAGS += -Wno-format-truncation
endif
-KBUILD_CFLAGS += $(call cc-option, -Wno-stringop-truncation)
+KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_STRINGOP_TRUNCATION)
KBUILD_CFLAGS += -Wno-override-init # alias for -Wno-initializer-overrides in clang
diff --git a/scripts/check-function-names.sh b/scripts/check-function-names.sh
index 08071133e5a5..94883e690627 100755
--- a/scripts/check-function-names.sh
+++ b/scripts/check-function-names.sh
@@ -13,7 +13,8 @@ if [ ! -f "$objfile" ]; then
exit 1
fi
-bad_symbols=$(${NM:-nm} "$objfile" | awk '$2 ~ /^[TtWw]$/ {print $3}' | grep -E '^(startup|exit|split|unlikely|hot|unknown)(\.|$)')
+bad_symbols=$(${NM:-nm} -p "$objfile" | awk '$2 ~ /^[TtWw]$/ {print $3}' |
+ grep -E '^(startup|exit|split|unlikely|hot|unknown)(\.|$)')
if [ -n "$bad_symbols" ]; then
echo "$bad_symbols" | while read -r sym; do
diff --git a/scripts/elf-parse.c b/scripts/elf-parse.c
index 99869ff91a8c..ce1c2a670244 100644
--- a/scripts/elf-parse.c
+++ b/scripts/elf-parse.c
@@ -17,15 +17,21 @@ struct elf_funcs elf_parser;
* Get the whole file as a programming convenience in order to avoid
* malloc+lseek+read+free of many pieces. If successful, then mmap
* avoids copying unused pieces; else just read the whole file.
- * Open for both read and write.
+ * Open for both read and write if writable is true, otherwise open
+ * read-only.
*/
-static void *map_file(char const *fname, size_t *size)
+static void *map_file(char const *fname, size_t *size, bool writable)
{
- int fd;
+ int fd, prot = PROT_READ, flags = MAP_PRIVATE;
struct stat sb;
void *addr = NULL;
- fd = open(fname, O_RDWR);
+ if (writable) {
+ prot |= PROT_WRITE;
+ flags = MAP_SHARED;
+ }
+
+ fd = open(fname, writable ? O_RDWR : O_RDONLY);
if (fd < 0) {
perror(fname);
return NULL;
@@ -39,7 +45,7 @@ static void *map_file(char const *fname, size_t *size)
goto out;
}
- addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ addr = mmap(0, sb.st_size, prot, flags, fd, 0);
if (addr == MAP_FAILED) {
fprintf(stderr, "Could not mmap file: %s\n", fname);
goto out;
@@ -57,6 +63,12 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
Elf_Ehdr *ehdr = addr;
uint16_t type;
+ if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
+ ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
+ fprintf(stderr, "unrecognized ELF file %s\n", fname);
+ return -1;
+ }
+
switch (ehdr->e32.e_ident[EI_DATA]) {
case ELFDATA2LSB:
elf_parser.r = rle;
@@ -78,12 +90,6 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
return -1;
}
- if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
- ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
- fprintf(stderr, "unrecognized ELF file %s\n", fname);
- return -1;
- }
-
type = elf_parser.r2(&ehdr->e32.e_type);
if (!((1 << type) & types)) {
fprintf(stderr, "Invalid ELF type file %s\n", fname);
@@ -103,7 +109,9 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
elf_parser.shdr_name = shdr32_name;
elf_parser.shdr_type = shdr32_type;
elf_parser.shdr_entsize = shdr32_entsize;
+ elf_parser.shdr_flags = shdr32_flags;
elf_parser.sym_type = sym32_type;
+ elf_parser.sym_bind = sym32_bind;
elf_parser.sym_name = sym32_name;
elf_parser.sym_value = sym32_value;
elf_parser.sym_shndx = sym32_shndx;
@@ -133,7 +141,9 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
elf_parser.shdr_name = shdr64_name;
elf_parser.shdr_type = shdr64_type;
elf_parser.shdr_entsize = shdr64_entsize;
+ elf_parser.shdr_flags = shdr64_flags;
elf_parser.sym_type = sym64_type;
+ elf_parser.sym_bind = sym64_bind;
elf_parser.sym_name = sym64_name;
elf_parser.sym_value = sym64_value;
elf_parser.sym_shndx = sym64_shndx;
@@ -174,12 +184,13 @@ int elf_map_long_size(void *addr)
return ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
}
-void *elf_map(char const *fname, size_t *size, uint32_t types)
+static void *__elf_map(char const *fname, size_t *size, uint32_t types,
+ bool writable)
{
void *addr;
int ret;
- addr = map_file(fname, size);
+ addr = map_file(fname, size, writable);
if (!addr)
return NULL;
@@ -192,7 +203,73 @@ void *elf_map(char const *fname, size_t *size, uint32_t types)
return addr;
}
+void *elf_map(char const *fname, size_t *size, uint32_t types)
+{
+ return __elf_map(fname, size, types, true);
+}
+
+/* For tools that only read the file. */
+void *elf_map_ro(char const *fname, size_t *size, uint32_t types)
+{
+ return __elf_map(fname, size, types, false);
+}
+
void elf_unmap(void *addr, size_t size)
{
munmap(addr, size);
}
+
+/*
+ * Open an ELF file and map it read-only, locating its section headers, section
+ * names and symbol table which are populated in the elf out parameter.
+ *
+ * Returns 0 on success, otherwise -1.
+ */
+int elf_open_ro(char const *fname, uint32_t types, struct elf_file *elf)
+{
+ Elf_Ehdr *ehdr;
+ Elf_Shdr *first;
+ unsigned int shstrndx, i;
+
+ memset(elf, 0, sizeof(*elf));
+ elf->base = elf_map_ro(fname, &elf->size, types);
+ if (!elf->base)
+ return -1;
+
+ ehdr = elf->base;
+ elf->shdrs = (const char *)elf->base + ehdr_shoff(ehdr);
+ elf->shentsize = ehdr_shentsize(ehdr);
+ first = elf_section(elf, 0);
+
+ /* A count or index too large for the header lives in section 0. */
+ elf->shnum = ehdr_shnum(ehdr);
+ if (elf->shnum == SHN_UNDEF)
+ elf->shnum = shdr_size(first);
+ shstrndx = ehdr_shstrndx(ehdr);
+ if (shstrndx == SHN_XINDEX)
+ shstrndx = shdr_link(first);
+ elf->shstrtab = (const char *)elf->base +
+ shdr_offset(elf_section(elf, shstrndx));
+
+ for (i = 0; i < elf->shnum && !elf->symtab; i++)
+ if (shdr_type(elf_section(elf, i)) == SHT_SYMTAB)
+ elf->symtab = elf_section(elf, i);
+
+ if (!elf->symtab) {
+ fprintf(stderr, "%s: no symbol table\n", fname);
+ elf_close(elf);
+ return -1;
+ }
+
+ elf->strtab = (const char *)elf->base +
+ shdr_offset(elf_section(elf, shdr_link(elf->symtab)));
+ elf->nr_syms = shdr_size(elf->symtab) / shdr_entsize(elf->symtab);
+
+ return 0;
+}
+
+void elf_close(struct elf_file *elf)
+{
+ elf_unmap(elf->base, elf->size);
+ elf->base = NULL;
+}
diff --git a/scripts/elf-parse.h b/scripts/elf-parse.h
index f4411e03069d..c5ad754da254 100644
--- a/scripts/elf-parse.h
+++ b/scripts/elf-parse.h
@@ -37,10 +37,12 @@ struct elf_funcs {
uint64_t (*shdr_offset)(Elf_Shdr *shdr);
uint64_t (*shdr_size)(Elf_Shdr *shdr);
uint64_t (*shdr_entsize)(Elf_Shdr *shdr);
+ uint64_t (*shdr_flags)(Elf_Shdr *shdr);
uint32_t (*shdr_link)(Elf_Shdr *shdr);
uint32_t (*shdr_name)(Elf_Shdr *shdr);
uint32_t (*shdr_type)(Elf_Shdr *shdr);
uint8_t (*sym_type)(Elf_Sym *sym);
+ uint8_t (*sym_bind)(Elf_Sym *sym);
uint32_t (*sym_name)(Elf_Sym *sym);
uint64_t (*sym_value)(Elf_Sym *sym);
uint16_t (*sym_shndx)(Elf_Sym *sym);
@@ -143,6 +145,7 @@ SHDR_ADDR(addr)
SHDR_ADDR(offset)
SHDR_ADDR(size)
SHDR_ADDR(entsize)
+SHDR_ADDR(flags)
SHDR_WORD(link)
SHDR_WORD(name)
@@ -211,6 +214,21 @@ static inline uint8_t sym_type(Elf_Sym *sym)
return elf_parser.sym_type(sym);
}
+static inline uint8_t sym64_bind(Elf_Sym *sym)
+{
+ return ELF64_ST_BIND(sym->e64.st_info);
+}
+
+static inline uint8_t sym32_bind(Elf_Sym *sym)
+{
+ return ELF32_ST_BIND(sym->e32.st_info);
+}
+
+static inline uint8_t sym_bind(Elf_Sym *sym)
+{
+ return elf_parser.sym_bind(sym);
+}
+
SYM_ADDR(value)
SYM_WORD(name)
SYM_HALF(shndx)
@@ -298,8 +316,44 @@ static inline void w8le(uint64_t val, uint64_t *x)
}
void *elf_map(char const *fname, size_t *size, uint32_t types);
+void *elf_map_ro(char const *fname, size_t *size, uint32_t types);
void elf_unmap(void *addr, size_t size);
int elf_map_machine(void *addr);
int elf_map_long_size(void *addr);
+/* A mapped file with its section headers, section names and symbol table. */
+struct elf_file {
+ void *base;
+ size_t size;
+ const char *shdrs;
+ unsigned int shnum, shentsize;
+ const char *shstrtab;
+ Elf_Shdr *symtab;
+ const char *strtab;
+ size_t nr_syms;
+};
+
+int elf_open_ro(char const *fname, uint32_t types, struct elf_file *elf);
+void elf_close(struct elf_file *elf);
+
+static inline Elf_Shdr *elf_section(const struct elf_file *elf,
+ unsigned int index)
+{
+ return (Elf_Shdr *)(elf->shdrs + (size_t)index * elf->shentsize);
+}
+
+static inline const char *elf_section_name(const struct elf_file *elf,
+ Elf_Shdr *shdr)
+{
+ return elf->shstrtab + shdr_name(shdr);
+}
+
+static inline Elf_Sym *elf_symbol(const struct elf_file *elf, size_t index)
+{
+ const char *base = elf->base;
+
+ return (Elf_Sym *)(base + shdr_offset(elf->symtab) +
+ index * shdr_entsize(elf->symtab));
+}
+
#endif /* _SCRIPTS_ELF_PARSE_H */
diff --git a/scripts/jobserver-exec b/scripts/jobserver-exec
index 21b319e6c9a5..89119acb1b9e 100755
--- a/scripts/jobserver-exec
+++ b/scripts/jobserver-exec
@@ -4,7 +4,8 @@
"""
Determines how many parallel tasks "make" is expecting, as it is
not exposed via any special variables, reserves them all, runs a subprocess
-with PARALLELISM environment variable set, and releases the jobs back again.
+with PARALLELISM environment variable set and any %PARALLELISM% in its
+arguments replaced by the count, and releases the jobs back again.
See:
https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html#POSIX-Jobserver
diff --git a/scripts/kallsyms-sysmap.c b/scripts/kallsyms-sysmap.c
new file mode 100644
index 000000000000..a482968eba51
--- /dev/null
+++ b/scripts/kallsyms-sysmap.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Obtain symbols from vmlinux for usage by kallsyms. Replaces mksysmap.
+ *
+ * To retain compatibility, it provides the same output as nm, only faster.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xalloc.h>
+
+#include "elf-parse.h"
+#include "kallsyms.h"
+
+/*
+ * What mksysmap dropped from System.map, by name: symbols that are not needed
+ * there, or not suitable for kallsyms.
+ */
+static const char *const sysmap_omit_prefixes[] = {
+ /* local symbols for ARM, MIPS, etc. */
+ "$",
+ /* local labels, .LBB, .Ltmpxxx, .L__unnamed_xx, .LASANPC, etc. */
+ ".L",
+ /* arm64 EFI stub namespace */
+ "__efistub_",
+ /* arm64 local symbols in PIE namespace */
+ "__pi_$",
+ "__pi_.L",
+ /* arm64 local symbols in non-VHE KVM namespace */
+ "__kvm_nvhe_$",
+ "__kvm_nvhe_.L",
+ /* CFI type identifiers */
+ "__kcfi_typeid_",
+ "__kvm_nvhe___kcfi_typeid_",
+ "__pi___kcfi_typeid_",
+ /* CRC from modversions */
+ "__crc_",
+ /* EXPORT_SYMBOL (symbol name) */
+ "__kstrtab_",
+ /* EXPORT_SYMBOL (namespace) */
+ "__kstrtabns_",
+ /* MODULE_DEVICE_TABLE (symbol name) */
+ "__mod_device_table__",
+};
+
+static const char *const sysmap_omit_suffixes[] = {
+ /* arm */
+ "_from_arm",
+ "_from_thumb",
+ "_veneer",
+};
+
+static const char *const sysmap_omit_names[] = {
+ /* for LoongArch? */
+ "L0",
+ /* ppc */
+ "_SDA_BASE_",
+ "_SDA2_BASE_",
+};
+
+/* Symbols that contain the pattern anywhere are dropped. */
+static const char *const sysmap_omit_patterns[] = {
+ /* ppc stub */
+ ".long_branch.",
+ ".plt_branch.",
+};
+
+/* __<alnum>*Thunk_: the linker's range extension thunks on arm. */
+static bool is_range_thunk(const char *name)
+{
+ const char *p;
+
+ if (!string_starts_with(name, "__"))
+ return false;
+ for (p = name + 2; isalnum((unsigned char)*p); p++)
+ ;
+ return p - name >= 7 && *p == '_' && strncmp(p - 5, "Thunk", 5) == 0;
+}
+
+/* __UNIQUE_ID_modinfo_<n>: the MODULE_INFO() strings of built-in code. */
+static bool is_modinfo_id(const char *name)
+{
+ static const char prefix[] = "__UNIQUE_ID_modinfo_";
+ const char *p;
+
+ if (!string_starts_with(name, prefix))
+ return false;
+ for (p = name + strlen(prefix); isdigit((unsigned char)*p); p++)
+ ;
+ return !*p;
+}
+
+static bool sysmap_omits(const char *name, char type)
+{
+ size_t i;
+
+ /* Absolute, undefined and debugging symbols. */
+ if (type == 'a' || type == 'N' || type == 'U' || type == 'w')
+ return true;
+
+ for (i = 0; i < ARRAY_SIZE(sysmap_omit_prefixes); i++)
+ if (string_starts_with(name, sysmap_omit_prefixes[i]))
+ return true;
+ for (i = 0; i < ARRAY_SIZE(sysmap_omit_suffixes); i++)
+ if (string_ends_with(name, sysmap_omit_suffixes[i]))
+ return true;
+ for (i = 0; i < ARRAY_SIZE(sysmap_omit_names); i++)
+ if (strcmp(name, sysmap_omit_names[i]) == 0)
+ return true;
+ for (i = 0; i < ARRAY_SIZE(sysmap_omit_patterns); i++)
+ if (strstr(name, sysmap_omit_patterns[i]))
+ return true;
+
+ return is_range_thunk(name) || is_modinfo_id(name);
+}
+
+/* nm's letter for a symbol defined in a section, as BFD classifies it. */
+static char section_symbol_type(Elf_Shdr *shdr, const char *secname)
+{
+ static const char *const debug_prefixes[] = {
+ ".debug", ".zdebug", ".gnu.debuglto_.debug_",
+ ".gnu.linkonce.wi.", ".line", ".stab",
+ };
+ const uint64_t flags = shdr_flags(shdr);
+ size_t i;
+
+ if (flags & SHF_EXECINSTR)
+ return 't';
+ if (flags & SHF_ALLOC) {
+ if (shdr_type(shdr) == SHT_NOBITS)
+ return 'b';
+ return flags & SHF_WRITE ? 'd' : 'r';
+ }
+ for (i = 0; i < ARRAY_SIZE(debug_prefixes); i++)
+ if (string_starts_with(secname, debug_prefixes[i]))
+ return 'N';
+ if (shdr_type(shdr) != SHT_NOBITS && !(flags & SHF_WRITE))
+ return 'n';
+ return '?';
+}
+
+/* The letter nm prints for a symbol, or 0 for one it leaves out. */
+static char elf_symbol_type(const struct elf_file *elf, Elf_Sym *sym)
+{
+ unsigned int bind = sym_bind(sym), type = sym_type(sym);
+ unsigned int shndx = sym_shndx(sym);
+ Elf_Shdr *shdr;
+ char c;
+
+ if (type == STT_SECTION || type == STT_FILE)
+ return 0;
+ if (shndx == SHN_COMMON)
+ return 'C';
+ if (shndx == SHN_UNDEF) {
+ if (bind == STB_WEAK)
+ return type == STT_OBJECT ? 'v' : 'w';
+ return 'U';
+ }
+ if (type == STT_GNU_IFUNC)
+ return 'i';
+ if (bind == STB_WEAK)
+ return type == STT_OBJECT ? 'V' : 'W';
+ if (bind == STB_GNU_UNIQUE)
+ return 'u';
+ if (bind != STB_GLOBAL && bind != STB_LOCAL)
+ return '?';
+
+ if (shndx == SHN_ABS) {
+ c = 'a';
+ } else if (shndx < elf->shnum) {
+ shdr = elf_section(elf, shndx);
+ c = section_symbol_type(shdr, elf_section_name(elf, shdr));
+ } else {
+ return '?';
+ }
+
+ return bind == STB_GLOBAL ? toupper(c) : c;
+}
+
+/* nm -n order: by address, then by name. */
+static int compare_symbols(const void *a, const void *b)
+{
+ const struct sysmap_symbol *sa = a, *sb = b;
+
+ if (sa->addr != sb->addr)
+ return sa->addr < sb->addr ? -1 : 1;
+ return strcmp(sa->name, sb->name);
+}
+
+/* The symbols "nm -n | mksysmap" would list, in that order. */
+static struct sysmap_symbol *elf_read_symbols(const struct elf_file *elf,
+ size_t *nr_kept)
+{
+ struct sysmap_symbol *syms = xmalloc(elf->nr_syms * sizeof(*syms));
+ size_t i, n = 0;
+
+ for (i = 1; i < elf->nr_syms; i++) {
+ Elf_Sym *sym = elf_symbol(elf, i);
+ const char *name = elf->strtab + sym_name(sym);
+ char type = elf_symbol_type(elf, sym);
+
+ if (!type || sysmap_omits(name, type))
+ continue;
+
+ syms[n].addr = sym_value(sym);
+ syms[n].name = name;
+ syms[n].type = type;
+ n++;
+ }
+
+ qsort(syms, n, sizeof(*syms), compare_symbols);
+ *nr_kept = n;
+ return syms;
+}
+
+struct sysmap *sysmap_read(const char *path)
+{
+ struct sysmap *map = xcalloc(1, sizeof(*map));
+
+ /* The names point into the mapping; keep it until the map is freed. */
+ if (elf_open_ro(path, (1 << ET_EXEC) | (1 << ET_DYN), &map->elf))
+ exit(EXIT_FAILURE);
+ map->syms = elf_read_symbols(&map->elf, &map->nr_syms);
+ map->addr_width = elf_map_long_size(map->elf.base) * 2;
+
+ return map;
+}
+
+void sysmap_write(const struct sysmap *map, FILE *out)
+{
+ size_t i;
+
+ for (i = 0; i < map->nr_syms; i++) {
+ const struct sysmap_symbol *s = &map->syms[i];
+
+ fprintf(out, "%0*llx %c %s\n", map->addr_width, s->addr, s->type,
+ s->name);
+ }
+}
+
+void sysmap_free(struct sysmap *map)
+{
+ free(map->syms);
+ elf_close(&map->elf);
+ free(map);
+}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 494852ade6d8..ecb444078c1c 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -5,7 +5,15 @@
* 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] [--sysmap=out.map] in out.bin > out.S
+ * kallsyms --sysmap=out.map in
+ *
+ * in is vmlinux; an empty file stands for the first link, which has no
+ * symbols yet, and gives an empty table. --sysmap also writes the symbols
+ * in System.map format.
+ *
+ * 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
@@ -18,7 +26,6 @@
*
*/
-#include <errno.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
@@ -26,10 +33,10 @@
#include <string.h>
#include <ctype.h>
#include <limits.h>
-
+#include <sys/stat.h>
#include <xalloc.h>
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+#include "kallsyms.h"
#define KSYM_NAME_LEN 512
@@ -58,20 +65,60 @@ static unsigned int table_size, table_cnt;
static int all_symbols;
static int pc_relative;
-static int token_profit[0x10000];
+/* A dynamic array of symbols, encoded by symbol index. */
+struct sym_arr {
+ unsigned int *sym_indexes;
+ unsigned int cnt, cap;
+};
+
+/* Every pair of bytes is a token. */
+#define NR_TOKENS 0x10000
+
+static int token_profit[NR_TOKENS];
+static struct sym_arr token_syms[NR_TOKENS];
/* the table that holds the result of the compression */
static unsigned char best_table[256][2];
static unsigned char best_table_len[256];
+static unsigned int sym_arr_last(const struct sym_arr *arr)
+{
+ return arr->cnt ? arr->sym_indexes[arr->cnt - 1] : UINT_MAX;
+}
+
+static void sym_arr_maybe_expand(struct sym_arr *arr)
+{
+ if (arr->cap > arr->cnt)
+ return;
+
+ arr->cap = arr->cap ? arr->cap * 2 : 16;
+ arr->sym_indexes = xrealloc(arr->sym_indexes,
+ arr->cap * sizeof(*arr->sym_indexes));
+}
+
+static void sym_arr_add(struct sym_arr *arr, unsigned int sym_idx)
+{
+ sym_arr_maybe_expand(arr);
+ arr->sym_indexes[arr->cnt++] = sym_idx;
+}
+
+static void sym_arr_free(struct sym_arr *arr)
+{
+ free(arr->sym_indexes);
+ arr->sym_indexes = NULL;
+ arr->cnt = 0;
+ arr->cap = 0;
+}
static void usage(void)
{
- fprintf(stderr, "Usage: kallsyms [--all-symbols] in.map > out.S\n");
+ fprintf(stderr, "Usage: kallsyms [--all-symbols] [--pc-relative] [--sysmap=out.map]\n"
+ " in out.bin > out.S\n"
+ " kallsyms --sysmap=out.map vmlinux\n");
exit(1);
}
-static char *sym_name(const struct sym_entry *s)
+static char *sym_entry_name(const struct sym_entry *s)
{
return (char *)s->sym + 1;
}
@@ -112,37 +159,12 @@ static void check_symbol_range(const char *sym, unsigned long long addr,
}
}
-static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
+static struct sym_entry *add_symbol(unsigned long long addr, char type,
+ const char *name)
{
- char *name, type, *p;
- unsigned long long addr;
- size_t len;
- ssize_t readlen;
+ size_t len = strlen(name);
struct sym_entry *sym;
- errno = 0;
- readlen = getline(buf, buf_len, in);
- if (readlen < 0) {
- if (errno) {
- perror("read_symbol");
- exit(EXIT_FAILURE);
- }
- return NULL;
- }
-
- if ((*buf)[readlen - 1] == '\n')
- (*buf)[readlen - 1] = 0;
-
- addr = strtoull(*buf, &p, 16);
-
- if (*buf == p || *p++ != ' ' || !isascii((type = *p++)) || *p++ != ' ') {
- fprintf(stderr, "line format error\n");
- exit(EXIT_FAILURE);
- }
-
- name = p;
- len = strlen(name);
-
if (len >= KSYM_NAME_LEN) {
fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n"
"Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n",
@@ -167,7 +189,7 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
sym->addr = addr;
sym->len = len;
sym->sym[0] = type;
- strcpy(sym_name(sym), name);
+ strcpy(sym_entry_name(sym), name);
return sym;
}
@@ -188,14 +210,9 @@ static int symbol_in_range(const struct sym_entry *s,
return 0;
}
-static bool string_starts_with(const char *s, const char *prefix)
-{
- return strncmp(s, prefix, strlen(prefix)) == 0;
-}
-
static int symbol_valid(const struct sym_entry *s)
{
- const char *name = sym_name(s);
+ const char *name = sym_entry_name(s);
/* if --all-symbols is not specified, then symbols outside the text
* and inittext sections are discarded */
@@ -245,36 +262,55 @@ static void shrink_table(void)
table_cnt = pos;
}
-static void read_map(const char *in)
+static void add_table_entry(struct sym_entry *sym)
{
- FILE *fp;
- struct sym_entry *sym;
- char *buf = NULL;
- size_t buflen = 0;
+ sym->seq = table_cnt;
- fp = fopen(in, "r");
- if (!fp) {
- perror(in);
- exit(1);
+ if (table_cnt >= table_size) {
+ table_size = table_size ? table_size * 2 : 10000;
+ table = xrealloc(table, sizeof(*table) * table_size);
}
- while (!feof(fp)) {
- sym = read_symbol(fp, &buf, &buflen);
- if (!sym)
- continue;
+ table[table_cnt++] = sym;
+}
- sym->seq = table_cnt;
+static bool file_is_empty(const char *path)
+{
+ struct stat st;
- if (table_cnt >= table_size) {
- table_size += 10000;
- table = xrealloc(table, sizeof(*table) * table_size);
- }
+ if (stat(path, &st)) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+
+ return st.st_size == 0;
+}
- table[table_cnt++] = sym;
+/*
+ * Read the symbols from vmlinux, writing System.map if asked to. The first
+ * link has no symbols yet: an empty file gives an empty table.
+ */
+static void read_elf(const char *path, FILE *sysmap_out)
+{
+ struct sysmap *map;
+ size_t i;
+
+ if (file_is_empty(path))
+ return;
+
+ map = sysmap_read(path);
+ if (sysmap_out)
+ sysmap_write(map, sysmap_out);
+
+ for (i = 0; i < map->nr_syms; i++) {
+ const struct sysmap_symbol *s = &map->syms[i];
+ struct sym_entry *sym = add_symbol(s->addr, s->type, s->name);
+
+ if (sym)
+ add_table_entry(sym);
}
- free(buf);
- fclose(fp);
+ sysmap_free(map);
}
static void output_label(const char *label)
@@ -284,6 +320,26 @@ static void output_label(const char *label)
printf("%s:\n", label);
}
+static long bin_pos(FILE *file)
+{
+ const long pos = ftell(file);
+
+ if (pos < 0) {
+ perror("kallsyms: ftell");
+ exit(EXIT_FAILURE);
+ }
+
+ return pos;
+}
+
+static void write_incbin(const char *filename, long start, long end)
+{
+ if (start >= end)
+ return;
+
+ printf("\t.incbin \"%s\", %ld, %ld\n", filename, start, end - start);
+}
+
/* uncompress a compressed symbol. When this function is called, the best table
* might still be compressed itself, so the function needs to be recursive */
static int expand_symbol(const unsigned char *data, int len, char *result)
@@ -317,7 +373,7 @@ static int compare_names(const void *a, const void *b)
const struct sym_entry *sa = *(const struct sym_entry **)a;
const struct sym_entry *sb = *(const struct sym_entry **)b;
- ret = strcmp(sym_name(sa), sym_name(sb));
+ ret = strcmp(sym_entry_name(sa), sym_entry_name(sb));
if (!ret) {
if (sa->addr > sb->addr)
return 1;
@@ -336,11 +392,12 @@ static void sort_symbols_by_name(void)
qsort(table, table_cnt, sizeof(table[0]), compare_names);
}
-static void write_src(void)
+static void write_src(FILE *out_bin_file, const char *out_bin_name)
{
- unsigned int i, k, off;
+ unsigned int i, off;
unsigned int best_idx[256];
unsigned int *markers, markers_cnt;
+ long bin_start;
char buf[KSYM_NAME_LEN];
printf("\t.section .rodata, \"a\"\n");
@@ -355,6 +412,7 @@ static void write_src(void)
markers = xmalloc(sizeof(*markers) * markers_cnt);
output_label("kallsyms_names");
+ bin_start = bin_pos(out_bin_file);
off = 0;
for (i = 0; i < table_cnt; i++) {
if ((i & 0xFF) == 0)
@@ -378,26 +436,24 @@ static void write_src(void)
/* Encode length with ULEB128. */
if (table[i]->len <= 0x7F) {
/* Most symbols use a single byte for the length. */
- printf("\t.byte 0x%02x", table[i]->len);
+ fputc(table[i]->len, out_bin_file);
off += table[i]->len + 1;
} else {
/* "Big" symbols use two bytes. */
- printf("\t.byte 0x%02x, 0x%02x",
- (table[i]->len & 0x7F) | 0x80,
- (table[i]->len >> 7) & 0x7F);
+ fputc((table[i]->len & 0x7F) | 0x80, out_bin_file);
+ fputc((table[i]->len >> 7) & 0x7F, out_bin_file);
off += table[i]->len + 2;
}
- for (k = 0; k < table[i]->len; k++)
- printf(", 0x%02x", table[i]->sym[k]);
+ fwrite(table[i]->sym, 1, table[i]->len, out_bin_file);
/*
* Now that we wrote out the compressed symbol name, restore the
- * original name and print it in the comment.
+ * original name for the comments below.
*/
expand_symbol(table[i]->sym, table[i]->len, buf);
strcpy((char *)table[i]->sym, buf);
- printf("\t/* %s */\n", table[i]->sym);
}
+ write_incbin(out_bin_name, bin_start, bin_pos(out_bin_file));
printf(".size kallsyms_names, . - kallsyms_names\n");
printf("\n");
@@ -410,13 +466,15 @@ static void write_src(void)
free(markers);
output_label("kallsyms_token_table");
+ bin_start = bin_pos(out_bin_file);
off = 0;
for (i = 0; i < 256; i++) {
best_idx[i] = off;
expand_symbol(best_table[i], best_table_len[i], buf);
- printf("\t.asciz\t\"%s\"\n", buf);
+ fwrite(buf, 1, strlen(buf) + 1, out_bin_file);
off += strlen(buf) + 1;
}
+ write_incbin(out_bin_name, bin_start, bin_pos(out_bin_file));
printf(".size kallsyms_token_table, . - kallsyms_token_table\n");
printf("\n");
@@ -449,15 +507,25 @@ static void write_src(void)
sort_symbols_by_name();
output_label("kallsyms_seqs_of_names");
- for (i = 0; i < table_cnt; i++)
- printf("\t.byte 0x%02x, 0x%02x, 0x%02x\t/* %s */\n",
- (unsigned char)(table[i]->seq >> 16),
- (unsigned char)(table[i]->seq >> 8),
- (unsigned char)(table[i]->seq >> 0),
- table[i]->sym);
+ bin_start = bin_pos(out_bin_file);
+ for (i = 0; i < table_cnt; i++) {
+ fputc(table[i]->seq >> 16, out_bin_file);
+ fputc(table[i]->seq >> 8, out_bin_file);
+ fputc(table[i]->seq >> 0, out_bin_file);
+ }
+ write_incbin(out_bin_name, bin_start, bin_pos(out_bin_file));
printf("\n");
}
+static unsigned int token_index(unsigned char first, unsigned char second)
+{
+ return first + (second << 8);
+}
+
+static unsigned int sym_token_index(const unsigned char *symbol, int first_idx)
+{
+ return token_index(symbol[first_idx], symbol[first_idx + 1]);
+}
/* table lookup compression functions */
@@ -467,7 +535,7 @@ static void learn_symbol(const unsigned char *symbol, int len)
int i;
for (i = 0; i < len - 1; i++)
- token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
+ token_profit[sym_token_index(symbol, i)]++;
}
/* decrease the count for all the possible tokens in a symbol */
@@ -476,16 +544,76 @@ static void forget_symbol(const unsigned char *symbol, int len)
int i;
for (i = 0; i < len - 1; i++)
- token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
+ token_profit[sym_token_index(symbol, i)]--;
+}
+
+static void token_add_symbol(unsigned int token_idx, unsigned int sym_idx)
+{
+ struct sym_arr *arr = &token_syms[token_idx];
+
+ /* Symbol indexes kept in sorted order, check for duplicate. */
+ if (sym_arr_last(arr) == sym_idx)
+ return;
+
+ sym_arr_add(arr, sym_idx);
+}
+
+static void symbol_index_all_tokens(const unsigned char *symbol, int len,
+ unsigned int sym_idx)
+{
+ int i;
+
+ for (i = 0; i < len - 1; i++) {
+ const unsigned int token_idx = sym_token_index(symbol, i);
+
+ token_add_symbol(token_idx, sym_idx);
+ }
+}
+
+/*
+ * The symbol just got compressed. The only parts of the symbol that changed
+ * meaningfully are those containing the newly assigned compressed char, so
+ * index those.
+ */
+static void symbol_index_new_tokens(const unsigned char *symbol, int len,
+ unsigned int sym_idx, int compressed_chr)
+{
+ int i;
+
+ for (i = 0; i < len - 1; i++) {
+ const unsigned int token_idx = sym_token_index(symbol, i);
+
+ if (symbol[i] == compressed_chr ||
+ symbol[i + 1] == compressed_chr)
+ token_add_symbol(token_idx, sym_idx);
+ }
}
-/* do the initial token count */
static void build_initial_token_table(void)
{
unsigned int i;
for (i = 0; i < table_cnt; i++)
learn_symbol(table[i]->sym, table[i]->len);
+
+ /*
+ * The initial occurrence counts tell us exactly how much memory should
+ * be reserved for each token's symbol array.
+ */
+ for (i = 0; i < ARRAY_SIZE(token_syms); i++) {
+ const int nr_syms = token_profit[i];
+
+ if (!nr_syms)
+ continue;
+
+ token_syms[i].cap = nr_syms;
+ token_syms[i].sym_indexes =
+ xmalloc(nr_syms * sizeof(unsigned int));
+ }
+
+ /* For every symbol, index every token -> symbol it is present in. */
+ for (i = 0; i < table_cnt; i++)
+ symbol_index_all_tokens(table[i]->sym, table[i]->len, i);
}
static unsigned char *find_token(unsigned char *str, int len,
@@ -502,27 +630,31 @@ static unsigned char *find_token(unsigned char *str, int len,
/* replace a given token in all the valid symbols. Use the sampled symbols
* to update the counts */
-static void compress_symbols(const unsigned char *str, int idx)
+static void compress_symbols(const unsigned char *str, int compressed_chr)
{
- unsigned int i, len, size;
+ const unsigned int token_idx = sym_token_index(str, 0);
+ struct sym_arr *arr = &token_syms[token_idx];
+ unsigned int sym_idx, j, len, size;
unsigned char *p1, *p2;
- for (i = 0; i < table_cnt; i++) {
+ /* Iterate through all symbols this token is found in and compress. */
+ for (j = 0; j < arr->cnt; j++) {
+ sym_idx = arr->sym_indexes[j];
- len = table[i]->len;
- p1 = table[i]->sym;
+ len = table[sym_idx]->len;
+ p1 = table[sym_idx]->sym;
/* find the token on the symbol */
p2 = find_token(p1, len, str);
if (!p2) continue;
/* decrease the counts for this symbol's tokens */
- forget_symbol(table[i]->sym, len);
+ forget_symbol(table[sym_idx]->sym, len);
size = len;
do {
- *p2 = idx;
+ *p2 = compressed_chr;
p2++;
size -= (p2 - p1);
memmove(p2, p2 + 1, size);
@@ -536,11 +668,15 @@ static void compress_symbols(const unsigned char *str, int idx)
} while (p2);
- table[i]->len = len;
+ table[sym_idx]->len = len;
/* increase the counts for this symbol's new tokens */
- learn_symbol(table[i]->sym, len);
+ learn_symbol(table[sym_idx]->sym, len);
+ symbol_index_new_tokens(table[sym_idx]->sym, len, sym_idx,
+ compressed_chr);
}
+
+ sym_arr_free(arr); /* No symbol contains this token any more. */
}
/* search the token with the maximum profit */
@@ -551,7 +687,7 @@ static int find_best_token(void)
bestprofit=-10000;
best = 0;
- for (i = 0; i < 0x10000; i++) {
+ for (i = 0; i < ARRAY_SIZE(token_profit); i++) {
if (token_profit[i] > bestprofit) {
best = i;
bestprofit = token_profit[i];
@@ -615,7 +751,7 @@ static void optimize_token_table(void)
/* guess for "linker script provide" symbol */
static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
{
- const char *symbol = sym_name(se);
+ const char *symbol = sym_entry_name(se);
int len = se->len - 1;
if (len < 8)
@@ -672,8 +808,8 @@ static int compare_symbols(const void *a, const void *b)
return wa - wb;
/* sort by the number of prefix underscores */
- wa = strspn(sym_name(sa), "_");
- wb = strspn(sym_name(sb), "_");
+ wa = strspn(sym_entry_name(sa), "_");
+ wb = strspn(sym_entry_name(sb), "_");
if (wa != wb)
return wa - wb;
@@ -688,10 +824,14 @@ static void sort_symbols(void)
int main(int argc, char **argv)
{
+ const char *in, *sysmap = NULL, *out_bin_name;
+ FILE *sysmap_out = NULL, *out_bin_file;
+
while (1) {
static const struct option long_options[] = {
{"all-symbols", no_argument, &all_symbols, 1},
{"pc-relative", no_argument, &pc_relative, 1},
+ {"sysmap", required_argument, NULL, 's'},
{},
};
@@ -699,18 +839,55 @@ int main(int argc, char **argv)
if (c == -1)
break;
- if (c != 0)
+ if (c == 's')
+ sysmap = optarg;
+ else if (c != 0)
usage();
}
- if (optind >= argc)
+ if (optind + 2 != argc && !(sysmap && optind + 1 == argc))
usage();
- read_map(argv[optind]);
+ in = argv[optind];
+ if (sysmap) {
+ sysmap_out = fopen(sysmap, "w");
+ if (!sysmap_out) {
+ perror(sysmap);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (optind + 1 == argc) {
+ read_elf(in, sysmap_out);
+ if (ferror(sysmap_out) || fclose(sysmap_out)) {
+ perror(sysmap);
+ exit(EXIT_FAILURE);
+ }
+ return 0;
+ }
+
+ out_bin_name = argv[optind + 1];
+ out_bin_file = fopen(out_bin_name, "w");
+ if (!out_bin_file) {
+ perror(out_bin_name);
+ exit(EXIT_FAILURE);
+ }
+
+ read_elf(in, sysmap_out);
+ if (sysmap_out && (ferror(sysmap_out) || fclose(sysmap_out))) {
+ perror(sysmap);
+ exit(EXIT_FAILURE);
+ }
shrink_table();
sort_symbols();
optimize_token_table();
- write_src();
+ write_src(out_bin_file, out_bin_name);
+
+ /* Write errors are latched in the stream, so one check at the end covers them all. */
+ if (ferror(out_bin_file) || fclose(out_bin_file)) {
+ perror(out_bin_name);
+ exit(EXIT_FAILURE);
+ }
return 0;
}
diff --git a/scripts/kallsyms.h b/scripts/kallsyms.h
new file mode 100644
index 000000000000..4b2801ba6285
--- /dev/null
+++ b/scripts/kallsyms.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef KALLSYMS_H
+#define KALLSYMS_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <array_size.h>
+#include "elf-parse.h"
+
+static inline bool string_starts_with(const char *s, const char *prefix)
+{
+ return strncmp(s, prefix, strlen(prefix)) == 0;
+}
+
+static inline bool string_ends_with(const char *s, const char *suffix)
+{
+ size_t len = strlen(s), suffix_len = strlen(suffix);
+
+ return len >= suffix_len && strcmp(s + len - suffix_len, suffix) == 0;
+}
+
+/* A symbol as nm lists it. */
+struct sysmap_symbol {
+ unsigned long long addr;
+ const char *name;
+ char type;
+};
+
+/* The symbols of an ELF file that System.map lists, in its order. */
+struct sysmap {
+ struct sysmap_symbol *syms;
+ size_t nr_syms;
+ int addr_width; /* hex digits of an address */
+ struct elf_file elf; /* the mapping the names point into */
+};
+
+struct sysmap *sysmap_read(const char *path);
+void sysmap_write(const struct sysmap *map, FILE *out);
+void sysmap_free(struct sysmap *map);
+
+#endif /* KALLSYMS_H */
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index ab0b8125c8cb..c520741f85c2 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -96,6 +96,11 @@ vmlinux_link()
ldflags="${ldflags} ${wl}--strip-debug"
fi
+ # Only the final link actually requires the relocations.
+ if [ "${output}" = "${VMLINUX}" ] && is_enabled CONFIG_ARCH_VMLINUX_NEEDS_RELOCS; then
+ ldflags="${ldflags} ${wl}--emit-relocs"
+ fi
+
if [ -n "${generate_map}" ]; then
ldflags="${ldflags} ${wl}-Map=vmlinux.map"
fi
@@ -118,11 +123,15 @@ kallsymso_changed()
! cmp -s "${kallsymso_prev}.sym" "${kallsymso}.sym"
}
-# Create ${2}.o file with all symbols from the ${1} object file
+# Create ${2}.o with the kallsyms tables for ${1} (the vmlinux, or an empty
+# listing for the first pass); list the symbols used in ${3} if given.
kallsyms()
{
local kallsymopt;
+ if [ -n "${3:-}" ]; then
+ kallsymopt="--sysmap=${3}"
+ fi
if is_enabled CONFIG_KALLSYMS_ALL; then
kallsymopt="${kallsymopt} --all-symbols"
fi
@@ -132,7 +141,7 @@ kallsyms()
fi
info KSYMS "${2}.S"
- scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S"
+ scripts/kallsyms ${kallsymopt} "${1}" "${2}.bin" > "${2}.S"
info AS "${2}.o"
${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \
@@ -145,23 +154,20 @@ kallsyms()
# Perform kallsyms for the given temporary vmlinux.
sysmap_and_kallsyms()
{
- mksysmap "${1}" "${1}.syms"
- kallsyms "${1}.syms" "${1}.kallsyms"
-
+ kallsyms "${1}" "${1}.kallsyms" "${1}.syms"
kallsyms_sysmap=${1}.syms
}
# Create map file with all symbols from ${1}
-# See mksymap for additional details
mksysmap()
{
- info NM ${2}
- ${NM} -n "${1}" | sed -f "${srctree}/scripts/mksysmap" > "${2}"
+ info SYSMAP ${2}
+ scripts/kallsyms --sysmap="${2}" "${1}"
}
sorttable()
{
- ${NM} -S ${1} > .tmp_vmlinux.nm-sort
+ ${NM} -p -S ${1} > .tmp_vmlinux.nm-sort
${objtree}/scripts/sorttable -s .tmp_vmlinux.nm-sort ${1}
}
diff --git a/scripts/mksysmap b/scripts/mksysmap
deleted file mode 100755
index 856b26ba2ac0..000000000000
--- a/scripts/mksysmap
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/bin/sed -f
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# sed script to filter out symbols that are not needed for System.map,
-# or not suitable for kallsyms. The input should be 'nm -n <file>'.
-#
-# System.map is used by module-init tools and some debugging
-# tools to retrieve the actual addresses of symbols in the kernel.
-#
-# readprofile starts reading symbols when _stext is found, and
-# continue until it finds a symbol which is not either of 'T', 't',
-# 'W' or 'w'.
-#
-# ---------------------------------------------------------------------------
-# Ignored symbol types
-#
-
-# a: local absolute symbols
-# N: debugging symbols
-# U: undefined global symbols
-# w: local weak symbols
-/ [aNUw] /d
-
-# ---------------------------------------------------------------------------
-# Ignored prefixes
-# (do not forget a space before each pattern)
-
-# local symbols for ARM, MIPS, etc.
-/ \$/d
-
-# local labels, .LBB, .Ltmpxxx, .L__unnamed_xx, .LASANPC, etc.
-/ \.L/d
-
-# arm64 EFI stub namespace
-/ __efistub_/d
-
-# arm64 local symbols in PIE namespace
-/ __pi_\$/d
-/ __pi_\.L/d
-
-# arm64 local symbols in non-VHE KVM namespace
-/ __kvm_nvhe_\$/d
-/ __kvm_nvhe_\.L/d
-
-# lld arm/aarch64/mips thunks
-/ __[[:alnum:]]*Thunk_/d
-
-# CFI type identifiers
-/ __kcfi_typeid_/d
-/ __kvm_nvhe___kcfi_typeid_/d
-/ __pi___kcfi_typeid_/d
-
-# CRC from modversions
-/ __crc_/d
-
-# EXPORT_SYMBOL (symbol name)
-/ __kstrtab_/d
-
-# EXPORT_SYMBOL (namespace)
-/ __kstrtabns_/d
-
-# MODULE_DEVICE_TABLE (symbol name)
-/ __mod_device_table__/d
-
-# ---------------------------------------------------------------------------
-# Ignored suffixes
-# (do not forget '$' after each pattern)
-
-# arm
-/_from_arm$/d
-/_from_thumb$/d
-/_veneer$/d
-
-# ---------------------------------------------------------------------------
-# Ignored symbols (exact match)
-# (do not forget a space before and '$' after each pattern)
-
-# for LoongArch?
-/ L0$/d
-
-# ppc
-/ _SDA_BASE_$/d
-/ _SDA2_BASE_$/d
-
-# MODULE_INFO()
-/ __UNIQUE_ID_modinfo_[0-9]*$/d
-
-# ---------------------------------------------------------------------------
-# Ignored patterns
-# (symbols that contain the pattern are ignored)
-
-# ppc stub
-/\.long_branch\./d
-/\.plt_branch\./d
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index d7b50581c732..88e49a5c4251 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -322,10 +322,23 @@ static int parse_symbols(const char *fname)
return -1;
}
- while (fscanf(fp, "%16s %16s %c %*s\n", addr_str, size_str, &type) == 3) {
+ while (fscanf(fp, "%16s %16s %c%*[^\n]", addr_str, size_str, &type) == 3) {
uint64_t addr;
uint64_t size;
+ /*
+ * nm outputs size-less entries with a missing 2nd value, which
+ * means fscanf() just misread its fields.
+ *
+ * These don't matter as a call site cannot be in an empty
+ * function, so just skip them.
+ *
+ * nm pads address and size to the same width, so if their
+ * widths differ, this is a misread.
+ */
+ if (strlen(size_str) != strlen(addr_str))
+ continue;
+
/* Only care about functions */
if (type != 't' && type != 'T' && type != 'W')
continue;
diff --git a/scripts/ver_linux b/scripts/ver_linux
index 00bdaf30d590..e06d7c650710 100755
--- a/scripts/ver_linux
+++ b/scripts/ver_linux
@@ -57,6 +57,7 @@ BEGIN {
printversion("pahole", version("pahole --version"))
printversion("Pcmcia-cs", version("cardmgr -V"))
printversion("pcmciautils", version("pccardctl -V"))
+ printversion("pigz", version("pigz --version"))
printversion("PPP", version("pppd --version"))
printversion("procps", version("ps --version"))
printversion("Python", version("python3 -V"))
diff --git a/tools/lib/python/jobserver.py b/tools/lib/python/jobserver.py
index 0b1ffdf9f7a3..7e94635bf7d9 100755
--- a/tools/lib/python/jobserver.py
+++ b/tools/lib/python/jobserver.py
@@ -29,6 +29,10 @@ $claim child to do the actual work.
The end goal here is to keep the total number of build tasks under the
limit established by the initial ``make -j$n_proc`` call.
+A command that takes its thread count on the command line rather than from
+the environment can use the ``%PARALLELISM%`` token in its arguments, which
+is replaced by the count, or by 1 when there is no jobserver.
+
See:
https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html#POSIX-Jobserver
"""
@@ -38,6 +42,8 @@ import os
import subprocess
import sys
+PARALLELISM_TOKEN = "%PARALLELISM%"
+
def warn(text, *args):
print(f'WARNING: {text}', *args, file = sys.stderr)
@@ -182,6 +188,9 @@ class JobserverExec:
Run a command setting PARALLELISM env variable to the number of
available job slots (claim) + 1, e.g. it will reserve claim slots
to do the actual build work, plus one to monitor its children.
+
+ Any %PARALLELISM% in the command's arguments is replaced by the same
+ number, or by 1 when there is no jobserver.
"""
self.open() # Ensure that self.claim is set
@@ -192,4 +201,8 @@ class JobserverExec:
if self.claim:
os.environ["PARALLELISM"] = str(self.claim)
+ if not isinstance(cmd, str):
+ parallelism = str(self.claim or 1)
+ cmd = [arg.replace(PARALLELISM_TOKEN, parallelism) for arg in cmd]
+
return subprocess.call(cmd, *args, **pwargs)
diff --git a/usr/Makefile b/usr/Makefile
index 5b97ee66c00a..975c68e5b6b6 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -76,7 +76,7 @@ $(obj)/initramfs_data.cpio: $(srctree)/scripts/gen_initramfs.sh scripts/gen_init
endif
$(obj)/initramfs_inc_data: $(cpio-data) FORCE
- $(call if_changed,$(compress-y))
+ +$(call if_changed,$(compress-y))
targets += initramfs_data.cpio initramfs_inc_data