diff options
author | Paul Mundt <lethal@linux-sh.org> | 2008-09-05 11:13:48 +0900 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2008-09-05 16:21:28 +1000 |
commit | 011e3d8660ea44b934f6468b70b1411c97a123a8 (patch) | |
tree | 6c1251c55c5c57365c116e79a83185990717dee4 | |
parent | 0723defb5308ac7fce296f8b596bff4df6803f01 (diff) |
sh: Add ELF relocation support for R_SH_DIR32/R_SH_REL32 relocs.
Simple handler for the common SHcompact ELF relocations.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r-- | kexec/arch/sh/kexec-elf-rel-sh.c | 45 |
1 files changed, 40 insertions, 5 deletions
diff --git a/kexec/arch/sh/kexec-elf-rel-sh.c b/kexec/arch/sh/kexec-elf-rel-sh.c index 3e16b28..c1aaa60 100644 --- a/kexec/arch/sh/kexec-elf-rel-sh.c +++ b/kexec/arch/sh/kexec-elf-rel-sh.c @@ -1,3 +1,15 @@ +/* + * kexec-elf-rel-sh.c - ELF relocations for SuperH + * Copyright (C) 2008 Paul Mundt + * + * Based on the SHcompact module loader (arch/sh/kernel/module.c) in the + * Linux kernel, which is written by: + * + * Copyright (C) 2003 - 2008 Kaz Kojima & Paul Mundt + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ #include <stdio.h> #include <elf.h> #include "../../kexec.h" @@ -5,14 +17,37 @@ int machine_verify_elf_rel(struct mem_ehdr *ehdr) { + /* Intentionally don't bother with endianness validation, it's + * configurable */ - die("machine_verify_elf_rel is not implemented\n"); - return 0; + if (ehdr->ei_class != ELFCLASS32) + return 0; + if (ehdr->e_machine != EM_SH) + return 0; + + return 1; } void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type, - void *location, unsigned long address, unsigned long value) + void *orig_loc, unsigned long address, unsigned long relocation) { - die("Unknown rela relocation: %lu\n", r_type); - return; + uint32_t *location = orig_loc; + uint32_t value; + + switch (r_type) { + case R_SH_DIR32: + value = get_unaligned(location); + value += relocation; + put_unaligned(value, location); + break; + case R_SH_REL32: + relocation = (relocation - (uint32_t)location); + value = get_unaligned(location); + value += relocation; + put_unaligned(value, location); + break; + default: + die("Unknown rela relocation: %lu\n", r_type); + break; + } } |