1 /* 2 * arch/xtensa/kernel/module.c 3 * 4 * Module support. 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 * 10 * Copyright (C) 2001 - 2006 Tensilica Inc. 11 * 12 * Chris Zankel <chris@zankel.net> 13 * 14 */ 15 16 #include <linux/module.h> 17 #include <linux/moduleloader.h> 18 #include <linux/elf.h> 19 #include <linux/vmalloc.h> 20 #include <linux/fs.h> 21 #include <linux/string.h> 22 #include <linux/kernel.h> 23 #include <linux/cache.h> 24 25 static int 26 decode_calln_opcode (unsigned char *location) 27 { 28 #ifdef __XTENSA_EB__ 29 return (location[0] & 0xf0) == 0x50; 30 #endif 31 #ifdef __XTENSA_EL__ 32 return (location[0] & 0xf) == 0x5; 33 #endif 34 } 35 36 static int 37 decode_l32r_opcode (unsigned char *location) 38 { 39 #ifdef __XTENSA_EB__ 40 return (location[0] & 0xf0) == 0x10; 41 #endif 42 #ifdef __XTENSA_EL__ 43 return (location[0] & 0xf) == 0x1; 44 #endif 45 } 46 47 int apply_relocate_add(Elf32_Shdr *sechdrs, 48 const char *strtab, 49 unsigned int symindex, 50 unsigned int relsec, 51 struct module *mod) 52 { 53 unsigned int i; 54 Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; 55 Elf32_Sym *sym; 56 unsigned char *location; 57 uint32_t value; 58 59 pr_debug("Applying relocate section %u to %u\n", relsec, 60 sechdrs[relsec].sh_info); 61 62 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { 63 location = (char *)sechdrs[sechdrs[relsec].sh_info].sh_addr 64 + rela[i].r_offset; 65 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 66 + ELF32_R_SYM(rela[i].r_info); 67 value = sym->st_value + rela[i].r_addend; 68 69 switch (ELF32_R_TYPE(rela[i].r_info)) { 70 case R_XTENSA_NONE: 71 case R_XTENSA_DIFF8: 72 case R_XTENSA_DIFF16: 73 case R_XTENSA_DIFF32: 74 case R_XTENSA_ASM_EXPAND: 75 break; 76 77 case R_XTENSA_32: 78 case R_XTENSA_PLT: 79 *(uint32_t *)location += value; 80 break; 81 82 case R_XTENSA_SLOT0_OP: 83 if (decode_calln_opcode(location)) { 84 value -= ((unsigned long)location & -4) + 4; 85 if ((value & 3) != 0 || 86 ((value + (1 << 19)) >> 20) != 0) { 87 pr_err("%s: relocation out of range, " 88 "section %d reloc %d " 89 "sym '%s'\n", 90 mod->name, relsec, i, 91 strtab + sym->st_name); 92 return -ENOEXEC; 93 } 94 value = (signed int)value >> 2; 95 #ifdef __XTENSA_EB__ 96 location[0] = ((location[0] & ~0x3) | 97 ((value >> 16) & 0x3)); 98 location[1] = (value >> 8) & 0xff; 99 location[2] = value & 0xff; 100 #endif 101 #ifdef __XTENSA_EL__ 102 location[0] = ((location[0] & ~0xc0) | 103 ((value << 6) & 0xc0)); 104 location[1] = (value >> 2) & 0xff; 105 location[2] = (value >> 10) & 0xff; 106 #endif 107 } else if (decode_l32r_opcode(location)) { 108 value -= (((unsigned long)location + 3) & -4); 109 if ((value & 3) != 0 || 110 (signed int)value >> 18 != -1) { 111 pr_err("%s: relocation out of range, " 112 "section %d reloc %d " 113 "sym '%s'\n", 114 mod->name, relsec, i, 115 strtab + sym->st_name); 116 return -ENOEXEC; 117 } 118 value = (signed int)value >> 2; 119 120 #ifdef __XTENSA_EB__ 121 location[1] = (value >> 8) & 0xff; 122 location[2] = value & 0xff; 123 #endif 124 #ifdef __XTENSA_EL__ 125 location[1] = value & 0xff; 126 location[2] = (value >> 8) & 0xff; 127 #endif 128 } 129 /* FIXME: Ignore any other opcodes. The Xtensa 130 assembler currently assumes that the linker will 131 always do relaxation and so all PC-relative 132 operands need relocations. (The assembler also 133 writes out the tentative PC-relative values, 134 assuming no link-time relaxation, so it is usually 135 safe to ignore the relocations.) If the 136 assembler's "--no-link-relax" flag can be made to 137 work, and if all kernel modules can be assembled 138 with that flag, then unexpected relocations could 139 be detected here. */ 140 break; 141 142 case R_XTENSA_SLOT1_OP: 143 case R_XTENSA_SLOT2_OP: 144 case R_XTENSA_SLOT3_OP: 145 case R_XTENSA_SLOT4_OP: 146 case R_XTENSA_SLOT5_OP: 147 case R_XTENSA_SLOT6_OP: 148 case R_XTENSA_SLOT7_OP: 149 case R_XTENSA_SLOT8_OP: 150 case R_XTENSA_SLOT9_OP: 151 case R_XTENSA_SLOT10_OP: 152 case R_XTENSA_SLOT11_OP: 153 case R_XTENSA_SLOT12_OP: 154 case R_XTENSA_SLOT13_OP: 155 case R_XTENSA_SLOT14_OP: 156 pr_err("%s: unexpected FLIX relocation: %u\n", 157 mod->name, 158 ELF32_R_TYPE(rela[i].r_info)); 159 return -ENOEXEC; 160 161 case R_XTENSA_SLOT0_ALT: 162 case R_XTENSA_SLOT1_ALT: 163 case R_XTENSA_SLOT2_ALT: 164 case R_XTENSA_SLOT3_ALT: 165 case R_XTENSA_SLOT4_ALT: 166 case R_XTENSA_SLOT5_ALT: 167 case R_XTENSA_SLOT6_ALT: 168 case R_XTENSA_SLOT7_ALT: 169 case R_XTENSA_SLOT8_ALT: 170 case R_XTENSA_SLOT9_ALT: 171 case R_XTENSA_SLOT10_ALT: 172 case R_XTENSA_SLOT11_ALT: 173 case R_XTENSA_SLOT12_ALT: 174 case R_XTENSA_SLOT13_ALT: 175 case R_XTENSA_SLOT14_ALT: 176 pr_err("%s: unexpected ALT relocation: %u\n", 177 mod->name, 178 ELF32_R_TYPE(rela[i].r_info)); 179 return -ENOEXEC; 180 181 default: 182 pr_err("%s: unexpected relocation: %u\n", 183 mod->name, 184 ELF32_R_TYPE(rela[i].r_info)); 185 return -ENOEXEC; 186 } 187 } 188 return 0; 189 } 190
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.