Skip to content

Commit

Permalink
MN10300: Add support for new ELF relocs in kernel modules
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mark Salter authored and Linus Torvalds committed Jun 18, 2009
1 parent d282922 commit 5ae8606
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
2 changes: 2 additions & 0 deletions arch/mn10300/include/asm/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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..
Expand Down
39 changes: 36 additions & 3 deletions arch/mn10300/kernel/module.c
Original file line number Diff line number Diff line change
@@ -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
*
Expand Down Expand Up @@ -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;

Expand All @@ -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 */
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 5ae8606

Please sign in to comment.