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 /*
2  * AVR32-specific kernel module loader
3  *
4  * Copyright (C) 2005-2006 Atmel Corporation
5  *
6  * GOT initialization parts are based on the s390 version
7  * Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH,
8  * IBM Corporation
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14 
15 #include <linux/bug.h>
16 #include <linux/elf.h>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/moduleloader.h>
20 #include <linux/vmalloc.h>
21 
22 void module_free(struct module *mod, void *module_region)
23 {
24  vfree(mod->arch.syminfo);
25  mod->arch.syminfo = NULL;
26 
27  vfree(module_region);
28 }
29 
30 static inline int check_rela(Elf32_Rela *rela, struct module *module,
31  char *strings, Elf32_Sym *symbols)
32 {
33  struct mod_arch_syminfo *info;
34 
35  info = module->arch.syminfo + ELF32_R_SYM(rela->r_info);
36  switch (ELF32_R_TYPE(rela->r_info)) {
37  case R_AVR32_GOT32:
38  case R_AVR32_GOT16:
39  case R_AVR32_GOT8:
40  case R_AVR32_GOT21S:
41  case R_AVR32_GOT18SW: /* mcall */
42  case R_AVR32_GOT16S: /* ld.w */
43  if (rela->r_addend != 0) {
45  "GOT relocation against %s at offset %u with addend\n",
46  strings + symbols[ELF32_R_SYM(rela->r_info)].st_name,
47  rela->r_offset);
48  return -ENOEXEC;
49  }
50  if (info->got_offset == -1UL) {
51  info->got_offset = module->arch.got_size;
52  module->arch.got_size += sizeof(void *);
53  }
54  pr_debug("GOT[%3lu] %s\n", info->got_offset,
55  strings + symbols[ELF32_R_SYM(rela->r_info)].st_name);
56  break;
57  }
58 
59  return 0;
60 }
61 
63  char *secstrings, struct module *module)
64 {
66  Elf32_Sym *symbols;
67  Elf32_Rela *rela;
68  char *strings;
69  int nrela, i, j;
70  int ret;
71 
72  /* Find the symbol table */
73  symtab = NULL;
74  for (i = 0; i < hdr->e_shnum; i++)
75  switch (sechdrs[i].sh_type) {
76  case SHT_SYMTAB:
77  symtab = &sechdrs[i];
78  break;
79  }
80  if (!symtab) {
81  printk(KERN_ERR "module %s: no symbol table\n", module->name);
82  return -ENOEXEC;
83  }
84 
85  /* Allocate room for one syminfo structure per symbol. */
86  module->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym);
87  module->arch.syminfo = vmalloc(module->arch.nsyms
88  * sizeof(struct mod_arch_syminfo));
89  if (!module->arch.syminfo)
90  return -ENOMEM;
91 
92  symbols = (void *)hdr + symtab->sh_offset;
93  strings = (void *)hdr + sechdrs[symtab->sh_link].sh_offset;
94  for (i = 0; i < module->arch.nsyms; i++) {
95  if (symbols[i].st_shndx == SHN_UNDEF &&
96  strcmp(strings + symbols[i].st_name,
97  "_GLOBAL_OFFSET_TABLE_") == 0)
98  /* "Define" it as absolute. */
99  symbols[i].st_shndx = SHN_ABS;
100  module->arch.syminfo[i].got_offset = -1UL;
101  module->arch.syminfo[i].got_initialized = 0;
102  }
103 
104  /* Allocate GOT entries for symbols that need it. */
105  module->arch.got_size = 0;
106  for (i = 0; i < hdr->e_shnum; i++) {
107  if (sechdrs[i].sh_type != SHT_RELA)
108  continue;
109  nrela = sechdrs[i].sh_size / sizeof(Elf32_Rela);
110  rela = (void *)hdr + sechdrs[i].sh_offset;
111  for (j = 0; j < nrela; j++) {
112  ret = check_rela(rela + j, module,
113  strings, symbols);
114  if (ret)
115  goto out_free_syminfo;
116  }
117  }
118 
119  /*
120  * Increase core size to make room for GOT and set start
121  * offset for GOT.
122  */
123  module->core_size = ALIGN(module->core_size, 4);
124  module->arch.got_offset = module->core_size;
125  module->core_size += module->arch.got_size;
126 
127  return 0;
128 
129 out_free_syminfo:
130  vfree(module->arch.syminfo);
131  module->arch.syminfo = NULL;
132 
133  return ret;
134 }
135 
136 static inline int reloc_overflow(struct module *module, const char *reloc_name,
137  Elf32_Addr relocation)
138 {
139  printk(KERN_ERR "module %s: Value %lx does not fit relocation %s\n",
140  module->name, (unsigned long)relocation, reloc_name);
141  return -ENOEXEC;
142 }
143 
144 #define get_u16(loc) (*((uint16_t *)loc))
145 #define put_u16(loc, val) (*((uint16_t *)loc) = (val))
146 
147 int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
148  unsigned int symindex, unsigned int relindex,
149  struct module *module)
150 {
151  Elf32_Shdr *symsec = sechdrs + symindex;
152  Elf32_Shdr *relsec = sechdrs + relindex;
153  Elf32_Shdr *dstsec = sechdrs + relsec->sh_info;
154  Elf32_Rela *rel = (void *)relsec->sh_addr;
155  unsigned int i;
156  int ret = 0;
157 
158  for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rela); i++, rel++) {
159  struct mod_arch_syminfo *info;
160  Elf32_Sym *sym;
161  Elf32_Addr relocation;
163  uint32_t value;
164 
165  location = (void *)dstsec->sh_addr + rel->r_offset;
166  sym = (Elf32_Sym *)symsec->sh_addr + ELF32_R_SYM(rel->r_info);
167  relocation = sym->st_value + rel->r_addend;
168 
169  info = module->arch.syminfo + ELF32_R_SYM(rel->r_info);
170 
171  /* Initialize GOT entry if necessary */
172  switch (ELF32_R_TYPE(rel->r_info)) {
173  case R_AVR32_GOT32:
174  case R_AVR32_GOT16:
175  case R_AVR32_GOT8:
176  case R_AVR32_GOT21S:
177  case R_AVR32_GOT18SW:
178  case R_AVR32_GOT16S:
179  if (!info->got_initialized) {
180  Elf32_Addr *gotent;
181 
182  gotent = (module->module_core
183  + module->arch.got_offset
184  + info->got_offset);
185  *gotent = relocation;
186  info->got_initialized = 1;
187  }
188 
189  relocation = info->got_offset;
190  break;
191  }
192 
193  switch (ELF32_R_TYPE(rel->r_info)) {
194  case R_AVR32_32:
195  case R_AVR32_32_CPENT:
196  *location = relocation;
197  break;
198  case R_AVR32_22H_PCREL:
199  relocation -= (Elf32_Addr)location;
200  if ((relocation & 0xffe00001) != 0
201  && (relocation & 0xffc00001) != 0xffc00000)
202  return reloc_overflow(module,
203  "R_AVR32_22H_PCREL",
204  relocation);
205  relocation >>= 1;
206 
207  value = *location;
208  value = ((value & 0xe1ef0000)
209  | (relocation & 0xffff)
210  | ((relocation & 0x10000) << 4)
211  | ((relocation & 0x1e0000) << 8));
212  *location = value;
213  break;
214  case R_AVR32_11H_PCREL:
215  relocation -= (Elf32_Addr)location;
216  if ((relocation & 0xfffffc01) != 0
217  && (relocation & 0xfffff801) != 0xfffff800)
218  return reloc_overflow(module,
219  "R_AVR32_11H_PCREL",
220  relocation);
221  value = get_u16(location);
222  value = ((value & 0xf00c)
223  | ((relocation & 0x1fe) << 3)
224  | ((relocation & 0x600) >> 9));
225  put_u16(location, value);
226  break;
227  case R_AVR32_9H_PCREL:
228  relocation -= (Elf32_Addr)location;
229  if ((relocation & 0xffffff01) != 0
230  && (relocation & 0xfffffe01) != 0xfffffe00)
231  return reloc_overflow(module,
232  "R_AVR32_9H_PCREL",
233  relocation);
234  value = get_u16(location);
235  value = ((value & 0xf00f)
236  | ((relocation & 0x1fe) << 3));
237  put_u16(location, value);
238  break;
239  case R_AVR32_9UW_PCREL:
240  relocation -= ((Elf32_Addr)location) & 0xfffffffc;
241  if ((relocation & 0xfffffc03) != 0)
242  return reloc_overflow(module,
243  "R_AVR32_9UW_PCREL",
244  relocation);
245  value = get_u16(location);
246  value = ((value & 0xf80f)
247  | ((relocation & 0x1fc) << 2));
248  put_u16(location, value);
249  break;
250  case R_AVR32_GOTPC:
251  /*
252  * R6 = PC - (PC - GOT)
253  *
254  * At this point, relocation contains the
255  * value of PC. Just subtract the value of
256  * GOT, and we're done.
257  */
258  pr_debug("GOTPC: PC=0x%x, got_offset=0x%lx, core=0x%p\n",
259  relocation, module->arch.got_offset,
260  module->module_core);
261  relocation -= ((unsigned long)module->module_core
262  + module->arch.got_offset);
263  *location = relocation;
264  break;
265  case R_AVR32_GOT18SW:
266  if ((relocation & 0xfffe0003) != 0
267  && (relocation & 0xfffc0003) != 0xffff0000)
268  return reloc_overflow(module, "R_AVR32_GOT18SW",
269  relocation);
270  relocation >>= 2;
271  /* fall through */
272  case R_AVR32_GOT16S:
273  if ((relocation & 0xffff8000) != 0
274  && (relocation & 0xffff0000) != 0xffff0000)
275  return reloc_overflow(module, "R_AVR32_GOT16S",
276  relocation);
277  pr_debug("GOT reloc @ 0x%x -> %u\n",
278  rel->r_offset, relocation);
279  value = *location;
280  value = ((value & 0xffff0000)
281  | (relocation & 0xffff));
282  *location = value;
283  break;
284 
285  default:
286  printk(KERN_ERR "module %s: Unknown relocation: %u\n",
287  module->name, ELF32_R_TYPE(rel->r_info));
288  return -ENOEXEC;
289  }
290  }
291 
292  return ret;
293 }
294 
295 int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
296  struct module *module)
297 {
298  vfree(module->arch.syminfo);
299  module->arch.syminfo = NULL;
300 
301  return 0;
302 }