Skip to content

Commit 6d92bc9

Browse files
hjl-toolsIngo Molnar
authored andcommitted
x86/build: Build compressed x86 kernels as PIE
The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X relocation to get the symbol address in PIC. When the compressed x86 kernel isn't built as PIC, the linker optimizes R_386_GOT32X relocations to their fixed symbol addresses. However, when the compressed x86 kernel is loaded at a different address, it leads to the following load failure: Failed to allocate space for phdrs during the decompression stage. If the compressed x86 kernel is relocatable at run-time, it should be compiled with -fPIE, instead of -fPIC, if possible and should be built as Position Independent Executable (PIE) so that linker won't optimize R_386_GOT32X relocation to its fixed symbol address. Older linkers generate R_386_32 relocations against locally defined symbols, _bss, _ebss, _got and _egot, in PIE. It isn't wrong, just less optimal than R_386_RELATIVE. But the x86 kernel fails to properly handle R_386_32 relocations when relocating the kernel. To generate R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as hidden in both 32-bit and 64-bit x86 kernels. To build a 64-bit compressed x86 kernel as PIE, we need to disable the relocation overflow check to avoid relocation overflow errors. We do this with a new linker command-line option, -z noreloc-overflow, which got added recently: commit 4c10bbaa0912742322f10d9d5bb630ba4e15dfa7 Author: H.J. Lu <hjl.tools@gmail.com> Date: Tue Mar 15 11:07:06 2016 -0700 Add -z noreloc-overflow option to x86-64 ld Add -z noreloc-overflow command-line option to the x86-64 ELF linker to disable relocation overflow check. This can be used to avoid relocation overflow check if there will be no dynamic relocation overflow at run-time. The 64-bit compressed x86 kernel is built as PIE only if the linker supports -z noreloc-overflow. So far 64-bit relocatable compressed x86 kernel boots fine even when it is built as a normal executable. Signed-off-by: H.J. Lu <hjl.tools@gmail.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org [ Edited the changelog and comments. ] Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 591b1d8 commit 6d92bc9

File tree

3 files changed

+49
-1
lines changed

3 files changed

+49
-1
lines changed

arch/x86/boot/compressed/Makefile

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
2626
vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
2727

2828
KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
29-
KBUILD_CFLAGS += -fno-strict-aliasing -fPIC
29+
KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC)
3030
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
3131
cflags-$(CONFIG_X86_32) := -march=i386
3232
cflags-$(CONFIG_X86_64) := -mcmodel=small
@@ -40,6 +40,18 @@ GCOV_PROFILE := n
4040
UBSAN_SANITIZE :=n
4141

4242
LDFLAGS := -m elf_$(UTS_MACHINE)
43+
ifeq ($(CONFIG_RELOCATABLE),y)
44+
# If kernel is relocatable, build compressed kernel as PIE.
45+
ifeq ($(CONFIG_X86_32),y)
46+
LDFLAGS += $(call ld-option, -pie) $(call ld-option, --no-dynamic-linker)
47+
else
48+
# To build 64-bit compressed kernel as PIE, we disable relocation
49+
# overflow check to avoid relocation overflow error with a new linker
50+
# command-line option, -z noreloc-overflow.
51+
LDFLAGS += $(shell $(LD) --help 2>&1 | grep -q "\-z noreloc-overflow" \
52+
&& echo "-z noreloc-overflow -pie --no-dynamic-linker")
53+
endif
54+
endif
4355
LDFLAGS_vmlinux := -T
4456

4557
hostprogs-y := mkpiggy

arch/x86/boot/compressed/head_32.S

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@
3131
#include <asm/asm-offsets.h>
3232
#include <asm/bootparam.h>
3333

34+
/*
35+
* The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
36+
* relocation to get the symbol address in PIC. When the compressed x86
37+
* kernel isn't built as PIC, the linker optimizes R_386_GOT32X
38+
* relocations to their fixed symbol addresses. However, when the
39+
* compressed x86 kernel is loaded at a different address, it leads
40+
* to the following load failure:
41+
*
42+
* Failed to allocate space for phdrs
43+
*
44+
* during the decompression stage.
45+
*
46+
* If the compressed x86 kernel is relocatable at run-time, it should be
47+
* compiled with -fPIE, instead of -fPIC, if possible and should be built as
48+
* Position Independent Executable (PIE) so that linker won't optimize
49+
* R_386_GOT32X relocation to its fixed symbol address. Older
50+
* linkers generate R_386_32 relocations against locally defined symbols,
51+
* _bss, _ebss, _got and _egot, in PIE. It isn't wrong, just less
52+
* optimal than R_386_RELATIVE. But the x86 kernel fails to properly handle
53+
* R_386_32 relocations when relocating the kernel. To generate
54+
* R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
55+
* hidden:
56+
*/
57+
.hidden _bss
58+
.hidden _ebss
59+
.hidden _got
60+
.hidden _egot
61+
3462
__HEAD
3563
ENTRY(startup_32)
3664
#ifdef CONFIG_EFI_STUB

arch/x86/boot/compressed/head_64.S

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@
3333
#include <asm/asm-offsets.h>
3434
#include <asm/bootparam.h>
3535

36+
/*
37+
* Locally defined symbols should be marked hidden:
38+
*/
39+
.hidden _bss
40+
.hidden _ebss
41+
.hidden _got
42+
.hidden _egot
43+
3644
__HEAD
3745
.code32
3846
ENTRY(startup_32)

0 commit comments

Comments
 (0)