diff options
| author | Nathan Chancellor <nathan@kernel.org> | 2026-10-11 01:22:02 +0100 |
|---|---|---|
| committer | Nathan Chancellor <nathan@kernel.org> | 2026-10-11 01:22:02 +0100 |
| commit | fd26cc1da1ec4dbe4ca19d0c94f802ff4300a788 (patch) | |
| tree | f343bf7e191d0567d77f8f352fdd53111b75e8e1 | |
| parent | 185b2c6a021ac46c62342fa814e5e2393f8396c5 (diff) | |
| parent | ae5f6044c4cdffe2b3361b15c1d6fc67b339f2a4 (diff) | |
| download | linux-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>
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 @@ -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 |
