linux/scripts/link-vmlinux.sh
<<
>>
Prefs
   1#!/bin/sh
   2# SPDX-License-Identifier: GPL-2.0
   3#
   4# link vmlinux
   5#
   6# vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_OBJS) and
   7# $(KBUILD_VMLINUX_LIBS). Most are built-in.a files from top-level directories
   8# in the kernel tree, others are specified in arch/$(ARCH)/Makefile.
   9# $(KBUILD_VMLINUX_LIBS) are archives which are linked conditionally
  10# (not within --whole-archive), and do not require symbol indexes added.
  11#
  12# vmlinux
  13#   ^
  14#   |
  15#   +--< $(KBUILD_VMLINUX_OBJS)
  16#   |    +--< init/built-in.a drivers/built-in.a mm/built-in.a + more
  17#   |
  18#   +--< $(KBUILD_VMLINUX_LIBS)
  19#   |    +--< lib/lib.a + more
  20#   |
  21#   +-< ${kallsymso} (see description in KALLSYMS section)
  22#
  23# vmlinux version (uname -v) cannot be updated during normal
  24# descending-into-subdirs phase since we do not yet know if we need to
  25# update vmlinux.
  26# Therefore this step is delayed until just before final link of vmlinux.
  27#
  28# System.map is generated to document addresses of all kernel symbols
  29
  30# Error out on error
  31set -e
  32
  33LD="$1"
  34KBUILD_LDFLAGS="$2"
  35LDFLAGS_vmlinux="$3"
  36
  37# Nice output in kbuild format
  38# Will be supressed by "make -s"
  39info()
  40{
  41        printf "  %-7s %s\n" "${1}" "${2}"
  42}
  43
  44# Generate a linker script to ensure correct ordering of initcalls.
  45gen_initcalls()
  46{
  47        info GEN .tmp_initcalls.lds
  48
  49        ${PYTHON} ${srctree}/scripts/jobserver-exec             \
  50        ${PERL} ${srctree}/scripts/generate_initcall_order.pl   \
  51                ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS}   \
  52                > .tmp_initcalls.lds
  53}
  54
  55# If CONFIG_LTO_CLANG is selected, collect generated symbol versions into
  56# .tmp_symversions.lds
  57gen_symversions()
  58{
  59        info GEN .tmp_symversions.lds
  60        rm -f .tmp_symversions.lds
  61
  62        for o in ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS}; do
  63                if [ -f ${o}.symversions ]; then
  64                        cat ${o}.symversions >> .tmp_symversions.lds
  65                fi
  66        done
  67}
  68
  69# Link of vmlinux.o used for section mismatch analysis
  70# ${1} output file
  71modpost_link()
  72{
  73        local objects
  74        local lds=""
  75
  76        objects="--whole-archive                                \
  77                ${KBUILD_VMLINUX_OBJS}                          \
  78                --no-whole-archive                              \
  79                --start-group                                   \
  80                ${KBUILD_VMLINUX_LIBS}                          \
  81                --end-group"
  82
  83        if [ -n "${CONFIG_LTO_CLANG}" ]; then
  84                gen_initcalls
  85                lds="-T .tmp_initcalls.lds"
  86
  87                if [ -n "${CONFIG_MODVERSIONS}" ]; then
  88                        gen_symversions
  89                        lds="${lds} -T .tmp_symversions.lds"
  90                fi
  91
  92                # This might take a while, so indicate that we're doing
  93                # an LTO link
  94                info LTO ${1}
  95        else
  96                info LD ${1}
  97        fi
  98
  99        ${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${lds} ${objects}
 100}
 101
 102objtool_link()
 103{
 104        local objtoolcmd;
 105        local objtoolopt;
 106
 107        if [ "${CONFIG_LTO_CLANG} ${CONFIG_STACK_VALIDATION}" = "y y" ]; then
 108                # Don't perform vmlinux validation unless explicitly requested,
 109                # but run objtool on vmlinux.o now that we have an object file.
 110                if [ -n "${CONFIG_UNWINDER_ORC}" ]; then
 111                        objtoolcmd="orc generate"
 112                fi
 113
 114                objtoolopt="${objtoolopt} --duplicate"
 115
 116                if [ -n "${CONFIG_FTRACE_MCOUNT_USE_OBJTOOL}" ]; then
 117                        objtoolopt="${objtoolopt} --mcount"
 118                fi
 119        fi
 120
 121        if [ -n "${CONFIG_VMLINUX_VALIDATION}" ]; then
 122                objtoolopt="${objtoolopt} --noinstr"
 123        fi
 124
 125        if [ -n "${objtoolopt}" ]; then
 126                if [ -z "${objtoolcmd}" ]; then
 127                        objtoolcmd="check"
 128                fi
 129                objtoolopt="${objtoolopt} --vmlinux"
 130                if [ -z "${CONFIG_FRAME_POINTER}" ]; then
 131                        objtoolopt="${objtoolopt} --no-fp"
 132                fi
 133                if [ -n "${CONFIG_GCOV_KERNEL}" ] || [ -n "${CONFIG_LTO_CLANG}" ]; then
 134                        objtoolopt="${objtoolopt} --no-unreachable"
 135                fi
 136                if [ -n "${CONFIG_RETPOLINE}" ]; then
 137                        objtoolopt="${objtoolopt} --retpoline"
 138                fi
 139                if [ -n "${CONFIG_X86_SMAP}" ]; then
 140                        objtoolopt="${objtoolopt} --uaccess"
 141                fi
 142                info OBJTOOL ${1}
 143                tools/objtool/objtool ${objtoolcmd} ${objtoolopt} ${1}
 144        fi
 145}
 146
 147# Link of vmlinux
 148# ${1} - output file
 149# ${2}, ${3}, ... - optional extra .o files
 150vmlinux_link()
 151{
 152        local lds="${objtree}/${KBUILD_LDS}"
 153        local output=${1}
 154        local objects
 155        local strip_debug
 156        local map_option
 157
 158        info LD ${output}
 159
 160        # skip output file argument
 161        shift
 162
 163        # The kallsyms linking does not need debug symbols included.
 164        if [ "$output" != "${output#.tmp_vmlinux.kallsyms}" ] ; then
 165                strip_debug=-Wl,--strip-debug
 166        fi
 167
 168        if [ -n "${CONFIG_VMLINUX_MAP}" ]; then
 169                map_option="-Map=${output}.map"
 170        fi
 171
 172        if [ "${SRCARCH}" != "um" ]; then
 173                if [ -n "${CONFIG_LTO_CLANG}" ]; then
 174                        # Use vmlinux.o instead of performing the slow LTO
 175                        # link again.
 176                        objects="--whole-archive                \
 177                                vmlinux.o                       \
 178                                --no-whole-archive              \
 179                                ${@}"
 180                else
 181                        objects="--whole-archive                \
 182                                ${KBUILD_VMLINUX_OBJS}          \
 183                                --no-whole-archive              \
 184                                --start-group                   \
 185                                ${KBUILD_VMLINUX_LIBS}          \
 186                                --end-group                     \
 187                                ${@}"
 188                fi
 189
 190                ${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux}      \
 191                        ${strip_debug#-Wl,}                     \
 192                        -o ${output}                            \
 193                        ${map_option}                           \
 194                        -T ${lds} ${objects}
 195        else
 196                objects="-Wl,--whole-archive                    \
 197                        ${KBUILD_VMLINUX_OBJS}                  \
 198                        -Wl,--no-whole-archive                  \
 199                        -Wl,--start-group                       \
 200                        ${KBUILD_VMLINUX_LIBS}                  \
 201                        -Wl,--end-group                         \
 202                        ${@}"
 203
 204                ${CC} ${CFLAGS_vmlinux}                         \
 205                        ${strip_debug}                          \
 206                        -o ${output}                            \
 207                        ${map_option:+-Wl,${map_option}}        \
 208                        -Wl,-T,${lds}                           \
 209                        ${objects}                              \
 210                        -lutil -lrt -lpthread
 211                rm -f linux
 212        fi
 213}
 214
 215# generate .BTF typeinfo from DWARF debuginfo
 216# ${1} - vmlinux image
 217# ${2} - file to dump raw BTF data into
 218gen_btf()
 219{
 220        local pahole_ver
 221        local extra_paholeopt=
 222
 223        if ! [ -x "$(command -v ${PAHOLE})" ]; then
 224                echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available"
 225                return 1
 226        fi
 227
 228        pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/')
 229        if [ "${pahole_ver}" -lt "116" ]; then
 230                echo >&2 "BTF: ${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.16"
 231                return 1
 232        fi
 233
 234        vmlinux_link ${1}
 235
 236        if [ "${pahole_ver}" -ge "118" ] && [ "${pahole_ver}" -le "121" ]; then
 237                # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars
 238                extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_vars"
 239        fi
 240        if [ "${pahole_ver}" -ge "121" ]; then
 241                extra_paholeopt="${extra_paholeopt} --btf_gen_floats"
 242        fi
 243
 244        info "BTF" ${2}
 245        LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${extra_paholeopt} ${1}
 246
 247        # Create ${2} which contains just .BTF section but no symbols. Add
 248        # SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all
 249        # deletes all symbols including __start_BTF and __stop_BTF, which will
 250        # be redefined in the linker script. Add 2>/dev/null to suppress GNU
 251        # objcopy warnings: "empty loadable segment detected at ..."
 252        ${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \
 253                --strip-all ${1} ${2} 2>/dev/null
 254        # Change e_type to ET_REL so that it can be used to link final vmlinux.
 255        # Unlike GNU ld, lld does not allow an ET_EXEC input.
 256        printf '\1' | dd of=${2} conv=notrunc bs=1 seek=16 status=none
 257}
 258
 259# Create ${2} .S file with all symbols from the ${1} object file
 260kallsyms()
 261{
 262        local kallsymopt;
 263
 264        if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then
 265                kallsymopt="${kallsymopt} --all-symbols"
 266        fi
 267
 268        if [ -n "${CONFIG_KALLSYMS_ABSOLUTE_PERCPU}" ]; then
 269                kallsymopt="${kallsymopt} --absolute-percpu"
 270        fi
 271
 272        if [ -n "${CONFIG_KALLSYMS_BASE_RELATIVE}" ]; then
 273                kallsymopt="${kallsymopt} --base-relative"
 274        fi
 275
 276        info KSYMS ${2}
 277        ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2}
 278}
 279
 280# Perform one step in kallsyms generation, including temporary linking of
 281# vmlinux.
 282kallsyms_step()
 283{
 284        kallsymso_prev=${kallsymso}
 285        kallsyms_vmlinux=.tmp_vmlinux.kallsyms${1}
 286        kallsymso=${kallsyms_vmlinux}.o
 287        kallsyms_S=${kallsyms_vmlinux}.S
 288
 289        vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o}
 290        kallsyms ${kallsyms_vmlinux} ${kallsyms_S}
 291
 292        info AS ${kallsyms_S}
 293        ${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \
 294              ${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
 295              -c -o ${kallsymso} ${kallsyms_S}
 296}
 297
 298# Create map file with all symbols from ${1}
 299# See mksymap for additional details
 300mksysmap()
 301{
 302        ${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2}
 303}
 304
 305sorttable()
 306{
 307        ${objtree}/scripts/sorttable ${1}
 308}
 309
 310# Delete output files in case of error
 311cleanup()
 312{
 313        rm -f .btf.*
 314        rm -f .tmp_System.map
 315        rm -f .tmp_initcalls.lds
 316        rm -f .tmp_symversions.lds
 317        rm -f .tmp_vmlinux*
 318        rm -f System.map
 319        rm -f vmlinux
 320        rm -f vmlinux.map
 321        rm -f vmlinux.o
 322        rm -f .vmlinux.d
 323}
 324
 325# Use "make V=1" to debug this script
 326case "${KBUILD_VERBOSE}" in
 327*1*)
 328        set -x
 329        ;;
 330esac
 331
 332if [ "$1" = "clean" ]; then
 333        cleanup
 334        exit 0
 335fi
 336
 337# We need access to CONFIG_ symbols
 338. include/config/auto.conf
 339
 340# Update version
 341info GEN .version
 342if [ -r .version ]; then
 343        VERSION=$(expr 0$(cat .version) + 1)
 344        echo $VERSION > .version
 345else
 346        rm -f .version
 347        echo 1 > .version
 348fi;
 349
 350# final build of init/
 351${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1
 352
 353#link vmlinux.o
 354modpost_link vmlinux.o
 355objtool_link vmlinux.o
 356
 357# modpost vmlinux.o to check for section mismatches
 358${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1
 359
 360info MODINFO modules.builtin.modinfo
 361${OBJCOPY} -j .modinfo -O binary vmlinux.o modules.builtin.modinfo
 362info GEN modules.builtin
 363# The second line aids cases where multiple modules share the same object.
 364tr '\0' '\n' < modules.builtin.modinfo | sed -n 's/^[[:alnum:]:_]*\.file=//p' |
 365        tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$/.ko/' > modules.builtin
 366
 367btf_vmlinux_bin_o=""
 368if [ -n "${CONFIG_DEBUG_INFO_BTF}" ]; then
 369        btf_vmlinux_bin_o=.btf.vmlinux.bin.o
 370        if ! gen_btf .tmp_vmlinux.btf $btf_vmlinux_bin_o ; then
 371                echo >&2 "Failed to generate BTF for vmlinux"
 372                echo >&2 "Try to disable CONFIG_DEBUG_INFO_BTF"
 373                exit 1
 374        fi
 375fi
 376
 377kallsymso=""
 378kallsymso_prev=""
 379kallsyms_vmlinux=""
 380if [ -n "${CONFIG_KALLSYMS}" ]; then
 381
 382        # kallsyms support
 383        # Generate section listing all symbols and add it into vmlinux
 384        # It's a three step process:
 385        # 1)  Link .tmp_vmlinux1 so it has all symbols and sections,
 386        #     but __kallsyms is empty.
 387        #     Running kallsyms on that gives us .tmp_kallsyms1.o with
 388        #     the right size
 389        # 2)  Link .tmp_vmlinux2 so it now has a __kallsyms section of
 390        #     the right size, but due to the added section, some
 391        #     addresses have shifted.
 392        #     From here, we generate a correct .tmp_kallsyms2.o
 393        # 3)  That link may have expanded the kernel image enough that
 394        #     more linker branch stubs / trampolines had to be added, which
 395        #     introduces new names, which further expands kallsyms. Do another
 396        #     pass if that is the case. In theory it's possible this results
 397        #     in even more stubs, but unlikely.
 398        #     KALLSYMS_EXTRA_PASS=1 may also used to debug or work around
 399        #     other bugs.
 400        # 4)  The correct ${kallsymso} is linked into the final vmlinux.
 401        #
 402        # a)  Verify that the System.map from vmlinux matches the map from
 403        #     ${kallsymso}.
 404
 405        kallsyms_step 1
 406        kallsyms_step 2
 407
 408        # step 3
 409        size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso_prev})
 410        size2=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso})
 411
 412        if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
 413                kallsyms_step 3
 414        fi
 415fi
 416
 417vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o}
 418
 419# fill in BTF IDs
 420if [ -n "${CONFIG_DEBUG_INFO_BTF}" -a -n "${CONFIG_BPF}" ]; then
 421        info BTFIDS vmlinux
 422        ${RESOLVE_BTFIDS} vmlinux
 423fi
 424
 425if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then
 426        info SORTTAB vmlinux
 427        if ! sorttable vmlinux; then
 428                echo >&2 Failed to sort kernel tables
 429                exit 1
 430        fi
 431fi
 432
 433info SYSMAP System.map
 434mksysmap vmlinux System.map
 435
 436# step a (see comment above)
 437if [ -n "${CONFIG_KALLSYMS}" ]; then
 438        mksysmap ${kallsyms_vmlinux} .tmp_System.map
 439
 440        if ! cmp -s System.map .tmp_System.map; then
 441                echo >&2 Inconsistent kallsyms data
 442                echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround
 443                exit 1
 444        fi
 445fi
 446
 447# For fixdep
 448echo "vmlinux: $0" > .vmlinux.d
 449