mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
af73d78bd3
When CONFIG_DEBUG_INFO is enabled, the two kallsyms linking steps spend
time collecting and writing the dwarf sections to the temporary output
files. kallsyms does not need this information, and leaving it off
halves their linking time. This is especially noticeable without
CONFIG_DEBUG_INFO_REDUCED. The BTF linking stage, however, does still
need those details.
Refactor the BTF and kallsyms generation stages slightly for more
regularized temporary names. Skip debug during kallsyms links.
Additionally move "info BTF" to the correct place since commit
8959e39272
("kbuild: Parameterize kallsyms generation and correct
reporting"), which added "info LD ..." to vmlinux_link calls.
For a full debug info build with BTF, my link time goes from 1m06s to
0m54s, saving about 12 seconds, or 18%.
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/202003031814.4AEA3351@keescook
342 lines
8.3 KiB
Bash
Executable File
342 lines
8.3 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# link vmlinux
|
|
#
|
|
# vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_OBJS) and
|
|
# $(KBUILD_VMLINUX_LIBS). Most are built-in.a files from top-level directories
|
|
# in the kernel tree, others are specified in arch/$(ARCH)/Makefile.
|
|
# $(KBUILD_VMLINUX_LIBS) are archives which are linked conditionally
|
|
# (not within --whole-archive), and do not require symbol indexes added.
|
|
#
|
|
# vmlinux
|
|
# ^
|
|
# |
|
|
# +--< $(KBUILD_VMLINUX_OBJS)
|
|
# | +--< init/built-in.a drivers/built-in.a mm/built-in.a + more
|
|
# |
|
|
# +--< $(KBUILD_VMLINUX_LIBS)
|
|
# | +--< lib/lib.a + more
|
|
# |
|
|
# +-< ${kallsymso} (see description in KALLSYMS section)
|
|
#
|
|
# vmlinux version (uname -v) cannot be updated during normal
|
|
# descending-into-subdirs phase since we do not yet know if we need to
|
|
# update vmlinux.
|
|
# Therefore this step is delayed until just before final link of vmlinux.
|
|
#
|
|
# System.map is generated to document addresses of all kernel symbols
|
|
|
|
# Error out on error
|
|
set -e
|
|
|
|
# Nice output in kbuild format
|
|
# Will be supressed by "make -s"
|
|
info()
|
|
{
|
|
if [ "${quiet}" != "silent_" ]; then
|
|
printf " %-7s %s\n" "${1}" "${2}"
|
|
fi
|
|
}
|
|
|
|
# Link of vmlinux.o used for section mismatch analysis
|
|
# ${1} output file
|
|
modpost_link()
|
|
{
|
|
local objects
|
|
|
|
objects="--whole-archive \
|
|
${KBUILD_VMLINUX_OBJS} \
|
|
--no-whole-archive \
|
|
--start-group \
|
|
${KBUILD_VMLINUX_LIBS} \
|
|
--end-group"
|
|
|
|
${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${objects}
|
|
}
|
|
|
|
# Link of vmlinux
|
|
# ${1} - output file
|
|
# ${2}, ${3}, ... - optional extra .o files
|
|
vmlinux_link()
|
|
{
|
|
local lds="${objtree}/${KBUILD_LDS}"
|
|
local output=${1}
|
|
local objects
|
|
local strip_debug
|
|
|
|
info LD ${output}
|
|
|
|
# skip output file argument
|
|
shift
|
|
|
|
# The kallsyms linking does not need debug symbols included.
|
|
if [ "$output" != "${output#.tmp_vmlinux.kallsyms}" ] ; then
|
|
strip_debug=-Wl,--strip-debug
|
|
fi
|
|
|
|
if [ "${SRCARCH}" != "um" ]; then
|
|
objects="--whole-archive \
|
|
${KBUILD_VMLINUX_OBJS} \
|
|
--no-whole-archive \
|
|
--start-group \
|
|
${KBUILD_VMLINUX_LIBS} \
|
|
--end-group \
|
|
${@}"
|
|
|
|
${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} \
|
|
${strip_debug#-Wl,} \
|
|
-o ${output} \
|
|
-T ${lds} ${objects}
|
|
else
|
|
objects="-Wl,--whole-archive \
|
|
${KBUILD_VMLINUX_OBJS} \
|
|
-Wl,--no-whole-archive \
|
|
-Wl,--start-group \
|
|
${KBUILD_VMLINUX_LIBS} \
|
|
-Wl,--end-group \
|
|
${@}"
|
|
|
|
${CC} ${CFLAGS_vmlinux} \
|
|
${strip_debug} \
|
|
-o ${output} \
|
|
-Wl,-T,${lds} \
|
|
${objects} \
|
|
-lutil -lrt -lpthread
|
|
rm -f linux
|
|
fi
|
|
}
|
|
|
|
# generate .BTF typeinfo from DWARF debuginfo
|
|
# ${1} - vmlinux image
|
|
# ${2} - file to dump raw BTF data into
|
|
gen_btf()
|
|
{
|
|
local pahole_ver
|
|
local bin_arch
|
|
local bin_format
|
|
local bin_file
|
|
|
|
if ! [ -x "$(command -v ${PAHOLE})" ]; then
|
|
echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available"
|
|
return 1
|
|
fi
|
|
|
|
pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/')
|
|
if [ "${pahole_ver}" -lt "113" ]; then
|
|
echo >&2 "BTF: ${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.13"
|
|
return 1
|
|
fi
|
|
|
|
vmlinux_link ${1}
|
|
|
|
info "BTF" ${2}
|
|
LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1}
|
|
|
|
# dump .BTF section into raw binary file to link with final vmlinux
|
|
bin_arch=$(LANG=C ${OBJDUMP} -f ${1} | grep architecture | \
|
|
cut -d, -f1 | cut -d' ' -f2)
|
|
bin_format=$(LANG=C ${OBJDUMP} -f ${1} | grep 'file format' | \
|
|
awk '{print $4}')
|
|
bin_file=.btf.vmlinux.bin
|
|
${OBJCOPY} --change-section-address .BTF=0 \
|
|
--set-section-flags .BTF=alloc -O binary \
|
|
--only-section=.BTF ${1} $bin_file
|
|
${OBJCOPY} -I binary -O ${bin_format} -B ${bin_arch} \
|
|
--rename-section .data=.BTF $bin_file ${2}
|
|
}
|
|
|
|
# Create ${2} .o file with all symbols from the ${1} object file
|
|
kallsyms()
|
|
{
|
|
info KSYM ${2}
|
|
local kallsymopt;
|
|
|
|
if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then
|
|
kallsymopt="${kallsymopt} --all-symbols"
|
|
fi
|
|
|
|
if [ -n "${CONFIG_KALLSYMS_ABSOLUTE_PERCPU}" ]; then
|
|
kallsymopt="${kallsymopt} --absolute-percpu"
|
|
fi
|
|
|
|
if [ -n "${CONFIG_KALLSYMS_BASE_RELATIVE}" ]; then
|
|
kallsymopt="${kallsymopt} --base-relative"
|
|
fi
|
|
|
|
local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
|
|
${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
|
|
|
|
local afile="`basename ${2} .o`.S"
|
|
|
|
${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${afile}
|
|
${CC} ${aflags} -c -o ${2} ${afile}
|
|
}
|
|
|
|
# Perform one step in kallsyms generation, including temporary linking of
|
|
# vmlinux.
|
|
kallsyms_step()
|
|
{
|
|
kallsymso_prev=${kallsymso}
|
|
kallsyms_vmlinux=.tmp_vmlinux.kallsyms${1}
|
|
kallsymso=${kallsyms_vmlinux}.o
|
|
|
|
vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o}
|
|
kallsyms ${kallsyms_vmlinux} ${kallsymso}
|
|
}
|
|
|
|
# Create map file with all symbols from ${1}
|
|
# See mksymap for additional details
|
|
mksysmap()
|
|
{
|
|
${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2}
|
|
}
|
|
|
|
sorttable()
|
|
{
|
|
${objtree}/scripts/sorttable ${1}
|
|
}
|
|
|
|
# Delete output files in case of error
|
|
cleanup()
|
|
{
|
|
rm -f .btf.*
|
|
rm -f .tmp_System.map
|
|
rm -f .tmp_vmlinux*
|
|
rm -f System.map
|
|
rm -f vmlinux
|
|
rm -f vmlinux.o
|
|
}
|
|
|
|
on_exit()
|
|
{
|
|
if [ $? -ne 0 ]; then
|
|
cleanup
|
|
fi
|
|
}
|
|
trap on_exit EXIT
|
|
|
|
on_signals()
|
|
{
|
|
exit 1
|
|
}
|
|
trap on_signals HUP INT QUIT TERM
|
|
|
|
#
|
|
#
|
|
# Use "make V=1" to debug this script
|
|
case "${KBUILD_VERBOSE}" in
|
|
*1*)
|
|
set -x
|
|
;;
|
|
esac
|
|
|
|
if [ "$1" = "clean" ]; then
|
|
cleanup
|
|
exit 0
|
|
fi
|
|
|
|
# We need access to CONFIG_ symbols
|
|
. include/config/auto.conf
|
|
|
|
# Update version
|
|
info GEN .version
|
|
if [ -r .version ]; then
|
|
VERSION=$(expr 0$(cat .version) + 1)
|
|
echo $VERSION > .version
|
|
else
|
|
rm -f .version
|
|
echo 1 > .version
|
|
fi;
|
|
|
|
# final build of init/
|
|
${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1
|
|
|
|
#link vmlinux.o
|
|
info LD vmlinux.o
|
|
modpost_link vmlinux.o
|
|
|
|
# modpost vmlinux.o to check for section mismatches
|
|
${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1
|
|
|
|
info MODINFO modules.builtin.modinfo
|
|
${OBJCOPY} -j .modinfo -O binary vmlinux.o modules.builtin.modinfo
|
|
info GEN modules.builtin
|
|
# The second line aids cases where multiple modules share the same object.
|
|
tr '\0' '\n' < modules.builtin.modinfo | sed -n 's/^[[:alnum:]:_]*\.file=//p' |
|
|
tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$/.ko/' > modules.builtin
|
|
|
|
btf_vmlinux_bin_o=""
|
|
if [ -n "${CONFIG_DEBUG_INFO_BTF}" ]; then
|
|
btf_vmlinux_bin_o=.btf.vmlinux.bin.o
|
|
if ! gen_btf .tmp_vmlinux.btf $btf_vmlinux_bin_o ; then
|
|
echo >&2 "Failed to generate BTF for vmlinux"
|
|
echo >&2 "Try to disable CONFIG_DEBUG_INFO_BTF"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
kallsymso=""
|
|
kallsymso_prev=""
|
|
kallsyms_vmlinux=""
|
|
if [ -n "${CONFIG_KALLSYMS}" ]; then
|
|
|
|
# kallsyms support
|
|
# Generate section listing all symbols and add it into vmlinux
|
|
# It's a three step process:
|
|
# 1) Link .tmp_vmlinux1 so it has all symbols and sections,
|
|
# but __kallsyms is empty.
|
|
# Running kallsyms on that gives us .tmp_kallsyms1.o with
|
|
# the right size
|
|
# 2) Link .tmp_vmlinux2 so it now has a __kallsyms section of
|
|
# the right size, but due to the added section, some
|
|
# addresses have shifted.
|
|
# From here, we generate a correct .tmp_kallsyms2.o
|
|
# 3) That link may have expanded the kernel image enough that
|
|
# more linker branch stubs / trampolines had to be added, which
|
|
# introduces new names, which further expands kallsyms. Do another
|
|
# pass if that is the case. In theory it's possible this results
|
|
# in even more stubs, but unlikely.
|
|
# KALLSYMS_EXTRA_PASS=1 may also used to debug or work around
|
|
# other bugs.
|
|
# 4) The correct ${kallsymso} is linked into the final vmlinux.
|
|
#
|
|
# a) Verify that the System.map from vmlinux matches the map from
|
|
# ${kallsymso}.
|
|
|
|
kallsyms_step 1
|
|
kallsyms_step 2
|
|
|
|
# step 3
|
|
size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso_prev})
|
|
size2=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso})
|
|
|
|
if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
|
|
kallsyms_step 3
|
|
fi
|
|
fi
|
|
|
|
vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o}
|
|
|
|
if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then
|
|
info SORTTAB vmlinux
|
|
if ! sorttable vmlinux; then
|
|
echo >&2 Failed to sort kernel tables
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
info SYSMAP System.map
|
|
mksysmap vmlinux System.map
|
|
|
|
# step a (see comment above)
|
|
if [ -n "${CONFIG_KALLSYMS}" ]; then
|
|
mksysmap ${kallsyms_vmlinux} .tmp_System.map
|
|
|
|
if ! cmp -s System.map .tmp_System.map; then
|
|
echo >&2 Inconsistent kallsyms data
|
|
echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround
|
|
exit 1
|
|
fi
|
|
fi
|