Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: module: add support for place relative relocations

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>

+23 -2
+5
arch/arm/include/asm/elf.h
··· 51 51 #define R_ARM_NONE 0 52 52 #define R_ARM_PC24 1 53 53 #define R_ARM_ABS32 2 54 + #define R_ARM_REL32 3 54 55 #define R_ARM_CALL 28 55 56 #define R_ARM_JUMP24 29 56 57 #define R_ARM_TARGET1 38 ··· 59 58 #define R_ARM_PREL31 42 60 59 #define R_ARM_MOVW_ABS_NC 43 61 60 #define R_ARM_MOVT_ABS 44 61 + #define R_ARM_MOVW_PREL_NC 45 62 + #define R_ARM_MOVT_PREL 46 62 63 63 64 #define R_ARM_THM_CALL 10 64 65 #define R_ARM_THM_JUMP24 30 65 66 #define R_ARM_THM_MOVW_ABS_NC 47 66 67 #define R_ARM_THM_MOVT_ABS 48 68 + #define R_ARM_THM_MOVW_PREL_NC 49 69 + #define R_ARM_THM_MOVT_PREL 50 67 70 68 71 /* 69 72 * These are used to set parameters in the core dumps.
+18 -2
arch/arm/kernel/module.c
··· 185 185 *(u32 *)loc |= offset & 0x7fffffff; 186 186 break; 187 187 188 + case R_ARM_REL32: 189 + *(u32 *)loc += sym->st_value - loc; 190 + break; 191 + 188 192 case R_ARM_MOVW_ABS_NC: 189 193 case R_ARM_MOVT_ABS: 194 + case R_ARM_MOVW_PREL_NC: 195 + case R_ARM_MOVT_PREL: 190 196 offset = tmp = __mem_to_opcode_arm(*(u32 *)loc); 191 197 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff); 192 198 offset = (offset ^ 0x8000) - 0x8000; 193 199 194 200 offset += sym->st_value; 195 - if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS) 201 + if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_PREL || 202 + ELF32_R_TYPE(rel->r_info) == R_ARM_MOVW_PREL_NC) 203 + offset -= loc; 204 + if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS || 205 + ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_PREL) 196 206 offset >>= 16; 197 207 198 208 tmp &= 0xfff0f000; ··· 293 283 294 284 case R_ARM_THM_MOVW_ABS_NC: 295 285 case R_ARM_THM_MOVT_ABS: 286 + case R_ARM_THM_MOVW_PREL_NC: 287 + case R_ARM_THM_MOVT_PREL: 296 288 upper = __mem_to_opcode_thumb16(*(u16 *)loc); 297 289 lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2)); 298 290 ··· 314 302 offset = (offset ^ 0x8000) - 0x8000; 315 303 offset += sym->st_value; 316 304 317 - if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS) 305 + if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_PREL || 306 + ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVW_PREL_NC) 307 + offset -= loc; 308 + if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS || 309 + ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_PREL) 318 310 offset >>= 16; 319 311 320 312 upper = (u16)((upper & 0xfbf0) |