linux/arch/arc/kernel/module.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/moduleloader.h>
  11#include <linux/kernel.h>
  12#include <linux/elf.h>
  13#include <linux/vmalloc.h>
  14#include <linux/slab.h>
  15#include <linux/fs.h>
  16#include <linux/string.h>
  17#include <asm/unwind.h>
  18
  19static inline void arc_write_me(unsigned short *addr, unsigned long value)
  20{
  21        *addr = (value & 0xffff0000) >> 16;
  22        *(addr + 1) = (value & 0xffff);
  23}
  24
  25/* ARC specific section quirks - before relocation loop in generic loader
  26 *
  27 * For dwarf unwinding out of modules, this needs to
  28 * 1. Ensure the .debug_frame is allocatable (ARC Linker bug: despite
  29 *    -fasynchronous-unwind-tables it doesn't).
  30 * 2. Since we are iterating thru sec hdr tbl anyways, make a note of
  31 *    the exact section index, for later use.
  32 */
  33int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
  34                              char *secstr, struct module *mod)
  35{
  36#ifdef CONFIG_ARC_DW2_UNWIND
  37        int i;
  38
  39        mod->arch.unw_sec_idx = 0;
  40        mod->arch.unw_info = NULL;
  41
  42        for (i = 1; i < hdr->e_shnum; i++) {
  43                if (strcmp(secstr+sechdrs[i].sh_name, ".debug_frame") == 0) {
  44                        sechdrs[i].sh_flags |= SHF_ALLOC;
  45                        mod->arch.unw_sec_idx = i;
  46                        break;
  47                }
  48        }
  49#endif
  50        return 0;
  51}
  52
  53void module_arch_cleanup(struct module *mod)
  54{
  55#ifdef CONFIG_ARC_DW2_UNWIND
  56        if (mod->arch.unw_info)
  57                unwind_remove_table(mod->arch.unw_info, 0);
  58#endif
  59}
  60
  61int apply_relocate_add(Elf32_Shdr *sechdrs,
  62                       const char *strtab,
  63                       unsigned int symindex,   /* sec index for sym tbl */
  64                       unsigned int relsec,     /* sec index for relo sec */
  65                       struct module *module)
  66{
  67        int i, n;
  68        Elf32_Rela *rel_entry = (void *)sechdrs[relsec].sh_addr;
  69        Elf32_Sym *sym_entry, *sym_sec;
  70        Elf32_Addr relocation;
  71        Elf32_Addr location;
  72        Elf32_Addr sec_to_patch;
  73        int relo_type;
  74
  75        sec_to_patch = sechdrs[sechdrs[relsec].sh_info].sh_addr;
  76        sym_sec = (Elf32_Sym *) sechdrs[symindex].sh_addr;
  77        n = sechdrs[relsec].sh_size / sizeof(*rel_entry);
  78
  79        pr_debug("\n========== Module Sym reloc ===========================\n");
  80        pr_debug("Section to fixup %x\n", sec_to_patch);
  81        pr_debug("=========================================================\n");
  82        pr_debug("rela->r_off | rela->addend | sym->st_value | ADDR | VALUE\n");
  83        pr_debug("=========================================================\n");
  84
  85        /* Loop thru entries in relocation section */
  86        for (i = 0; i < n; i++) {
  87
  88                /* This is where to make the change */
  89                location = sec_to_patch + rel_entry[i].r_offset;
  90
  91                /* This is the symbol it is referring to.  Note that all
  92                   undefined symbols have been resolved.  */
  93                sym_entry = sym_sec + ELF32_R_SYM(rel_entry[i].r_info);
  94
  95                relocation = sym_entry->st_value + rel_entry[i].r_addend;
  96
  97                pr_debug("\t%x\t\t%x\t\t%x  %x %x [%s]\n",
  98                        rel_entry[i].r_offset, rel_entry[i].r_addend,
  99                        sym_entry->st_value, location, relocation,
 100                        strtab + sym_entry->st_name);
 101
 102                /* This assumes modules are built with -mlong-calls
 103                 * so any branches/jumps are absolute 32 bit jmps
 104                 * global data access again is abs 32 bit.
 105                 * Both of these are handled by same relocation type
 106                 */
 107                relo_type = ELF32_R_TYPE(rel_entry[i].r_info);
 108
 109                if (likely(R_ARC_32_ME == relo_type))
 110                        arc_write_me((unsigned short *)location, relocation);
 111                else if (R_ARC_32 == relo_type)
 112                        *((Elf32_Addr *) location) = relocation;
 113                else
 114                        goto relo_err;
 115
 116        }
 117        return 0;
 118
 119relo_err:
 120        pr_err("%s: unknown relocation: %u\n",
 121                module->name, ELF32_R_TYPE(rel_entry[i].r_info));
 122        return -ENOEXEC;
 123
 124}
 125
 126/* Just before lift off: After sections have been relocated, we add the
 127 * dwarf section to unwinder table pool
 128 * This couldn't be done in module_frob_arch_sections() because
 129 * relocations had not been applied by then
 130 */
 131int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
 132                    struct module *mod)
 133{
 134#ifdef CONFIG_ARC_DW2_UNWIND
 135        void *unw;
 136        int unwsec = mod->arch.unw_sec_idx;
 137
 138        if (unwsec) {
 139                unw = unwind_add_table(mod, (void *)sechdrs[unwsec].sh_addr,
 140                                       sechdrs[unwsec].sh_size);
 141                mod->arch.unw_info = unw;
 142        }
 143#endif
 144        return 0;
 145}
 146