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> 24257cb251SWill Deacon #include <linux/kernel.h> 25257cb251SWill Deacon #include <linux/mm.h> 26257cb251SWill Deacon #include <linux/moduleloader.h> 27257cb251SWill Deacon #include <linux/vmalloc.h> 28257cb251SWill Deacon 29257cb251SWill Deacon void *module_alloc(unsigned long size) 30257cb251SWill Deacon { 31257cb251SWill Deacon return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 32257cb251SWill Deacon GFP_KERNEL, PAGE_KERNEL_EXEC, -1, 33257cb251SWill Deacon __builtin_return_address(0)); 34257cb251SWill Deacon } 35257cb251SWill Deacon 36257cb251SWill Deacon enum aarch64_reloc_op { 37257cb251SWill Deacon RELOC_OP_NONE, 38257cb251SWill Deacon RELOC_OP_ABS, 39257cb251SWill Deacon RELOC_OP_PREL, 40257cb251SWill Deacon RELOC_OP_PAGE, 41257cb251SWill Deacon }; 42257cb251SWill Deacon 43257cb251SWill Deacon static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val) 44257cb251SWill Deacon { 45257cb251SWill Deacon switch (reloc_op) { 46257cb251SWill Deacon case RELOC_OP_ABS: 47257cb251SWill Deacon return val; 48257cb251SWill Deacon case RELOC_OP_PREL: 49257cb251SWill Deacon return val - (u64)place; 50257cb251SWill Deacon case RELOC_OP_PAGE: 51257cb251SWill Deacon return (val & ~0xfff) - ((u64)place & ~0xfff); 52257cb251SWill Deacon case RELOC_OP_NONE: 53257cb251SWill Deacon return 0; 54257cb251SWill Deacon } 55257cb251SWill Deacon 56257cb251SWill Deacon pr_err("do_reloc: unknown relocation operation %d\n", reloc_op); 57257cb251SWill Deacon return 0; 58257cb251SWill Deacon } 59257cb251SWill Deacon 60257cb251SWill Deacon static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) 61257cb251SWill Deacon { 62257cb251SWill Deacon u64 imm_mask = (1 << len) - 1; 63257cb251SWill Deacon s64 sval = do_reloc(op, place, val); 64257cb251SWill Deacon 65257cb251SWill Deacon switch (len) { 66257cb251SWill Deacon case 16: 67257cb251SWill Deacon *(s16 *)place = sval; 68257cb251SWill Deacon break; 69257cb251SWill Deacon case 32: 70257cb251SWill Deacon *(s32 *)place = sval; 71257cb251SWill Deacon break; 72257cb251SWill Deacon case 64: 73257cb251SWill Deacon *(s64 *)place = sval; 74257cb251SWill Deacon break; 75257cb251SWill Deacon default: 76257cb251SWill Deacon pr_err("Invalid length (%d) for data relocation\n", len); 77257cb251SWill Deacon return 0; 78257cb251SWill Deacon } 79257cb251SWill Deacon 80257cb251SWill Deacon /* 81257cb251SWill Deacon * Extract the upper value bits (including the sign bit) and 82257cb251SWill Deacon * shift them to bit 0. 83257cb251SWill Deacon */ 84257cb251SWill Deacon sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); 85257cb251SWill Deacon 86257cb251SWill Deacon /* 87257cb251SWill Deacon * Overflow has occurred if the value is not representable in 88257cb251SWill Deacon * len bits (i.e the bottom len bits are not sign-extended and 89257cb251SWill Deacon * the top bits are not all zero). 90257cb251SWill Deacon */ 91257cb251SWill Deacon if ((u64)(sval + 1) > 2) 92257cb251SWill Deacon return -ERANGE; 93257cb251SWill Deacon 94257cb251SWill Deacon return 0; 95257cb251SWill Deacon } 96257cb251SWill Deacon 97257cb251SWill Deacon enum aarch64_imm_type { 98257cb251SWill Deacon INSN_IMM_MOVNZ, 99257cb251SWill Deacon INSN_IMM_MOVK, 100257cb251SWill Deacon INSN_IMM_ADR, 101257cb251SWill Deacon INSN_IMM_26, 102257cb251SWill Deacon INSN_IMM_19, 103257cb251SWill Deacon INSN_IMM_16, 104257cb251SWill Deacon INSN_IMM_14, 105257cb251SWill Deacon INSN_IMM_12, 106257cb251SWill Deacon INSN_IMM_9, 107257cb251SWill Deacon }; 108257cb251SWill Deacon 109257cb251SWill Deacon static u32 encode_insn_immediate(enum aarch64_imm_type type, u32 insn, u64 imm) 110257cb251SWill Deacon { 111257cb251SWill Deacon u32 immlo, immhi, lomask, himask, mask; 112257cb251SWill Deacon int shift; 113257cb251SWill Deacon 114*122e2fa0SWill Deacon /* The instruction stream is always little endian. */ 115*122e2fa0SWill Deacon insn = le32_to_cpu(insn); 116*122e2fa0SWill Deacon 117257cb251SWill Deacon switch (type) { 118257cb251SWill Deacon case INSN_IMM_MOVNZ: 119257cb251SWill Deacon /* 120257cb251SWill Deacon * For signed MOVW relocations, we have to manipulate the 121257cb251SWill Deacon * instruction encoding depending on whether or not the 122257cb251SWill Deacon * immediate is less than zero. 123257cb251SWill Deacon */ 124257cb251SWill Deacon insn &= ~(3 << 29); 125257cb251SWill Deacon if ((s64)imm >= 0) { 126257cb251SWill Deacon /* >=0: Set the instruction to MOVZ (opcode 10b). */ 127257cb251SWill Deacon insn |= 2 << 29; 128257cb251SWill Deacon } else { 129257cb251SWill Deacon /* 130257cb251SWill Deacon * <0: Set the instruction to MOVN (opcode 00b). 131257cb251SWill Deacon * Since we've masked the opcode already, we 132257cb251SWill Deacon * don't need to do anything other than 133257cb251SWill Deacon * inverting the new immediate field. 134257cb251SWill Deacon */ 135257cb251SWill Deacon imm = ~imm; 136257cb251SWill Deacon } 137257cb251SWill Deacon case INSN_IMM_MOVK: 138257cb251SWill Deacon mask = BIT(16) - 1; 139257cb251SWill Deacon shift = 5; 140257cb251SWill Deacon break; 141257cb251SWill Deacon case INSN_IMM_ADR: 142257cb251SWill Deacon lomask = 0x3; 143257cb251SWill Deacon himask = 0x7ffff; 144257cb251SWill Deacon immlo = imm & lomask; 145257cb251SWill Deacon imm >>= 2; 146257cb251SWill Deacon immhi = imm & himask; 147257cb251SWill Deacon imm = (immlo << 24) | (immhi); 148257cb251SWill Deacon mask = (lomask << 24) | (himask); 149257cb251SWill Deacon shift = 5; 150257cb251SWill Deacon break; 151257cb251SWill Deacon case INSN_IMM_26: 152257cb251SWill Deacon mask = BIT(26) - 1; 153257cb251SWill Deacon shift = 0; 154257cb251SWill Deacon break; 155257cb251SWill Deacon case INSN_IMM_19: 156257cb251SWill Deacon mask = BIT(19) - 1; 157257cb251SWill Deacon shift = 5; 158257cb251SWill Deacon break; 159257cb251SWill Deacon case INSN_IMM_16: 160257cb251SWill Deacon mask = BIT(16) - 1; 161257cb251SWill Deacon shift = 5; 162257cb251SWill Deacon break; 163257cb251SWill Deacon case INSN_IMM_14: 164257cb251SWill Deacon mask = BIT(14) - 1; 165257cb251SWill Deacon shift = 5; 166257cb251SWill Deacon break; 167257cb251SWill Deacon case INSN_IMM_12: 168257cb251SWill Deacon mask = BIT(12) - 1; 169257cb251SWill Deacon shift = 10; 170257cb251SWill Deacon break; 171257cb251SWill Deacon case INSN_IMM_9: 172257cb251SWill Deacon mask = BIT(9) - 1; 173257cb251SWill Deacon shift = 12; 174257cb251SWill Deacon break; 175257cb251SWill Deacon default: 176257cb251SWill Deacon pr_err("encode_insn_immediate: unknown immediate encoding %d\n", 177257cb251SWill Deacon type); 178257cb251SWill Deacon return 0; 179257cb251SWill Deacon } 180257cb251SWill Deacon 181257cb251SWill Deacon /* Update the immediate field. */ 182257cb251SWill Deacon insn &= ~(mask << shift); 183257cb251SWill Deacon insn |= (imm & mask) << shift; 184257cb251SWill Deacon 185*122e2fa0SWill Deacon return cpu_to_le32(insn); 186257cb251SWill Deacon } 187257cb251SWill Deacon 188257cb251SWill Deacon static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, 189257cb251SWill Deacon int lsb, enum aarch64_imm_type imm_type) 190257cb251SWill Deacon { 191257cb251SWill Deacon u64 imm, limit = 0; 192257cb251SWill Deacon s64 sval; 193257cb251SWill Deacon u32 insn = *(u32 *)place; 194257cb251SWill Deacon 195257cb251SWill Deacon sval = do_reloc(op, place, val); 196257cb251SWill Deacon sval >>= lsb; 197257cb251SWill Deacon imm = sval & 0xffff; 198257cb251SWill Deacon 199257cb251SWill Deacon /* Update the instruction with the new encoding. */ 200257cb251SWill Deacon *(u32 *)place = encode_insn_immediate(imm_type, insn, imm); 201257cb251SWill Deacon 202257cb251SWill Deacon /* Shift out the immediate field. */ 203257cb251SWill Deacon sval >>= 16; 204257cb251SWill Deacon 205257cb251SWill Deacon /* 206257cb251SWill Deacon * For unsigned immediates, the overflow check is straightforward. 207257cb251SWill Deacon * For signed immediates, the sign bit is actually the bit past the 208257cb251SWill Deacon * most significant bit of the field. 209257cb251SWill Deacon * The INSN_IMM_16 immediate type is unsigned. 210257cb251SWill Deacon */ 211257cb251SWill Deacon if (imm_type != INSN_IMM_16) { 212257cb251SWill Deacon sval++; 213257cb251SWill Deacon limit++; 214257cb251SWill Deacon } 215257cb251SWill Deacon 216257cb251SWill Deacon /* Check the upper bits depending on the sign of the immediate. */ 217257cb251SWill Deacon if ((u64)sval > limit) 218257cb251SWill Deacon return -ERANGE; 219257cb251SWill Deacon 220257cb251SWill Deacon return 0; 221257cb251SWill Deacon } 222257cb251SWill Deacon 223257cb251SWill Deacon static int reloc_insn_imm(enum aarch64_reloc_op op, void *place, u64 val, 224257cb251SWill Deacon int lsb, int len, enum aarch64_imm_type imm_type) 225257cb251SWill Deacon { 226257cb251SWill Deacon u64 imm, imm_mask; 227257cb251SWill Deacon s64 sval; 228257cb251SWill Deacon u32 insn = *(u32 *)place; 229257cb251SWill Deacon 230257cb251SWill Deacon /* Calculate the relocation value. */ 231257cb251SWill Deacon sval = do_reloc(op, place, val); 232257cb251SWill Deacon sval >>= lsb; 233257cb251SWill Deacon 234257cb251SWill Deacon /* Extract the value bits and shift them to bit 0. */ 235257cb251SWill Deacon imm_mask = (BIT(lsb + len) - 1) >> lsb; 236257cb251SWill Deacon imm = sval & imm_mask; 237257cb251SWill Deacon 238257cb251SWill Deacon /* Update the instruction's immediate field. */ 239257cb251SWill Deacon *(u32 *)place = encode_insn_immediate(imm_type, insn, imm); 240257cb251SWill Deacon 241257cb251SWill Deacon /* 242257cb251SWill Deacon * Extract the upper value bits (including the sign bit) and 243257cb251SWill Deacon * shift them to bit 0. 244257cb251SWill Deacon */ 245257cb251SWill Deacon sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); 246257cb251SWill Deacon 247257cb251SWill Deacon /* 248257cb251SWill Deacon * Overflow has occurred if the upper bits are not all equal to 249257cb251SWill Deacon * the sign bit of the value. 250257cb251SWill Deacon */ 251257cb251SWill Deacon if ((u64)(sval + 1) >= 2) 252257cb251SWill Deacon return -ERANGE; 253257cb251SWill Deacon 254257cb251SWill Deacon return 0; 255257cb251SWill Deacon } 256257cb251SWill Deacon 257257cb251SWill Deacon int apply_relocate_add(Elf64_Shdr *sechdrs, 258257cb251SWill Deacon const char *strtab, 259257cb251SWill Deacon unsigned int symindex, 260257cb251SWill Deacon unsigned int relsec, 261257cb251SWill Deacon struct module *me) 262257cb251SWill Deacon { 263257cb251SWill Deacon unsigned int i; 264257cb251SWill Deacon int ovf; 265257cb251SWill Deacon bool overflow_check; 266257cb251SWill Deacon Elf64_Sym *sym; 267257cb251SWill Deacon void *loc; 268257cb251SWill Deacon u64 val; 269257cb251SWill Deacon Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 270257cb251SWill Deacon 271257cb251SWill Deacon for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 272257cb251SWill Deacon /* loc corresponds to P in the AArch64 ELF document. */ 273257cb251SWill Deacon loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 274257cb251SWill Deacon + rel[i].r_offset; 275257cb251SWill Deacon 276257cb251SWill Deacon /* sym is the ELF symbol we're referring to. */ 277257cb251SWill Deacon sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 278257cb251SWill Deacon + ELF64_R_SYM(rel[i].r_info); 279257cb251SWill Deacon 280257cb251SWill Deacon /* val corresponds to (S + A) in the AArch64 ELF document. */ 281257cb251SWill Deacon val = sym->st_value + rel[i].r_addend; 282257cb251SWill Deacon 283257cb251SWill Deacon /* Check for overflow by default. */ 284257cb251SWill Deacon overflow_check = true; 285257cb251SWill Deacon 286257cb251SWill Deacon /* Perform the static relocation. */ 287257cb251SWill Deacon switch (ELF64_R_TYPE(rel[i].r_info)) { 288257cb251SWill Deacon /* Null relocations. */ 289257cb251SWill Deacon case R_ARM_NONE: 290257cb251SWill Deacon case R_AARCH64_NONE: 291257cb251SWill Deacon ovf = 0; 292257cb251SWill Deacon break; 293257cb251SWill Deacon 294257cb251SWill Deacon /* Data relocations. */ 295257cb251SWill Deacon case R_AARCH64_ABS64: 296257cb251SWill Deacon overflow_check = false; 297257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); 298257cb251SWill Deacon break; 299257cb251SWill Deacon case R_AARCH64_ABS32: 300257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); 301257cb251SWill Deacon break; 302257cb251SWill Deacon case R_AARCH64_ABS16: 303257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); 304257cb251SWill Deacon break; 305257cb251SWill Deacon case R_AARCH64_PREL64: 306257cb251SWill Deacon overflow_check = false; 307257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); 308257cb251SWill Deacon break; 309257cb251SWill Deacon case R_AARCH64_PREL32: 310257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); 311257cb251SWill Deacon break; 312257cb251SWill Deacon case R_AARCH64_PREL16: 313257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); 314257cb251SWill Deacon break; 315257cb251SWill Deacon 316257cb251SWill Deacon /* MOVW instruction relocations. */ 317257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0_NC: 318257cb251SWill Deacon overflow_check = false; 319257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0: 320257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 321257cb251SWill Deacon INSN_IMM_16); 322257cb251SWill Deacon break; 323257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1_NC: 324257cb251SWill Deacon overflow_check = false; 325257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1: 326257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 327257cb251SWill Deacon INSN_IMM_16); 328257cb251SWill Deacon break; 329257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2_NC: 330257cb251SWill Deacon overflow_check = false; 331257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2: 332257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 333257cb251SWill Deacon INSN_IMM_16); 334257cb251SWill Deacon break; 335257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G3: 336257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 337257cb251SWill Deacon overflow_check = false; 338257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, 339257cb251SWill Deacon INSN_IMM_16); 340257cb251SWill Deacon break; 341257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G0: 342257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 343257cb251SWill Deacon INSN_IMM_MOVNZ); 344257cb251SWill Deacon break; 345257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G1: 346257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 347257cb251SWill Deacon INSN_IMM_MOVNZ); 348257cb251SWill Deacon break; 349257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G2: 350257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 351257cb251SWill Deacon INSN_IMM_MOVNZ); 352257cb251SWill Deacon break; 353257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0_NC: 354257cb251SWill Deacon overflow_check = false; 355257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 356257cb251SWill Deacon INSN_IMM_MOVK); 357257cb251SWill Deacon break; 358257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0: 359257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 360257cb251SWill Deacon INSN_IMM_MOVNZ); 361257cb251SWill Deacon break; 362257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1_NC: 363257cb251SWill Deacon overflow_check = false; 364257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 365257cb251SWill Deacon INSN_IMM_MOVK); 366257cb251SWill Deacon break; 367257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1: 368257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 369257cb251SWill Deacon INSN_IMM_MOVNZ); 370257cb251SWill Deacon break; 371257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2_NC: 372257cb251SWill Deacon overflow_check = false; 373257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 374257cb251SWill Deacon INSN_IMM_MOVK); 375257cb251SWill Deacon break; 376257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2: 377257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 378257cb251SWill Deacon INSN_IMM_MOVNZ); 379257cb251SWill Deacon break; 380257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G3: 381257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 382257cb251SWill Deacon overflow_check = false; 383257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, 384257cb251SWill Deacon INSN_IMM_MOVNZ); 385257cb251SWill Deacon break; 386257cb251SWill Deacon 387257cb251SWill Deacon /* Immediate instruction relocations. */ 388257cb251SWill Deacon case R_AARCH64_LD_PREL_LO19: 389257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 390257cb251SWill Deacon INSN_IMM_19); 391257cb251SWill Deacon break; 392257cb251SWill Deacon case R_AARCH64_ADR_PREL_LO21: 393257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, 394257cb251SWill Deacon INSN_IMM_ADR); 395257cb251SWill Deacon break; 396257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21_NC: 397257cb251SWill Deacon overflow_check = false; 398257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21: 399257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, 400257cb251SWill Deacon INSN_IMM_ADR); 401257cb251SWill Deacon break; 402257cb251SWill Deacon case R_AARCH64_ADD_ABS_LO12_NC: 403257cb251SWill Deacon case R_AARCH64_LDST8_ABS_LO12_NC: 404257cb251SWill Deacon overflow_check = false; 405257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, 406257cb251SWill Deacon INSN_IMM_12); 407257cb251SWill Deacon break; 408257cb251SWill Deacon case R_AARCH64_LDST16_ABS_LO12_NC: 409257cb251SWill Deacon overflow_check = false; 410257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, 411257cb251SWill Deacon INSN_IMM_12); 412257cb251SWill Deacon break; 413257cb251SWill Deacon case R_AARCH64_LDST32_ABS_LO12_NC: 414257cb251SWill Deacon overflow_check = false; 415257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, 416257cb251SWill Deacon INSN_IMM_12); 417257cb251SWill Deacon break; 418257cb251SWill Deacon case R_AARCH64_LDST64_ABS_LO12_NC: 419257cb251SWill Deacon overflow_check = false; 420257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, 421257cb251SWill Deacon INSN_IMM_12); 422257cb251SWill Deacon break; 423257cb251SWill Deacon case R_AARCH64_LDST128_ABS_LO12_NC: 424257cb251SWill Deacon overflow_check = false; 425257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, 426257cb251SWill Deacon INSN_IMM_12); 427257cb251SWill Deacon break; 428257cb251SWill Deacon case R_AARCH64_TSTBR14: 429257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, 430257cb251SWill Deacon INSN_IMM_14); 431257cb251SWill Deacon break; 432257cb251SWill Deacon case R_AARCH64_CONDBR19: 433257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 434257cb251SWill Deacon INSN_IMM_19); 435257cb251SWill Deacon break; 436257cb251SWill Deacon case R_AARCH64_JUMP26: 437257cb251SWill Deacon case R_AARCH64_CALL26: 438257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, 439257cb251SWill Deacon INSN_IMM_26); 440257cb251SWill Deacon break; 441257cb251SWill Deacon 442257cb251SWill Deacon default: 443257cb251SWill Deacon pr_err("module %s: unsupported RELA relocation: %llu\n", 444257cb251SWill Deacon me->name, ELF64_R_TYPE(rel[i].r_info)); 445257cb251SWill Deacon return -ENOEXEC; 446257cb251SWill Deacon } 447257cb251SWill Deacon 448257cb251SWill Deacon if (overflow_check && ovf == -ERANGE) 449257cb251SWill Deacon goto overflow; 450257cb251SWill Deacon 451257cb251SWill Deacon } 452257cb251SWill Deacon 453257cb251SWill Deacon return 0; 454257cb251SWill Deacon 455257cb251SWill Deacon overflow: 456257cb251SWill Deacon pr_err("module %s: overflow in relocation type %d val %Lx\n", 457257cb251SWill Deacon me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); 458257cb251SWill Deacon return -ENOEXEC; 459257cb251SWill Deacon } 460