1 // SPDX-License-Identifier: GPL-2.0-only 1 2 /* 3 * linux/arch/arm/kernel/module.c 4 * 5 * Copyright (C) 2002 Russell King. 6 * Modified for nommu by Hyok S. Choi 7 * 8 * Module allocation method suggested by Andi 9 */ 10 #include <linux/module.h> 11 #include <linux/moduleloader.h> 12 #include <linux/kernel.h> 13 #include <linux/mm.h> 14 #include <linux/elf.h> 15 #include <linux/fs.h> 16 #include <linux/string.h> 17 18 #include <asm/sections.h> 19 #include <asm/smp_plat.h> 20 #include <asm/unwind.h> 21 #include <asm/opcodes.h> 22 23 bool module_init_section(const char *name) 24 { 25 return strstarts(name, ".init") || 26 strstarts(name, ".ARM.extab.in 27 strstarts(name, ".ARM.exidx.in 28 } 29 30 bool module_exit_section(const char *name) 31 { 32 return strstarts(name, ".exit") || 33 strstarts(name, ".ARM.extab.ex 34 strstarts(name, ".ARM.exidx.ex 35 } 36 37 #ifdef CONFIG_ARM_HAS_GROUP_RELOCS 38 /* 39 * This implements the partitioning algorithm 40 * documented in the ARM AArch32 ELF psABI (IH 41 * 42 * A single PC-relative symbol reference is di 43 * operations, where the final one could be in 44 * instruction with immediate offset. E.g., 45 * 46 * ADD Rd, PC, #... or 47 * ADD Rd, Rd, #... 48 * LDR Rd, [Rd, #...] 49 * 50 * The latter has a guaranteed range of only 1 51 * of limited use in the kernel. However, the 52 * -/+ 256 MiB, (2x8 + 12 == 28 bits), which m 53 * any in-kernel symbol reference (unless modu 54 * 55 * The main advantage of this approach over th 56 * load is that literal loads may miss in the 57 * lower cache efficiency for variables that a 58 * different places in the code. 59 */ 60 static u32 get_group_rem(u32 group, u32 *offse 61 { 62 u32 val = *offset; 63 u32 shift; 64 do { 65 shift = val ? (31 - __fls(val) 66 *offset = val; 67 if (!val) 68 break; 69 val &= 0xffffff >> shift; 70 } while (group--); 71 return shift; 72 } 73 #endif 74 75 int 76 apply_relocate(Elf32_Shdr *sechdrs, const char 77 unsigned int relindex, struct m 78 { 79 Elf32_Shdr *symsec = sechdrs + syminde 80 Elf32_Shdr *relsec = sechdrs + relinde 81 Elf32_Shdr *dstsec = sechdrs + relsec- 82 Elf32_Rel *rel = (void *)relsec->sh_ad 83 unsigned int i; 84 85 for (i = 0; i < relsec->sh_size / size 86 unsigned long loc; 87 Elf32_Sym *sym; 88 const char *symname; 89 #ifdef CONFIG_ARM_HAS_GROUP_RELOCS 90 u32 shift, group = 1; 91 #endif 92 s32 offset; 93 u32 tmp; 94 #ifdef CONFIG_THUMB2_KERNEL 95 u32 upper, lower, sign, j1, j2 96 #endif 97 98 offset = ELF32_R_SYM(rel->r_in 99 if (offset < 0 || offset > (sy 100 pr_err("%s: section %u 101 module->name, 102 return -ENOEXEC; 103 } 104 105 sym = ((Elf32_Sym *)symsec->sh 106 symname = strtab + sym->st_nam 107 108 if (rel->r_offset < 0 || rel-> 109 pr_err("%s: section %u 110 module->name, r 111 rel->r_offset, 112 return -ENOEXEC; 113 } 114 115 loc = dstsec->sh_addr + rel->r 116 117 switch (ELF32_R_TYPE(rel->r_in 118 case R_ARM_NONE: 119 /* ignore */ 120 break; 121 122 case R_ARM_ABS32: 123 case R_ARM_TARGET1: 124 *(u32 *)loc += sym->st 125 break; 126 127 case R_ARM_PC24: 128 case R_ARM_CALL: 129 case R_ARM_JUMP24: 130 if (sym->st_value & 3) 131 pr_err("%s: se 132 module- 133 return -ENOEXE 134 } 135 136 offset = __mem_to_opco 137 offset = (offset & 0x0 138 offset = sign_extend32 139 140 offset += sym->st_valu 141 142 /* 143 * Route through a PLT 144 * supported range. No 145 * contains the absolu 146 * @sym + addend, corr 147 */ 148 if (IS_ENABLED(CONFIG_ 149 (offset <= (s32)0x 150 offset >= (s32)0x 151 offset = get_m 152 153 - loc 154 155 if (offset <= (s32)0xf 156 offset >= (s32)0x0 157 pr_err("%s: se 158 module- 159 ELF32_R 160 sym->st 161 return -ENOEXE 162 } 163 164 offset >>= 2; 165 offset &= 0x00ffffff; 166 167 *(u32 *)loc &= __opcod 168 *(u32 *)loc |= __opcod 169 break; 170 171 case R_ARM_V4BX: 172 /* Preserve Rm and the 173 * other bits to re-cod 174 * MOV PC,Rm. 175 */ 176 *(u32 *)loc &= __opcode 177 *(u32 *)loc |= __opcode 178 break; 179 180 case R_ARM_PREL31: 181 offset = (*(s32 *)loc 182 offset += sym->st_valu 183 if (offset >= 0x400000 184 pr_err("%s: se 185 module- 186 ELF32_R 187 sym->st 188 return -ENOEXE 189 } 190 *(u32 *)loc &= 0x80000 191 *(u32 *)loc |= offset 192 break; 193 194 case R_ARM_REL32: 195 *(u32 *)loc += sym->st 196 break; 197 198 case R_ARM_MOVW_ABS_NC: 199 case R_ARM_MOVT_ABS: 200 case R_ARM_MOVW_PREL_NC: 201 case R_ARM_MOVT_PREL: 202 offset = tmp = __mem_t 203 offset = ((offset & 0x 204 offset = sign_extend32 205 206 offset += sym->st_valu 207 if (ELF32_R_TYPE(rel-> 208 ELF32_R_TYPE(rel-> 209 offset -= loc; 210 if (ELF32_R_TYPE(rel-> 211 ELF32_R_TYPE(rel-> 212 offset >>= 16; 213 214 tmp &= 0xfff0f000; 215 tmp |= ((offset & 0xf0 216 (offset & 0x0f 217 218 *(u32 *)loc = __opcode 219 break; 220 221 #ifdef CONFIG_ARM_HAS_GROUP_RELOCS 222 case R_ARM_ALU_PC_G0_NC: 223 group = 0; 224 fallthrough; 225 case R_ARM_ALU_PC_G1_NC: 226 tmp = __mem_to_opcode_ 227 offset = ror32(tmp & 0 228 if (tmp & BIT(22)) 229 offset = -offs 230 offset += sym->st_valu 231 if (offset < 0) { 232 offset = -offs 233 tmp = (tmp & ~ 234 } else { 235 tmp = (tmp & ~ 236 } 237 238 shift = get_group_rem( 239 if (shift < 24) { 240 offset >>= 24 241 offset |= (shi 242 } 243 *(u32 *)loc = __opcode 244 break; 245 246 case R_ARM_LDR_PC_G2: 247 tmp = __mem_to_opcode_ 248 offset = tmp & 0xfff; 249 if (~tmp & BIT(23)) 250 offset = -offs 251 offset += sym->st_valu 252 if (offset < 0) { 253 offset = -offs 254 tmp &= ~BIT(23 255 } else { 256 tmp |= BIT(23) 257 } 258 get_group_rem(2, &offs 259 260 if (offset > 0xfff) { 261 pr_err("%s: se 262 module- 263 ELF32_R 264 sym->st 265 return -ENOEXE 266 } 267 *(u32 *)loc = __opcode 268 break; 269 #endif 270 #ifdef CONFIG_THUMB2_KERNEL 271 case R_ARM_THM_CALL: 272 case R_ARM_THM_JUMP24: 273 /* 274 * For function symbol 275 * allowed (no interwo 276 * 277 * For non-function sy 278 * has no specific ARM 279 * the branch is resol 280 * that interworking i 281 */ 282 if (ELF32_ST_TYPE(sym- 283 !(sym->st_value & 284 pr_err("%s: se 285 module- 286 return -ENOEXE 287 } 288 289 upper = __mem_to_opcod 290 lower = __mem_to_opcod 291 292 /* 293 * 25 bit signed addre 294 * instructions): 295 * S:I1:I2:imm10:imm 296 * where: 297 * S = upper[10] 298 * I1 = ~(J1 ^ S) 299 * I2 = ~(J2 ^ S) 300 * imm10 = upper[9:0 301 * imm11 = lower[10: 302 * J1 = lower[13] 303 * J2 = lower[11] 304 */ 305 sign = (upper >> 10) & 306 j1 = (lower >> 13) & 1 307 j2 = (lower >> 11) & 1 308 offset = (sign << 24) 309 ((~(j2 ^ sign) 310 ((upper & 0x03 311 ((lower & 0x07 312 offset = sign_extend32 313 offset += sym->st_valu 314 315 /* 316 * Route through a PLT 317 * supported range. 318 */ 319 if (IS_ENABLED(CONFIG_ 320 (offset <= (s32)0x 321 offset >= (s32)0x 322 offset = get_m 323 324 - loc 325 326 if (offset <= (s32)0xf 327 offset >= (s32)0x0 328 pr_err("%s: se 329 module- 330 ELF32_R 331 sym->st 332 return -ENOEXE 333 } 334 335 sign = (offset >> 24) 336 j1 = sign ^ (~(offset 337 j2 = sign ^ (~(offset 338 upper = (u16)((upper & 339 (( 340 lower = (u16)((lower & 341 (j1 << 1 342 ((offset 343 344 *(u16 *)loc = __opcode 345 *(u16 *)(loc + 2) = __ 346 break; 347 348 case R_ARM_THM_MOVW_ABS_NC: 349 case R_ARM_THM_MOVT_ABS: 350 case R_ARM_THM_MOVW_PREL_NC: 351 case R_ARM_THM_MOVT_PREL: 352 upper = __mem_to_opcod 353 lower = __mem_to_opcod 354 355 /* 356 * MOVT/MOVW instructi 357 * 358 * i = upper[10] 359 * imm4 = upper[3:0] 360 * imm3 = lower[14:12] 361 * imm8 = lower[7:0] 362 * 363 * imm16 = imm4:i:imm3 364 */ 365 offset = ((upper & 0x0 366 ((upper & 0x04 367 ((lower & 0x70 368 offset = sign_extend32 369 offset += sym->st_valu 370 371 if (ELF32_R_TYPE(rel-> 372 ELF32_R_TYPE(rel-> 373 offset -= loc; 374 if (ELF32_R_TYPE(rel-> 375 ELF32_R_TYPE(rel-> 376 offset >>= 16; 377 378 upper = (u16)((upper & 379 ((offset 380 ((offset 381 lower = (u16)((lower & 382 ((offset 383 (offset 384 *(u16 *)loc = __opcode 385 *(u16 *)(loc + 2) = __ 386 break; 387 #endif 388 389 default: 390 pr_err("%s: unknown re 391 module->name, E 392 return -ENOEXEC; 393 } 394 } 395 return 0; 396 } 397 398 static const Elf_Shdr *find_mod_section(const 399 const Elf_Shdr *sechdrs, const char *n 400 { 401 const Elf_Shdr *s, *se; 402 const char *secstrs = (void *)hdr + se 403 404 for (s = sechdrs, se = sechdrs + hdr-> 405 if (strcmp(name, secstrs + s-> 406 return s; 407 408 return NULL; 409 } 410 411 extern void fixup_pv_table(const void *, unsig 412 extern void fixup_smp(const void *, unsigned l 413 414 int module_finalize(const Elf32_Ehdr *hdr, con 415 struct module *mod) 416 { 417 const Elf_Shdr *s = NULL; 418 #ifdef CONFIG_ARM_UNWIND 419 const char *secstrs = (void *)hdr + se 420 const Elf_Shdr *sechdrs_end = sechdrs 421 struct list_head *unwind_list = &mod-> 422 423 INIT_LIST_HEAD(unwind_list); 424 mod->arch.init_table = NULL; 425 426 for (s = sechdrs; s < sechdrs_end; s++ 427 const char *secname = secstrs 428 const char *txtname; 429 const Elf_Shdr *txt_sec; 430 431 if (!(s->sh_flags & SHF_ALLOC) 432 s->sh_type != ELF_SECTION_ 433 continue; 434 435 if (!strcmp(".ARM.exidx", secn 436 txtname = ".text"; 437 else 438 txtname = secname + st 439 txt_sec = find_mod_section(hdr 440 441 if (txt_sec) { 442 struct unwind_table *t 443 unwind_table_a 444 445 446 447 448 list_add(&table->mod_l 449 450 /* save init table for 451 if (strcmp(".ARM.exidx 452 mod->arch.init 453 } 454 } 455 #endif 456 #ifdef CONFIG_ARM_PATCH_PHYS_VIRT 457 s = find_mod_section(hdr, sechdrs, ".p 458 if (s) 459 fixup_pv_table((void *)s->sh_a 460 #endif 461 s = find_mod_section(hdr, sechdrs, ".a 462 if (s && !is_smp()) 463 #ifdef CONFIG_SMP_ON_UP 464 fixup_smp((void *)s->sh_addr, 465 #else 466 return -EINVAL; 467 #endif 468 return 0; 469 } 470 471 void 472 module_arch_cleanup(struct module *mod) 473 { 474 #ifdef CONFIG_ARM_UNWIND 475 struct unwind_table *tmp; 476 struct unwind_table *n; 477 478 list_for_each_entry_safe(tmp, n, 479 &mod->arch.unwind_list 480 list_del(&tmp->mod_list); 481 unwind_table_del(tmp); 482 } 483 mod->arch.init_table = NULL; 484 #endif 485 } 486 487 void __weak module_arch_freeing_init(struct mo 488 { 489 #ifdef CONFIG_ARM_UNWIND 490 struct unwind_table *init = mod->arch. 491 492 if (init) { 493 mod->arch.init_table = NULL; 494 list_del(&init->mod_list); 495 unwind_table_del(init); 496 } 497 #endif 498 } 499
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.