[PATCH] x86/kallsyms: fix GOLD link failure with new relative kallsyms table format

From: Ard Biesheuvel
Date: Fri Mar 18 2016 - 05:04:55 EST

Commit 2213e9a66bb8 ("kallsyms: add support for relative offsets in
kallsyms address table") changed the default kallsyms symbol table format
to use relative references rather than absolute addresses. This reduces the
size of the kallsyms symbol table by 50% on 64-bit architectures, and
further reduces the size of the relocation tables used by relocatable
kernels. Since the memory footprint of the static kernel image is always
much smaller than 4 GB, these relative references are assumed to be
representable in 32 bits, even when the native word size is 64 bits.

On 64-bit architectures, this obviously only works if the distance between
each relative reference and the chosen anchor point is representable in 32
bits, and so the table generation code in scripts/kallsyms.c scans the
table for the lowest value that is covered by the kernel text, and selects
it as the anchor point.

However, when using the GOLD linker rather than the default BFD linker to
build the x86_64 kernel, the symbol phys_offset_64, which is the result of
arithmetic defined in the linker script, is emitted as a 'T' rather than an
'A' type symbol, resulting in scripts/kallsyms.c to mistake it for a
suitable anchor point, even though it is far away from the actual kernel
image in the virtual address space. This results in out-of-range warnings
from scripts/kallsyms.c and a broken build.

So let's align with the BFD linker, and emit the phys_offset_[32|64]
symbols as absolute symbols explicitly. Note that the out of range issue
does not exist on 32-bit x86, but this patch changes both symbols for

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>
arch/x86/kernel/vmlinux.lds.S | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 5af9958cbdb6..6bb070e54fda 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -81,11 +81,11 @@ PHDRS {
#ifdef CONFIG_X86_32
- phys_startup_32 = startup_32 - LOAD_OFFSET;
+ phys_startup_32 = ABSOLUTE(startup_32 - LOAD_OFFSET);
- phys_startup_64 = startup_64 - LOAD_OFFSET;
+ phys_startup_64 = ABSOLUTE(startup_64 - LOAD_OFFSET);

/* Text and read-only data */