ARM: module: add support for place relative relocations
authorArd Biesheuvel <ardb@kernel.org>
Mon, 14 Sep 2020 08:24:37 +0000 (11:24 +0300)
committerArd Biesheuvel <ardb@kernel.org>
Wed, 28 Oct 2020 15:59:43 +0000 (16:59 +0100)
When using the new adr_l/ldr_l/str_l macros to refer to external symbols
from modules, the linker may emit place relative ELF relocations that
need to be fixed up by the module loader. So add support for these.

Reviewed-by: Nicolas Pitre <nico@fluxnic.net>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
arch/arm/include/asm/elf.h
arch/arm/kernel/module.c

index b078d99..0ac62a5 100644 (file)
@@ -51,6 +51,7 @@ typedef struct user_fp elf_fpregset_t;
 #define R_ARM_NONE             0
 #define R_ARM_PC24             1
 #define R_ARM_ABS32            2
+#define R_ARM_REL32            3
 #define R_ARM_CALL             28
 #define R_ARM_JUMP24           29
 #define R_ARM_TARGET1          38
@@ -58,11 +59,15 @@ typedef struct user_fp elf_fpregset_t;
 #define R_ARM_PREL31           42
 #define R_ARM_MOVW_ABS_NC      43
 #define R_ARM_MOVT_ABS         44
+#define R_ARM_MOVW_PREL_NC     45
+#define R_ARM_MOVT_PREL                46
 
 #define R_ARM_THM_CALL         10
 #define R_ARM_THM_JUMP24       30
 #define R_ARM_THM_MOVW_ABS_NC  47
 #define R_ARM_THM_MOVT_ABS     48
+#define R_ARM_THM_MOVW_PREL_NC 49
+#define R_ARM_THM_MOVT_PREL    50
 
 /*
  * These are used to set parameters in the core dumps.
index e15444b..beac45e 100644 (file)
@@ -185,14 +185,24 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                        *(u32 *)loc |= offset & 0x7fffffff;
                        break;
 
+               case R_ARM_REL32:
+                       *(u32 *)loc += sym->st_value - loc;
+                       break;
+
                case R_ARM_MOVW_ABS_NC:
                case R_ARM_MOVT_ABS:
+               case R_ARM_MOVW_PREL_NC:
+               case R_ARM_MOVT_PREL:
                        offset = tmp = __mem_to_opcode_arm(*(u32 *)loc);
                        offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
                        offset = (offset ^ 0x8000) - 0x8000;
 
                        offset += sym->st_value;
-                       if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS)
+                       if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_PREL ||
+                           ELF32_R_TYPE(rel->r_info) == R_ARM_MOVW_PREL_NC)
+                               offset -= loc;
+                       if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS ||
+                           ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_PREL)
                                offset >>= 16;
 
                        tmp &= 0xfff0f000;
@@ -283,6 +293,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 
                case R_ARM_THM_MOVW_ABS_NC:
                case R_ARM_THM_MOVT_ABS:
+               case R_ARM_THM_MOVW_PREL_NC:
+               case R_ARM_THM_MOVT_PREL:
                        upper = __mem_to_opcode_thumb16(*(u16 *)loc);
                        lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2));
 
@@ -302,7 +314,11 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                        offset = (offset ^ 0x8000) - 0x8000;
                        offset += sym->st_value;
 
-                       if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS)
+                       if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_PREL ||
+                           ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVW_PREL_NC)
+                               offset -= loc;
+                       if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS ||
+                           ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_PREL)
                                offset >>= 16;
 
                        upper = (u16)((upper & 0xfbf0) |