aboutsummaryrefslogtreecommitdiff
path: root/arch/mn10300/kernel/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mn10300/kernel/module.c')
-rw-r--r--arch/mn10300/kernel/module.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/arch/mn10300/kernel/module.c b/arch/mn10300/kernel/module.c
index 6b287f2e8e84..6aea7fd76993 100644
--- a/arch/mn10300/kernel/module.c
+++ b/arch/mn10300/kernel/module.c
@@ -1,6 +1,6 @@
/* MN10300 Kernel module helper routines
*
- * Copyright (C) 2007, 2008 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2007, 2008, 2009 Red Hat, Inc. All Rights Reserved.
* Written by Mark Salter (msalter@redhat.com)
* - Derived from arch/i386/kernel/module.c
*
@@ -48,8 +48,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region)
{
vfree(module_region);
- /* FIXME: If module_region == mod->init_region, trim exception
- * table entries. */
}
/*
@@ -105,10 +103,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
unsigned int relsec,
struct module *me)
{
- unsigned int i;
+ unsigned int i, sym_diff_seen = 0;
Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
Elf32_Sym *sym;
- Elf32_Addr relocation;
+ Elf32_Addr relocation, sym_diff_val = 0;
uint8_t *location;
uint32_t value;
@@ -128,6 +126,22 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
/* this is the adjustment to be made */
relocation = sym->st_value + rel[i].r_addend;
+ if (sym_diff_seen) {
+ switch (ELF32_R_TYPE(rel[i].r_info)) {
+ case R_MN10300_32:
+ case R_MN10300_24:
+ case R_MN10300_16:
+ case R_MN10300_8:
+ relocation -= sym_diff_val;
+ sym_diff_seen = 0;
+ break;
+ default:
+ printk(KERN_ERR "module %s: Unexpected SYM_DIFF relocation: %u\n",
+ me->name, ELF32_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+
switch (ELF32_R_TYPE(rel[i].r_info)) {
/* for the first four relocation types, we simply
* store the adjustment at the location given */
@@ -159,12 +173,29 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
*location = relocation - (uint32_t) location;
break;
+ case R_MN10300_SYM_DIFF:
+ /* This is used to adjust the next reloc as required
+ * by relaxation. */
+ sym_diff_seen = 1;
+ sym_diff_val = sym->st_value;
+ break;
+
+ case R_MN10300_ALIGN:
+ /* Just ignore the ALIGN relocs.
+ * Only interesting if kernel performed relaxation. */
+ continue;
+
default:
printk(KERN_ERR "module %s: Unknown relocation: %u\n",
me->name, ELF32_R_TYPE(rel[i].r_info));
return -ENOEXEC;
}
}
+ if (sym_diff_seen) {
+ printk(KERN_ERR "module %s: Nothing follows SYM_DIFF relocation: %u\n",
+ me->name, ELF32_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
return 0;
}