| 1 | |
| 2 | |
| 3 | *
|
| 4 | * The best reference for this stuff is probably the Processor-
|
| 5 | * Specific ELF Supplement for PA-RISC:
|
| 6 | * https://parisc.wiki.kernel.org/index.php/File:Elf-pa-hp.pdf
|
| 7 | *
|
| 8 | * Linux/PA-RISC Project
|
| 9 | * Copyright (C) 2003 Randolph Chung <tausq at debian . org>
|
| 10 | * Copyright (C) 2008 Helge Deller <[email protected]>
|
| 11 | *
|
| 12 | * Notes:
|
| 13 | * - PLT stub handling
|
| 14 | * On 32bit (and sometimes 64bit) and with big kernel modules like xfs or
|
| 15 | * ipv6 the relocation types R_PARISC_PCREL17F and R_PARISC_PCREL22F may
|
| 16 | * fail to reach their PLT stub if we only create one big stub array for
|
| 17 | * all sections at the beginning of the core or init section.
|
| 18 | * Instead we now insert individual PLT stub entries directly in front of
|
| 19 | * of the code sections where the stubs are actually called.
|
| 20 | * This reduces the distance between the PCREL location and the stub entry
|
| 21 | * so that the relocations can be fulfilled.
|
| 22 | * While calculating the final layout of the kernel module in memory, the
|
| 23 | * kernel module loader calls arch_mod_section_prepend() to request the
|
| 24 | * to be reserved amount of memory in front of each individual section.
|
| 25 | *
|
| 26 | * - SEGREL32 handling
|
| 27 | * We are not doing SEGREL32 handling correctly. According to the ABI, we
|
| 28 | * should do a value offset, like this:
|
| 29 | * if (in_init(me, (void *)val))
|
| 30 | * val -= (uint32_t)me->mem[MOD_INIT_TEXT].base;
|
| 31 | * else
|
| 32 | * val -= (uint32_t)me->mem[MOD_TEXT].base;
|
| 33 | * However, SEGREL32 is used only for PARISC unwind entries, and we want
|
| 34 | * those entries to have an absolute address, and not just an offset.
|
| 35 | *
|
| 36 | * The unwind table mechanism has the ability to specify an offset for
|
| 37 | * the unwind table; however, because we split off the init functions into
|
| 38 | * a different piece of memory, it is not possible to do this using a
|
| 39 | * single offset. Instead, we use the above hack for now.
|
| 40 |
|
| 41 |
|
| 42 | #include <linux/moduleloader.h>
|
| 43 | #include <linux/elf.h>
|
| 44 | #include <linux/fs.h>
|
| 45 | #include <linux/ftrace.h>
|
| 46 | #include <linux/string.h>
|
| 47 | #include <linux/kernel.h>
|
| 48 | #include <linux/bug.h>
|
| 49 | #include <linux/mm.h>
|
| 50 | #include <linux/slab.h>
|
| 51 |
|
| 52 | #include <asm/unwind.h>
|
| 53 | #include <asm/sections.h>
|
| 54 |
|
| 55 | #define RELOC_REACHABLE(val, bits) \
|
| 56 | (( ( !((val) & (1<<((bits)-1))) && ((val)>>(bits)) != 0 ) || \
|
| 57 | ( ((val) & (1<<((bits)-1))) && ((val)>>(bits)) != (((__typeof__(val))(~0))>>((bits)+2)))) ? \
|
| 58 | 0 : 1)
|
| 59 |
|
| 60 | #define CHECK_RELOC(val, bits) \
|
| 61 | if (!RELOC_REACHABLE(val, bits)) { \
|
| 62 | printk(KERN_ERR "module %s relocation of symbol %s is out of range (0x%lx in %d bits)\n", \
|
| 63 | me->name, strtab + sym->st_name, (unsigned long)val, bits); \
|
| 64 | return -ENOEXEC; \
|
| 65 | }
|
| 66 |
|
| 67 | |
| 68 | * the bottom of the table, which has a maximum signed displacement of
|
| 69 | * 0x3fff; however, since we're only going forward, this becomes
|
| 70 | * 0x1fff, and thus, since each GOT entry is 8 bytes long we can have
|
| 71 | * at most 1023 entries.
|
| 72 | * To overcome this 14bit displacement with some kernel modules, we'll
|
| 73 | * use instead the unusal 16bit displacement method (see reassemble_16a)
|
| 74 | * which gives us a maximum positive displacement of 0x7fff, and as such
|
| 75 | * allows us to allocate up to 4095 GOT entries.
|
| 76 | #define MAX_GOTS 4095
|
| 77 |
|
| 78 | #ifndef CONFIG_64BIT
|
| 79 | struct got_entry {
|
| 80 | Elf32_Addr addr;
|
| 81 | };
|
| 82 |
|
| 83 | struct stub_entry {
|
| 84 | Elf32_Word insns[2];
|
| 85 | };
|
| 86 | #else
|
| 87 | struct got_entry {
|
| 88 | Elf64_Addr addr;
|
| 89 | };
|
| 90 |
|
| 91 | struct stub_entry {
|
| 92 | Elf64_Word insns[4];
|
| 93 | };
|
| 94 | #endif
|
| 95 |
|
| 96 |
|
| 97 | #define rnd(x) (((x)+0x1000)&~0x1fff)
|
| 98 |
|
| 99 | #define fsel(v,a) ((v)+(a))
|
| 100 |
|
| 101 | #define lsel(v,a) (((v)+(a))>>11)
|
| 102 |
|
| 103 | #define rsel(v,a) (((v)+(a))&0x7ff)
|
| 104 |
|
| 105 | #define lrsel(v,a) (((v)+rnd(a))>>11)
|
| 106 |
|
| 107 | #define rrsel(v,a) ((((v)+rnd(a))&0x7ff)+((a)-rnd(a)))
|
| 108 |
|
| 109 | #define mask(x,sz) ((x) & ~((1<<(sz))-1))
|
| 110 |
|
| 111 |
|
| 112 | |
| 113 | insertion into an opcode. pa-risc uses all sorts of weird bitfields
|
| 114 | in the instruction to hold the value.
|
| 115 | static inline int sign_unext(int x, int len)
|
| 116 | {
|
| 117 | int len_ones;
|
| 118 |
|
| 119 | len_ones = (1 << len) - 1;
|
| 120 | return x & len_ones;
|
| 121 | }
|
| 122 |
|
| 123 | static inline int low_sign_unext(int x, int len)
|
| 124 | {
|
| 125 | int sign, temp;
|
| 126 |
|
| 127 | sign = (x >> (len-1)) & 1;
|
| 128 | temp = sign_unext(x, len-1);
|
| 129 | return (temp << 1) | sign;
|
| 130 | }
|
| 131 |
|
| 132 | static inline int reassemble_14(int as14)
|
| 133 | {
|
| 134 | return (((as14 & 0x1fff) << 1) |
|
| 135 | ((as14 & 0x2000) >> 13));
|
| 136 | }
|
| 137 |
|
| 138 | static inline int reassemble_16a(int as16)
|
| 139 | {
|
| 140 | int s, t;
|
| 141 |
|
| 142 |
|
| 143 | t = (as16 << 1) & 0xffff;
|
| 144 | s = (as16 & 0x8000);
|
| 145 | return (t ^ s ^ (s >> 1)) | (s >> 15);
|
| 146 | }
|
| 147 |
|
| 148 |
|
| 149 | static inline int reassemble_17(int as17)
|
| 150 | {
|
| 151 | return (((as17 & 0x10000) >> 16) |
|
| 152 | ((as17 & 0x0f800) << 5) |
|
| 153 | ((as17 & 0x00400) >> 8) |
|
| 154 | ((as17 & 0x003ff) << 3));
|
| 155 | }
|
| 156 |
|
| 157 | static inline int reassemble_21(int as21)
|
| 158 | {
|
| 159 | return (((as21 & 0x100000) >> 20) |
|
| 160 | ((as21 & 0x0ffe00) >> 8) |
|
| 161 | ((as21 & 0x000180) << 7) |
|
| 162 | ((as21 & 0x00007c) << 14) |
|
| 163 | ((as21 & 0x000003) << 12));
|
| 164 | }
|
| 165 |
|
| 166 | static inline int reassemble_22(int as22)
|
| 167 | {
|
| 168 | return (((as22 & 0x200000) >> 21) |
|
| 169 | ((as22 & 0x1f0000) << 5) |
|
| 170 | ((as22 & 0x00f800) << 5) |
|
| 171 | ((as22 & 0x000400) >> 8) |
|
| 172 | ((as22 & 0x0003ff) << 3));
|
| 173 | }
|
| 174 |
|
| 175 | #ifndef CONFIG_64BIT
|
| 176 | static inline unsigned long count_gots(const Elf_Rela *rela, unsigned long n)
|
| 177 | {
|
| 178 | return 0;
|
| 179 | }
|
| 180 |
|
| 181 | static inline unsigned long count_fdescs(const Elf_Rela *rela, unsigned long n)
|
| 182 | {
|
| 183 | return 0;
|
| 184 | }
|
| 185 |
|
| 186 | static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n)
|
| 187 | {
|
| 188 | unsigned long cnt = 0;
|
| 189 |
|
| 190 | for (; n > 0; n--, rela++)
|
| 191 | {
|
| 192 | switch (ELF32_R_TYPE(rela->r_info)) {
|
| 193 | case R_PARISC_PCREL17F:
|
| 194 | case R_PARISC_PCREL22F:
|
| 195 | cnt++;
|
| 196 | }
|
| 197 | }
|
| 198 |
|
| 199 | return cnt;
|
| 200 | }
|
| 201 | #else
|
| 202 | static inline unsigned long count_gots(const Elf_Rela *rela, unsigned long n)
|
| 203 | {
|
| 204 | unsigned long cnt = 0;
|
| 205 |
|
| 206 | for (; n > 0; n--, rela++)
|
| 207 | {
|
| 208 | switch (ELF64_R_TYPE(rela->r_info)) {
|
| 209 | case R_PARISC_LTOFF21L:
|
| 210 | case R_PARISC_LTOFF14R:
|
| 211 | case R_PARISC_PCREL22F:
|
| 212 | cnt++;
|
| 213 | }
|
| 214 | }
|
| 215 |
|
| 216 | return cnt;
|
| 217 | }
|
| 218 |
|
| 219 | static inline unsigned long count_fdescs(const Elf_Rela *rela, unsigned long n)
|
| 220 | {
|
| 221 | unsigned long cnt = 0;
|
| 222 |
|
| 223 | for (; n > 0; n--, rela++)
|
| 224 | {
|
| 225 | switch (ELF64_R_TYPE(rela->r_info)) {
|
| 226 | case R_PARISC_FPTR64:
|
| 227 | cnt++;
|
| 228 | }
|
| 229 | }
|
| 230 |
|
| 231 | return cnt;
|
| 232 | }
|
| 233 |
|
| 234 | static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n)
|
| 235 | {
|
| 236 | unsigned long cnt = 0;
|
| 237 |
|
| 238 | for (; n > 0; n--, rela++)
|
| 239 | {
|
| 240 | switch (ELF64_R_TYPE(rela->r_info)) {
|
| 241 | case R_PARISC_PCREL22F:
|
| 242 | cnt++;
|
| 243 | }
|
| 244 | }
|
| 245 |
|
| 246 | return cnt;
|
| 247 | }
|
| 248 | #endif
|
| 249 |
|
| 250 | void module_arch_freeing_init(struct module *mod)
|
| 251 | {
|
| 252 | kfree(mod->arch.section);
|
| 253 | mod->arch.section = NULL;
|
| 254 | }
|
| 255 |
|
| 256 |
|
| 257 | unsigned int arch_mod_section_prepend(struct module *mod,
|
| 258 | unsigned int section)
|
| 259 | {
|
| 260 | |
| 261 | * one additional for correct alignment of the stubs)
|
| 262 | return (mod->arch.section[section].stub_entries + 1)
|
| 263 | * sizeof(struct stub_entry);
|
| 264 | }
|
| 265 |
|
| 266 | #define CONST
|
| 267 | int module_frob_arch_sections(CONST Elf_Ehdr *hdr,
|
| 268 | CONST Elf_Shdr *sechdrs,
|
| 269 | CONST char *secstrings,
|
| 270 | struct module *me)
|
| 271 | {
|
| 272 | unsigned long gots = 0, fdescs = 0, len;
|
| 273 | unsigned int i;
|
| 274 | struct module_memory *mod_mem;
|
| 275 |
|
| 276 | len = hdr->e_shnum * sizeof(me->arch.section[0]);
|
| 277 | me->arch.section = kzalloc(len, GFP_KERNEL);
|
| 278 | if (!me->arch.section)
|
| 279 | return -ENOMEM;
|
| 280 |
|
| 281 | for (i = 1; i < hdr->e_shnum; i++) {
|
| 282 | const Elf_Rela *rels = (void *)sechdrs[i].sh_addr;
|
| 283 | unsigned long nrels = sechdrs[i].sh_size / sizeof(*rels);
|
| 284 | unsigned int count, s;
|
| 285 |
|
| 286 | if (strncmp(secstrings + sechdrs[i].sh_name,
|
| 287 | ".PARISC.unwind", 14) == 0)
|
| 288 | me->arch.unwind_section = i;
|
| 289 |
|
| 290 | if (sechdrs[i].sh_type != SHT_RELA)
|
| 291 | continue;
|
| 292 |
|
| 293 | |
| 294 | * we leave them here to make the code common. the
|
| 295 | * compiler will do its thing and optimize out the
|
| 296 | * stuff we don't need
|
| 297 |
|
| 298 | gots += count_gots(rels, nrels);
|
| 299 | fdescs += count_fdescs(rels, nrels);
|
| 300 |
|
| 301 | |
| 302 | * we could reduce the number of necessary stubs and save
|
| 303 | * some memory.
|
| 304 | count = count_stubs(rels, nrels);
|
| 305 | if (!count)
|
| 306 | continue;
|
| 307 |
|
| 308 |
|
| 309 |
|
| 310 | s = sechdrs[i].sh_info;
|
| 311 |
|
| 312 |
|
| 313 | WARN_ON(me->arch.section[s].stub_entries);
|
| 314 |
|
| 315 |
|
| 316 | me->arch.section[s].stub_entries += count;
|
| 317 | }
|
| 318 |
|
| 319 | mod_mem = &me->mem[MOD_TEXT];
|
| 320 |
|
| 321 | mod_mem->size = ALIGN(mod_mem->size, 16);
|
| 322 | me->arch.got_offset = mod_mem->size;
|
| 323 | mod_mem->size += gots * sizeof(struct got_entry);
|
| 324 |
|
| 325 | mod_mem->size = ALIGN(mod_mem->size, 16);
|
| 326 | me->arch.fdesc_offset = mod_mem->size;
|
| 327 | mod_mem->size += fdescs * sizeof(Elf_Fdesc);
|
| 328 |
|
| 329 | me->arch.got_max = gots;
|
| 330 | me->arch.fdesc_max = fdescs;
|
| 331 |
|
| 332 | return 0;
|
| 333 | }
|
| 334 |
|
| 335 | #ifdef CONFIG_64BIT
|
| 336 | static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
|
| 337 | {
|
| 338 | unsigned int i;
|
| 339 | struct got_entry *got;
|
| 340 |
|
| 341 | value += addend;
|
| 342 |
|
| 343 | BUG_ON(value == 0);
|
| 344 |
|
| 345 | got = me->mem[MOD_TEXT].base + me->arch.got_offset;
|
| 346 | for (i = 0; got[i].addr; i++)
|
| 347 | if (got[i].addr == value)
|
| 348 | goto out;
|
| 349 |
|
| 350 | BUG_ON(++me->arch.got_count > me->arch.got_max);
|
| 351 |
|
| 352 | got[i].addr = value;
|
| 353 | out:
|
| 354 | pr_debug("GOT ENTRY %d[%lx] val %lx\n", i, i*sizeof(struct got_entry),
|
| 355 | value);
|
| 356 | return i * sizeof(struct got_entry);
|
| 357 | }
|
| 358 | #endif
|
| 359 |
|
| 360 | #ifdef CONFIG_64BIT
|
| 361 | static Elf_Addr get_fdesc(struct module *me, unsigned long value)
|
| 362 | {
|
| 363 | Elf_Fdesc *fdesc = me->mem[MOD_TEXT].base + me->arch.fdesc_offset;
|
| 364 |
|
| 365 | if (!value) {
|
| 366 | printk(KERN_ERR "%s: zero OPD requested!\n", me->name);
|
| 367 | return 0;
|
| 368 | }
|
| 369 |
|
| 370 |
|
| 371 | while (fdesc->addr) {
|
| 372 | if (fdesc->addr == value)
|
| 373 | return (Elf_Addr)fdesc;
|
| 374 | fdesc++;
|
| 375 | }
|
| 376 |
|
| 377 | BUG_ON(++me->arch.fdesc_count > me->arch.fdesc_max);
|
| 378 |
|
| 379 |
|
| 380 | fdesc->addr = value;
|
| 381 | fdesc->gp = (Elf_Addr)me->mem[MOD_TEXT].base + me->arch.got_offset;
|
| 382 | return (Elf_Addr)fdesc;
|
| 383 | }
|
| 384 | #endif
|
| 385 |
|
| 386 | enum elf_stub_type {
|
| 387 | ELF_STUB_GOT,
|
| 388 | ELF_STUB_MILLI,
|
| 389 | ELF_STUB_DIRECT,
|
| 390 | };
|
| 391 |
|
| 392 | static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
|
| 393 | enum elf_stub_type stub_type, Elf_Addr loc0, unsigned int targetsec)
|
| 394 | {
|
| 395 | struct stub_entry *stub;
|
| 396 | int __maybe_unused d;
|
| 397 |
|
| 398 |
|
| 399 | if (!me->arch.section[targetsec].stub_offset) {
|
| 400 | loc0 -= (me->arch.section[targetsec].stub_entries + 1) *
|
| 401 | sizeof(struct stub_entry);
|
| 402 |
|
| 403 | loc0 = ALIGN(loc0, sizeof(struct stub_entry));
|
| 404 | me->arch.section[targetsec].stub_offset = loc0;
|
| 405 | }
|
| 406 |
|
| 407 |
|
| 408 | stub = (void *) me->arch.section[targetsec].stub_offset;
|
| 409 | me->arch.section[targetsec].stub_offset += sizeof(struct stub_entry);
|
| 410 |
|
| 411 |
|
| 412 | BUG_ON(0 == me->arch.section[targetsec].stub_entries--);
|
| 413 |
|
| 414 |
|
| 415 | #ifndef CONFIG_64BIT
|
| 416 | |
| 417 | * ldil L'XXX,%r1
|
| 418 | * be,n R'XXX(%sr4,%r1)
|
| 419 |
|
| 420 | |
| 421 |
|
| 422 | stub->insns[0] = 0x20200000;
|
| 423 | stub->insns[1] = 0xe0202002;
|
| 424 |
|
| 425 | stub->insns[0] |= reassemble_21(lrsel(value, addend));
|
| 426 | stub->insns[1] |= reassemble_17(rrsel(value, addend) / 4);
|
| 427 |
|
| 428 | #else
|
| 429 | |
| 430 | * for normal function calls:
|
| 431 | * ldd 0(%dp),%dp
|
| 432 | * ldd 10(%dp), %r1
|
| 433 | * bve (%r1)
|
| 434 | * ldd 18(%dp), %dp
|
| 435 | *
|
| 436 | * for millicode:
|
| 437 | * ldil 0, %r1
|
| 438 | * ldo 0(%r1), %r1
|
| 439 | * ldd 10(%r1), %r1
|
| 440 | * bve,n (%r1)
|
| 441 | *
|
| 442 | * for direct branches (jumps between different section of the
|
| 443 | * same module):
|
| 444 | * ldil 0, %r1
|
| 445 | * ldo 0(%r1), %r1
|
| 446 | * bve,n (%r1)
|
| 447 |
|
| 448 | switch (stub_type) {
|
| 449 | case ELF_STUB_GOT:
|
| 450 | d = get_got(me, value, addend);
|
| 451 | if (d <= 15) {
|
| 452 |
|
| 453 | stub->insns[0] = 0x0f6010db;
|
| 454 | stub->insns[0] |= low_sign_unext(d, 5) << 16;
|
| 455 | } else {
|
| 456 |
|
| 457 | stub->insns[0] = 0x537b0000;
|
| 458 | stub->insns[0] |= reassemble_16a(d);
|
| 459 | }
|
| 460 | stub->insns[1] = 0x53610020;
|
| 461 | stub->insns[2] = 0xe820d000;
|
| 462 | stub->insns[3] = 0x537b0030;
|
| 463 | break;
|
| 464 | case ELF_STUB_MILLI:
|
| 465 | stub->insns[0] = 0x20200000;
|
| 466 | stub->insns[1] = 0x34210000;
|
| 467 | stub->insns[2] = 0x50210020;
|
| 468 | stub->insns[3] = 0xe820d002;
|
| 469 |
|
| 470 | stub->insns[0] |= reassemble_21(lrsel(value, addend));
|
| 471 | stub->insns[1] |= reassemble_14(rrsel(value, addend));
|
| 472 | break;
|
| 473 | case ELF_STUB_DIRECT:
|
| 474 | stub->insns[0] = 0x20200000;
|
| 475 | stub->insns[1] = 0x34210000;
|
| 476 | stub->insns[2] = 0xe820d002;
|
| 477 |
|
| 478 | stub->insns[0] |= reassemble_21(lrsel(value, addend));
|
| 479 | stub->insns[1] |= reassemble_14(rrsel(value, addend));
|
| 480 | break;
|
| 481 | }
|
| 482 |
|
| 483 | #endif
|
| 484 |
|
| 485 | return (Elf_Addr)stub;
|
| 486 | }
|
| 487 |
|
| 488 | #ifndef CONFIG_64BIT
|
| 489 | int apply_relocate_add(Elf_Shdr *sechdrs,
|
| 490 | const char *strtab,
|
| 491 | unsigned int symindex,
|
| 492 | unsigned int relsec,
|
| 493 | struct module *me)
|
| 494 | {
|
| 495 | int i;
|
| 496 | Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
|
| 497 | Elf32_Sym *sym;
|
| 498 | Elf32_Word *loc;
|
| 499 | Elf32_Addr val;
|
| 500 | Elf32_Sword addend;
|
| 501 | Elf32_Addr dot;
|
| 502 | Elf_Addr loc0;
|
| 503 | unsigned int targetsec = sechdrs[relsec].sh_info;
|
| 504 | |
| 505 | register unsigned long dp asm ("r27");
|
| 506 |
|
| 507 | pr_debug("Applying relocate section %u to %u\n", relsec,
|
| 508 | targetsec);
|
| 509 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
| 510 |
|
| 511 | loc = (void *)sechdrs[targetsec].sh_addr
|
| 512 | + rel[i].r_offset;
|
| 513 |
|
| 514 | loc0 = sechdrs[targetsec].sh_addr;
|
| 515 |
|
| 516 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
|
| 517 | + ELF32_R_SYM(rel[i].r_info);
|
| 518 | if (!sym->st_value) {
|
| 519 | printk(KERN_WARNING "%s: Unknown symbol %s\n",
|
| 520 | me->name, strtab + sym->st_name);
|
| 521 | return -ENOENT;
|
| 522 | }
|
| 523 | |
| 524 | dot = (Elf32_Addr)loc & ~0x03;
|
| 525 |
|
| 526 | val = sym->st_value;
|
| 527 | addend = rel[i].r_addend;
|
| 528 |
|
| 529 | #if 0 |
| 530 | #define r(t) ELF32_R_TYPE(rel[i].r_info)==t ? #t :
|
| 531 | pr_debug("Symbol %s loc 0x%x val 0x%x addend 0x%x: %s\n",
|
| 532 | strtab + sym->st_name,
|
| 533 | (uint32_t)loc, val, addend,
|
| 534 | r(R_PARISC_PLABEL32)
|
| 535 | r(R_PARISC_DIR32)
|
| 536 | r(R_PARISC_DIR21L)
|
| 537 | r(R_PARISC_DIR14R)
|
| 538 | r(R_PARISC_SEGREL32)
|
| 539 | r(R_PARISC_DPREL21L)
|
| 540 | r(R_PARISC_DPREL14R)
|
| 541 | r(R_PARISC_PCREL17F)
|
| 542 | r(R_PARISC_PCREL22F)
|
| 543 | "UNKNOWN");
|
| 544 | #undef r
|
| 545 | #endif
|
| 546 |
|
| 547 | switch (ELF32_R_TYPE(rel[i].r_info)) {
|
| 548 | case R_PARISC_PLABEL32:
|
| 549 |
|
| 550 |
|
| 551 | *loc = fsel(val, addend);
|
| 552 | break;
|
| 553 | case R_PARISC_DIR32:
|
| 554 |
|
| 555 | *loc = fsel(val, addend);
|
| 556 | break;
|
| 557 | case R_PARISC_DIR21L:
|
| 558 |
|
| 559 | val = lrsel(val, addend);
|
| 560 | *loc = mask(*loc, 21) | reassemble_21(val);
|
| 561 | break;
|
| 562 | case R_PARISC_DIR14R:
|
| 563 |
|
| 564 | val = rrsel(val, addend);
|
| 565 | *loc = mask(*loc, 14) | reassemble_14(val);
|
| 566 | break;
|
| 567 | case R_PARISC_SEGREL32:
|
| 568 |
|
| 569 | |
| 570 | * the beginning of this file.
|
| 571 |
|
| 572 | *loc = fsel(val, addend);
|
| 573 | break;
|
| 574 | case R_PARISC_SECREL32:
|
| 575 |
|
| 576 | *loc = fsel(val, addend);
|
| 577 | break;
|
| 578 | case R_PARISC_DPREL21L:
|
| 579 |
|
| 580 | val = lrsel(val - dp, addend);
|
| 581 | *loc = mask(*loc, 21) | reassemble_21(val);
|
| 582 | break;
|
| 583 | case R_PARISC_DPREL14R:
|
| 584 |
|
| 585 | val = rrsel(val - dp, addend);
|
| 586 | *loc = mask(*loc, 14) | reassemble_14(val);
|
| 587 | break;
|
| 588 | case R_PARISC_PCREL17F:
|
| 589 |
|
| 590 |
|
| 591 | val += addend;
|
| 592 | val = (val - dot - 8)/4;
|
| 593 | if (!RELOC_REACHABLE(val, 17)) {
|
| 594 | |
| 595 | * stub entry instead
|
| 596 | val = get_stub(me, sym->st_value, addend,
|
| 597 | ELF_STUB_DIRECT, loc0, targetsec);
|
| 598 | val = (val - dot - 8)/4;
|
| 599 | CHECK_RELOC(val, 17);
|
| 600 | }
|
| 601 | *loc = (*loc & ~0x1f1ffd) | reassemble_17(val);
|
| 602 | break;
|
| 603 | case R_PARISC_PCREL22F:
|
| 604 |
|
| 605 |
|
| 606 | val += addend;
|
| 607 | val = (val - dot - 8)/4;
|
| 608 | if (!RELOC_REACHABLE(val, 22)) {
|
| 609 | |
| 610 | * stub entry instead
|
| 611 | val = get_stub(me, sym->st_value, addend,
|
| 612 | ELF_STUB_DIRECT, loc0, targetsec);
|
| 613 | val = (val - dot - 8)/4;
|
| 614 | CHECK_RELOC(val, 22);
|
| 615 | }
|
| 616 | *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val);
|
| 617 | break;
|
| 618 | case R_PARISC_PCREL32:
|
| 619 |
|
| 620 | *loc = val - dot - 8 + addend;
|
| 621 | break;
|
| 622 |
|
| 623 | default:
|
| 624 | printk(KERN_ERR "module %s: Unknown relocation: %u\n",
|
| 625 | me->name, ELF32_R_TYPE(rel[i].r_info));
|
| 626 | return -ENOEXEC;
|
| 627 | }
|
| 628 | }
|
| 629 |
|
| 630 | return 0;
|
| 631 | }
|
| 632 |
|
| 633 | #else
|
| 634 | int apply_relocate_add(Elf_Shdr *sechdrs,
|
| 635 | const char *strtab,
|
| 636 | unsigned int symindex,
|
| 637 | unsigned int relsec,
|
| 638 | struct module *me)
|
| 639 | {
|
| 640 | int i;
|
| 641 | Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
|
| 642 | Elf64_Sym *sym;
|
| 643 | Elf64_Word *loc;
|
| 644 | Elf64_Xword *loc64;
|
| 645 | Elf64_Addr val;
|
| 646 | Elf64_Sxword addend;
|
| 647 | Elf64_Addr dot;
|
| 648 | Elf_Addr loc0;
|
| 649 | unsigned int targetsec = sechdrs[relsec].sh_info;
|
| 650 |
|
| 651 | pr_debug("Applying relocate section %u to %u\n", relsec,
|
| 652 | targetsec);
|
| 653 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
| 654 |
|
| 655 | loc = (void *)sechdrs[targetsec].sh_addr
|
| 656 | + rel[i].r_offset;
|
| 657 |
|
| 658 | loc0 = sechdrs[targetsec].sh_addr;
|
| 659 |
|
| 660 | sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
|
| 661 | + ELF64_R_SYM(rel[i].r_info);
|
| 662 | if (!sym->st_value) {
|
| 663 | printk(KERN_WARNING "%s: Unknown symbol %s\n",
|
| 664 | me->name, strtab + sym->st_name);
|
| 665 | return -ENOENT;
|
| 666 | }
|
| 667 | |
| 668 | dot = (Elf64_Addr)loc & ~0x03;
|
| 669 | loc64 = (Elf64_Xword *)loc;
|
| 670 |
|
| 671 | val = sym->st_value;
|
| 672 | addend = rel[i].r_addend;
|
| 673 |
|
| 674 | #if 0 |
| 675 | #define r(t) ELF64_R_TYPE(rel[i].r_info)==t ? #t :
|
| 676 | printk("Symbol %s loc %p val 0x%Lx addend 0x%Lx: %s\n",
|
| 677 | strtab + sym->st_name,
|
| 678 | loc, val, addend,
|
| 679 | r(R_PARISC_LTOFF14R)
|
| 680 | r(R_PARISC_LTOFF21L)
|
| 681 | r(R_PARISC_PCREL22F)
|
| 682 | r(R_PARISC_DIR64)
|
| 683 | r(R_PARISC_SEGREL32)
|
| 684 | r(R_PARISC_FPTR64)
|
| 685 | "UNKNOWN");
|
| 686 | #undef r
|
| 687 | #endif
|
| 688 |
|
| 689 | switch (ELF64_R_TYPE(rel[i].r_info)) {
|
| 690 | case R_PARISC_LTOFF21L:
|
| 691 |
|
| 692 | val = get_got(me, val, addend);
|
| 693 | pr_debug("LTOFF21L Symbol %s loc %p val %llx\n",
|
| 694 | strtab + sym->st_name,
|
| 695 | loc, val);
|
| 696 | val = lrsel(val, 0);
|
| 697 | *loc = mask(*loc, 21) | reassemble_21(val);
|
| 698 | break;
|
| 699 | case R_PARISC_LTOFF14R:
|
| 700 |
|
| 701 |
|
| 702 | val = get_got(me, val, addend);
|
| 703 | val = rrsel(val, 0);
|
| 704 | pr_debug("LTOFF14R Symbol %s loc %p val %llx\n",
|
| 705 | strtab + sym->st_name,
|
| 706 | loc, val);
|
| 707 | *loc = mask(*loc, 14) | reassemble_14(val);
|
| 708 | break;
|
| 709 | case R_PARISC_PCREL22F:
|
| 710 |
|
| 711 | pr_debug("PCREL22F Symbol %s loc %p val %llx\n",
|
| 712 | strtab + sym->st_name,
|
| 713 | loc, val);
|
| 714 | val += addend;
|
| 715 |
|
| 716 | if (within_module(val, me)) {
|
| 717 | |
| 718 | * to the module, but in a different section,
|
| 719 | * so stub the jump in case it's more than 22
|
| 720 | * bits away
|
| 721 | val = (val - dot - 8)/4;
|
| 722 | if (!RELOC_REACHABLE(val, 22)) {
|
| 723 | |
| 724 | * stub entry instead
|
| 725 | val = get_stub(me, sym->st_value,
|
| 726 | addend, ELF_STUB_DIRECT,
|
| 727 | loc0, targetsec);
|
| 728 | } else {
|
| 729 |
|
| 730 | val = sym->st_value;
|
| 731 | val += addend;
|
| 732 | }
|
| 733 | } else {
|
| 734 | val = sym->st_value;
|
| 735 | if (strncmp(strtab + sym->st_name, "$$", 2)
|
| 736 | == 0)
|
| 737 | val = get_stub(me, val, addend, ELF_STUB_MILLI,
|
| 738 | loc0, targetsec);
|
| 739 | else
|
| 740 | val = get_stub(me, val, addend, ELF_STUB_GOT,
|
| 741 | loc0, targetsec);
|
| 742 | }
|
| 743 | pr_debug("STUB FOR %s loc %px, val %llx+%llx at %llx\n",
|
| 744 | strtab + sym->st_name, loc, sym->st_value,
|
| 745 | addend, val);
|
| 746 | val = (val - dot - 8)/4;
|
| 747 | CHECK_RELOC(val, 22);
|
| 748 | *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val);
|
| 749 | break;
|
| 750 | case R_PARISC_PCREL32:
|
| 751 |
|
| 752 | *loc = val - dot - 8 + addend;
|
| 753 | break;
|
| 754 | case R_PARISC_PCREL64:
|
| 755 |
|
| 756 | *loc64 = val - dot - 8 + addend;
|
| 757 | break;
|
| 758 | case R_PARISC_DIR64:
|
| 759 |
|
| 760 | *loc64 = val + addend;
|
| 761 | break;
|
| 762 | case R_PARISC_SEGREL32:
|
| 763 |
|
| 764 | |
| 765 | * the beginning of this file.
|
| 766 |
|
| 767 | *loc = fsel(val, addend);
|
| 768 | break;
|
| 769 | case R_PARISC_SECREL32:
|
| 770 |
|
| 771 | *loc = fsel(val, addend);
|
| 772 | break;
|
| 773 | case R_PARISC_FPTR64:
|
| 774 |
|
| 775 | if (within_module(val + addend, me)) {
|
| 776 | *loc64 = get_fdesc(me, val+addend);
|
| 777 | pr_debug("FDESC for %s at %llx points to %llx\n",
|
| 778 | strtab + sym->st_name, *loc64,
|
| 779 | ((Elf_Fdesc *)*loc64)->addr);
|
| 780 | } else {
|
| 781 | |
| 782 | * module then val+addend is a pointer
|
| 783 | * to the function descriptor
|
| 784 | pr_debug("Non local FPTR64 Symbol %s loc %p val %llx\n",
|
| 785 | strtab + sym->st_name,
|
| 786 | loc, val);
|
| 787 | *loc64 = val + addend;
|
| 788 | }
|
| 789 | break;
|
| 790 |
|
| 791 | default:
|
| 792 | printk(KERN_ERR "module %s: Unknown relocation: %Lu\n",
|
| 793 | me->name, ELF64_R_TYPE(rel[i].r_info));
|
| 794 | return -ENOEXEC;
|
| 795 | }
|
| 796 | }
|
| 797 | return 0;
|
| 798 | }
|
| 799 | #endif
|
| 800 |
|
| 801 | static void
|
| 802 | register_unwind_table(struct module *me,
|
| 803 | const Elf_Shdr *sechdrs)
|
| 804 | {
|
| 805 | unsigned char *table, *end;
|
| 806 | unsigned long gp;
|
| 807 |
|
| 808 | if (!me->arch.unwind_section)
|
| 809 | return;
|
| 810 |
|
| 811 | table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr;
|
| 812 | end = table + sechdrs[me->arch.unwind_section].sh_size;
|
| 813 | gp = (Elf_Addr)me->mem[MOD_TEXT].base + me->arch.got_offset;
|
| 814 |
|
| 815 | pr_debug("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n",
|
| 816 | me->arch.unwind_section, table, end, gp);
|
| 817 | me->arch.unwind = unwind_table_add(me->name, 0, gp, table, end);
|
| 818 | }
|
| 819 |
|
| 820 | static void
|
| 821 | deregister_unwind_table(struct module *me)
|
| 822 | {
|
| 823 | if (me->arch.unwind)
|
| 824 | unwind_table_remove(me->arch.unwind);
|
| 825 | }
|
| 826 |
|
| 827 | int module_finalize(const Elf_Ehdr *hdr,
|
| 828 | const Elf_Shdr *sechdrs,
|
| 829 | struct module *me)
|
| 830 | {
|
| 831 | int i;
|
| 832 | unsigned long nsyms;
|
| 833 | const char *strtab = NULL;
|
| 834 | const Elf_Shdr *s;
|
| 835 | char *secstrings;
|
| 836 | int symindex __maybe_unused = -1;
|
| 837 | Elf_Sym *newptr, *oldptr;
|
| 838 | Elf_Shdr *symhdr = NULL;
|
| 839 | #ifdef DEBUG
|
| 840 | Elf_Fdesc *entry;
|
| 841 | u32 *addr;
|
| 842 |
|
| 843 | entry = (Elf_Fdesc *)me->init;
|
| 844 | printk("FINALIZE, ->init FPTR is %p, GP %lx ADDR %lx\n", entry,
|
| 845 | entry->gp, entry->addr);
|
| 846 | addr = (u32 *)entry->addr;
|
| 847 | printk("INSNS: %x %x %x %x\n",
|
| 848 | addr[0], addr[1], addr[2], addr[3]);
|
| 849 | printk("got entries used %ld, gots max %ld\n"
|
| 850 | "fdescs used %ld, fdescs max %ld\n",
|
| 851 | me->arch.got_count, me->arch.got_max,
|
| 852 | me->arch.fdesc_count, me->arch.fdesc_max);
|
| 853 | #endif
|
| 854 |
|
| 855 | register_unwind_table(me, sechdrs);
|
| 856 |
|
| 857 | |
| 858 | * ourselves
|
| 859 | for (i = 1; i < hdr->e_shnum; i++) {
|
| 860 | if(sechdrs[i].sh_type == SHT_SYMTAB
|
| 861 | && (sechdrs[i].sh_flags & SHF_ALLOC)) {
|
| 862 | int strindex = sechdrs[i].sh_link;
|
| 863 | symindex = i;
|
| 864 | |
| 865 | * The cast is to drop the const from
|
| 866 | * the sechdrs pointer
|
| 867 | symhdr = (Elf_Shdr *)&sechdrs[i];
|
| 868 | strtab = (char *)sechdrs[strindex].sh_addr;
|
| 869 | break;
|
| 870 | }
|
| 871 | }
|
| 872 |
|
| 873 | pr_debug("module %s: strtab %p, symhdr %p\n",
|
| 874 | me->name, strtab, symhdr);
|
| 875 |
|
| 876 | if(me->arch.got_count > MAX_GOTS) {
|
| 877 | printk(KERN_ERR "%s: Global Offset Table overflow (used %ld, allowed %d)\n",
|
| 878 | me->name, me->arch.got_count, MAX_GOTS);
|
| 879 | return -EINVAL;
|
| 880 | }
|
| 881 |
|
| 882 | kfree(me->arch.section);
|
| 883 | me->arch.section = NULL;
|
| 884 |
|
| 885 |
|
| 886 | if(symhdr == NULL)
|
| 887 | return 0;
|
| 888 |
|
| 889 | oldptr = (void *)symhdr->sh_addr;
|
| 890 | newptr = oldptr + 1;
|
| 891 | nsyms = symhdr->sh_size / sizeof(Elf_Sym);
|
| 892 | pr_debug("OLD num_symtab %lu\n", nsyms);
|
| 893 |
|
| 894 | for (i = 1; i < nsyms; i++) {
|
| 895 | oldptr++;
|
| 896 | if(strncmp(strtab + oldptr->st_name,
|
| 897 | ".L", 2) == 0)
|
| 898 | continue;
|
| 899 |
|
| 900 | if(newptr != oldptr)
|
| 901 | *newptr++ = *oldptr;
|
| 902 | else
|
| 903 | newptr++;
|
| 904 |
|
| 905 | }
|
| 906 | nsyms = newptr - (Elf_Sym *)symhdr->sh_addr;
|
| 907 | pr_debug("NEW num_symtab %lu\n", nsyms);
|
| 908 | symhdr->sh_size = nsyms * sizeof(Elf_Sym);
|
| 909 |
|
| 910 |
|
| 911 | secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
| 912 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
|
| 913 | void *aseg = (void *) s->sh_addr;
|
| 914 | char *secname = secstrings + s->sh_name;
|
| 915 |
|
| 916 | if (!strcmp(".altinstructions", secname))
|
| 917 |
|
| 918 | apply_alternatives(aseg, aseg + s->sh_size, me->name);
|
| 919 |
|
| 920 | #ifdef CONFIG_DYNAMIC_FTRACE
|
| 921 | |
| 922 | * -ffunction-sections so we must relocate the addresses in the
|
| 923 | * ftrace callsite section.
|
| 924 |
|
| 925 | if (symindex != -1 && !strcmp(secname, FTRACE_CALLSITE_SECTION)) {
|
| 926 | int err;
|
| 927 | if (s->sh_type == SHT_REL)
|
| 928 | err = apply_relocate((Elf_Shdr *)sechdrs,
|
| 929 | strtab, symindex,
|
| 930 | s - sechdrs, me);
|
| 931 | else if (s->sh_type == SHT_RELA)
|
| 932 | err = apply_relocate_add((Elf_Shdr *)sechdrs,
|
| 933 | strtab, symindex,
|
| 934 | s - sechdrs, me);
|
| 935 | if (err)
|
| 936 | return err;
|
| 937 | }
|
| 938 | #endif
|
| 939 | }
|
| 940 | return 0;
|
| 941 | }
|
| 942 |
|
| 943 | void module_arch_cleanup(struct module *mod)
|
| 944 | {
|
| 945 | deregister_unwind_table(mod);
|
| 946 | }
|
| 947 |
|
| 948 | #ifdef CONFIG_64BIT
|
| 949 | void *dereference_module_function_descriptor(struct module *mod, void *ptr)
|
| 950 | {
|
| 951 | unsigned long start_opd = (Elf64_Addr)mod->mem[MOD_TEXT].base +
|
| 952 | mod->arch.fdesc_offset;
|
| 953 | unsigned long end_opd = start_opd +
|
| 954 | mod->arch.fdesc_count * sizeof(Elf64_Fdesc);
|
| 955 |
|
| 956 | if (ptr < (void *)start_opd || ptr >= (void *)end_opd)
|
| 957 | return ptr;
|
| 958 |
|
| 959 | return dereference_function_descriptor(ptr);
|
| 960 | }
|
| 961 | #endif
|