Merge branch 'kbuild-next-speedups' into kbuild-next

This is the first round of commits and fix-ups from Lorenzo's Kbuild
speed up series.

Signed-off-by: Nathan Chancellor <nathan@kernel.org>
This commit is contained in:
Nathan Chancellor 2026-10-17 15:20:23 -07:00
commit 997208ce9f
No known key found for this signature in database
GPG Key ID: 1D6B269171C01A96
52 changed files with 1163 additions and 493 deletions

View File

@ -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

View File

@ -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

View File

@ -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
****************

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
#

View File

@ -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) \

View File

@ -855,7 +855,7 @@
KLP_SYMID
#define MODINFO \
.modinfo : { *(.modinfo) }
.modinfo (INFO) : { KEEP(*(.modinfo)) }
#ifdef CONFIG_GENERIC_BUG
#define BUG_TABLE \

View File

@ -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

View File

@ -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 $<

View File

@ -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

272
scripts/Kconfig.toolchain Normal file
View File

@ -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)"

View File

@ -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

View File

@ -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
# ---------------------------------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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

248
scripts/kallsyms-sysmap.c Normal file
View File

@ -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);
}

View File

@ -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);
}
table[table_cnt++] = sym;
if (stat(path, &st)) {
perror(path);
exit(EXIT_FAILURE);
}
free(buf);
fclose(fp);
return st.st_size == 0;
}
/*
* 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);
}
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;
}

44
scripts/kallsyms.h Normal file
View File

@ -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 */

View File

@ -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}
}

View File

@ -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

View File

@ -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;

View File

@ -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"))

View File

@ -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)

View File

@ -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