summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Redfearn <matt.redfearn@imgtec.com>2016-03-31 05:05:32 -0400
committerRalf Baechle <ralf@linux-mips.org>2016-05-13 08:02:01 -0400
commit766c580356ecca88b32c47b8128bec7d6d014533 (patch)
treec28f4c6d7d4b1fcb6d77cc7d7222cc1bb34ef594
parentcb4253aa0f77f20be018970dbe5d01d78b930ef9 (diff)
MIPS: tools: Add relocs tool
This tool is based on the x86/boot/tools/relocs tool. It parses the relocations present in the vmlinux elf file, building a table of relocations that will be necessary to run the kernel from an address other than its link address. This table is inserted into the vmlinux elf, in the .data.relocs section. The table is subsequently used by the code in arch/mips/kernel/relocate.c (added later) to relocate the kernel. The tool, by default, also marks all relocation sections as 0 length. This is due to objcopy currently being unable to handle copying the relocations between 64 and 32 bit elf files as is done when building a 64 bit kernel. Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com> Cc: linux-mips@linux-mips.org Cc: kernel-hardening@lists.openwall.com Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/12981/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/boot/tools/Makefile8
-rw-r--r--arch/mips/boot/tools/relocs.c680
-rw-r--r--arch/mips/boot/tools/relocs.h45
-rw-r--r--arch/mips/boot/tools/relocs_32.c17
-rw-r--r--arch/mips/boot/tools/relocs_64.c27
-rw-r--r--arch/mips/boot/tools/relocs_main.c84
6 files changed, 861 insertions, 0 deletions
diff --git a/arch/mips/boot/tools/Makefile b/arch/mips/boot/tools/Makefile
new file mode 100644
index 000000000000..d232a68f6c8a
--- /dev/null
+++ b/arch/mips/boot/tools/Makefile
@@ -0,0 +1,8 @@
1
2hostprogs-y += relocs
3relocs-objs += relocs_32.o
4relocs-objs += relocs_64.o
5relocs-objs += relocs_main.o
6PHONY += relocs
7relocs: $(obj)/relocs
8 @:
diff --git a/arch/mips/boot/tools/relocs.c b/arch/mips/boot/tools/relocs.c
new file mode 100644
index 000000000000..b9cbf78527e8
--- /dev/null
+++ b/arch/mips/boot/tools/relocs.c
@@ -0,0 +1,680 @@
1/* This is included from relocs_32/64.c */
2
3#define ElfW(type) _ElfW(ELF_BITS, type)
4#define _ElfW(bits, type) __ElfW(bits, type)
5#define __ElfW(bits, type) Elf##bits##_##type
6
7#define Elf_Addr ElfW(Addr)
8#define Elf_Ehdr ElfW(Ehdr)
9#define Elf_Phdr ElfW(Phdr)
10#define Elf_Shdr ElfW(Shdr)
11#define Elf_Sym ElfW(Sym)
12
13static Elf_Ehdr ehdr;
14
15struct relocs {
16 uint32_t *offset;
17 unsigned long count;
18 unsigned long size;
19};
20
21static struct relocs relocs;
22
23struct section {
24 Elf_Shdr shdr;
25 struct section *link;
26 Elf_Sym *symtab;
27 Elf_Rel *reltab;
28 char *strtab;
29 long shdr_offset;
30};
31static struct section *secs;
32
33static const char * const regex_sym_kernel = {
34/* Symbols matching these regex's should never be relocated */
35 "^(__crc_)",
36};
37
38static regex_t sym_regex_c;
39
40static int regex_skip_reloc(const char *sym_name)
41{
42 return !regexec(&sym_regex_c, sym_name, 0, NULL, 0);
43}
44
45static void regex_init(void)
46{
47 char errbuf[128];
48 int err;
49
50 err = regcomp(&sym_regex_c, regex_sym_kernel,
51 REG_EXTENDED|REG_NOSUB);
52
53 if (err) {
54 regerror(err, &sym_regex_c, errbuf, sizeof(errbuf));
55 die("%s", errbuf);
56 }
57}
58
59static const char *rel_type(unsigned type)
60{
61 static const char * const type_name[] = {
62#define REL_TYPE(X)[X] = #X
63 REL_TYPE(R_MIPS_NONE),
64 REL_TYPE(R_MIPS_16),
65 REL_TYPE(R_MIPS_32),
66 REL_TYPE(R_MIPS_REL32),
67 REL_TYPE(R_MIPS_26),
68 REL_TYPE(R_MIPS_HI16),
69 REL_TYPE(R_MIPS_LO16),
70 REL_TYPE(R_MIPS_GPREL16),
71 REL_TYPE(R_MIPS_LITERAL),
72 REL_TYPE(R_MIPS_GOT16),
73 REL_TYPE(R_MIPS_PC16),
74 REL_TYPE(R_MIPS_CALL16),
75 REL_TYPE(R_MIPS_GPREL32),
76 REL_TYPE(R_MIPS_64),
77 REL_TYPE(R_MIPS_HIGHER),
78 REL_TYPE(R_MIPS_HIGHEST),
79 REL_TYPE(R_MIPS_PC21_S2),
80 REL_TYPE(R_MIPS_PC26_S2),
81#undef REL_TYPE
82 };
83 const char *name = "unknown type rel type name";
84
85 if (type < ARRAY_SIZE(type_name) && type_name[type])
86 name = type_name[type];
87 return name;
88}
89
90static const char *sec_name(unsigned shndx)
91{
92 const char *sec_strtab;
93 const char *name;
94
95 sec_strtab = secs[ehdr.e_shstrndx].strtab;
96 if (shndx < ehdr.e_shnum)
97 name = sec_strtab + secs[shndx].shdr.sh_name;
98 else if (shndx == SHN_ABS)
99 name = "ABSOLUTE";
100 else if (shndx == SHN_COMMON)
101 name = "COMMON";
102 else
103 name = "<noname>";
104 return name;
105}
106
107static struct section *sec_lookup(const char *secname)
108{
109 int i;
110
111 for (i = 0; i < ehdr.e_shnum; i++)
112 if (strcmp(secname, sec_name(i)) == 0)
113 return &secs[i];
114
115 return NULL;
116}
117
118static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
119{
120 const char *name;
121
122 if (sym->st_name)
123 name = sym_strtab + sym->st_name;
124 else
125 name = sec_name(sym->st_shndx);
126 return name;
127}
128
129#if BYTE_ORDER == LITTLE_ENDIAN
130#define le16_to_cpu(val) (val)
131#define le32_to_cpu(val) (val)
132#define le64_to_cpu(val) (val)
133#define be16_to_cpu(val) bswap_16(val)
134#define be32_to_cpu(val) bswap_32(val)
135#define be64_to_cpu(val) bswap_64(val)
136
137#define cpu_to_le16(val) (val)
138#define cpu_to_le32(val) (val)
139#define cpu_to_le64(val) (val)
140#define cpu_to_be16(val) bswap_16(val)
141#define cpu_to_be32(val) bswap_32(val)
142#define cpu_to_be64(val) bswap_64(val)
143#endif
144#if BYTE_ORDER == BIG_ENDIAN
145#define le16_to_cpu(val) bswap_16(val)
146#define le32_to_cpu(val) bswap_32(val)
147#define le64_to_cpu(val) bswap_64(val)
148#define be16_to_cpu(val) (val)
149#define be32_to_cpu(val) (val)
150#define be64_to_cpu(val) (val)
151
152#define cpu_to_le16(val) bswap_16(val)
153#define cpu_to_le32(val) bswap_32(val)
154#define cpu_to_le64(val) bswap_64(val)
155#define cpu_to_be16(val) (val)
156#define cpu_to_be32(val) (val)
157#define cpu_to_be64(val) (val)
158#endif
159
160static uint16_t elf16_to_cpu(uint16_t val)
161{
162 if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
163 return le16_to_cpu(val);
164 else
165 return be16_to_cpu(val);
166}
167
168static uint32_t elf32_to_cpu(uint32_t val)
169{
170 if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
171 return le32_to_cpu(val);
172 else
173 return be32_to_cpu(val);
174}
175
176static uint32_t cpu_to_elf32(uint32_t val)
177{
178 if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
179 return cpu_to_le32(val);
180 else
181 return cpu_to_be32(val);
182}
183
184#define elf_half_to_cpu(x) elf16_to_cpu(x)
185#define elf_word_to_cpu(x) elf32_to_cpu(x)
186
187#if ELF_BITS == 64
188static uint64_t elf64_to_cpu(uint64_t val)
189{
190 if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
191 return le64_to_cpu(val);
192 else
193 return be64_to_cpu(val);
194}
195#define elf_addr_to_cpu(x) elf64_to_cpu(x)
196#define elf_off_to_cpu(x) elf64_to_cpu(x)
197#define elf_xword_to_cpu(x) elf64_to_cpu(x)
198#else
199#define elf_addr_to_cpu(x) elf32_to_cpu(x)
200#define elf_off_to_cpu(x) elf32_to_cpu(x)
201#define elf_xword_to_cpu(x) elf32_to_cpu(x)
202#endif
203
204static void read_ehdr(FILE *fp)
205{
206 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
207 die("Cannot read ELF header: %s\n", strerror(errno));
208
209 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0)
210 die("No ELF magic\n");
211
212 if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
213 die("Not a %d bit executable\n", ELF_BITS);
214
215 if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) &&
216 (ehdr.e_ident[EI_DATA] != ELFDATA2MSB))
217 die("Unknown ELF Endianness\n");
218
219 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
220 die("Unknown ELF version\n");
221
222 /* Convert the fields to native endian */
223 ehdr.e_type = elf_half_to_cpu(ehdr.e_type);
224 ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine);
225 ehdr.e_version = elf_word_to_cpu(ehdr.e_version);
226 ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry);
227 ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff);
228 ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff);
229 ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags);
230 ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize);
231 ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
232 ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum);
233 ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
234 ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum);
235 ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx);
236
237 if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN))
238 die("Unsupported ELF header type\n");
239
240 if (ehdr.e_machine != ELF_MACHINE)
241 die("Not for %s\n", ELF_MACHINE_NAME);
242
243 if (ehdr.e_version != EV_CURRENT)
244 die("Unknown ELF version\n");
245
246 if (ehdr.e_ehsize != sizeof(Elf_Ehdr))
247 die("Bad Elf header size\n");
248
249 if (ehdr.e_phentsize != sizeof(Elf_Phdr))
250 die("Bad program header entry\n");
251
252 if (ehdr.e_shentsize != sizeof(Elf_Shdr))
253 die("Bad section header entry\n");
254
255 if (ehdr.e_shstrndx >= ehdr.e_shnum)
256 die("String table index out of bounds\n");
257}
258
259static void read_shdrs(FILE *fp)
260{
261 int i;
262 Elf_Shdr shdr;
263
264 secs = calloc(ehdr.e_shnum, sizeof(struct section));
265 if (!secs)
266 die("Unable to allocate %d section headers\n", ehdr.e_shnum);
267
268 if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0)
269 die("Seek to %d failed: %s\n", ehdr.e_shoff, strerror(errno));
270
271 for (i = 0; i < ehdr.e_shnum; i++) {
272 struct section *sec = &secs[i];
273
274 sec->shdr_offset = ftell(fp);
275 if (fread(&shdr, sizeof(shdr), 1, fp) != 1)
276 die("Cannot read ELF section headers %d/%d: %s\n",
277 i, ehdr.e_shnum, strerror(errno));
278 sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name);
279 sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type);
280 sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags);
281 sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr);
282 sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset);
283 sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size);
284 sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link);
285 sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info);
286 sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
287 sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize);
288 if (sec->shdr.sh_link < ehdr.e_shnum)
289 sec->link = &secs[sec->shdr.sh_link];
290 }
291}
292
293static void read_strtabs(FILE *fp)
294{
295 int i;
296
297 for (i = 0; i < ehdr.e_shnum; i++) {
298 struct section *sec = &secs[i];
299
300 if (sec->shdr.sh_type != SHT_STRTAB)
301 continue;
302
303 sec->strtab = malloc(sec->shdr.sh_size);
304 if (!sec->strtab)
305 die("malloc of %d bytes for strtab failed\n",
306 sec->shdr.sh_size);
307
308 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0)
309 die("Seek to %d failed: %s\n",
310 sec->shdr.sh_offset, strerror(errno));
311
312 if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) !=
313 sec->shdr.sh_size)
314 die("Cannot read symbol table: %s\n", strerror(errno));
315 }
316}
317
318static void read_symtabs(FILE *fp)
319{
320 int i, j;
321
322 for (i = 0; i < ehdr.e_shnum; i++) {
323 struct section *sec = &secs[i];
324 if (sec->shdr.sh_type != SHT_SYMTAB)
325 continue;
326
327 sec->symtab = malloc(sec->shdr.sh_size);
328 if (!sec->symtab)
329 die("malloc of %d bytes for symtab failed\n",
330 sec->shdr.sh_size);
331
332 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0)
333 die("Seek to %d failed: %s\n",
334 sec->shdr.sh_offset, strerror(errno));
335
336 if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) !=
337 sec->shdr.sh_size)
338 die("Cannot read symbol table: %s\n", strerror(errno));
339
340 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
341 Elf_Sym *sym = &sec->symtab[j];
342
343 sym->st_name = elf_word_to_cpu(sym->st_name);
344 sym->st_value = elf_addr_to_cpu(sym->st_value);
345 sym->st_size = elf_xword_to_cpu(sym->st_size);
346 sym->st_shndx = elf_half_to_cpu(sym->st_shndx);
347 }
348 }
349}
350
351static void read_relocs(FILE *fp)
352{
353 static unsigned long base = 0;
354 int i, j;
355
356 if (!base) {
357 struct section *sec = sec_lookup(".text");
358
359 if (!sec)
360 die("Could not find .text section\n");
361
362 base = sec->shdr.sh_addr;
363 }
364
365 for (i = 0; i < ehdr.e_shnum; i++) {
366 struct section *sec = &secs[i];
367
368 if (sec->shdr.sh_type != SHT_REL_TYPE)
369 continue;
370
371 sec->reltab = malloc(sec->shdr.sh_size);
372 if (!sec->reltab)
373 die("malloc of %d bytes for relocs failed\n",
374 sec->shdr.sh_size);
375
376 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0)
377 die("Seek to %d failed: %s\n",
378 sec->shdr.sh_offset, strerror(errno));
379
380 if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) !=
381 sec->shdr.sh_size)
382 die("Cannot read symbol table: %s\n", strerror(errno));
383
384 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
385 Elf_Rel *rel = &sec->reltab[j];
386
387 rel->r_offset = elf_addr_to_cpu(rel->r_offset);
388 /* Set offset into kernel image */
389 rel->r_offset -= base;
390#if (ELF_BITS == 32)
391 rel->r_info = elf_xword_to_cpu(rel->r_info);
392#else
393 /* Convert MIPS64 RELA format - only the symbol
394 * index needs converting to native endianness
395 */
396 rel->r_info = rel->r_info;
397 ELF_R_SYM(rel->r_info) = elf32_to_cpu(ELF_R_SYM(rel->r_info));
398#endif
399#if (SHT_REL_TYPE == SHT_RELA)
400 rel->r_addend = elf_xword_to_cpu(rel->r_addend);
401#endif
402 }
403 }
404}
405
406static void remove_relocs(FILE *fp)
407{
408 int i;
409 Elf_Shdr shdr;
410
411 for (i = 0; i < ehdr.e_shnum; i++) {
412 struct section *sec = &secs[i];
413
414 if (sec->shdr.sh_type != SHT_REL_TYPE)
415 continue;
416
417 if (fseek(fp, sec->shdr_offset, SEEK_SET) < 0)
418 die("Seek to %d failed: %s\n",
419 sec->shdr_offset, strerror(errno));
420
421 if (fread(&shdr, sizeof(shdr), 1, fp) != 1)
422 die("Cannot read ELF section headers %d/%d: %s\n",
423 i, ehdr.e_shnum, strerror(errno));
424
425 /* Set relocation section size to 0, effectively removing it.
426 * This is necessary due to lack of support for relocations
427 * in objcopy when creating 32bit elf from 64bit elf.
428 */
429 shdr.sh_size = 0;
430
431 if (fseek(fp, sec->shdr_offset, SEEK_SET) < 0)
432 die("Seek to %d failed: %s\n",
433 sec->shdr_offset, strerror(errno));
434
435 if (fwrite(&shdr, sizeof(shdr), 1, fp) != 1)
436 die("Cannot write ELF section headers %d/%d: %s\n",
437 i, ehdr.e_shnum, strerror(errno));
438 }
439}
440
441static void add_reloc(struct relocs *r, uint32_t offset, unsigned type)
442{
443 /* Relocation representation in binary table:
444 * |76543210|76543210|76543210|76543210|
445 * | Type | offset from _text >> 2 |
446 */
447 offset >>= 2;
448 if (offset > 0x00FFFFFF)
449 die("Kernel image exceeds maximum size for relocation!\n");
450
451 offset = (offset & 0x00FFFFFF) | ((type & 0xFF) << 24);
452
453 if (r->count == r->size) {
454 unsigned long newsize = r->size + 50000;
455 void *mem = realloc(r->offset, newsize * sizeof(r->offset[0]));
456
457 if (!mem)
458 die("realloc failed\n");
459
460 r->offset = mem;
461 r->size = newsize;
462 }
463 r->offset[r->count++] = offset;
464}
465
466static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
467 Elf_Sym *sym, const char *symname))
468{
469 int i;
470
471 /* Walk through the relocations */
472 for (i = 0; i < ehdr.e_shnum; i++) {
473 char *sym_strtab;
474 Elf_Sym *sh_symtab;
475 struct section *sec_applies, *sec_symtab;
476 int j;
477 struct section *sec = &secs[i];
478
479 if (sec->shdr.sh_type != SHT_REL_TYPE)
480 continue;
481
482 sec_symtab = sec->link;
483 sec_applies = &secs[sec->shdr.sh_info];
484 if (!(sec_applies->shdr.sh_flags & SHF_ALLOC))
485 continue;
486
487 sh_symtab = sec_symtab->symtab;
488 sym_strtab = sec_symtab->link->strtab;
489 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
490 Elf_Rel *rel = &sec->reltab[j];
491 Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
492 const char *symname = sym_name(sym_strtab, sym);
493
494 process(sec, rel, sym, symname);
495 }
496 }
497}
498
499static int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
500 const char *symname)
501{
502 unsigned r_type = ELF_R_TYPE(rel->r_info);
503 unsigned bind = ELF_ST_BIND(sym->st_info);
504
505 if ((bind == STB_WEAK) && (sym->st_value == 0)) {
506 /* Don't relocate weak symbols without a target */
507 return 0;
508 }
509
510 if (regex_skip_reloc(symname))
511 return 0;
512
513 switch (r_type) {
514 case R_MIPS_NONE:
515 case R_MIPS_REL32:
516 case R_MIPS_PC16:
517 case R_MIPS_PC21_S2:
518 case R_MIPS_PC26_S2:
519 /*
520 * NONE can be ignored and PC relative relocations don't
521 * need to be adjusted.
522 */
523 case R_MIPS_HIGHEST:
524 case R_MIPS_HIGHER:
525 /* We support relocating within the same 4Gb segment only,
526 * thus leaving the top 32bits unchanged
527 */
528 case R_MIPS_LO16:
529 /* We support relocating by 64k jumps only
530 * thus leaving the bottom 16bits unchanged
531 */
532 break;
533
534 case R_MIPS_64:
535 case R_MIPS_32:
536 case R_MIPS_26:
537 case R_MIPS_HI16:
538 add_reloc(&relocs, rel->r_offset, r_type);
539 break;
540
541 default:
542 die("Unsupported relocation type: %s (%d)\n",
543 rel_type(r_type), r_type);
544 break;
545 }
546
547 return 0;
548}
549
550static int write_reloc_as_bin(uint32_t v, FILE *f)
551{
552 unsigned char buf[4];
553
554 v = cpu_to_elf32(v);
555
556 memcpy(buf, &v, sizeof(uint32_t));
557 return fwrite(buf, 1, 4, f);
558}
559
560static int write_reloc_as_text(uint32_t v, FILE *f)
561{
562 int res;
563
564 res = fprintf(f, "\t.long 0x%08"PRIx32"\n", v);
565 if (res < 0)
566 return res;
567 else
568 return sizeof(uint32_t);
569}
570
571static void emit_relocs(int as_text, int as_bin, FILE *outf)
572{
573 int i;
574 int (*write_reloc)(uint32_t, FILE *) = write_reloc_as_bin;
575 int size = 0;
576 int size_reserved;
577 struct section *sec_reloc;
578
579 sec_reloc = sec_lookup(".data.reloc");
580 if (!sec_reloc)
581 die("Could not find relocation section\n");
582
583 size_reserved = sec_reloc->shdr.sh_size;
584
585 /* Collect up the relocations */
586 walk_relocs(do_reloc);
587
588 /* Print the relocations */
589 if (as_text) {
590 /* Print the relocations in a form suitable that
591 * gas will like.
592 */
593 printf(".section \".data.reloc\",\"a\"\n");
594 printf(".balign 4\n");
595 /* Output text to stdout */
596 write_reloc = write_reloc_as_text;
597 outf = stdout;
598 } else if (as_bin) {
599 /* Output raw binary to stdout */
600 outf = stdout;
601 } else {
602 /* Seek to offset of the relocation section.
603 * Each relocation is then written into the
604 * vmlinux kernel image.
605 */
606 if (fseek(outf, sec_reloc->shdr.sh_offset, SEEK_SET) < 0) {
607 die("Seek to %d failed: %s\n",
608 sec_reloc->shdr.sh_offset, strerror(errno));
609 }
610 }
611
612 for (i = 0; i < relocs.count; i++)
613 size += write_reloc(relocs.offset[i], outf);
614
615 /* Print a stop, but only if we've actually written some relocs */
616 if (size)
617 size += write_reloc(0, outf);
618
619 if (size > size_reserved)
620 /* Die, but suggest a value for CONFIG_RELOCATION_TABLE_SIZE
621 * which will fix this problem and allow a bit of headroom
622 * if more kernel features are enabled
623 */
624 die("Relocations overflow available space!\n" \
625 "Please adjust CONFIG_RELOCATION_TABLE_SIZE " \
626 "to at least 0x%08x\n", (size + 0x1000) & ~0xFFF);
627}
628
629/*
630 * As an aid to debugging problems with different linkers
631 * print summary information about the relocs.
632 * Since different linkers tend to emit the sections in
633 * different orders we use the section names in the output.
634 */
635static int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
636 const char *symname)
637{
638 printf("%16s 0x%08x %16s %40s %16s\n",
639 sec_name(sec->shdr.sh_info),
640 (unsigned int)rel->r_offset,
641 rel_type(ELF_R_TYPE(rel->r_info)),
642 symname,
643 sec_name(sym->st_shndx));
644 return 0;
645}
646
647static void print_reloc_info(void)
648{
649 printf("%16s %10s %16s %40s %16s\n",
650 "reloc section",
651 "offset",
652 "reloc type",
653 "symbol",
654 "symbol section");
655 walk_relocs(do_reloc_info);
656}
657
658#if ELF_BITS == 64
659# define process process_64
660#else
661# define process process_32
662#endif
663
664void process(FILE *fp, int as_text, int as_bin,
665 int show_reloc_info, int keep_relocs)
666{
667 regex_init();
668 read_ehdr(fp);
669 read_shdrs(fp);
670 read_strtabs(fp);
671 read_symtabs(fp);
672 read_relocs(fp);
673 if (show_reloc_info) {
674 print_reloc_info();
675 return;
676 }
677 emit_relocs(as_text, as_bin, fp);
678 if (!keep_relocs)
679 remove_relocs(fp);
680}
diff --git a/arch/mips/boot/tools/relocs.h b/arch/mips/boot/tools/relocs.h
new file mode 100644
index 000000000000..3cf676f49e18
--- /dev/null
+++ b/arch/mips/boot/tools/relocs.h
@@ -0,0 +1,45 @@
1#ifndef RELOCS_H
2#define RELOCS_H
3
4#include <stdio.h>
5#include <stdarg.h>
6#include <stdlib.h>
7#include <stdint.h>
8#include <inttypes.h>
9#include <string.h>
10#include <errno.h>
11#include <unistd.h>
12#include <elf.h>
13#include <byteswap.h>
14#define USE_BSD
15#include <endian.h>
16#include <regex.h>
17
18void die(char *fmt, ...);
19
20/*
21 * Introduced for MIPSr6
22 */
23#ifndef R_MIPS_PC21_S2
24#define R_MIPS_PC21_S2 60
25#endif
26
27#ifndef R_MIPS_PC26_S2
28#define R_MIPS_PC26_S2 61
29#endif
30
31#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
32
33enum symtype {
34 S_ABS,
35 S_REL,
36 S_SEG,
37 S_LIN,
38 S_NSYMTYPES
39};
40
41void process_32(FILE *fp, int as_text, int as_bin,
42 int show_reloc_info, int keep_relocs);
43void process_64(FILE *fp, int as_text, int as_bin,
44 int show_reloc_info, int keep_relocs);
45#endif /* RELOCS_H */
diff --git a/arch/mips/boot/tools/relocs_32.c b/arch/mips/boot/tools/relocs_32.c
new file mode 100644
index 000000000000..915bdc07f5ed
--- /dev/null
+++ b/arch/mips/boot/tools/relocs_32.c
@@ -0,0 +1,17 @@
1#include "relocs.h"
2
3#define ELF_BITS 32
4
5#define ELF_MACHINE EM_MIPS
6#define ELF_MACHINE_NAME "MIPS"
7#define SHT_REL_TYPE SHT_REL
8#define Elf_Rel ElfW(Rel)
9
10#define ELF_CLASS ELFCLASS32
11#define ELF_R_SYM(val) ELF32_R_SYM(val)
12#define ELF_R_TYPE(val) ELF32_R_TYPE(val)
13#define ELF_ST_TYPE(o) ELF32_ST_TYPE(o)
14#define ELF_ST_BIND(o) ELF32_ST_BIND(o)
15#define ELF_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o)
16
17#include "relocs.c"
diff --git a/arch/mips/boot/tools/relocs_64.c b/arch/mips/boot/tools/relocs_64.c
new file mode 100644
index 000000000000..b671b5e2dcd8
--- /dev/null
+++ b/arch/mips/boot/tools/relocs_64.c
@@ -0,0 +1,27 @@
1#include "relocs.h"
2
3#define ELF_BITS 64
4
5#define ELF_MACHINE EM_MIPS
6#define ELF_MACHINE_NAME "MIPS64"
7#define SHT_REL_TYPE SHT_RELA
8#define Elf_Rel Elf64_Rela
9
10typedef uint8_t Elf64_Byte;
11
12typedef struct {
13 Elf64_Word r_sym; /* Symbol index. */
14 Elf64_Byte r_ssym; /* Special symbol. */
15 Elf64_Byte r_type3; /* Third relocation. */
16 Elf64_Byte r_type2; /* Second relocation. */
17 Elf64_Byte r_type; /* First relocation. */
18} Elf64_Mips_Rela;
19
20#define ELF_CLASS ELFCLASS64
21#define ELF_R_SYM(val) (((Elf64_Mips_Rela *)(&val))->r_sym)
22#define ELF_R_TYPE(val) (((Elf64_Mips_Rela *)(&val))->r_type)
23#define ELF_ST_TYPE(o) ELF64_ST_TYPE(o)
24#define ELF_ST_BIND(o) ELF64_ST_BIND(o)
25#define ELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o)
26
27#include "relocs.c"
diff --git a/arch/mips/boot/tools/relocs_main.c b/arch/mips/boot/tools/relocs_main.c
new file mode 100644
index 000000000000..d8fe2343b8d0
--- /dev/null
+++ b/arch/mips/boot/tools/relocs_main.c
@@ -0,0 +1,84 @@
1
2#include <stdio.h>
3#include <stdint.h>
4#include <stdarg.h>
5#include <stdlib.h>
6#include <string.h>
7#include <errno.h>
8#include <endian.h>
9#include <elf.h>
10
11#include "relocs.h"
12
13void die(char *fmt, ...)
14{
15 va_list ap;
16
17 va_start(ap, fmt);
18 vfprintf(stderr, fmt, ap);
19 va_end(ap);
20 exit(1);
21}
22
23static void usage(void)
24{
25 die("relocs [--reloc-info|--text|--bin|--keep] vmlinux\n");
26}
27
28int main(int argc, char **argv)
29{
30 int show_reloc_info, as_text, as_bin, keep_relocs;
31 const char *fname;
32 FILE *fp;
33 int i;
34 unsigned char e_ident[EI_NIDENT];
35
36 show_reloc_info = 0;
37 as_text = 0;
38 as_bin = 0;
39 keep_relocs = 0;
40 fname = NULL;
41 for (i = 1; i < argc; i++) {
42 char *arg = argv[i];
43
44 if (*arg == '-') {
45 if (strcmp(arg, "--reloc-info") == 0) {
46 show_reloc_info = 1;
47 continue;
48 }
49 if (strcmp(arg, "--text") == 0) {
50 as_text = 1;
51 continue;
52 }
53 if (strcmp(arg, "--bin") == 0) {
54 as_bin = 1;
55 continue;
56 }
57 if (strcmp(arg, "--keep") == 0) {
58 keep_relocs = 1;
59 continue;
60 }
61 } else if (!fname) {
62 fname = arg;
63 continue;
64 }
65 usage();
66 }
67 if (!fname)
68 usage();
69
70 fp = fopen(fname, "r+");
71 if (!fp)
72 die("Cannot open %s: %s\n", fname, strerror(errno));
73
74 if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT)
75 die("Cannot read %s: %s", fname, strerror(errno));
76
77 rewind(fp);
78 if (e_ident[EI_CLASS] == ELFCLASS64)
79 process_64(fp, as_text, as_bin, show_reloc_info, keep_relocs);
80 else
81 process_32(fp, as_text, as_bin, show_reloc_info, keep_relocs);
82 fclose(fp);
83 return 0;
84}