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