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