MN10300: Add support for new ELF relocs in kernel modules
Add support for new relocs which may show up in MN10300 kernel modules due to linker relaxation. Signed-off-by: Mark Salter <msalter@redhat.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
d282922461
commit
5ae8606d57
@ -28,6 +28,8 @@
|
||||
#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */
|
||||
#define R_MN10300_24 9 /* Direct 24 bit. */
|
||||
#define R_MN10300_RELATIVE 23 /* Adjust by program base. */
|
||||
#define R_MN10300_SYM_DIFF 33 /* Adjustment when relaxing. */
|
||||
#define R_MN10300_ALIGN 34 /* Alignment requirement. */
|
||||
|
||||
/*
|
||||
* ELF register definitions..
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user