1 /* Kernel module help for SH. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published by 5 the Free Software Foundation; either version 2 of the License, or 6 (at your option) any later version. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program; if not, write to the Free Software 15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 */ 17 #include <linux/moduleloader.h> 18 #include <linux/elf.h> 19 #include <linux/vmalloc.h> 20 #include <linux/fs.h> 21 #include <linux/string.h> 22 #include <linux/kernel.h> 23 24 #if 0 25 #define DEBUGP printk 26 #else 27 #define DEBUGP(fmt...) 28 #endif 29 30 void *module_alloc(unsigned long size) 31 { 32 if (size == 0) 33 return NULL; 34 return vmalloc(size); 35 } 36 37 38 /* Free memory returned from module_alloc */ 39 void module_free(struct module *mod, void *module_region) 40 { 41 vfree(module_region); 42 /* FIXME: If module_region == mod->init_region, trim exception 43 table entries. */ 44 } 45 46 /* We don't need anything special. */ 47 int module_frob_arch_sections(Elf_Ehdr *hdr, 48 Elf_Shdr *sechdrs, 49 char *secstrings, 50 struct module *mod) 51 { 52 return 0; 53 } 54 55 #define COPY_UNALIGNED_WORD(sw, tw, align) \ 56 { \ 57 void *__s = &(sw), *__t = &(tw); \ 58 unsigned short *__s2 = __s, *__t2 = __t; \ 59 unsigned char *__s1 = __s, *__t1 = __t; \ 60 switch ((align)) \ 61 { \ 62 case 0: \ 63 *(unsigned long *) __t = *(unsigned long *) __s; \ 64 break; \ 65 case 2: \ 66 *__t2++ = *__s2++; \ 67 *__t2 = *__s2; \ 68 break; \ 69 default: \ 70 *__t1++ = *__s1++; \ 71 *__t1++ = *__s1++; \ 72 *__t1++ = *__s1++; \ 73 *__t1 = *__s1; \ 74 break; \ 75 } \ 76 } 77 78 int apply_relocate_add(Elf32_Shdr *sechdrs, 79 const char *strtab, 80 unsigned int symindex, 81 unsigned int relsec, 82 struct module *me) 83 { 84 unsigned int i; 85 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; 86 Elf32_Sym *sym; 87 Elf32_Addr relocation; 88 uint32_t *location; 89 uint32_t value; 90 int align; 91 92 DEBUGP("Applying relocate section %u to %u\n", relsec, 93 sechdrs[relsec].sh_info); 94 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 95 /* This is where to make the change */ 96 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 97 + rel[i].r_offset; 98 /* This is the symbol it is referring to. Note that all 99 undefined symbols have been resolved. */ 100 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 101 + ELF32_R_SYM(rel[i].r_info); 102 relocation = sym->st_value + rel[i].r_addend; 103 align = (int)location & 3; 104 105 switch (ELF32_R_TYPE(rel[i].r_info)) { 106 case R_SH_DIR32: 107 COPY_UNALIGNED_WORD (*location, value, align); 108 value += relocation; 109 COPY_UNALIGNED_WORD (value, *location, align); 110 break; 111 case R_SH_REL32: 112 relocation = (relocation - (Elf32_Addr) location); 113 COPY_UNALIGNED_WORD (*location, value, align); 114 value += relocation; 115 COPY_UNALIGNED_WORD (value, *location, align); 116 break; 117 default: 118 printk(KERN_ERR "module %s: Unknown relocation: %u\n", 119 me->name, ELF32_R_TYPE(rel[i].r_info)); 120 return -ENOEXEC; 121 } 122 } 123 return 0; 124 } 125 126 int apply_relocate(Elf32_Shdr *sechdrs, 127 const char *strtab, 128 unsigned int symindex, 129 unsigned int relsec, 130 struct module *me) 131 { 132 printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", 133 me->name); 134 return -ENOEXEC; 135 } 136 137 int module_finalize(const Elf_Ehdr *hdr, 138 const Elf_Shdr *sechdrs, 139 struct module *me) 140 { 141 return 0; 142 } 143 144 void module_arch_cleanup(struct module *mod) 145 { 146 } 147