| 1 | |
| 2 | |
| 3 |
|
| 4 | SHcompact version by Kaz Kojima and Paul Mundt.
|
| 5 |
|
| 6 | SHmedia bits:
|
| 7 |
|
| 8 | Copyright 2004 SuperH (UK) Ltd
|
| 9 | Author: Richard Curnow
|
| 10 |
|
| 11 | Based on the sh version, and on code from the sh64-specific parts of
|
| 12 | modutils, originally written by Richard Curnow and Ben Gaster.
|
| 13 |
|
| 14 | #include <linux/moduleloader.h>
|
| 15 | #include <linux/elf.h>
|
| 16 | #include <linux/vmalloc.h>
|
| 17 | #include <linux/bug.h>
|
| 18 | #include <linux/fs.h>
|
| 19 | #include <linux/string.h>
|
| 20 | #include <linux/kernel.h>
|
| 21 | #include <linux/unaligned.h>
|
| 22 | #include <asm/dwarf.h>
|
| 23 |
|
| 24 | int apply_relocate_add(Elf32_Shdr *sechdrs,
|
| 25 | const char *strtab,
|
| 26 | unsigned int symindex,
|
| 27 | unsigned int relsec,
|
| 28 | struct module *me)
|
| 29 | {
|
| 30 | unsigned int i;
|
| 31 | Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
|
| 32 | Elf32_Sym *sym;
|
| 33 | Elf32_Addr relocation;
|
| 34 | uint32_t *location;
|
| 35 | uint32_t value;
|
| 36 |
|
| 37 | pr_debug("Applying relocate section %u to %u\n", relsec,
|
| 38 | sechdrs[relsec].sh_info);
|
| 39 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
| 40 |
|
| 41 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
|
| 42 | + rel[i].r_offset;
|
| 43 | |
| 44 | undefined symbols have been resolved.
|
| 45 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
|
| 46 | + ELF32_R_SYM(rel[i].r_info);
|
| 47 | relocation = sym->st_value + rel[i].r_addend;
|
| 48 |
|
| 49 | switch (ELF32_R_TYPE(rel[i].r_info)) {
|
| 50 | case R_SH_NONE:
|
| 51 | break;
|
| 52 | case R_SH_DIR32:
|
| 53 | value = get_unaligned(location);
|
| 54 | value += relocation;
|
| 55 | put_unaligned(value, location);
|
| 56 | break;
|
| 57 | case R_SH_REL32:
|
| 58 | relocation = (relocation - (Elf32_Addr) location);
|
| 59 | value = get_unaligned(location);
|
| 60 | value += relocation;
|
| 61 | put_unaligned(value, location);
|
| 62 | break;
|
| 63 | case R_SH_IMM_LOW16:
|
| 64 | *location = (*location & ~0x3fffc00) |
|
| 65 | ((relocation & 0xffff) << 10);
|
| 66 | break;
|
| 67 | case R_SH_IMM_MEDLOW16:
|
| 68 | *location = (*location & ~0x3fffc00) |
|
| 69 | (((relocation >> 16) & 0xffff) << 10);
|
| 70 | break;
|
| 71 | case R_SH_IMM_LOW16_PCREL:
|
| 72 | relocation -= (Elf32_Addr) location;
|
| 73 | *location = (*location & ~0x3fffc00) |
|
| 74 | ((relocation & 0xffff) << 10);
|
| 75 | break;
|
| 76 | case R_SH_IMM_MEDLOW16_PCREL:
|
| 77 | relocation -= (Elf32_Addr) location;
|
| 78 | *location = (*location & ~0x3fffc00) |
|
| 79 | (((relocation >> 16) & 0xffff) << 10);
|
| 80 | break;
|
| 81 | default:
|
| 82 | printk(KERN_ERR "module %s: Unknown relocation: %u\n",
|
| 83 | me->name, ELF32_R_TYPE(rel[i].r_info));
|
| 84 | return -ENOEXEC;
|
| 85 | }
|
| 86 | }
|
| 87 | return 0;
|
| 88 | }
|
| 89 |
|
| 90 | int module_finalize(const Elf_Ehdr *hdr,
|
| 91 | const Elf_Shdr *sechdrs,
|
| 92 | struct module *me)
|
| 93 | {
|
| 94 | int ret = 0;
|
| 95 |
|
| 96 | ret |= module_dwarf_finalize(hdr, sechdrs, me);
|
| 97 |
|
| 98 | return ret;
|
| 99 | }
|
| 100 |
|
| 101 | void module_arch_cleanup(struct module *mod)
|
| 102 | {
|
| 103 | module_dwarf_cleanup(mod);
|
| 104 | }
|