1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* Kernel module help for SH. |
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 <asm/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 | /* This is where to make the change */ |
41 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr |
42 | + rel[i].r_offset; |
43 | /* This is the symbol it is referring to. Note that all |
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 | } |
105 | |