diff options
Diffstat (limited to 'arch/sh/kernel/module.c')
| -rw-r--r-- | arch/sh/kernel/module.c | 130 |
1 files changed, 55 insertions, 75 deletions
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c index 142a4e5b7eb..1b525dedd29 100644 --- a/arch/sh/kernel/module.c +++ b/arch/sh/kernel/module.c @@ -1,5 +1,15 @@ /* Kernel module help for SH. + SHcompact version by Kaz Kojima and Paul Mundt. + + SHmedia bits: + + Copyright 2004 SuperH (UK) Ltd + Author: Richard Curnow + + Based on the sh version, and on code from the sh64-specific parts of + modutils, originally written by Richard Curnow and Ben Gaster. + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -17,63 +27,12 @@ #include <linux/moduleloader.h> #include <linux/elf.h> #include <linux/vmalloc.h> +#include <linux/bug.h> #include <linux/fs.h> #include <linux/string.h> #include <linux/kernel.h> - -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(fmt...) -#endif - -void *module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - return vmalloc(size); -} - - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ -} - -/* We don't need anything special. */ -int module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod) -{ - return 0; -} - -#define COPY_UNALIGNED_WORD(sw, tw, align) \ -{ \ - void *__s = &(sw), *__t = &(tw); \ - unsigned short *__s2 = __s, *__t2 = __t; \ - unsigned char *__s1 = __s, *__t1 = __t; \ - switch ((align)) \ - { \ - case 0: \ - *(unsigned long *) __t = *(unsigned long *) __s; \ - break; \ - case 2: \ - *__t2++ = *__s2++; \ - *__t2 = *__s2; \ - break; \ - default: \ - *__t1++ = *__s1++; \ - *__t1++ = *__s1++; \ - *__t1++ = *__s1++; \ - *__t1 = *__s1; \ - break; \ - } \ -} +#include <asm/unaligned.h> +#include <asm/dwarf.h> int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, @@ -87,10 +46,9 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, Elf32_Addr relocation; uint32_t *location; uint32_t value; - int align; - DEBUGP("Applying relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); + pr_debug("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr @@ -100,19 +58,47 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + ELF32_R_SYM(rel[i].r_info); relocation = sym->st_value + rel[i].r_addend; - align = (int)location & 3; + +#ifdef CONFIG_SUPERH64 + /* For text addresses, bit2 of the st_other field indicates + * whether the symbol is SHmedia (1) or SHcompact (0). If + * SHmedia, the LSB of the symbol needs to be asserted + * for the CPU to be in SHmedia mode when it starts executing + * the branch target. */ + relocation |= !!(sym->st_other & 4); +#endif switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_SH_NONE: + break; case R_SH_DIR32: - COPY_UNALIGNED_WORD (*location, value, align); + value = get_unaligned(location); value += relocation; - COPY_UNALIGNED_WORD (value, *location, align); + put_unaligned(value, location); break; case R_SH_REL32: - relocation = (relocation - (Elf32_Addr) location); - COPY_UNALIGNED_WORD (*location, value, align); + relocation = (relocation - (Elf32_Addr) location); + value = get_unaligned(location); value += relocation; - COPY_UNALIGNED_WORD (value, *location, align); + put_unaligned(value, location); + break; + case R_SH_IMM_LOW16: + *location = (*location & ~0x3fffc00) | + ((relocation & 0xffff) << 10); + break; + case R_SH_IMM_MEDLOW16: + *location = (*location & ~0x3fffc00) | + (((relocation >> 16) & 0xffff) << 10); + break; + case R_SH_IMM_LOW16_PCREL: + relocation -= (Elf32_Addr) location; + *location = (*location & ~0x3fffc00) | + ((relocation & 0xffff) << 10); + break; + case R_SH_IMM_MEDLOW16_PCREL: + relocation -= (Elf32_Addr) location; + *location = (*location & ~0x3fffc00) | + (((relocation >> 16) & 0xffff) << 10); break; default: printk(KERN_ERR "module %s: Unknown relocation: %u\n", @@ -123,24 +109,18 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, return 0; } -int apply_relocate(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", - me->name); - return -ENOEXEC; -} - int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { - return 0; + int ret = 0; + + ret |= module_dwarf_finalize(hdr, sechdrs, me); + + return ret; } void module_arch_cleanup(struct module *mod) { + module_dwarf_cleanup(mod); } |
