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:
Mark Salter 2009-06-17 22:51:11 +01:00 committed by Linus Torvalds
parent d282922461
commit 5ae8606d57
2 changed files with 38 additions and 3 deletions

View file

@ -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..

View file

@ -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;
}