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 15a66af298SGreg Ungerer #define DEBUGP printk 161da177e4SLinus Torvalds #else 17a66af298SGreg Ungerer #define DEBUGP(fmt...) 181da177e4SLinus Torvalds #endif 19a66af298SGreg Ungerer 20a66af298SGreg Ungerer #ifdef CONFIG_MODULES 21a66af298SGreg Ungerer 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: 50*2e76c283SGeert Uytterhoeven /* Add the value, subtract its position */ 51a66af298SGreg Ungerer *location += sym->st_value - (uint32_t)location; 52a66af298SGreg Ungerer break; 53a66af298SGreg Ungerer default: 54a66af298SGreg Ungerer printk(KERN_ERR "module %s: Unknown relocation: %u\n", 55a66af298SGreg Ungerer me->name, ELF32_R_TYPE(rel[i].r_info)); 56a66af298SGreg Ungerer return -ENOEXEC; 57a66af298SGreg Ungerer } 58a66af298SGreg Ungerer } 59a66af298SGreg Ungerer return 0; 60a66af298SGreg Ungerer } 61a66af298SGreg Ungerer 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: 90*2e76c283SGeert 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: 94a66af298SGreg Ungerer printk(KERN_ERR "module %s: Unknown relocation: %u\n", 95a66af298SGreg Ungerer me->name, ELF32_R_TYPE(rel[i].r_info)); 96a66af298SGreg Ungerer return -ENOEXEC; 97a66af298SGreg Ungerer } 98a66af298SGreg Ungerer } 99a66af298SGreg Ungerer return 0; 100a66af298SGreg Ungerer } 101a66af298SGreg Ungerer 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 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