linux/arch/hexagon/kernel/module.c
<<
>>
Prefs
   1/*
   2 * Kernel module loader for Hexagon
   3 *
   4 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 and
   8 * only version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18 * 02110-1301, USA.
  19 */
  20
  21#include <asm/module.h>
  22#include <linux/elf.h>
  23#include <linux/module.h>
  24#include <linux/moduleloader.h>
  25#include <linux/vmalloc.h>
  26
  27#if 0
  28#define DEBUGP printk
  29#else
  30#define DEBUGP(fmt , ...)
  31#endif
  32
  33/*
  34 * module_frob_arch_sections - tweak got/plt sections.
  35 * @hdr - pointer to elf header
  36 * @sechdrs - pointer to elf load section headers
  37 * @secstrings - symbol names
  38 * @mod - pointer to module
  39 */
  40int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
  41                                char *secstrings,
  42                                struct module *mod)
  43{
  44        unsigned int i;
  45        int found = 0;
  46
  47        /* Look for .plt and/or .got.plt and/or .init.plt sections */
  48        for (i = 0; i < hdr->e_shnum; i++) {
  49                DEBUGP("Section %d is %s\n", i,
  50                       secstrings + sechdrs[i].sh_name);
  51                if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0)
  52                        found = i+1;
  53                if (strcmp(secstrings + sechdrs[i].sh_name, ".got.plt") == 0)
  54                        found = i+1;
  55                if (strcmp(secstrings + sechdrs[i].sh_name, ".rela.plt") == 0)
  56                        found = i+1;
  57        }
  58
  59        /* At this time, we don't support modules comiled with -shared */
  60        if (found) {
  61                printk(KERN_WARNING
  62                        "Module '%s' contains unexpected .plt/.got sections.\n",
  63                        mod->name);
  64                /*  return -ENOEXEC;  */
  65        }
  66
  67        return 0;
  68}
  69
  70/*
  71 * apply_relocate_add - perform rela relocations.
  72 * @sechdrs - pointer to section headers
  73 * @strtab - some sort of start address?
  74 * @symindex - symbol index offset or something?
  75 * @relsec - address to relocate to?
  76 * @module - pointer to module
  77 *
  78 * Perform rela relocations.
  79 */
  80int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
  81                        unsigned int symindex, unsigned int relsec,
  82                        struct module *module)
  83{
  84        unsigned int i;
  85        Elf32_Sym *sym;
  86        uint32_t *location;
  87        uint32_t value;
  88        unsigned int nrelocs = sechdrs[relsec].sh_size / sizeof(Elf32_Rela);
  89        Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
  90        Elf32_Word sym_info = sechdrs[relsec].sh_info;
  91        Elf32_Sym *sym_base = (Elf32_Sym *) sechdrs[symindex].sh_addr;
  92        void *loc_base = (void *) sechdrs[sym_info].sh_addr;
  93
  94        DEBUGP("Applying relocations in section %u to section %u base=%p\n",
  95               relsec, sym_info, loc_base);
  96
  97        for (i = 0; i < nrelocs; i++) {
  98
  99                /* Symbol to relocate */
 100                sym = sym_base + ELF32_R_SYM(rela[i].r_info);
 101
 102                /* Where to make the change */
 103                location = loc_base + rela[i].r_offset;
 104
 105                /* `Everything is relative'. */
 106                value = sym->st_value + rela[i].r_addend;
 107
 108                DEBUGP("%d: value=%08x loc=%p reloc=%d symbol=%s\n",
 109                       i, value, location, ELF32_R_TYPE(rela[i].r_info),
 110                       sym->st_name ?
 111                       &strtab[sym->st_name] : "(anonymous)");
 112
 113                switch (ELF32_R_TYPE(rela[i].r_info)) {
 114                case R_HEXAGON_B22_PCREL: {
 115                        int dist = (int)(value - (uint32_t)location);
 116                        if ((dist < -0x00800000) ||
 117                            (dist >= 0x00800000)) {
 118                                printk(KERN_ERR
 119                                       "%s: %s: %08x=%08x-%08x %s\n",
 120                                       module->name,
 121                                       "R_HEXAGON_B22_PCREL reloc out of range",
 122                                       dist, value, (uint32_t)location,
 123                                       sym->st_name ?
 124                                       &strtab[sym->st_name] : "(anonymous)");
 125                                return -ENOEXEC;
 126                        }
 127                        DEBUGP("B22_PCREL contents: %08X.\n", *location);
 128                        *location &= ~0x01ff3fff;
 129                        *location |= 0x00003fff & dist;
 130                        *location |= 0x01ff0000 & (dist<<2);
 131                        DEBUGP("Contents after reloc: %08x\n", *location);
 132                        break;
 133                }
 134                case R_HEXAGON_HI16:
 135                        value = (value>>16) & 0xffff;
 136                        /* fallthrough */
 137                case R_HEXAGON_LO16:
 138                        *location &= ~0x00c03fff;
 139                        *location |= value & 0x3fff;
 140                        *location |= (value & 0xc000) << 8;
 141                        break;
 142                case R_HEXAGON_32:
 143                        *location = value;
 144                        break;
 145                case R_HEXAGON_32_PCREL:
 146                        *location = value - (uint32_t)location;
 147                        break;
 148                case R_HEXAGON_PLT_B22_PCREL:
 149                case R_HEXAGON_GOTOFF_LO16:
 150                case R_HEXAGON_GOTOFF_HI16:
 151                        printk(KERN_ERR "%s: GOT/PLT relocations unsupported\n",
 152                               module->name);
 153                        return -ENOEXEC;
 154                default:
 155                        printk(KERN_ERR "%s: unknown relocation: %u\n",
 156                               module->name,
 157                               ELF32_R_TYPE(rela[i].r_info));
 158                        return -ENOEXEC;
 159                }
 160        }
 161        return 0;
 162}
 163