1 /* 2 * Kernel module help for s390. 3 * 4 * S390 version 5 * Copyright IBM Corp. 2002, 2003 6 * Author(s): Arnd Bergmann (arndb@de.ibm.com) 7 * Martin Schwidefsky (schwidefsky@de.ibm.com) 8 * 9 * based on i386 version 10 * Copyright (C) 2001 Rusty Russell. 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 */ 26 #include <linux/module.h> 27 #include <linux/elf.h> 28 #include <linux/vmalloc.h> 29 #include <linux/fs.h> 30 #include <linux/string.h> 31 #include <linux/kernel.h> 32 #include <linux/moduleloader.h> 33 #include <linux/bug.h> 34 35 #if 0 36 #define DEBUGP printk 37 #else 38 #define DEBUGP(fmt , ...) 39 #endif 40 41 #define PLT_ENTRY_SIZE 20 42 43 void *module_alloc(unsigned long size) 44 { 45 if (PAGE_ALIGN(size) > MODULES_LEN) 46 return NULL; 47 return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 48 GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, 49 __builtin_return_address(0)); 50 } 51 52 void module_arch_freeing_init(struct module *mod) 53 { 54 vfree(mod->arch.syminfo); 55 mod->arch.syminfo = NULL; 56 } 57 58 static void check_rela(Elf_Rela *rela, struct module *me) 59 { 60 struct mod_arch_syminfo *info; 61 62 info = me->arch.syminfo + ELF_R_SYM (rela->r_info); 63 switch (ELF_R_TYPE (rela->r_info)) { 64 case R_390_GOT12: /* 12 bit GOT offset. */ 65 case R_390_GOT16: /* 16 bit GOT offset. */ 66 case R_390_GOT20: /* 20 bit GOT offset. */ 67 case R_390_GOT32: /* 32 bit GOT offset. */ 68 case R_390_GOT64: /* 64 bit GOT offset. */ 69 case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */ 70 case R_390_GOTPLT12: /* 12 bit offset to jump slot. */ 71 case R_390_GOTPLT16: /* 16 bit offset to jump slot. */ 72 case R_390_GOTPLT20: /* 20 bit offset to jump slot. */ 73 case R_390_GOTPLT32: /* 32 bit offset to jump slot. */ 74 case R_390_GOTPLT64: /* 64 bit offset to jump slot. */ 75 case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */ 76 if (info->got_offset == -1UL) { 77 info->got_offset = me->arch.got_size; 78 me->arch.got_size += sizeof(void*); 79 } 80 break; 81 case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */ 82 case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */ 83 case R_390_PLT32: /* 32 bit PC relative PLT address. */ 84 case R_390_PLT64: /* 64 bit PC relative PLT address. */ 85 case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */ 86 case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */ 87 case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */ 88 if (info->plt_offset == -1UL) { 89 info->plt_offset = me->arch.plt_size; 90 me->arch.plt_size += PLT_ENTRY_SIZE; 91 } 92 break; 93 case R_390_COPY: 94 case R_390_GLOB_DAT: 95 case R_390_JMP_SLOT: 96 case R_390_RELATIVE: 97 /* Only needed if we want to support loading of 98 modules linked with -shared. */ 99 break; 100 } 101 } 102 103 /* 104 * Account for GOT and PLT relocations. We can't add sections for 105 * got and plt but we can increase the core module size. 106 */ 107 int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, 108 char *secstrings, struct module *me) 109 { 110 Elf_Shdr *symtab; 111 Elf_Sym *symbols; 112 Elf_Rela *rela; 113 char *strings; 114 int nrela, i, j; 115 116 /* Find symbol table and string table. */ 117 symtab = NULL; 118 for (i = 0; i < hdr->e_shnum; i++) 119 switch (sechdrs[i].sh_type) { 120 case SHT_SYMTAB: 121 symtab = sechdrs + i; 122 break; 123 } 124 if (!symtab) { 125 printk(KERN_ERR "module %s: no symbol table\n", me->name); 126 return -ENOEXEC; 127 } 128 129 /* Allocate one syminfo structure per symbol. */ 130 me->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym); 131 me->arch.syminfo = vmalloc(me->arch.nsyms * 132 sizeof(struct mod_arch_syminfo)); 133 if (!me->arch.syminfo) 134 return -ENOMEM; 135 symbols = (void *) hdr + symtab->sh_offset; 136 strings = (void *) hdr + sechdrs[symtab->sh_link].sh_offset; 137 for (i = 0; i < me->arch.nsyms; i++) { 138 if (symbols[i].st_shndx == SHN_UNDEF && 139 strcmp(strings + symbols[i].st_name, 140 "_GLOBAL_OFFSET_TABLE_") == 0) 141 /* "Define" it as absolute. */ 142 symbols[i].st_shndx = SHN_ABS; 143 me->arch.syminfo[i].got_offset = -1UL; 144 me->arch.syminfo[i].plt_offset = -1UL; 145 me->arch.syminfo[i].got_initialized = 0; 146 me->arch.syminfo[i].plt_initialized = 0; 147 } 148 149 /* Search for got/plt relocations. */ 150 me->arch.got_size = me->arch.plt_size = 0; 151 for (i = 0; i < hdr->e_shnum; i++) { 152 if (sechdrs[i].sh_type != SHT_RELA) 153 continue; 154 nrela = sechdrs[i].sh_size / sizeof(Elf_Rela); 155 rela = (void *) hdr + sechdrs[i].sh_offset; 156 for (j = 0; j < nrela; j++) 157 check_rela(rela + j, me); 158 } 159 160 /* Increase core size by size of got & plt and set start 161 offsets for got and plt. */ 162 me->core_size = ALIGN(me->core_size, 4); 163 me->arch.got_offset = me->core_size; 164 me->core_size += me->arch.got_size; 165 me->arch.plt_offset = me->core_size; 166 me->core_size += me->arch.plt_size; 167 return 0; 168 } 169 170 static int apply_rela_bits(Elf_Addr loc, Elf_Addr val, 171 int sign, int bits, int shift) 172 { 173 unsigned long umax; 174 long min, max; 175 176 if (val & ((1UL << shift) - 1)) 177 return -ENOEXEC; 178 if (sign) { 179 val = (Elf_Addr)(((long) val) >> shift); 180 min = -(1L << (bits - 1)); 181 max = (1L << (bits - 1)) - 1; 182 if ((long) val < min || (long) val > max) 183 return -ENOEXEC; 184 } else { 185 val >>= shift; 186 umax = ((1UL << (bits - 1)) << 1) - 1; 187 if ((unsigned long) val > umax) 188 return -ENOEXEC; 189 } 190 191 if (bits == 8) 192 *(unsigned char *) loc = val; 193 else if (bits == 12) 194 *(unsigned short *) loc = (val & 0xfff) | 195 (*(unsigned short *) loc & 0xf000); 196 else if (bits == 16) 197 *(unsigned short *) loc = val; 198 else if (bits == 20) 199 *(unsigned int *) loc = (val & 0xfff) << 16 | 200 (val & 0xff000) >> 4 | 201 (*(unsigned int *) loc & 0xf00000ff); 202 else if (bits == 32) 203 *(unsigned int *) loc = val; 204 else if (bits == 64) 205 *(unsigned long *) loc = val; 206 return 0; 207 } 208 209 static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, 210 const char *strtab, struct module *me) 211 { 212 struct mod_arch_syminfo *info; 213 Elf_Addr loc, val; 214 int r_type, r_sym; 215 int rc = -ENOEXEC; 216 217 /* This is where to make the change */ 218 loc = base + rela->r_offset; 219 /* This is the symbol it is referring to. Note that all 220 undefined symbols have been resolved. */ 221 r_sym = ELF_R_SYM(rela->r_info); 222 r_type = ELF_R_TYPE(rela->r_info); 223 info = me->arch.syminfo + r_sym; 224 val = symtab[r_sym].st_value; 225 226 switch (r_type) { 227 case R_390_NONE: /* No relocation. */ 228 rc = 0; 229 break; 230 case R_390_8: /* Direct 8 bit. */ 231 case R_390_12: /* Direct 12 bit. */ 232 case R_390_16: /* Direct 16 bit. */ 233 case R_390_20: /* Direct 20 bit. */ 234 case R_390_32: /* Direct 32 bit. */ 235 case R_390_64: /* Direct 64 bit. */ 236 val += rela->r_addend; 237 if (r_type == R_390_8) 238 rc = apply_rela_bits(loc, val, 0, 8, 0); 239 else if (r_type == R_390_12) 240 rc = apply_rela_bits(loc, val, 0, 12, 0); 241 else if (r_type == R_390_16) 242 rc = apply_rela_bits(loc, val, 0, 16, 0); 243 else if (r_type == R_390_20) 244 rc = apply_rela_bits(loc, val, 1, 20, 0); 245 else if (r_type == R_390_32) 246 rc = apply_rela_bits(loc, val, 0, 32, 0); 247 else if (r_type == R_390_64) 248 rc = apply_rela_bits(loc, val, 0, 64, 0); 249 break; 250 case R_390_PC16: /* PC relative 16 bit. */ 251 case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ 252 case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */ 253 case R_390_PC32: /* PC relative 32 bit. */ 254 case R_390_PC64: /* PC relative 64 bit. */ 255 val += rela->r_addend - loc; 256 if (r_type == R_390_PC16) 257 rc = apply_rela_bits(loc, val, 1, 16, 0); 258 else if (r_type == R_390_PC16DBL) 259 rc = apply_rela_bits(loc, val, 1, 16, 1); 260 else if (r_type == R_390_PC32DBL) 261 rc = apply_rela_bits(loc, val, 1, 32, 1); 262 else if (r_type == R_390_PC32) 263 rc = apply_rela_bits(loc, val, 1, 32, 0); 264 else if (r_type == R_390_PC64) 265 rc = apply_rela_bits(loc, val, 1, 64, 0); 266 break; 267 case R_390_GOT12: /* 12 bit GOT offset. */ 268 case R_390_GOT16: /* 16 bit GOT offset. */ 269 case R_390_GOT20: /* 20 bit GOT offset. */ 270 case R_390_GOT32: /* 32 bit GOT offset. */ 271 case R_390_GOT64: /* 64 bit GOT offset. */ 272 case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */ 273 case R_390_GOTPLT12: /* 12 bit offset to jump slot. */ 274 case R_390_GOTPLT20: /* 20 bit offset to jump slot. */ 275 case R_390_GOTPLT16: /* 16 bit offset to jump slot. */ 276 case R_390_GOTPLT32: /* 32 bit offset to jump slot. */ 277 case R_390_GOTPLT64: /* 64 bit offset to jump slot. */ 278 case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */ 279 if (info->got_initialized == 0) { 280 Elf_Addr *gotent; 281 282 gotent = me->module_core + me->arch.got_offset + 283 info->got_offset; 284 *gotent = val; 285 info->got_initialized = 1; 286 } 287 val = info->got_offset + rela->r_addend; 288 if (r_type == R_390_GOT12 || 289 r_type == R_390_GOTPLT12) 290 rc = apply_rela_bits(loc, val, 0, 12, 0); 291 else if (r_type == R_390_GOT16 || 292 r_type == R_390_GOTPLT16) 293 rc = apply_rela_bits(loc, val, 0, 16, 0); 294 else if (r_type == R_390_GOT20 || 295 r_type == R_390_GOTPLT20) 296 rc = apply_rela_bits(loc, val, 1, 20, 0); 297 else if (r_type == R_390_GOT32 || 298 r_type == R_390_GOTPLT32) 299 rc = apply_rela_bits(loc, val, 0, 32, 0); 300 else if (r_type == R_390_GOT64 || 301 r_type == R_390_GOTPLT64) 302 rc = apply_rela_bits(loc, val, 0, 64, 0); 303 else if (r_type == R_390_GOTENT || 304 r_type == R_390_GOTPLTENT) { 305 val += (Elf_Addr) me->module_core - loc; 306 rc = apply_rela_bits(loc, val, 1, 32, 1); 307 } 308 break; 309 case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */ 310 case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */ 311 case R_390_PLT32: /* 32 bit PC relative PLT address. */ 312 case R_390_PLT64: /* 64 bit PC relative PLT address. */ 313 case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */ 314 case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */ 315 case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */ 316 if (info->plt_initialized == 0) { 317 unsigned int *ip; 318 ip = me->module_core + me->arch.plt_offset + 319 info->plt_offset; 320 ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */ 321 ip[1] = 0x100a0004; 322 ip[2] = 0x07f10000; 323 ip[3] = (unsigned int) (val >> 32); 324 ip[4] = (unsigned int) val; 325 info->plt_initialized = 1; 326 } 327 if (r_type == R_390_PLTOFF16 || 328 r_type == R_390_PLTOFF32 || 329 r_type == R_390_PLTOFF64) 330 val = me->arch.plt_offset - me->arch.got_offset + 331 info->plt_offset + rela->r_addend; 332 else { 333 if (!((r_type == R_390_PLT16DBL && 334 val - loc + 0xffffUL < 0x1ffffeUL) || 335 (r_type == R_390_PLT32DBL && 336 val - loc + 0xffffffffULL < 0x1fffffffeULL))) 337 val = (Elf_Addr) me->module_core + 338 me->arch.plt_offset + 339 info->plt_offset; 340 val += rela->r_addend - loc; 341 } 342 if (r_type == R_390_PLT16DBL) 343 rc = apply_rela_bits(loc, val, 1, 16, 1); 344 else if (r_type == R_390_PLTOFF16) 345 rc = apply_rela_bits(loc, val, 0, 16, 0); 346 else if (r_type == R_390_PLT32DBL) 347 rc = apply_rela_bits(loc, val, 1, 32, 1); 348 else if (r_type == R_390_PLT32 || 349 r_type == R_390_PLTOFF32) 350 rc = apply_rela_bits(loc, val, 0, 32, 0); 351 else if (r_type == R_390_PLT64 || 352 r_type == R_390_PLTOFF64) 353 rc = apply_rela_bits(loc, val, 0, 64, 0); 354 break; 355 case R_390_GOTOFF16: /* 16 bit offset to GOT. */ 356 case R_390_GOTOFF32: /* 32 bit offset to GOT. */ 357 case R_390_GOTOFF64: /* 64 bit offset to GOT. */ 358 val = val + rela->r_addend - 359 ((Elf_Addr) me->module_core + me->arch.got_offset); 360 if (r_type == R_390_GOTOFF16) 361 rc = apply_rela_bits(loc, val, 0, 16, 0); 362 else if (r_type == R_390_GOTOFF32) 363 rc = apply_rela_bits(loc, val, 0, 32, 0); 364 else if (r_type == R_390_GOTOFF64) 365 rc = apply_rela_bits(loc, val, 0, 64, 0); 366 break; 367 case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ 368 case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ 369 val = (Elf_Addr) me->module_core + me->arch.got_offset + 370 rela->r_addend - loc; 371 if (r_type == R_390_GOTPC) 372 rc = apply_rela_bits(loc, val, 1, 32, 0); 373 else if (r_type == R_390_GOTPCDBL) 374 rc = apply_rela_bits(loc, val, 1, 32, 1); 375 break; 376 case R_390_COPY: 377 case R_390_GLOB_DAT: /* Create GOT entry. */ 378 case R_390_JMP_SLOT: /* Create PLT entry. */ 379 case R_390_RELATIVE: /* Adjust by program base. */ 380 /* Only needed if we want to support loading of 381 modules linked with -shared. */ 382 return -ENOEXEC; 383 default: 384 printk(KERN_ERR "module %s: unknown relocation: %u\n", 385 me->name, r_type); 386 return -ENOEXEC; 387 } 388 if (rc) { 389 printk(KERN_ERR "module %s: relocation error for symbol %s " 390 "(r_type %i, value 0x%lx)\n", 391 me->name, strtab + symtab[r_sym].st_name, 392 r_type, (unsigned long) val); 393 return rc; 394 } 395 return 0; 396 } 397 398 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, 399 unsigned int symindex, unsigned int relsec, 400 struct module *me) 401 { 402 Elf_Addr base; 403 Elf_Sym *symtab; 404 Elf_Rela *rela; 405 unsigned long i, n; 406 int rc; 407 408 DEBUGP("Applying relocate section %u to %u\n", 409 relsec, sechdrs[relsec].sh_info); 410 base = sechdrs[sechdrs[relsec].sh_info].sh_addr; 411 symtab = (Elf_Sym *) sechdrs[symindex].sh_addr; 412 rela = (Elf_Rela *) sechdrs[relsec].sh_addr; 413 n = sechdrs[relsec].sh_size / sizeof(Elf_Rela); 414 415 for (i = 0; i < n; i++, rela++) { 416 rc = apply_rela(rela, base, symtab, strtab, me); 417 if (rc) 418 return rc; 419 } 420 return 0; 421 } 422 423 int module_finalize(const Elf_Ehdr *hdr, 424 const Elf_Shdr *sechdrs, 425 struct module *me) 426 { 427 jump_label_apply_nops(me); 428 vfree(me->arch.syminfo); 429 me->arch.syminfo = NULL; 430 return 0; 431 } 432