1 /* 2 * Kernel module support for Nios II. 3 * 4 * Copyright (C) 2004 Microtronix Datacom Ltd. 5 * Written by Wentao Xu <xuwentao@microtronix.com> 6 * Copyright (C) 2001, 2003 Rusty Russell 7 * 8 * This file is subject to the terms and conditions of the GNU General 9 * Public License. See the file COPYING in the main directory of this 10 * archive for more details. 11 */ 12 13 #include <linux/moduleloader.h> 14 #include <linux/elf.h> 15 #include <linux/mm.h> 16 #include <linux/slab.h> 17 #include <linux/fs.h> 18 #include <linux/string.h> 19 #include <linux/kernel.h> 20 21 #include <asm/cacheflush.h> 22 23 int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, 24 unsigned int symindex, unsigned int relsec, 25 struct module *mod) 26 { 27 unsigned int i; 28 Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; 29 30 pr_debug("Applying relocate section %u to %u\n", relsec, 31 sechdrs[relsec].sh_info); 32 33 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { 34 /* This is where to make the change */ 35 uint32_t word; 36 uint32_t *loc 37 = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 38 + rela[i].r_offset); 39 /* This is the symbol it is referring to. Note that all 40 undefined symbols have been resolved. */ 41 Elf32_Sym *sym 42 = ((Elf32_Sym *)sechdrs[symindex].sh_addr 43 + ELF32_R_SYM(rela[i].r_info)); 44 uint32_t v = sym->st_value + rela[i].r_addend; 45 46 pr_debug("reltype %d 0x%x name:<%s>\n", 47 ELF32_R_TYPE(rela[i].r_info), 48 rela[i].r_offset, strtab + sym->st_name); 49 50 switch (ELF32_R_TYPE(rela[i].r_info)) { 51 case R_NIOS2_NONE: 52 break; 53 case R_NIOS2_BFD_RELOC_32: 54 *loc += v; 55 break; 56 case R_NIOS2_PCREL16: 57 v -= (uint32_t)loc + 4; 58 if ((int32_t)v > 0x7fff || 59 (int32_t)v < -(int32_t)0x8000) { 60 pr_err("module %s: relocation overflow\n", 61 mod->name); 62 return -ENOEXEC; 63 } 64 word = *loc; 65 *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | 66 (word & 0x3f); 67 break; 68 case R_NIOS2_CALL26: 69 if (v & 3) { 70 pr_err("module %s: dangerous relocation\n", 71 mod->name); 72 return -ENOEXEC; 73 } 74 if ((v >> 28) != ((uint32_t)loc >> 28)) { 75 pr_err("module %s: relocation overflow\n", 76 mod->name); 77 return -ENOEXEC; 78 } 79 *loc = (*loc & 0x3f) | ((v >> 2) << 6); 80 break; 81 case R_NIOS2_HI16: 82 word = *loc; 83 *loc = ((((word >> 22) << 16) | 84 ((v >> 16) & 0xffff)) << 6) | (word & 0x3f); 85 break; 86 case R_NIOS2_LO16: 87 word = *loc; 88 *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | 89 (word & 0x3f); 90 break; 91 case R_NIOS2_HIADJ16: 92 { 93 Elf32_Addr word2; 94 95 word = *loc; 96 word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff; 97 *loc = ((((word >> 22) << 16) | word2) << 6) | 98 (word & 0x3f); 99 } 100 break; 101 102 default: 103 pr_err("module %s: Unknown reloc: %u\n", 104 mod->name, ELF32_R_TYPE(rela[i].r_info)); 105 return -ENOEXEC; 106 } 107 } 108 109 return 0; 110 } 111 112 int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, 113 struct module *me) 114 { 115 flush_cache_all(); 116 return 0; 117 } 118
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.