1 // SPDX-License-Identifier: GPL-2.0-only << 2 /* 1 /* 3 * linux/arch/arm/kernel/module.c !! 2 * This program is free software; you can redistribute it and/or modify >> 3 * it under the terms of the GNU General Public License as published by >> 4 * the Free Software Foundation; either version 2 of the License, or >> 5 * (at your option) any later version. 4 * 6 * 5 * Copyright (C) 2002 Russell King. !! 7 * This program is distributed in the hope that it will be useful, 6 * Modified for nommu by Hyok S. Choi !! 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of >> 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> 10 * GNU General Public License for more details. 7 * 11 * 8 * Module allocation method suggested by Andi !! 12 * You should have received a copy of the GNU General Public License >> 13 * along with this program; if not, write to the Free Software >> 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >> 15 * >> 16 * Copyright (C) 2001 Rusty Russell. >> 17 * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org) >> 18 * Copyright (C) 2005 Thiemo Seufer 9 */ 19 */ 10 #include <linux/module.h> !! 20 >> 21 #undef DEBUG >> 22 >> 23 #include <linux/extable.h> 11 #include <linux/moduleloader.h> 24 #include <linux/moduleloader.h> 12 #include <linux/kernel.h> << 13 #include <linux/mm.h> << 14 #include <linux/elf.h> 25 #include <linux/elf.h> >> 26 #include <linux/mm.h> >> 27 #include <linux/numa.h> >> 28 #include <linux/vmalloc.h> >> 29 #include <linux/slab.h> 15 #include <linux/fs.h> 30 #include <linux/fs.h> 16 #include <linux/string.h> 31 #include <linux/string.h> >> 32 #include <linux/kernel.h> >> 33 #include <linux/spinlock.h> >> 34 #include <linux/jump_label.h> 17 35 18 #include <asm/sections.h> !! 36 #include <asm/pgtable.h> /* MODULE_START */ 19 #include <asm/smp_plat.h> << 20 #include <asm/unwind.h> << 21 #include <asm/opcodes.h> << 22 37 23 bool module_init_section(const char *name) !! 38 struct mips_hi16 { 24 { !! 39 struct mips_hi16 *next; 25 return strstarts(name, ".init") || !! 40 Elf_Addr *addr; 26 strstarts(name, ".ARM.extab.in !! 41 Elf_Addr value; 27 strstarts(name, ".ARM.exidx.in !! 42 }; 28 } << 29 43 30 bool module_exit_section(const char *name) !! 44 static LIST_HEAD(dbe_list); 31 { !! 45 static DEFINE_SPINLOCK(dbe_lock); 32 return strstarts(name, ".exit") || << 33 strstarts(name, ".ARM.extab.ex << 34 strstarts(name, ".ARM.exidx.ex << 35 } << 36 46 37 #ifdef CONFIG_ARM_HAS_GROUP_RELOCS !! 47 #ifdef MODULE_START 38 /* !! 48 void *module_alloc(unsigned long size) 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 { 49 { 62 u32 val = *offset; !! 50 return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, 63 u32 shift; !! 51 GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, 64 do { !! 52 __builtin_return_address(0)); 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 } 53 } 73 #endif 54 #endif 74 55 75 int !! 56 static int apply_r_mips_none(struct module *me, u32 *location, 76 apply_relocate(Elf32_Shdr *sechdrs, const char !! 57 u32 base, Elf_Addr v, bool rela) 77 unsigned int relindex, struct m !! 58 { 78 { !! 59 return 0; 79 Elf32_Shdr *symsec = sechdrs + syminde !! 60 } 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 61 98 offset = ELF32_R_SYM(rel->r_in !! 62 static int apply_r_mips_32(struct module *me, u32 *location, 99 if (offset < 0 || offset > (sy !! 63 u32 base, Elf_Addr v, bool rela) 100 pr_err("%s: section %u !! 64 { 101 module->name, !! 65 *location = base + v; 102 return -ENOEXEC; << 103 } << 104 66 105 sym = ((Elf32_Sym *)symsec->sh !! 67 return 0; 106 symname = strtab + sym->st_nam !! 68 } 107 69 108 if (rel->r_offset < 0 || rel-> !! 70 static int apply_r_mips_26(struct module *me, u32 *location, 109 pr_err("%s: section %u !! 71 u32 base, Elf_Addr v, bool rela) 110 module->name, r !! 72 { 111 rel->r_offset, !! 73 if (v % 4) { 112 return -ENOEXEC; !! 74 pr_err("module %s: dangerous R_MIPS_26 relocation\n", 113 } !! 75 me->name); >> 76 return -ENOEXEC; >> 77 } 114 78 115 loc = dstsec->sh_addr + rel->r !! 79 if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { >> 80 pr_err("module %s: relocation overflow\n", >> 81 me->name); >> 82 return -ENOEXEC; >> 83 } 116 84 117 switch (ELF32_R_TYPE(rel->r_in !! 85 *location = (*location & ~0x03ffffff) | 118 case R_ARM_NONE: !! 86 ((base + (v >> 2)) & 0x03ffffff); 119 /* ignore */ << 120 break; << 121 87 122 case R_ARM_ABS32: !! 88 return 0; 123 case R_ARM_TARGET1: !! 89 } 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 90 140 offset += sym->st_valu !! 91 static int apply_r_mips_hi16(struct module *me, u32 *location, >> 92 u32 base, Elf_Addr v, bool rela) >> 93 { >> 94 struct mips_hi16 *n; 141 95 142 /* !! 96 if (rela) { 143 * Route through a PLT !! 97 *location = (*location & 0xffff0000) | 144 * supported range. No !! 98 ((((long long) v + 0x8000LL) >> 16) & 0xffff); 145 * contains the absolu !! 99 return 0; 146 * @sym + addend, corr !! 100 } 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 101 164 offset >>= 2; !! 102 /* 165 offset &= 0x00ffffff; !! 103 * We cannot relocate this one now because we don't know the value of >> 104 * the carry we need to add. Save the information, and let LO16 do the >> 105 * actual relocation. >> 106 */ >> 107 n = kmalloc(sizeof *n, GFP_KERNEL); >> 108 if (!n) >> 109 return -ENOMEM; >> 110 >> 111 n->addr = (Elf_Addr *)location; >> 112 n->value = v; >> 113 n->next = me->arch.r_mips_hi16_list; >> 114 me->arch.r_mips_hi16_list = n; 166 115 167 *(u32 *)loc &= __opcod !! 116 return 0; 168 *(u32 *)loc |= __opcod !! 117 } 169 break; << 170 118 171 case R_ARM_V4BX: !! 119 static void free_relocation_chain(struct mips_hi16 *l) 172 /* Preserve Rm and the !! 120 { 173 * other bits to re-cod !! 121 struct mips_hi16 *next; 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 122 194 case R_ARM_REL32: !! 123 while (l) { 195 *(u32 *)loc += sym->st !! 124 next = l->next; 196 break; !! 125 kfree(l); >> 126 l = next; >> 127 } >> 128 } 197 129 198 case R_ARM_MOVW_ABS_NC: !! 130 static int apply_r_mips_lo16(struct module *me, u32 *location, 199 case R_ARM_MOVT_ABS: !! 131 u32 base, Elf_Addr v, bool rela) 200 case R_ARM_MOVW_PREL_NC: !! 132 { 201 case R_ARM_MOVT_PREL: !! 133 unsigned long insnlo = base; 202 offset = tmp = __mem_t !! 134 struct mips_hi16 *l; 203 offset = ((offset & 0x !! 135 Elf_Addr val, vallo; 204 offset = sign_extend32 !! 136 205 !! 137 if (rela) { 206 offset += sym->st_valu !! 138 *location = (*location & 0xffff0000) | (v & 0xffff); 207 if (ELF32_R_TYPE(rel-> !! 139 return 0; 208 ELF32_R_TYPE(rel-> !! 140 } 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 141 218 *(u32 *)loc = __opcode !! 142 /* Sign extend the addend we extract from the lo insn. */ 219 break; !! 143 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; 220 144 221 #ifdef CONFIG_ARM_HAS_GROUP_RELOCS !! 145 if (me->arch.r_mips_hi16_list != NULL) { 222 case R_ARM_ALU_PC_G0_NC: !! 146 l = me->arch.r_mips_hi16_list; 223 group = 0; !! 147 while (l != NULL) { 224 fallthrough; !! 148 struct mips_hi16 *next; 225 case R_ARM_ALU_PC_G1_NC: !! 149 unsigned long insn; 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 150 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 /* 151 /* 274 * For function symbol !! 152 * The value for the HI16 had best be the same. 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 */ 153 */ 282 if (ELF32_ST_TYPE(sym- !! 154 if (v != l->value) 283 !(sym->st_value & !! 155 goto out_danger; 284 pr_err("%s: se << 285 module- << 286 return -ENOEXE << 287 } << 288 << 289 upper = __mem_to_opcod << 290 lower = __mem_to_opcod << 291 156 292 /* 157 /* 293 * 25 bit signed addre !! 158 * Do the HI16 relocation. Note that we actually don't 294 * instructions): !! 159 * need to know anything about the LO16 itself, except 295 * S:I1:I2:imm10:imm !! 160 * where to find the low 16 bits of the addend needed 296 * where: !! 161 * by the LO16. 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 */ 162 */ 305 sign = (upper >> 10) & !! 163 insn = *l->addr; 306 j1 = (lower >> 13) & 1 !! 164 val = ((insn & 0xffff) << 16) + vallo; 307 j2 = (lower >> 11) & 1 !! 165 val += v; 308 offset = (sign << 24) << 309 ((~(j2 ^ sign) << 310 ((upper & 0x03 << 311 ((lower & 0x07 << 312 offset = sign_extend32 << 313 offset += sym->st_valu << 314 166 315 /* 167 /* 316 * Route through a PLT !! 168 * Account for the sign extension that will happen in 317 * supported range. !! 169 * the low bits. 318 */ 170 */ 319 if (IS_ENABLED(CONFIG_ !! 171 val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff; 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 172 344 *(u16 *)loc = __opcode !! 173 insn = (insn & ~0xffff) | val; 345 *(u16 *)(loc + 2) = __ !! 174 *l->addr = insn; 346 break; !! 175 >> 176 next = l->next; >> 177 kfree(l); >> 178 l = next; >> 179 } 347 180 348 case R_ARM_THM_MOVW_ABS_NC: !! 181 me->arch.r_mips_hi16_list = NULL; 349 case R_ARM_THM_MOVT_ABS: !! 182 } 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 183 355 /* !! 184 /* 356 * MOVT/MOVW instructi !! 185 * Ok, we're done with the HI16 relocs. Now deal with the LO16. 357 * !! 186 */ 358 * i = upper[10] !! 187 val = v + vallo; 359 * imm4 = upper[3:0] !! 188 insnlo = (insnlo & ~0xffff) | (val & 0xffff); 360 * imm3 = lower[14:12] !! 189 *location = insnlo; 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 190 389 default: !! 191 return 0; 390 pr_err("%s: unknown re !! 192 391 module->name, E !! 193 out_danger: 392 return -ENOEXEC; !! 194 free_relocation_chain(l); 393 } !! 195 me->arch.r_mips_hi16_list = NULL; >> 196 >> 197 pr_err("module %s: dangerous R_MIPS_LO16 relocation\n", me->name); >> 198 >> 199 return -ENOEXEC; >> 200 } >> 201 >> 202 static int apply_r_mips_pc(struct module *me, u32 *location, u32 base, >> 203 Elf_Addr v, unsigned int bits) >> 204 { >> 205 unsigned long mask = GENMASK(bits - 1, 0); >> 206 unsigned long se_bits; >> 207 long offset; >> 208 >> 209 if (v % 4) { >> 210 pr_err("module %s: dangerous R_MIPS_PC%u relocation\n", >> 211 me->name, bits); >> 212 return -ENOEXEC; >> 213 } >> 214 >> 215 /* retrieve & sign extend implicit addend if any */ >> 216 offset = base & mask; >> 217 offset |= (offset & BIT(bits - 1)) ? ~mask : 0; >> 218 >> 219 offset += ((long)v - (long)location) >> 2; >> 220 >> 221 /* check the sign bit onwards are identical - ie. we didn't overflow */ >> 222 se_bits = (offset & BIT(bits - 1)) ? ~0ul : 0; >> 223 if ((offset & ~mask) != (se_bits & ~mask)) { >> 224 pr_err("module %s: relocation overflow\n", me->name); >> 225 return -ENOEXEC; 394 } 226 } >> 227 >> 228 *location = (*location & ~mask) | (offset & mask); >> 229 395 return 0; 230 return 0; 396 } 231 } 397 232 398 static const Elf_Shdr *find_mod_section(const !! 233 static int apply_r_mips_pc16(struct module *me, u32 *location, 399 const Elf_Shdr *sechdrs, const char *n !! 234 u32 base, Elf_Addr v, bool rela) >> 235 { >> 236 return apply_r_mips_pc(me, location, base, v, 16); >> 237 } >> 238 >> 239 static int apply_r_mips_pc21(struct module *me, u32 *location, >> 240 u32 base, Elf_Addr v, bool rela) >> 241 { >> 242 return apply_r_mips_pc(me, location, base, v, 21); >> 243 } >> 244 >> 245 static int apply_r_mips_pc26(struct module *me, u32 *location, >> 246 u32 base, Elf_Addr v, bool rela) 400 { 247 { 401 const Elf_Shdr *s, *se; !! 248 return apply_r_mips_pc(me, location, base, v, 26); 402 const char *secstrs = (void *)hdr + se !! 249 } >> 250 >> 251 static int apply_r_mips_64(struct module *me, u32 *location, >> 252 u32 base, Elf_Addr v, bool rela) >> 253 { >> 254 if (WARN_ON(!rela)) >> 255 return -EINVAL; 403 256 404 for (s = sechdrs, se = sechdrs + hdr-> !! 257 *(Elf_Addr *)location = v; 405 if (strcmp(name, secstrs + s-> << 406 return s; << 407 258 408 return NULL; !! 259 return 0; 409 } 260 } 410 261 411 extern void fixup_pv_table(const void *, unsig !! 262 static int apply_r_mips_higher(struct module *me, u32 *location, 412 extern void fixup_smp(const void *, unsigned l !! 263 u32 base, Elf_Addr v, bool rela) >> 264 { >> 265 if (WARN_ON(!rela)) >> 266 return -EINVAL; >> 267 >> 268 *location = (*location & 0xffff0000) | >> 269 ((((long long)v + 0x80008000LL) >> 32) & 0xffff); 413 270 414 int module_finalize(const Elf32_Ehdr *hdr, con !! 271 return 0; 415 struct module *mod) !! 272 } >> 273 >> 274 static int apply_r_mips_highest(struct module *me, u32 *location, >> 275 u32 base, Elf_Addr v, bool rela) 416 { 276 { 417 const Elf_Shdr *s = NULL; !! 277 if (WARN_ON(!rela)) 418 #ifdef CONFIG_ARM_UNWIND !! 278 return -EINVAL; 419 const char *secstrs = (void *)hdr + se << 420 const Elf_Shdr *sechdrs_end = sechdrs << 421 struct list_head *unwind_list = &mod-> << 422 279 423 INIT_LIST_HEAD(unwind_list); !! 280 *location = (*location & 0xffff0000) | 424 mod->arch.init_table = NULL; !! 281 ((((long long)v + 0x800080008000LL) >> 48) & 0xffff); 425 282 426 for (s = sechdrs; s < sechdrs_end; s++ !! 283 return 0; 427 const char *secname = secstrs !! 284 } 428 const char *txtname; << 429 const Elf_Shdr *txt_sec; << 430 285 431 if (!(s->sh_flags & SHF_ALLOC) !! 286 /** 432 s->sh_type != ELF_SECTION_ !! 287 * reloc_handler() - Apply a particular relocation to a module 433 continue; !! 288 * @me: the module to apply the reloc to >> 289 * @location: the address at which the reloc is to be applied >> 290 * @base: the existing value at location for REL-style; 0 for RELA-style >> 291 * @v: the value of the reloc, with addend for RELA-style >> 292 * >> 293 * Each implemented reloc_handler function applies a particular type of >> 294 * relocation to the module @me. Relocs that may be found in either REL or RELA >> 295 * variants can be handled by making use of the @base & @v parameters which are >> 296 * set to values which abstract the difference away from the particular reloc >> 297 * implementations. >> 298 * >> 299 * Return: 0 upon success, else -ERRNO >> 300 */ >> 301 typedef int (*reloc_handler)(struct module *me, u32 *location, >> 302 u32 base, Elf_Addr v, bool rela); >> 303 >> 304 /* The handlers for known reloc types */ >> 305 static reloc_handler reloc_handlers[] = { >> 306 [R_MIPS_NONE] = apply_r_mips_none, >> 307 [R_MIPS_32] = apply_r_mips_32, >> 308 [R_MIPS_26] = apply_r_mips_26, >> 309 [R_MIPS_HI16] = apply_r_mips_hi16, >> 310 [R_MIPS_LO16] = apply_r_mips_lo16, >> 311 [R_MIPS_PC16] = apply_r_mips_pc16, >> 312 [R_MIPS_64] = apply_r_mips_64, >> 313 [R_MIPS_HIGHER] = apply_r_mips_higher, >> 314 [R_MIPS_HIGHEST] = apply_r_mips_highest, >> 315 [R_MIPS_PC21_S2] = apply_r_mips_pc21, >> 316 [R_MIPS_PC26_S2] = apply_r_mips_pc26, >> 317 }; >> 318 >> 319 static int __apply_relocate(Elf_Shdr *sechdrs, const char *strtab, >> 320 unsigned int symindex, unsigned int relsec, >> 321 struct module *me, bool rela) >> 322 { >> 323 union { >> 324 Elf_Mips_Rel *rel; >> 325 Elf_Mips_Rela *rela; >> 326 } r; >> 327 reloc_handler handler; >> 328 Elf_Sym *sym; >> 329 u32 *location, base; >> 330 unsigned int i, type; >> 331 Elf_Addr v; >> 332 int err = 0; >> 333 size_t reloc_sz; >> 334 >> 335 pr_debug("Applying relocate section %u to %u\n", relsec, >> 336 sechdrs[relsec].sh_info); >> 337 >> 338 r.rel = (void *)sechdrs[relsec].sh_addr; >> 339 reloc_sz = rela ? sizeof(*r.rela) : sizeof(*r.rel); >> 340 me->arch.r_mips_hi16_list = NULL; >> 341 for (i = 0; i < sechdrs[relsec].sh_size / reloc_sz; i++) { >> 342 /* This is where to make the change */ >> 343 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr >> 344 + r.rel->r_offset; >> 345 /* This is the symbol it is referring to */ >> 346 sym = (Elf_Sym *)sechdrs[symindex].sh_addr >> 347 + ELF_MIPS_R_SYM(*r.rel); >> 348 if (sym->st_value >= -MAX_ERRNO) { >> 349 /* Ignore unresolved weak symbol */ >> 350 if (ELF_ST_BIND(sym->st_info) == STB_WEAK) >> 351 continue; >> 352 pr_warn("%s: Unknown symbol %s\n", >> 353 me->name, strtab + sym->st_name); >> 354 err = -ENOENT; >> 355 goto out; >> 356 } 434 357 435 if (!strcmp(".ARM.exidx", secn !! 358 type = ELF_MIPS_R_TYPE(*r.rel); 436 txtname = ".text"; !! 359 if (type < ARRAY_SIZE(reloc_handlers)) >> 360 handler = reloc_handlers[type]; 437 else 361 else 438 txtname = secname + st !! 362 handler = NULL; 439 txt_sec = find_mod_section(hdr !! 363 >> 364 if (!handler) { >> 365 pr_err("%s: Unknown relocation type %u\n", >> 366 me->name, type); >> 367 err = -EINVAL; >> 368 goto out; >> 369 } 440 370 441 if (txt_sec) { !! 371 if (rela) { 442 struct unwind_table *t !! 372 v = sym->st_value + r.rela->r_addend; 443 unwind_table_a !! 373 base = 0; 444 !! 374 r.rela = &r.rela[1]; 445 !! 375 } else { 446 !! 376 v = sym->st_value; 447 !! 377 base = *location; 448 list_add(&table->mod_l !! 378 r.rel = &r.rel[1]; 449 << 450 /* save init table for << 451 if (strcmp(".ARM.exidx << 452 mod->arch.init << 453 } 379 } >> 380 >> 381 err = handler(me, location, base, v, rela); >> 382 if (err) >> 383 goto out; 454 } 384 } 455 #endif !! 385 456 #ifdef CONFIG_ARM_PATCH_PHYS_VIRT !! 386 out: 457 s = find_mod_section(hdr, sechdrs, ".p !! 387 /* 458 if (s) !! 388 * Normally the hi16 list should be deallocated at this point. A 459 fixup_pv_table((void *)s->sh_a !! 389 * malformed binary however could contain a series of R_MIPS_HI16 460 #endif !! 390 * relocations not followed by a R_MIPS_LO16 relocation, or if we hit 461 s = find_mod_section(hdr, sechdrs, ".a !! 391 * an error processing a reloc we might have gotten here before 462 if (s && !is_smp()) !! 392 * reaching the R_MIPS_LO16. In either case, free up the list and 463 #ifdef CONFIG_SMP_ON_UP !! 393 * return an error. 464 fixup_smp((void *)s->sh_addr, !! 394 */ 465 #else !! 395 if (me->arch.r_mips_hi16_list) { 466 return -EINVAL; !! 396 free_relocation_chain(me->arch.r_mips_hi16_list); 467 #endif !! 397 me->arch.r_mips_hi16_list = NULL; 468 return 0; !! 398 err = err ?: -ENOEXEC; >> 399 } >> 400 >> 401 return err; 469 } 402 } 470 403 471 void !! 404 int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, 472 module_arch_cleanup(struct module *mod) !! 405 unsigned int symindex, unsigned int relsec, >> 406 struct module *me) 473 { 407 { 474 #ifdef CONFIG_ARM_UNWIND !! 408 return __apply_relocate(sechdrs, strtab, symindex, relsec, me, false); 475 struct unwind_table *tmp; !! 409 } 476 struct unwind_table *n; !! 410 477 !! 411 #ifdef CONFIG_MODULES_USE_ELF_RELA 478 list_for_each_entry_safe(tmp, n, !! 412 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, 479 &mod->arch.unwind_list !! 413 unsigned int symindex, unsigned int relsec, 480 list_del(&tmp->mod_list); !! 414 struct module *me) 481 unwind_table_del(tmp); !! 415 { >> 416 return __apply_relocate(sechdrs, strtab, symindex, relsec, me, true); >> 417 } >> 418 #endif /* CONFIG_MODULES_USE_ELF_RELA */ >> 419 >> 420 /* Given an address, look for it in the module exception tables. */ >> 421 const struct exception_table_entry *search_module_dbetables(unsigned long addr) >> 422 { >> 423 unsigned long flags; >> 424 const struct exception_table_entry *e = NULL; >> 425 struct mod_arch_specific *dbe; >> 426 >> 427 spin_lock_irqsave(&dbe_lock, flags); >> 428 list_for_each_entry(dbe, &dbe_list, dbe_list) { >> 429 e = search_extable(dbe->dbe_start, >> 430 dbe->dbe_end - dbe->dbe_start, addr); >> 431 if (e) >> 432 break; 482 } 433 } 483 mod->arch.init_table = NULL; !! 434 spin_unlock_irqrestore(&dbe_lock, flags); 484 #endif !! 435 >> 436 /* Now, if we found one, we are running inside it now, hence >> 437 we cannot unload the module, hence no refcnt needed. */ >> 438 return e; 485 } 439 } 486 440 487 void __weak module_arch_freeing_init(struct mo !! 441 /* Put in dbe list if necessary. */ >> 442 int module_finalize(const Elf_Ehdr *hdr, >> 443 const Elf_Shdr *sechdrs, >> 444 struct module *me) 488 { 445 { 489 #ifdef CONFIG_ARM_UNWIND !! 446 const Elf_Shdr *s; 490 struct unwind_table *init = mod->arch. !! 447 char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; >> 448 >> 449 /* Make jump label nops. */ >> 450 jump_label_apply_nops(me); 491 451 492 if (init) { !! 452 INIT_LIST_HEAD(&me->arch.dbe_list); 493 mod->arch.init_table = NULL; !! 453 for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 494 list_del(&init->mod_list); !! 454 if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) 495 unwind_table_del(init); !! 455 continue; >> 456 me->arch.dbe_start = (void *)s->sh_addr; >> 457 me->arch.dbe_end = (void *)s->sh_addr + s->sh_size; >> 458 spin_lock_irq(&dbe_lock); >> 459 list_add(&me->arch.dbe_list, &dbe_list); >> 460 spin_unlock_irq(&dbe_lock); 496 } 461 } 497 #endif !! 462 return 0; >> 463 } >> 464 >> 465 void module_arch_cleanup(struct module *mod) >> 466 { >> 467 spin_lock_irq(&dbe_lock); >> 468 list_del(&mod->arch.dbe_list); >> 469 spin_unlock_irq(&dbe_lock); 498 } 470 } 499 471
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.