diff options
Diffstat (limited to 'kexec/arch/sh/kexec-elf-rel-sh.c')
-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; + } } |