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 M32R.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; either version 2 of the License, or
6  (at your option) any later version.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17 
18 #include <linux/moduleloader.h>
19 #include <linux/elf.h>
20 #include <linux/vmalloc.h>
21 #include <linux/fs.h>
22 #include <linux/string.h>
23 #include <linux/kernel.h>
24 
25 #if 0
26 #define DEBUGP printk
27 #else
28 #define DEBUGP(fmt...)
29 #endif
30 
31 #define COPY_UNALIGNED_WORD(sw, tw, align) \
32 { \
33  void *__s = &(sw), *__t = &(tw); \
34  unsigned short *__s2 = __s, *__t2 =__t; \
35  unsigned char *__s1 = __s, *__t1 =__t; \
36  switch ((align)) \
37  { \
38  case 0: \
39  *(unsigned long *) __t = *(unsigned long *) __s; \
40  break; \
41  case 2: \
42  *__t2++ = *__s2++; \
43  *__t2 = *__s2; \
44  break; \
45  default: \
46  *__t1++ = *__s1++; \
47  *__t1++ = *__s1++; \
48  *__t1++ = *__s1++; \
49  *__t1 = *__s1; \
50  break; \
51  } \
52 }
53 
54 #define COPY_UNALIGNED_HWORD(sw, tw, align) \
55  { \
56  void *__s = &(sw), *__t = &(tw); \
57  unsigned short *__s2 = __s, *__t2 =__t; \
58  unsigned char *__s1 = __s, *__t1 =__t; \
59  switch ((align)) \
60  { \
61  case 0: \
62  *__t2 = *__s2; \
63  break; \
64  default: \
65  *__t1++ = *__s1++; \
66  *__t1 = *__s1; \
67  break; \
68  } \
69  }
70 
72  const char *strtab,
73  unsigned int symindex,
74  unsigned int relsec,
75  struct module *me)
76 {
77  unsigned int i;
78  Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
79  Elf32_Sym *sym;
80  Elf32_Addr relocation;
83  unsigned short *hlocation;
84  unsigned short hvalue;
85  int svalue;
86  int align;
87 
88  DEBUGP("Applying relocate section %u to %u\n", relsec,
89  sechdrs[relsec].sh_info);
90  for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
91  /* This is where to make the change */
92  location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
93  + rel[i].r_offset;
94  /* This is the symbol it is referring to. Note that all
95  undefined symbols have been resolved. */
96  sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
97  + ELF32_R_SYM(rel[i].r_info);
98  relocation = sym->st_value + rel[i].r_addend;
99  align = (int)location & 3;
100 
101  switch (ELF32_R_TYPE(rel[i].r_info)) {
102  case R_M32R_32_RELA:
103  COPY_UNALIGNED_WORD (*location, value, align);
104  value += relocation;
105  COPY_UNALIGNED_WORD (value, *location, align);
106  break;
108  COPY_UNALIGNED_WORD (*location, value, align);
109  relocation = (relocation >>16) & 0xffff;
110  /* RELA must has 0 at relocation field. */
111  value += relocation;
112  COPY_UNALIGNED_WORD (value, *location, align);
113  break;
115  COPY_UNALIGNED_WORD (*location, value, align);
116  if (relocation & 0x8000) relocation += 0x10000;
117  relocation = (relocation >>16) & 0xffff;
118  /* RELA must has 0 at relocation field. */
119  value += relocation;
120  COPY_UNALIGNED_WORD (value, *location, align);
121  break;
122  case R_M32R_16_RELA:
123  hlocation = (unsigned short *)location;
124  relocation = relocation & 0xffff;
125  /* RELA must has 0 at relocation field. */
126  hvalue = relocation;
127  COPY_UNALIGNED_WORD (hvalue, *hlocation, align);
128  break;
129  case R_M32R_SDA16_RELA:
130  case R_M32R_LO16_RELA:
131  COPY_UNALIGNED_WORD (*location, value, align);
132  relocation = relocation & 0xffff;
133  /* RELA must has 0 at relocation field. */
134  value += relocation;
135  COPY_UNALIGNED_WORD (value, *location, align);
136  break;
137  case R_M32R_24_RELA:
138  COPY_UNALIGNED_WORD (*location, value, align);
139  relocation = relocation & 0xffffff;
140  /* RELA must has 0 at relocation field. */
141  value += relocation;
142  COPY_UNALIGNED_WORD (value, *location, align);
143  break;
145  relocation = (relocation - (Elf32_Addr) location);
146  if (relocation < -0x20000 || 0x1fffc < relocation)
147  {
148  printk(KERN_ERR "module %s: relocation overflow: %u\n",
149  me->name, relocation);
150  return -ENOEXEC;
151  }
152  COPY_UNALIGNED_WORD (*location, value, align);
153  if (value & 0xffff)
154  {
155  /* RELA must has 0 at relocation field. */
156  printk(KERN_ERR "module %s: illegal relocation field: %u\n",
157  me->name, value);
158  return -ENOEXEC;
159  }
160  relocation = (relocation >> 2) & 0xffff;
161  value += relocation;
162  COPY_UNALIGNED_WORD (value, *location, align);
163  break;
165  hlocation = (unsigned short *)location;
166  relocation = (relocation - (Elf32_Addr) location);
167  COPY_UNALIGNED_HWORD (*hlocation, hvalue, align);
168  svalue = (int)hvalue;
169  svalue = (signed char)svalue << 2;
170  relocation += svalue;
171  relocation = (relocation >> 2) & 0xff;
172  hvalue = hvalue & 0xff00;
173  hvalue += relocation;
174  COPY_UNALIGNED_HWORD (hvalue, *hlocation, align);
175  break;
177  relocation = (relocation - (Elf32_Addr) location);
178  if (relocation < -0x2000000 || 0x1fffffc < relocation)
179  {
180  printk(KERN_ERR "module %s: relocation overflow: %u\n",
181  me->name, relocation);
182  return -ENOEXEC;
183  }
184  COPY_UNALIGNED_WORD (*location, value, align);
185  if (value & 0xffffff)
186  {
187  /* RELA must has 0 at relocation field. */
188  printk(KERN_ERR "module %s: illegal relocation field: %u\n",
189  me->name, value);
190  return -ENOEXEC;
191  }
192  relocation = (relocation >> 2) & 0xffffff;
193  value += relocation;
194  COPY_UNALIGNED_WORD (value, *location, align);
195  break;
196  default:
197  printk(KERN_ERR "module %s: Unknown relocation: %u\n",
198  me->name, ELF32_R_TYPE(rel[i].r_info));
199  return -ENOEXEC;
200  }
201  }
202  return 0;
203 }