1257cb251SWill Deacon /* 2257cb251SWill Deacon * AArch64 loadable module support. 3257cb251SWill Deacon * 4257cb251SWill Deacon * Copyright (C) 2012 ARM Limited 5257cb251SWill Deacon * 6257cb251SWill Deacon * This program is free software; you can redistribute it and/or modify 7257cb251SWill Deacon * it under the terms of the GNU General Public License version 2 as 8257cb251SWill Deacon * published by the Free Software Foundation. 9257cb251SWill Deacon * 10257cb251SWill Deacon * This program is distributed in the hope that it will be useful, 11257cb251SWill Deacon * but WITHOUT ANY WARRANTY; without even the implied warranty of 12257cb251SWill Deacon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13257cb251SWill Deacon * GNU General Public License for more details. 14257cb251SWill Deacon * 15257cb251SWill Deacon * You should have received a copy of the GNU General Public License 16257cb251SWill Deacon * along with this program. If not, see <http://www.gnu.org/licenses/>. 17257cb251SWill Deacon * 18257cb251SWill Deacon * Author: Will Deacon <will.deacon@arm.com> 19257cb251SWill Deacon */ 20257cb251SWill Deacon 21257cb251SWill Deacon #include <linux/bitops.h> 22257cb251SWill Deacon #include <linux/elf.h> 23257cb251SWill Deacon #include <linux/gfp.h> 2439d114ddSAndrey Ryabinin #include <linux/kasan.h> 25257cb251SWill Deacon #include <linux/kernel.h> 26257cb251SWill Deacon #include <linux/mm.h> 27257cb251SWill Deacon #include <linux/moduleloader.h> 28257cb251SWill Deacon #include <linux/vmalloc.h> 292c2b282dSPaul Walmsley #include <asm/alternative.h> 30c84fced8SJiang Liu #include <asm/insn.h> 31932ded4bSAndre Przywara #include <asm/sections.h> 32c84fced8SJiang Liu 33257cb251SWill Deacon void *module_alloc(unsigned long size) 34257cb251SWill Deacon { 3539d114ddSAndrey Ryabinin void *p; 3639d114ddSAndrey Ryabinin 3739d114ddSAndrey Ryabinin p = __vmalloc_node_range(size, MODULE_ALIGN, MODULES_VADDR, MODULES_END, 38cb9e3c29SAndrey Ryabinin GFP_KERNEL, PAGE_KERNEL_EXEC, 0, 39cb9e3c29SAndrey Ryabinin NUMA_NO_NODE, __builtin_return_address(0)); 4039d114ddSAndrey Ryabinin 4139d114ddSAndrey Ryabinin if (p && (kasan_module_alloc(p, size) < 0)) { 4239d114ddSAndrey Ryabinin vfree(p); 4339d114ddSAndrey Ryabinin return NULL; 4439d114ddSAndrey Ryabinin } 4539d114ddSAndrey Ryabinin 4639d114ddSAndrey Ryabinin return p; 47257cb251SWill Deacon } 48257cb251SWill Deacon 49257cb251SWill Deacon enum aarch64_reloc_op { 50257cb251SWill Deacon RELOC_OP_NONE, 51257cb251SWill Deacon RELOC_OP_ABS, 52257cb251SWill Deacon RELOC_OP_PREL, 53257cb251SWill Deacon RELOC_OP_PAGE, 54257cb251SWill Deacon }; 55257cb251SWill Deacon 56257cb251SWill Deacon static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val) 57257cb251SWill Deacon { 58257cb251SWill Deacon switch (reloc_op) { 59257cb251SWill Deacon case RELOC_OP_ABS: 60257cb251SWill Deacon return val; 61257cb251SWill Deacon case RELOC_OP_PREL: 62257cb251SWill Deacon return val - (u64)place; 63257cb251SWill Deacon case RELOC_OP_PAGE: 64257cb251SWill Deacon return (val & ~0xfff) - ((u64)place & ~0xfff); 65257cb251SWill Deacon case RELOC_OP_NONE: 66257cb251SWill Deacon return 0; 67257cb251SWill Deacon } 68257cb251SWill Deacon 69257cb251SWill Deacon pr_err("do_reloc: unknown relocation operation %d\n", reloc_op); 70257cb251SWill Deacon return 0; 71257cb251SWill Deacon } 72257cb251SWill Deacon 73257cb251SWill Deacon static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) 74257cb251SWill Deacon { 75257cb251SWill Deacon u64 imm_mask = (1 << len) - 1; 76257cb251SWill Deacon s64 sval = do_reloc(op, place, val); 77257cb251SWill Deacon 78257cb251SWill Deacon switch (len) { 79257cb251SWill Deacon case 16: 80257cb251SWill Deacon *(s16 *)place = sval; 81257cb251SWill Deacon break; 82257cb251SWill Deacon case 32: 83257cb251SWill Deacon *(s32 *)place = sval; 84257cb251SWill Deacon break; 85257cb251SWill Deacon case 64: 86257cb251SWill Deacon *(s64 *)place = sval; 87257cb251SWill Deacon break; 88257cb251SWill Deacon default: 89257cb251SWill Deacon pr_err("Invalid length (%d) for data relocation\n", len); 90257cb251SWill Deacon return 0; 91257cb251SWill Deacon } 92257cb251SWill Deacon 93257cb251SWill Deacon /* 94257cb251SWill Deacon * Extract the upper value bits (including the sign bit) and 95257cb251SWill Deacon * shift them to bit 0. 96257cb251SWill Deacon */ 97257cb251SWill Deacon sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); 98257cb251SWill Deacon 99257cb251SWill Deacon /* 100257cb251SWill Deacon * Overflow has occurred if the value is not representable in 101257cb251SWill Deacon * len bits (i.e the bottom len bits are not sign-extended and 102257cb251SWill Deacon * the top bits are not all zero). 103257cb251SWill Deacon */ 104257cb251SWill Deacon if ((u64)(sval + 1) > 2) 105257cb251SWill Deacon return -ERANGE; 106257cb251SWill Deacon 107257cb251SWill Deacon return 0; 108257cb251SWill Deacon } 109257cb251SWill Deacon 110*b24a5575SArd Biesheuvel enum aarch64_insn_movw_imm_type { 111*b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVNZ, 112*b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ, 113*b24a5575SArd Biesheuvel }; 114*b24a5575SArd Biesheuvel 115c84fced8SJiang Liu static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, 116*b24a5575SArd Biesheuvel int lsb, enum aarch64_insn_movw_imm_type imm_type) 117257cb251SWill Deacon { 118*b24a5575SArd Biesheuvel u64 imm; 119c84fced8SJiang Liu s64 sval; 120c84fced8SJiang Liu u32 insn = le32_to_cpu(*(u32 *)place); 121257cb251SWill Deacon 122c84fced8SJiang Liu sval = do_reloc(op, place, val); 123*b24a5575SArd Biesheuvel imm = sval >> lsb; 124122e2fa0SWill Deacon 125c84fced8SJiang Liu if (imm_type == AARCH64_INSN_IMM_MOVNZ) { 126257cb251SWill Deacon /* 127257cb251SWill Deacon * For signed MOVW relocations, we have to manipulate the 128257cb251SWill Deacon * instruction encoding depending on whether or not the 129257cb251SWill Deacon * immediate is less than zero. 130257cb251SWill Deacon */ 131257cb251SWill Deacon insn &= ~(3 << 29); 132*b24a5575SArd Biesheuvel if (sval >= 0) { 133257cb251SWill Deacon /* >=0: Set the instruction to MOVZ (opcode 10b). */ 134257cb251SWill Deacon insn |= 2 << 29; 135257cb251SWill Deacon } else { 136257cb251SWill Deacon /* 137257cb251SWill Deacon * <0: Set the instruction to MOVN (opcode 00b). 138257cb251SWill Deacon * Since we've masked the opcode already, we 139257cb251SWill Deacon * don't need to do anything other than 140257cb251SWill Deacon * inverting the new immediate field. 141257cb251SWill Deacon */ 142257cb251SWill Deacon imm = ~imm; 143257cb251SWill Deacon } 144257cb251SWill Deacon } 145257cb251SWill Deacon 146257cb251SWill Deacon /* Update the instruction with the new encoding. */ 147*b24a5575SArd Biesheuvel insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm); 148c84fced8SJiang Liu *(u32 *)place = cpu_to_le32(insn); 149257cb251SWill Deacon 150*b24a5575SArd Biesheuvel if (imm > U16_MAX) 151257cb251SWill Deacon return -ERANGE; 152257cb251SWill Deacon 153257cb251SWill Deacon return 0; 154257cb251SWill Deacon } 155257cb251SWill Deacon 156257cb251SWill Deacon static int reloc_insn_imm(enum aarch64_reloc_op op, void *place, u64 val, 157c84fced8SJiang Liu int lsb, int len, enum aarch64_insn_imm_type imm_type) 158257cb251SWill Deacon { 159257cb251SWill Deacon u64 imm, imm_mask; 160257cb251SWill Deacon s64 sval; 161c84fced8SJiang Liu u32 insn = le32_to_cpu(*(u32 *)place); 162257cb251SWill Deacon 163257cb251SWill Deacon /* Calculate the relocation value. */ 164257cb251SWill Deacon sval = do_reloc(op, place, val); 165257cb251SWill Deacon sval >>= lsb; 166257cb251SWill Deacon 167257cb251SWill Deacon /* Extract the value bits and shift them to bit 0. */ 168257cb251SWill Deacon imm_mask = (BIT(lsb + len) - 1) >> lsb; 169257cb251SWill Deacon imm = sval & imm_mask; 170257cb251SWill Deacon 171257cb251SWill Deacon /* Update the instruction's immediate field. */ 172c84fced8SJiang Liu insn = aarch64_insn_encode_immediate(imm_type, insn, imm); 173c84fced8SJiang Liu *(u32 *)place = cpu_to_le32(insn); 174257cb251SWill Deacon 175257cb251SWill Deacon /* 176257cb251SWill Deacon * Extract the upper value bits (including the sign bit) and 177257cb251SWill Deacon * shift them to bit 0. 178257cb251SWill Deacon */ 179257cb251SWill Deacon sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); 180257cb251SWill Deacon 181257cb251SWill Deacon /* 182257cb251SWill Deacon * Overflow has occurred if the upper bits are not all equal to 183257cb251SWill Deacon * the sign bit of the value. 184257cb251SWill Deacon */ 185257cb251SWill Deacon if ((u64)(sval + 1) >= 2) 186257cb251SWill Deacon return -ERANGE; 187257cb251SWill Deacon 188257cb251SWill Deacon return 0; 189257cb251SWill Deacon } 190257cb251SWill Deacon 191257cb251SWill Deacon int apply_relocate_add(Elf64_Shdr *sechdrs, 192257cb251SWill Deacon const char *strtab, 193257cb251SWill Deacon unsigned int symindex, 194257cb251SWill Deacon unsigned int relsec, 195257cb251SWill Deacon struct module *me) 196257cb251SWill Deacon { 197257cb251SWill Deacon unsigned int i; 198257cb251SWill Deacon int ovf; 199257cb251SWill Deacon bool overflow_check; 200257cb251SWill Deacon Elf64_Sym *sym; 201257cb251SWill Deacon void *loc; 202257cb251SWill Deacon u64 val; 203257cb251SWill Deacon Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 204257cb251SWill Deacon 205257cb251SWill Deacon for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 206257cb251SWill Deacon /* loc corresponds to P in the AArch64 ELF document. */ 207257cb251SWill Deacon loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 208257cb251SWill Deacon + rel[i].r_offset; 209257cb251SWill Deacon 210257cb251SWill Deacon /* sym is the ELF symbol we're referring to. */ 211257cb251SWill Deacon sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 212257cb251SWill Deacon + ELF64_R_SYM(rel[i].r_info); 213257cb251SWill Deacon 214257cb251SWill Deacon /* val corresponds to (S + A) in the AArch64 ELF document. */ 215257cb251SWill Deacon val = sym->st_value + rel[i].r_addend; 216257cb251SWill Deacon 217257cb251SWill Deacon /* Check for overflow by default. */ 218257cb251SWill Deacon overflow_check = true; 219257cb251SWill Deacon 220257cb251SWill Deacon /* Perform the static relocation. */ 221257cb251SWill Deacon switch (ELF64_R_TYPE(rel[i].r_info)) { 222257cb251SWill Deacon /* Null relocations. */ 223257cb251SWill Deacon case R_ARM_NONE: 224257cb251SWill Deacon case R_AARCH64_NONE: 225257cb251SWill Deacon ovf = 0; 226257cb251SWill Deacon break; 227257cb251SWill Deacon 228257cb251SWill Deacon /* Data relocations. */ 229257cb251SWill Deacon case R_AARCH64_ABS64: 230257cb251SWill Deacon overflow_check = false; 231257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); 232257cb251SWill Deacon break; 233257cb251SWill Deacon case R_AARCH64_ABS32: 234257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); 235257cb251SWill Deacon break; 236257cb251SWill Deacon case R_AARCH64_ABS16: 237257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); 238257cb251SWill Deacon break; 239257cb251SWill Deacon case R_AARCH64_PREL64: 240257cb251SWill Deacon overflow_check = false; 241257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); 242257cb251SWill Deacon break; 243257cb251SWill Deacon case R_AARCH64_PREL32: 244257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); 245257cb251SWill Deacon break; 246257cb251SWill Deacon case R_AARCH64_PREL16: 247257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); 248257cb251SWill Deacon break; 249257cb251SWill Deacon 250257cb251SWill Deacon /* MOVW instruction relocations. */ 251257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0_NC: 252257cb251SWill Deacon overflow_check = false; 253257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0: 254257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 255*b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 256257cb251SWill Deacon break; 257257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1_NC: 258257cb251SWill Deacon overflow_check = false; 259257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1: 260257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 261*b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 262257cb251SWill Deacon break; 263257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2_NC: 264257cb251SWill Deacon overflow_check = false; 265257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2: 266257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 267*b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 268257cb251SWill Deacon break; 269257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G3: 270257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 271257cb251SWill Deacon overflow_check = false; 272257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, 273*b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 274257cb251SWill Deacon break; 275257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G0: 276257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 277c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 278257cb251SWill Deacon break; 279257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G1: 280257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 281c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 282257cb251SWill Deacon break; 283257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G2: 284257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 285c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 286257cb251SWill Deacon break; 287257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0_NC: 288257cb251SWill Deacon overflow_check = false; 289257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 290*b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 291257cb251SWill Deacon break; 292257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0: 293257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 294c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 295257cb251SWill Deacon break; 296257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1_NC: 297257cb251SWill Deacon overflow_check = false; 298257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 299*b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 300257cb251SWill Deacon break; 301257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1: 302257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 303c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 304257cb251SWill Deacon break; 305257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2_NC: 306257cb251SWill Deacon overflow_check = false; 307257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 308*b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 309257cb251SWill Deacon break; 310257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2: 311257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 312c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 313257cb251SWill Deacon break; 314257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G3: 315257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 316257cb251SWill Deacon overflow_check = false; 317257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, 318c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 319257cb251SWill Deacon break; 320257cb251SWill Deacon 321257cb251SWill Deacon /* Immediate instruction relocations. */ 322257cb251SWill Deacon case R_AARCH64_LD_PREL_LO19: 323257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 324c84fced8SJiang Liu AARCH64_INSN_IMM_19); 325257cb251SWill Deacon break; 326257cb251SWill Deacon case R_AARCH64_ADR_PREL_LO21: 327257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, 328c84fced8SJiang Liu AARCH64_INSN_IMM_ADR); 329257cb251SWill Deacon break; 330df057cc7SWill Deacon #ifndef CONFIG_ARM64_ERRATUM_843419 331257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21_NC: 332257cb251SWill Deacon overflow_check = false; 333257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21: 334257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, 335c84fced8SJiang Liu AARCH64_INSN_IMM_ADR); 336257cb251SWill Deacon break; 337df057cc7SWill Deacon #endif 338257cb251SWill Deacon case R_AARCH64_ADD_ABS_LO12_NC: 339257cb251SWill Deacon case R_AARCH64_LDST8_ABS_LO12_NC: 340257cb251SWill Deacon overflow_check = false; 341257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, 342c84fced8SJiang Liu AARCH64_INSN_IMM_12); 343257cb251SWill Deacon break; 344257cb251SWill Deacon case R_AARCH64_LDST16_ABS_LO12_NC: 345257cb251SWill Deacon overflow_check = false; 346257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, 347c84fced8SJiang Liu AARCH64_INSN_IMM_12); 348257cb251SWill Deacon break; 349257cb251SWill Deacon case R_AARCH64_LDST32_ABS_LO12_NC: 350257cb251SWill Deacon overflow_check = false; 351257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, 352c84fced8SJiang Liu AARCH64_INSN_IMM_12); 353257cb251SWill Deacon break; 354257cb251SWill Deacon case R_AARCH64_LDST64_ABS_LO12_NC: 355257cb251SWill Deacon overflow_check = false; 356257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, 357c84fced8SJiang Liu AARCH64_INSN_IMM_12); 358257cb251SWill Deacon break; 359257cb251SWill Deacon case R_AARCH64_LDST128_ABS_LO12_NC: 360257cb251SWill Deacon overflow_check = false; 361257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, 362c84fced8SJiang Liu AARCH64_INSN_IMM_12); 363257cb251SWill Deacon break; 364257cb251SWill Deacon case R_AARCH64_TSTBR14: 365257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, 366c84fced8SJiang Liu AARCH64_INSN_IMM_14); 367257cb251SWill Deacon break; 368257cb251SWill Deacon case R_AARCH64_CONDBR19: 369257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 370c84fced8SJiang Liu AARCH64_INSN_IMM_19); 371257cb251SWill Deacon break; 372257cb251SWill Deacon case R_AARCH64_JUMP26: 373257cb251SWill Deacon case R_AARCH64_CALL26: 374257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, 375c84fced8SJiang Liu AARCH64_INSN_IMM_26); 376257cb251SWill Deacon break; 377257cb251SWill Deacon 378257cb251SWill Deacon default: 379257cb251SWill Deacon pr_err("module %s: unsupported RELA relocation: %llu\n", 380257cb251SWill Deacon me->name, ELF64_R_TYPE(rel[i].r_info)); 381257cb251SWill Deacon return -ENOEXEC; 382257cb251SWill Deacon } 383257cb251SWill Deacon 384257cb251SWill Deacon if (overflow_check && ovf == -ERANGE) 385257cb251SWill Deacon goto overflow; 386257cb251SWill Deacon 387257cb251SWill Deacon } 388257cb251SWill Deacon 389257cb251SWill Deacon return 0; 390257cb251SWill Deacon 391257cb251SWill Deacon overflow: 392257cb251SWill Deacon pr_err("module %s: overflow in relocation type %d val %Lx\n", 393257cb251SWill Deacon me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); 394257cb251SWill Deacon return -ENOEXEC; 395257cb251SWill Deacon } 396932ded4bSAndre Przywara 397932ded4bSAndre Przywara int module_finalize(const Elf_Ehdr *hdr, 398932ded4bSAndre Przywara const Elf_Shdr *sechdrs, 399932ded4bSAndre Przywara struct module *me) 400932ded4bSAndre Przywara { 401932ded4bSAndre Przywara const Elf_Shdr *s, *se; 402932ded4bSAndre Przywara const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 403932ded4bSAndre Przywara 404932ded4bSAndre Przywara for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { 405932ded4bSAndre Przywara if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) { 406932ded4bSAndre Przywara apply_alternatives((void *)s->sh_addr, s->sh_size); 407932ded4bSAndre Przywara return 0; 408932ded4bSAndre Przywara } 409932ded4bSAndre Przywara } 410932ded4bSAndre Przywara 411932ded4bSAndre Przywara return 0; 412932ded4bSAndre Przywara } 413