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