1a66af298SGreg Ungerer /*
2a66af298SGreg Ungerer * This file is subject to the terms and conditions of the GNU General Public
3a66af298SGreg Ungerer * License. See the file COPYING in the main directory of this archive
4a66af298SGreg Ungerer * for more details.
5a66af298SGreg Ungerer */
6a66af298SGreg Ungerer
7a66af298SGreg Ungerer #include <linux/moduleloader.h>
8a66af298SGreg Ungerer #include <linux/elf.h>
9a66af298SGreg Ungerer #include <linux/vmalloc.h>
10a66af298SGreg Ungerer #include <linux/fs.h>
11a66af298SGreg Ungerer #include <linux/string.h>
12a66af298SGreg Ungerer #include <linux/kernel.h>
13a66af298SGreg Ungerer
14a66af298SGreg Ungerer #if 0
15*7c79e1eeSGeert Uytterhoeven #define DEBUGP(fmt, ...) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
161da177e4SLinus Torvalds #else
17*7c79e1eeSGeert Uytterhoeven #define DEBUGP(fmt, ...) no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
181da177e4SLinus Torvalds #endif
19a66af298SGreg Ungerer
20a66af298SGreg Ungerer #ifdef CONFIG_MODULES
21a66af298SGreg Ungerer
apply_relocate(Elf32_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me)22a66af298SGreg Ungerer int apply_relocate(Elf32_Shdr *sechdrs,
23a66af298SGreg Ungerer const char *strtab,
24a66af298SGreg Ungerer unsigned int symindex,
25a66af298SGreg Ungerer unsigned int relsec,
26a66af298SGreg Ungerer struct module *me)
27a66af298SGreg Ungerer {
28a66af298SGreg Ungerer unsigned int i;
29a66af298SGreg Ungerer Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
30a66af298SGreg Ungerer Elf32_Sym *sym;
31a66af298SGreg Ungerer uint32_t *location;
32a66af298SGreg Ungerer
33a66af298SGreg Ungerer DEBUGP("Applying relocate section %u to %u\n", relsec,
34a66af298SGreg Ungerer sechdrs[relsec].sh_info);
35a66af298SGreg Ungerer for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
36a66af298SGreg Ungerer /* This is where to make the change */
37a66af298SGreg Ungerer location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
38a66af298SGreg Ungerer + rel[i].r_offset;
39a66af298SGreg Ungerer /* This is the symbol it is referring to. Note that all
40a66af298SGreg Ungerer undefined symbols have been resolved. */
41a66af298SGreg Ungerer sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
42a66af298SGreg Ungerer + ELF32_R_SYM(rel[i].r_info);
43a66af298SGreg Ungerer
44a66af298SGreg Ungerer switch (ELF32_R_TYPE(rel[i].r_info)) {
45a66af298SGreg Ungerer case R_68K_32:
46a66af298SGreg Ungerer /* We add the value into the location given */
47a66af298SGreg Ungerer *location += sym->st_value;
48a66af298SGreg Ungerer break;
49a66af298SGreg Ungerer case R_68K_PC32:
502e76c283SGeert Uytterhoeven /* Add the value, subtract its position */
51a66af298SGreg Ungerer *location += sym->st_value - (uint32_t)location;
52a66af298SGreg Ungerer break;
53a66af298SGreg Ungerer default:
54*7c79e1eeSGeert Uytterhoeven pr_err("module %s: Unknown relocation: %u\n", me->name,
55*7c79e1eeSGeert Uytterhoeven ELF32_R_TYPE(rel[i].r_info));
56a66af298SGreg Ungerer return -ENOEXEC;
57a66af298SGreg Ungerer }
58a66af298SGreg Ungerer }
59a66af298SGreg Ungerer return 0;
60a66af298SGreg Ungerer }
61a66af298SGreg Ungerer
apply_relocate_add(Elf32_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me)62a66af298SGreg Ungerer int apply_relocate_add(Elf32_Shdr *sechdrs,
63a66af298SGreg Ungerer const char *strtab,
64a66af298SGreg Ungerer unsigned int symindex,
65a66af298SGreg Ungerer unsigned int relsec,
66a66af298SGreg Ungerer struct module *me)
67a66af298SGreg Ungerer {
68a66af298SGreg Ungerer unsigned int i;
69a66af298SGreg Ungerer Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
70a66af298SGreg Ungerer Elf32_Sym *sym;
71a66af298SGreg Ungerer uint32_t *location;
72a66af298SGreg Ungerer
73a66af298SGreg Ungerer DEBUGP("Applying relocate_add section %u to %u\n", relsec,
74a66af298SGreg Ungerer sechdrs[relsec].sh_info);
75a66af298SGreg Ungerer for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
76a66af298SGreg Ungerer /* This is where to make the change */
77a66af298SGreg Ungerer location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
78a66af298SGreg Ungerer + rel[i].r_offset;
79a66af298SGreg Ungerer /* This is the symbol it is referring to. Note that all
80a66af298SGreg Ungerer undefined symbols have been resolved. */
81a66af298SGreg Ungerer sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
82a66af298SGreg Ungerer + ELF32_R_SYM(rel[i].r_info);
83a66af298SGreg Ungerer
84a66af298SGreg Ungerer switch (ELF32_R_TYPE(rel[i].r_info)) {
85a66af298SGreg Ungerer case R_68K_32:
86a66af298SGreg Ungerer /* We add the value into the location given */
87a66af298SGreg Ungerer *location = rel[i].r_addend + sym->st_value;
88a66af298SGreg Ungerer break;
89a66af298SGreg Ungerer case R_68K_PC32:
902e76c283SGeert Uytterhoeven /* Add the value, subtract its position */
91a66af298SGreg Ungerer *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
92a66af298SGreg Ungerer break;
93a66af298SGreg Ungerer default:
94*7c79e1eeSGeert Uytterhoeven pr_err("module %s: Unknown relocation: %u\n", me->name,
95*7c79e1eeSGeert Uytterhoeven ELF32_R_TYPE(rel[i].r_info));
96a66af298SGreg Ungerer return -ENOEXEC;
97a66af298SGreg Ungerer }
98a66af298SGreg Ungerer }
99a66af298SGreg Ungerer return 0;
100a66af298SGreg Ungerer }
101a66af298SGreg Ungerer
module_finalize(const Elf_Ehdr * hdr,const Elf_Shdr * sechdrs,struct module * mod)102a66af298SGreg Ungerer int module_finalize(const Elf_Ehdr *hdr,
103a66af298SGreg Ungerer const Elf_Shdr *sechdrs,
104a66af298SGreg Ungerer struct module *mod)
105a66af298SGreg Ungerer {
106a66af298SGreg Ungerer module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
107a66af298SGreg Ungerer return 0;
108a66af298SGreg Ungerer }
109a66af298SGreg Ungerer
110a66af298SGreg Ungerer #endif /* CONFIG_MODULES */
111a66af298SGreg Ungerer
module_fixup(struct module * mod,struct m68k_fixup_info * start,struct m68k_fixup_info * end)112a66af298SGreg Ungerer void module_fixup(struct module *mod, struct m68k_fixup_info *start,
113a66af298SGreg Ungerer struct m68k_fixup_info *end)
114a66af298SGreg Ungerer {
115a66af298SGreg Ungerer #ifdef CONFIG_MMU
116a66af298SGreg Ungerer struct m68k_fixup_info *fixup;
117a66af298SGreg Ungerer
118a66af298SGreg Ungerer for (fixup = start; fixup < end; fixup++) {
119a66af298SGreg Ungerer switch (fixup->type) {
120a66af298SGreg Ungerer case m68k_fixup_memoffset:
121a66af298SGreg Ungerer *(u32 *)fixup->addr = m68k_memoffset;
122a66af298SGreg Ungerer break;
123a66af298SGreg Ungerer case m68k_fixup_vnode_shift:
124a66af298SGreg Ungerer *(u16 *)fixup->addr += m68k_virt_to_node_shift;
125a66af298SGreg Ungerer break;
126a66af298SGreg Ungerer }
127a66af298SGreg Ungerer }
128a66af298SGreg Ungerer #endif
129a66af298SGreg Ungerer }
130