Commit 77e69ee7 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman

powerpc/64: modules support building with PCREL addresing

Build modules using PCREL addressing when CONFIG_PPC_KERNEL_PCREL=y.

- The module loader must handle several new relocation types:

  * R_PPC64_REL24_NOTOC is a function call handled like R_PPC_REL24, but
    does not restore r2 upon return. The external function call stub is
    changed to use pcrel addressing to load the function pointer rather
    than based on the module TOC.

  * R_PPC64_GOT_PCREL34 is a reference to external data. A GOT table
    must be built by hand, because the linker adds this during the final
    link (which is not done for kernel modules). The GOT table is built
    similarly to the way the external function call stub table is. This
    section is called .mygot because .got has a special meaning for the
    linker and can become upset.

  * R_PPC64_PCREL34 is used for local data addressing, but there is a
    special case where the percpu section is moved at load-time to the
    percpu area which is out of range of this relocation. This requires
    the PCREL34 relocations are converted to use GOT_PCREL34 addressing.
Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
[mpe: Some coding style & formatting fixups]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230408021752.862660-7-npiggin@gmail.com
parent 7e3a68be
...@@ -107,9 +107,7 @@ LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) += -z notext ...@@ -107,9 +107,7 @@ LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) += -z notext
LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y) LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y)
ifdef CONFIG_PPC64 ifdef CONFIG_PPC64
ifdef CONFIG_PPC_KERNEL_PCREL ifndef CONFIG_PPC_KERNEL_PCREL
KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-pcrel)
endif
ifeq ($(call cc-option-yn,-mcmodel=medium),y) ifeq ($(call cc-option-yn,-mcmodel=medium),y)
# -mcmodel=medium breaks modules because it uses 32bit offsets from # -mcmodel=medium breaks modules because it uses 32bit offsets from
# the TOC pointer to create pointers where possible. Pointers into the # the TOC pointer to create pointers where possible. Pointers into the
...@@ -124,6 +122,7 @@ else ...@@ -124,6 +122,7 @@ else
export NO_MINIMAL_TOC := -mno-minimal-toc export NO_MINIMAL_TOC := -mno-minimal-toc
endif endif
endif endif
endif
CFLAGS-$(CONFIG_PPC64) := $(call cc-option,-mtraceback=no) CFLAGS-$(CONFIG_PPC64) := $(call cc-option,-mtraceback=no)
ifdef CONFIG_PPC64_ELF_ABI_V2 ifdef CONFIG_PPC64_ELF_ABI_V2
......
...@@ -27,8 +27,13 @@ struct ppc_plt_entry { ...@@ -27,8 +27,13 @@ struct ppc_plt_entry {
struct mod_arch_specific { struct mod_arch_specific {
#ifdef __powerpc64__ #ifdef __powerpc64__
unsigned int stubs_section; /* Index of stubs section in module */ unsigned int stubs_section; /* Index of stubs section in module */
#ifdef CONFIG_PPC_KERNEL_PCREL
unsigned int got_section; /* What section is the GOT? */
unsigned int pcpu_section; /* .data..percpu section */
#else
unsigned int toc_section; /* What section is the TOC? */ unsigned int toc_section; /* What section is the TOC? */
bool toc_fixed; /* Have we fixed up .TOC.? */ bool toc_fixed; /* Have we fixed up .TOC.? */
#endif
/* For module function descriptor dereference */ /* For module function descriptor dereference */
unsigned long start_opd; unsigned long start_opd;
...@@ -52,12 +57,15 @@ struct mod_arch_specific { ...@@ -52,12 +57,15 @@ struct mod_arch_specific {
/* /*
* Select ELF headers. * Select ELF headers.
* Make empty section for module_frob_arch_sections to expand. * Make empty sections for module_frob_arch_sections to expand.
*/ */
#ifdef __powerpc64__ #ifdef __powerpc64__
# ifdef MODULE # ifdef MODULE
asm(".section .stubs,\"ax\",@nobits; .align 3; .previous"); asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
# ifdef CONFIG_PPC_KERNEL_PCREL
asm(".section .mygot,\"a\",@nobits; .align 3; .previous");
# endif
# endif # endif
#else #else
# ifdef MODULE # ifdef MODULE
......
...@@ -183,7 +183,7 @@ ...@@ -183,7 +183,7 @@
/* /*
* Used to name C functions called from asm * Used to name C functions called from asm
*/ */
#if defined(CONFIG_PPC_KERNEL_PCREL) && !defined(MODULE) #ifdef CONFIG_PPC_KERNEL_PCREL
#define CFUNC(name) name@notoc #define CFUNC(name) name@notoc
#else #else
#define CFUNC(name) name #define CFUNC(name) name
...@@ -216,7 +216,7 @@ ...@@ -216,7 +216,7 @@
.globl name; \ .globl name; \
name: name:
#if defined(CONFIG_PPC_KERNEL_PCREL) && !defined(MODULE) #ifdef CONFIG_PPC_KERNEL_PCREL
#define _GLOBAL_TOC _GLOBAL #define _GLOBAL_TOC _GLOBAL
#else #else
#define _GLOBAL_TOC(name) \ #define _GLOBAL_TOC(name) \
...@@ -379,7 +379,7 @@ GLUE(.,name): ...@@ -379,7 +379,7 @@ GLUE(.,name):
ori reg, reg, (expr)@l; \ ori reg, reg, (expr)@l; \
rldimi reg, tmp, 32, 0 rldimi reg, tmp, 32, 0
#if defined(CONFIG_PPC_KERNEL_PCREL) && !defined(MODULE) #ifdef CONFIG_PPC_KERNEL_PCREL
#define LOAD_REG_ADDR(reg,name) \ #define LOAD_REG_ADDR(reg,name) \
pla reg,name@pcrel pla reg,name@pcrel
......
...@@ -279,8 +279,12 @@ typedef elf_fpreg_t elf_vsrreghalf_t32[ELF_NVSRHALFREG]; ...@@ -279,8 +279,12 @@ typedef elf_fpreg_t elf_vsrreghalf_t32[ELF_NVSRHALFREG];
#define R_PPC64_TLSLD 108 #define R_PPC64_TLSLD 108
#define R_PPC64_TOCSAVE 109 #define R_PPC64_TOCSAVE 109
#define R_PPC64_REL24_NOTOC 116
#define R_PPC64_ENTRY 118 #define R_PPC64_ENTRY 118
#define R_PPC64_PCREL34 132
#define R_PPC64_GOT_PCREL34 133
#define R_PPC64_REL16 249 #define R_PPC64_REL16 249
#define R_PPC64_REL16_LO 250 #define R_PPC64_REL16_LO 250
#define R_PPC64_REL16_HI 251 #define R_PPC64_REL16_HI 251
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment