1 // SPDX-License-Identifier: GPL-2.0+ 2 /* Kernel module help for SH. 3 4 SHcompact version by Kaz Kojima and Paul Mundt. 5 6 SHmedia bits: 7 8 Copyright 2004 SuperH (UK) Ltd 9 Author: Richard Curnow 10 11 Based on the sh version, and on code from the sh64-specific parts of 12 modutils, originally written by Richard Curnow and Ben Gaster. 13 */ 14 #include <linux/moduleloader.h> 15 #include <linux/elf.h> 16 #include <linux/vmalloc.h> 17 #include <linux/bug.h> 18 #include <linux/fs.h> 19 #include <linux/string.h> 20 #include <linux/kernel.h> 21 #include <asm/unaligned.h> 22 #include <asm/dwarf.h> 23 24 int apply_relocate_add(Elf32_Shdr *sechdrs, 25 const char *strtab, 26 unsigned int symindex, 27 unsigned int relsec, 28 struct module *me) 29 { 30 unsigned int i; 31 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; 32 Elf32_Sym *sym; 33 Elf32_Addr relocation; 34 uint32_t *location; 35 uint32_t value; 36 37 pr_debug("Applying relocate section %u to %u\n", relsec, 38 sechdrs[relsec].sh_info); 39 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 40 /* This is where to make the change */ 41 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 42 + rel[i].r_offset; 43 /* This is the symbol it is referring to. Note that all 44 undefined symbols have been resolved. */ 45 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 46 + ELF32_R_SYM(rel[i].r_info); 47 relocation = sym->st_value + rel[i].r_addend; 48 49 switch (ELF32_R_TYPE(rel[i].r_info)) { 50 case R_SH_NONE: 51 break; 52 case R_SH_DIR32: 53 value = get_unaligned(location); 54 value += relocation; 55 put_unaligned(value, location); 56 break; 57 case R_SH_REL32: 58 relocation = (relocation - (Elf32_Addr) location); 59 value = get_unaligned(location); 60 value += relocation; 61 put_unaligned(value, location); 62 break; 63 case R_SH_IMM_LOW16: 64 *location = (*location & ~0x3fffc00) | 65 ((relocation & 0xffff) << 10); 66 break; 67 case R_SH_IMM_MEDLOW16: 68 *location = (*location & ~0x3fffc00) | 69 (((relocation >> 16) & 0xffff) << 10); 70 break; 71 case R_SH_IMM_LOW16_PCREL: 72 relocation -= (Elf32_Addr) location; 73 *location = (*location & ~0x3fffc00) | 74 ((relocation & 0xffff) << 10); 75 break; 76 case R_SH_IMM_MEDLOW16_PCREL: 77 relocation -= (Elf32_Addr) location; 78 *location = (*location & ~0x3fffc00) | 79 (((relocation >> 16) & 0xffff) << 10); 80 break; 81 default: 82 printk(KERN_ERR "module %s: Unknown relocation: %u\n", 83 me->name, ELF32_R_TYPE(rel[i].r_info)); 84 return -ENOEXEC; 85 } 86 } 87 return 0; 88 } 89 90 int module_finalize(const Elf_Ehdr *hdr, 91 const Elf_Shdr *sechdrs, 92 struct module *me) 93 { 94 int ret = 0; 95 96 ret |= module_dwarf_finalize(hdr, sechdrs, me); 97 98 return ret; 99 } 100 101 void module_arch_cleanup(struct module *mod) 102 { 103 module_dwarf_cleanup(mod); 104 } 105