mirror of
https://github.com/torvalds/linux.git
synced 2026-10-22 12:52:02 +02:00
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:
commit
997208ce9f
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
****************
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
31
Makefile
31
Makefile
|
|
@ -569,6 +569,9 @@ LZMA = lzma
|
|||
LZ4 = lz4
|
||||
XZ = xz
|
||||
ZSTD = zstd
|
||||
# The kernel image is compressed with pigz, on the job slots make has free,
|
||||
# if it is installed. Everything else uses KGZIP.
|
||||
KPGZIP := $(if $(shell command -v pigz 2>/dev/null),$(PYTHON3) $(abs_srctree)/scripts/jobserver-exec pigz -p %PARALLELISM%,$(KGZIP))
|
||||
TAR = tar
|
||||
|
||||
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
|
||||
|
|
@ -649,7 +652,7 @@ export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN LLVM_
|
|||
export HOSTRUSTC KBUILD_HOSTRUSTFLAGS
|
||||
export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
|
||||
export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
|
||||
export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD TAR
|
||||
export KGZIP KPGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD TAR
|
||||
export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS KBUILD_PROCMACROLDFLAGS LDFLAGS_MODULE
|
||||
export KBUILD_USERCFLAGS KBUILD_USERLDFLAGS
|
||||
|
||||
|
|
@ -947,8 +950,8 @@ KBUILD_RUSTFLAGS += -Coverflow-checks=$(if $(CONFIG_RUST_OVERFLOW_CHECKS),y,n)
|
|||
ifdef CONFIG_CC_IS_GCC
|
||||
# gcc-10 renamed --param=allow-store-data-races=0 to
|
||||
# -fno-allow-store-data-races.
|
||||
KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0)
|
||||
KBUILD_CFLAGS += $(call cc-option,-fno-allow-store-data-races)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_ALLOW_STORE_DATA_RACES_PARAM)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_NO_ALLOW_STORE_DATA_RACES)
|
||||
endif
|
||||
|
||||
ifdef CONFIG_READABLE_ASM
|
||||
|
|
@ -1012,18 +1015,20 @@ endif
|
|||
endif
|
||||
|
||||
# Explicitly clear padding bits during variable initialization
|
||||
KBUILD_CFLAGS += $(call cc-option,-fzero-init-padding-bits=all)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_ZERO_INIT_PADDING_BITS)
|
||||
|
||||
# While VLAs have been removed, GCC produces unreachable stack probes
|
||||
# for the randomize_kstack_offset feature. Disable it for all compilers.
|
||||
# Probed here rather than in Kconfig as clang only accepts it for some
|
||||
# sub-targets, so the architecture's flags matter.
|
||||
KBUILD_CFLAGS += $(call cc-option, -fno-stack-clash-protection)
|
||||
|
||||
# Get details on warnings generated due to GCC value tracking.
|
||||
KBUILD_CFLAGS += $(call cc-option, -fdiagnostics-show-context=2)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_DIAGNOSTICS_SHOW_CONTEXT)
|
||||
|
||||
# Show inlining notes for __attribute__((warning/error)) call chains.
|
||||
# GCC supports this unconditionally while Clang 23+ provides a flag.
|
||||
KBUILD_CFLAGS += $(call cc-option, -fdiagnostics-show-inlining-chain)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_DIAGNOSTICS_SHOW_INLINING_CHAIN)
|
||||
|
||||
# Clear used registers at func exit (to reduce data lifetime and ROP gadgets).
|
||||
ifdef CONFIG_ZERO_CALL_USED_REGS
|
||||
|
|
@ -1034,7 +1039,7 @@ ifdef CONFIG_FUNCTION_TRACER
|
|||
ifdef CONFIG_FTRACE_MCOUNT_USE_CC
|
||||
CC_FLAGS_FTRACE += -mrecord-mcount
|
||||
ifdef CONFIG_HAVE_NOP_MCOUNT
|
||||
ifeq ($(call cc-option-yn, -mnop-mcount),y)
|
||||
ifdef CONFIG_CC_HAS_MNOP_MCOUNT
|
||||
CC_FLAGS_FTRACE += -mnop-mcount
|
||||
CC_FLAGS_USING += -DCC_USING_NOP_MCOUNT
|
||||
endif
|
||||
|
|
@ -1052,8 +1057,7 @@ ifdef CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
|
|||
endif
|
||||
endif
|
||||
ifdef CONFIG_HAVE_FENTRY
|
||||
# s390-linux-gnu-gcc did not support -mfentry until gcc-9.
|
||||
ifeq ($(call cc-option-yn, -mfentry),y)
|
||||
ifdef CONFIG_CC_HAS_MFENTRY
|
||||
CC_FLAGS_FTRACE += -mfentry
|
||||
CC_FLAGS_USING += -DCC_USING_FENTRY
|
||||
endif
|
||||
|
|
@ -1161,7 +1165,7 @@ NOSTDINC_FLAGS += -nostdinc
|
|||
# the kernel uses only C99 flexible arrays for dynamically sized trailing
|
||||
# arrays. Enforce this for everything that may examine structure sizes and
|
||||
# perform bounds checking.
|
||||
KBUILD_CFLAGS += $(call cc-option, -fstrict-flex-arrays=3)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_STRICT_FLEX_ARRAYS)
|
||||
|
||||
# disable invalid "can't wrap" optimizations for signed / pointers
|
||||
KBUILD_CFLAGS += -fno-strict-overflow
|
||||
|
|
@ -1244,11 +1248,11 @@ LDFLAGS_vmlinux += --build-id=sha1
|
|||
# COMDAT-deduplicated sections. Use --force-group-allocation to resolve these
|
||||
# groups when linking modules. The option is available from ld.bfd 2.29 and
|
||||
# ld.lld 19.1.0.
|
||||
KBUILD_LDFLAGS_MODULE += $(call ld-option,--force-group-allocation)
|
||||
KBUILD_LDFLAGS_MODULE += $(CONFIG_LD_OPT_FORCE_GROUP_ALLOCATION)
|
||||
|
||||
KBUILD_LDFLAGS += -z noexecstack
|
||||
ifeq ($(CONFIG_LD_IS_BFD),y)
|
||||
KBUILD_LDFLAGS += $(call ld-option,--no-warn-rwx-segments)
|
||||
KBUILD_LDFLAGS += $(CONFIG_LD_OPT_NO_WARN_RWX_SEGMENTS)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
|
||||
|
|
@ -1266,8 +1270,9 @@ ifdef CONFIG_LD_ORPHAN_WARN
|
|||
LDFLAGS_vmlinux += --orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL)
|
||||
endif
|
||||
|
||||
# --emit-relocs is added by scripts/link-vmlinux.sh, for the final link only.
|
||||
ifneq ($(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS),)
|
||||
LDFLAGS_vmlinux += --emit-relocs --discard-none
|
||||
LDFLAGS_vmlinux += --discard-none
|
||||
endif
|
||||
|
||||
# Align the architecture of userspace programs with the kernel
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -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) \
|
||||
|
|
|
|||
|
|
@ -855,7 +855,7 @@
|
|||
KLP_SYMID
|
||||
|
||||
#define MODINFO \
|
||||
.modinfo : { *(.modinfo) }
|
||||
.modinfo (INFO) : { KEEP(*(.modinfo)) }
|
||||
|
||||
#ifdef CONFIG_GENERIC_BUG
|
||||
#define BUG_TABLE \
|
||||
|
|
|
|||
197
init/Kconfig
197
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
|
||||
|
|
|
|||
|
|
@ -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 $<
|
||||
|
||||
|
|
|
|||
|
|
@ -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
272
scripts/Kconfig.toolchain
Normal 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)"
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
248
scripts/kallsyms-sysmap.c
Normal 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);
|
||||
}
|
||||
|
|
@ -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
44
scripts/kallsyms.h
Normal 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 */
|
||||
|
|
@ -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}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user