Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
module.c
Go to the documentation of this file.
1 /* Kernel module help for SH.
2 
3  SHcompact version by Kaz Kojima and Paul Mundt.
4 
5  SHmedia bits:
6 
7  Copyright 2004 SuperH (UK) Ltd
8  Author: Richard Curnow
9 
10  Based on the sh version, and on code from the sh64-specific parts of
11  modutils, originally written by Richard Curnow and Ben Gaster.
12 
13  This program is free software; you can redistribute it and/or modify
14  it under the terms of the GNU General Public License as published by
15  the Free Software Foundation; either version 2 of the License, or
16  (at your option) any later version.
17 
18  This program is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  GNU General Public License for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with this program; if not, write to the Free Software
25  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27 #include <linux/moduleloader.h>
28 #include <linux/elf.h>
29 #include <linux/vmalloc.h>
30 #include <linux/bug.h>
31 #include <linux/fs.h>
32 #include <linux/string.h>
33 #include <linux/kernel.h>
34 #include <asm/unaligned.h>
35 #include <asm/dwarf.h>
36 
38  const char *strtab,
39  unsigned int symindex,
40  unsigned int relsec,
41  struct module *me)
42 {
43  unsigned int i;
44  Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
45  Elf32_Sym *sym;
46  Elf32_Addr relocation;
49 
50  pr_debug("Applying relocate section %u to %u\n", relsec,
51  sechdrs[relsec].sh_info);
52  for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
53  /* This is where to make the change */
54  location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
55  + rel[i].r_offset;
56  /* This is the symbol it is referring to. Note that all
57  undefined symbols have been resolved. */
58  sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
59  + ELF32_R_SYM(rel[i].r_info);
60  relocation = sym->st_value + rel[i].r_addend;
61 
62 #ifdef CONFIG_SUPERH64
63  /* For text addresses, bit2 of the st_other field indicates
64  * whether the symbol is SHmedia (1) or SHcompact (0). If
65  * SHmedia, the LSB of the symbol needs to be asserted
66  * for the CPU to be in SHmedia mode when it starts executing
67  * the branch target. */
68  relocation |= !!(sym->st_other & 4);
69 #endif
70 
71  switch (ELF32_R_TYPE(rel[i].r_info)) {
72  case R_SH_NONE:
73  break;
74  case R_SH_DIR32:
75  value = get_unaligned(location);
76  value += relocation;
77  put_unaligned(value, location);
78  break;
79  case R_SH_REL32:
80  relocation = (relocation - (Elf32_Addr) location);
81  value = get_unaligned(location);
82  value += relocation;
83  put_unaligned(value, location);
84  break;
85  case R_SH_IMM_LOW16:
86  *location = (*location & ~0x3fffc00) |
87  ((relocation & 0xffff) << 10);
88  break;
89  case R_SH_IMM_MEDLOW16:
90  *location = (*location & ~0x3fffc00) |
91  (((relocation >> 16) & 0xffff) << 10);
92  break;
94  relocation -= (Elf32_Addr) location;
95  *location = (*location & ~0x3fffc00) |
96  ((relocation & 0xffff) << 10);
97  break;
99  relocation -= (Elf32_Addr) location;
100  *location = (*location & ~0x3fffc00) |
101  (((relocation >> 16) & 0xffff) << 10);
102  break;
103  default:
104  printk(KERN_ERR "module %s: Unknown relocation: %u\n",
105  me->name, ELF32_R_TYPE(rel[i].r_info));
106  return -ENOEXEC;
107  }
108  }
109  return 0;
110 }
111 
113  const Elf_Shdr *sechdrs,
114  struct module *me)
115 {
116  int ret = 0;
117 
118  ret |= module_dwarf_finalize(hdr, sechdrs, me);
119 
120  return ret;
121 }
122 
124 {
126 }