powerpc: build-time fixup alternate feature relative addresses
Nicholas Piggin
reviewerRFC PATCH 1/1 powerpc: build-time fixup alternate feature relative addresses
Hi,
I'd like to revisit this patch to do the fixup of relative addresses for "else" part of alternate instruction patching at compile-time rather than runtime. Without this I pretty quickly run into "ftr_alt relocation truncated to fit" errors when trying to use feature patching for anything non-trivial.
Implement build-time fixup of alternate feature relative addresses for the out-of-line ("else") patch code. This is done post-link with a new powerpc build tool that parses relocations and fixup structures, and adjusts branch instructions.
The "else" part of the feature patching system currently requires the linker generate correct relative addresses for the linked location. The the kernel instruction patching code copies instructions delta bytes to runtime location, and applies negative delta to relative branches as it does.
This is nice and simple, however the requirement to generate valid relative addresses at the linked location is constraining:
- Sometimes it can't be done. Particularly in exception handlers that have fixed locations, and when both if and else parts of the fixup have relative references to the same code. This has caused headaches in the exception code, where things have to be juggled around until they work.
- It requires patch code to be placed near its destination location, despite never being executed in-place. This compounds real estate shortage in exception code, and puts this unused code near to (likely) performance critical code, which is not ideal.
- Alternate patch code can't be discarded after alt fixups are completed. Not a significant problem in practice, but it's tidy to have it, and the feature patching stuff is likely to see increased usage in future.
With this change, the relative branch adjustment is done at build, so patch code branches are correct for their destination location. Kernel runtime patching just moves the instructions.
__ftr_alt sections get moved out of the main text section and into an init region, which stops them cluttering the runtime text and allows them to be discarded at boot time.
Relative branches in the alt sections still need the linker to be happy otherwise it will fail the link. So the alt sections are made allocatable and executable, so branch stub trampolines for these branches can be added for them. The relocation and patching system simply ignores these branch stubs.
Static relocations have to be included in the vmlinux file after linking, so --emit-relocs is added to the build. Newer versoins of binutils can strip these off after they are used too. With older binutils, the resulting vmlinux becomes significantly larger due to the relocation data.
--- arch/powerpc/Makefile | 8 +- arch/powerpc/Makefile.postlink | 24 +- arch/powerpc/include/asm/feature-fixups.h | 5 +- arch/powerpc/kernel/vmlinux.lds.S | 8 +- arch/powerpc/lib/feature-fixups.c | 19 +- arch/powerpc/tools/Makefile | 3 + arch/powerpc/tools/relocs/.gitignore | 1 + arch/powerpc/tools/relocs/Makefile | 12 + arch/powerpc/tools/relocs/code-patching.c | 82 ++++ arch/powerpc/tools/relocs/code-patching.h | 7 + arch/powerpc/tools/relocs/elf_sections.c | 337 ++++++++++++++ arch/powerpc/tools/relocs/elf_sections.h | 50 ++ arch/powerpc/tools/relocs/process_relocs.c | 715 +++++++++++++++++++++++++++++ 13 files changed, 1250 insertions(+), 21 deletions(-) create mode 100644 arch/powerpc/tools/Makefile create mode 100644 arch/powerpc/tools/relocs/.gitignore create mode 100644 arch/powerpc/tools/relocs/Makefile create mode 100644 arch/powerpc/tools/relocs/code-patching.c create mode 100644 arch/powerpc/tools/relocs/code-patching.h create mode 100644 arch/powerpc/tools/relocs/elf_sections.c create mode 100644 arch/powerpc/tools/relocs/elf_sections.h create mode 100644 arch/powerpc/tools/relocs/process_relocs.c
arch/powerpc/Makefile +7 -1
@@ -104,6 +104,11 @@ LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y) LDFLAGS_vmlinux += $(call ld-option,--orphan-handling=warn) +# --emit-relocs required for post-link fixup of alternate feature +# text section relocations. +LDFLAGS_vmlinux += --emit-relocs +KBUILD_LDFLAGS_MODULE += --emit-relocs + ifeq ($(CONFIG_PPC64),y) ifeq ($(call cc-option-yn,-mcmodel=medium),y) # -mcmodel=medium breaks modules because it uses 32bit offsets from
@@ -417,6 +422,7 @@ checkbin: false ; \ fi +archscripts: scripts_basic + $(Q)$(MAKE) $(build)=arch/powerpc/tools CLEAN_FILES += $(TOUT) -
arch/powerpc/Makefile.postlink +21 -3
@@ -2,7 +2,9 @@ # Post-link powerpc pass # =========================================================================== # -# 1. Check that vmlinux relocations look sane +# 1. Invoke process_relocs to fix feature fixup alternate section branches. +# 2. Check that vmlinux relocations look sane +# 3. Strip static relocations (created by --emit-relocs) if binutils >= 2.27 PHONY := __archpost __archpost:
@@ -23,19 +25,35 @@ else $(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/relocs_check.sh "$(OBJDUMP)" "$@" endif +quiet_cmd_process_alt_ftr_relocs = FTR_ALT $@ + cmd_process_alt_ftr_relocs = \ + arch/powerpc/tools/relocs/process_relocs "$@" + +ifeq ($(call ld-ifversion, -ge, 227000000, y),y) +quiet_cmd_strip_relocs = STRIP $@ + cmd_strip_relocs = \ + $(OBJCOPY) $(shell for sec in \ + $$(readelf -St $@ | grep -B1 RELA | grep "\.rela" | \ + cut -d"]" -f2 | sed "s/[[:space:]]//" | \ + grep -v "^\.rela\.dyn$$" | sed "s/\.rela//") ; \ + do echo -n "--remove-relocation=$$sec " ; done) $@ +endif + # `@true` prevents complaint when there is nothing to be done vmlinux: FORCE - @true + $(call if_changed,process_alt_ftr_relocs) ifdef CONFIG_PPC64 $(call cmd,head_check) endif ifdef CONFIG_RELOCATABLE $(call if_changed,relocs_check) endif + $(call if_changed,strip_relocs) %.ko: FORCE - @true + $(call if_changed,process_alt_ftr_relocs) + $(call if_changed,strip_relocs) clean: rm -f .tmp_symbols.txt
arch/powerpc/include/asm/feature-fixups.h +4 -1
@@ -16,6 +16,9 @@* useable with the vdso shared library. There is also an assumption * that values will be negative, that is, the fixup table has to be * located after the code it fixes up. +* +* Please ensure that new section names, modifications to FTR_ENTRY +* encoding, etc., is handled by arch/powerpc/tools/relocs/ code. */ #if defined(CONFIG_PPC64 ) && !defined(__powerpc64__)/* 64 bits kernel, 32 bits code (ie. vdso32) */
@@ -33,7 +36,7 @@#define FTR_SECTION_ELSE_NESTED (label) \ label##2: \ - .pushsection __ftr_alt_##label,"a"; \ + .pushsection __ftr_alt_##label,"ax"; \ .align 2; \ label##3:
arch/powerpc/kernel/vmlinux.lds.S +5 -3
@@ -85,8 +85,7 @@ SECTIONS .text : AT(ADDR(.text) - LOAD_OFFSET) { ALIGN_FUNCTION(); #endif - /* careful! __ftr_alt_* sections need to be close to .text */ - *(.text.hot .text .text.fixup .text.unlikely .fixup __ftr_alt_* .ref.text); + *(.text.hot .text .text.fixup .text.unlikely .fixup .ref.text); SCHED_TEXT CPUIDLE_TEXT LOCK_TEXT
@@ -110,7 +109,6 @@ SECTIONS *(.got2) __got2_end = .; #endif /* CONFIG_PPC32 */ - } :kernel . = ALIGN(PAGE_SIZE);
@@ -139,6 +137,10 @@ SECTIONS __init_begin = .; INIT_TEXT_SECTION(PAGE_SIZE) :kernel + .__ftr_alternates.text : AT(ADDR(.__ftr_alternates.text) - LOAD_OFFSET) { + *(__ftr_alt*); + } + /* .exit.text is discarded at runtime, not link time, * to deal with references from __bug_table */
arch/powerpc/lib/feature-fixups.c +6 -13
@@ -46,20 +46,13 @@ static unsigned int *calc_addr(struct fixup_entry *fcur, long offset)static int patch_alt_instruction (unsigned int *src,unsigned int *dest,unsigned int *alt_start,unsigned int *alt_end) { -unsigned int instr; +unsigned int instr = *src; - instr = *src; - -if (instr_is_relative_branch (*src)) { -unsigned int *target = (unsigned int *)branch_target (src); - -/* Branch within the section doesn't need translating */ -if (target < alt_start || target >= alt_end) { - instr =translate_branch (dest, src); -if (!instr) -return 1 ; - } - } +/* +* We used to translate relative branches here, however we now +* do that by fixing up relocations after link with process_relocs +* tool in arch/powerpc/tools/relocs/ +*/ patch_instruction (dest, instr);
arch/powerpc/tools/Makefile new file +3 -0
@@ -0,0 +1,3 @@ +always := $(hostprogs-y) $(hostprogs-m) + +subdir-y += relocs
arch/powerpc/tools/relocs/.gitignore new file +1 -0
@@ -0,0 +1 @@ +process_relocs
arch/powerpc/tools/relocs/Makefile new file +12 -0
@@ -0,0 +1,12 @@ +HOST_EXTRACFLAGS += -Wno-unused-function +ifdef CONFIG_DEBUG_BUGVERBOSE +HOST_EXTRACFLAGS += -DCONFIG_DEBUG_BUGVERBOSE +endif + +hostprogs-y := process_relocs + +process_relocs-objs := process_relocs.o elf_sections.o code-patching.o + +always := $(hostprogs-y) + +HOSTLOADLIBES_process_relocs += -lelf
arch/powerpc/tools/relocs/code-patching.c new file +82 -0
82 lines not on this page · raw message
arch/powerpc/tools/relocs/code-patching.h new file +7 -0
@@ -0,0 +1,7 @@ +#ifndef __CODE_PATCHING_H__ +#define __CODE_PATCHING_H__ + +int set_branch_target (uint32_t *insn, +const uint64_t addr,uint64_t target); + +#endif
arch/powerpc/tools/relocs/elf_sections.c new file +337 -0
337 lines not on this page · raw message
arch/powerpc/tools/relocs/elf_sections.h new file +50 -0
50 lines not on this page · raw message
arch/powerpc/tools/relocs/process_relocs.c new file +715 -0
715 lines not on this page · raw message
Signature · 1 line
2.11.0