|
@@ -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
|
|
|
*
|
|
@@ -103,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;
|
|
|
|
|
@@ -126,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 */
|
|
@@ -157,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;
|
|
|
}
|
|
|
|