powerpc/64: Tool to check head sections location sanity
authorNicholas Piggin <npiggin@gmail.com>
Thu, 11 May 2017 17:40:39 +0000 (03:40 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 30 May 2017 04:59:51 +0000 (14:59 +1000)
Use a tool to check that the location of "fixed sections" are where
we expected them to be, which catches cases the linker script can't
(stubs being added to start of .text section), and which ends up
being neater.

Sample output:

  ERROR: start_text address is c000000000008100, should be c000000000008000
  ERROR: see comments in arch/powerpc/tools/head_check.sh

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[mpe: Fold in fix from Nick for 4.6 era toolchains]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/Makefile.postlink
arch/powerpc/include/asm/head-64.h
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/tools/head_check.sh [new file with mode: 0644]

index 50336930e6f747b8c4cb30bf7c1b9bf32adc94af..5db43ebbe2dfdc9e0197e558bad4917816cc5232 100644 (file)
@@ -10,6 +10,9 @@ __archpost:
 -include include/config/auto.conf
 include scripts/Kbuild.include
 
+quiet_cmd_head_check = CHKHEAD $@
+      cmd_head_check = $(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/head_check.sh "$(NM)" "$@"
+
 quiet_cmd_relocs_check = CHKREL  $@
 ifdef CONFIG_PPC_BOOK3S_64
       cmd_relocs_check =                                               \
@@ -24,6 +27,9 @@ endif
 
 vmlinux: FORCE
        @true
+ifdef CONFIG_PPC64
+       $(call cmd,head_check)
+endif
 ifdef CONFIG_RELOCATABLE
        $(call if_changed,relocs_check)
 endif
@@ -32,7 +38,7 @@ endif
        @true
 
 clean:
-       @true
+       rm -f .tmp_symbols.txt
 
 PHONY += FORCE clean
 
index 68828aa6e056230bf237a654e9ebab01883e561b..7ab95798f170172b887649e9ba16c16e0f95b444 100644 (file)
@@ -49,8 +49,8 @@
  *   CLOSE_FIXED_SECTION() or elsewhere, there may be something
  *   unexpected being added there. Remove the '. = x_len' line, rebuild, and
  *   check what is pushing the section down.
- * - If the build dies in linking, check arch/powerpc/kernel/vmlinux.lds.S
- *   for instructions.
+ * - If the build dies in linking, check arch/powerpc/tools/head_check.sh
+ *   comments.
  * - If the kernel crashes or hangs in very early boot, it could be linker
  *   stubs at the start of the main text.
  */
index be8578e02ab652f077f27ebb78953c4e1dc34ed8..e69155f0db364bb7a138f88b3d1a5ee240969e68 100644 (file)
@@ -58,7 +58,6 @@ SECTIONS
 #ifdef CONFIG_PPC64
                KEEP(*(.head.text.first_256B));
 #ifdef CONFIG_PPC_BOOK3E
-# define END_FIXED     0x100
 #else
                KEEP(*(.head.text.real_vectors));
                *(.head.text.real_trampolines);
@@ -66,12 +65,8 @@ SECTIONS
                *(.head.text.virt_trampolines);
 # if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
                KEEP(*(.head.data.fwnmi_page));
-#  define END_FIXED    0x8000
-# else
-#  define END_FIXED    0x7000
 # endif
 #endif
-               ASSERT((. == END_FIXED), "vmlinux.lds.S: fixed section overflow error");
 #else /* !CONFIG_PPC64 */
                HEAD_TEXT
 #endif
@@ -79,23 +74,6 @@ SECTIONS
 
        __head_end = .;
 
-       /*
-        * If the build dies here, it's likely code in head_64.S is referencing
-        * labels it can't reach, and the linker inserting stubs without the
-        * assembler's knowledge. To debug, remove the above assert and
-        * rebuild. Look for branch stubs in the fixed section region.
-        *
-        * Linker stub generation could be allowed in "trampoline"
-        * sections if absolutely necessary, but this would require
-        * some rework of the fixed sections. Before resorting to this,
-        * consider references that have sufficient addressing range,
-        * (e.g., hand coded trampolines) so the linker does not have
-        * to add stubs.
-        *
-        * Linker stubs at the top of the main text section are currently not
-        * detected, and will result in a crash at boot due to offsets being
-        * wrong.
-        */
 #ifdef CONFIG_PPC64
        /*
         * BLOCK(0) overrides the default output section alignment because
diff --git a/arch/powerpc/tools/head_check.sh b/arch/powerpc/tools/head_check.sh
new file mode 100644 (file)
index 0000000..ad9e572
--- /dev/null
@@ -0,0 +1,78 @@
+# Copyright © 2016 IBM Corporation
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+
+# This script checks the head of a vmlinux for linker stubs that
+# break our placement of fixed-location code for 64-bit.
+
+# based on relocs_check.pl
+# Copyright © 2009 IBM Corporation
+
+# NOTE!
+#
+# If the build dies here, it's likely code in head_64.S/exception-64*.S or
+# nearby, is branching to labels it can't reach directly, which results in the
+# linker inserting branch stubs. This can move code around in ways that break
+# the fixed section calculations (head-64.h). To debug this, disassemble the
+# vmlinux and look for branch stubs (long_branch, plt_branch, etc.) in the
+# fixed section region (0 - 0x8000ish). Check what code is calling those stubs,
+# and perhaps change so a direct branch can reach.
+#
+# A ".linker_stub_catch" section is used to catch some stubs generated by
+# early .text code, which tend to get placed at the start of the section.
+# If there are too many such stubs, they can overflow this section. Expanding
+# it may help (or reducing the number of stub branches).
+#
+# Linker stubs use the TOC pointer, so even if fixed section code could
+# tolerate them being inserted into head code, they can't be allowed in low
+# level entry code (boot, interrupt vectors, etc) until r2 is set up. This
+# could cause the kernel to die in early boot.
+
+# Turn this on if you want more debug output:
+# set -x
+
+if [ $# -lt 2 ]; then
+       echo "$0 [path to nm] [path to vmlinux]" 1>&2
+       exit 1
+fi
+
+# Have Kbuild supply the path to nm so we handle cross compilation.
+nm="$1"
+vmlinux="$2"
+
+# gcc-4.6-era toolchain make _stext an A (absolute) symbol rather than T
+$nm "$vmlinux" | grep -e " [TA] _stext$" -e " t start_first_256B$" -e " a text_start$" -e " t start_text$" -m4 > .tmp_symbols.txt
+
+
+vma=$(cat .tmp_symbols.txt | grep -e " [TA] _stext$" | cut -d' ' -f1)
+
+expected_start_head_addr=$vma
+
+start_head_addr=$(cat .tmp_symbols.txt | grep " t start_first_256B$" | cut -d' ' -f1)
+
+if [ "$start_head_addr" != "$expected_start_head_addr" ]; then
+       echo "ERROR: head code starts at $start_head_addr, should be $expected_start_head_addr"
+       echo "ERROR: try to enable LD_HEAD_STUB_CATCH config option"
+       echo "ERROR: see comments in arch/powerpc/tools/head_check.sh"
+
+       exit 1
+fi
+
+top_vma=$(echo $vma | cut -d'0' -f1)
+
+expected_start_text_addr=$(cat .tmp_symbols.txt | grep " a text_start$" | cut -d' ' -f1 | sed "s/^0/$top_vma/")
+
+start_text_addr=$(cat .tmp_symbols.txt | grep " t start_text$" | cut -d' ' -f1)
+
+if [ "$start_text_addr" != "$expected_start_text_addr" ]; then
+       echo "ERROR: start_text address is $start_text_addr, should be $expected_start_text_addr"
+       echo "ERROR: try to enable LD_HEAD_STUB_CATCH config option"
+       echo "ERROR: see comments in arch/powerpc/tools/head_check.sh"
+
+       exit 1
+fi
+
+rm -f .tmp_symbols.txt