mmc: mediatek: add support for MediaTek MT7621 SoC
[platform/kernel/u-boot.git] / tools / relocate-rela.c
1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause
2 /*
3  * Copyright 2013 Freescale Semiconductor, Inc.
4  *
5  * 64-bit and little-endian target only until we need to support a different
6  * arch that needs this.
7  */
8
9 #include <elf.h>
10 #include <errno.h>
11 #include <inttypes.h>
12 #include <stdarg.h>
13 #include <stdbool.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include "compiler.h"
18
19 #ifndef R_AARCH64_RELATIVE
20 #define R_AARCH64_RELATIVE      1027
21 #endif
22
23 static int ei_class;
24
25 static uint64_t rela_start, rela_end, text_base, dyn_start;
26
27 static const bool debug_en;
28
29 static void debug(const char *fmt, ...)
30 {
31         va_list args;
32
33         if (debug_en) {
34                 va_start(args, fmt);
35                 vprintf(fmt, args);
36                 va_end(args);
37         }
38 }
39
40 static bool supported_rela(Elf64_Rela *rela)
41 {
42         uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */
43         uint32_t type = rela->r_info & mask;
44
45         switch (type) {
46 #ifdef R_AARCH64_RELATIVE
47         case R_AARCH64_RELATIVE:
48                 return true;
49 #endif
50         default:
51                 fprintf(stderr, "warning: unsupported relocation type %"
52                                 PRIu32 " at %" PRIx64 "\n",
53                         type, rela->r_offset);
54
55                 return false;
56         }
57 }
58
59 static int decode_elf64(FILE *felf, char **argv)
60 {
61         size_t size;
62         Elf64_Ehdr header;
63         uint64_t section_header_base, section_header_size, sh_offset, sh_size;
64         Elf64_Shdr *sh_table; /* Elf symbol table */
65         int ret, i, machine;
66         char *sh_str;
67
68         debug("64bit version\n");
69
70         /* Make sure we are at start */
71         rewind(felf);
72
73         size = fread(&header, 1, sizeof(header), felf);
74         if (size != sizeof(header)) {
75                 fclose(felf);
76                 return 25;
77         }
78
79         machine = header.e_machine;
80         debug("Machine\t%d\n", machine);
81
82         if (machine != EM_AARCH64) {
83                 fprintf(stderr, "%s: Not supported machine type\n", argv[0]);
84                 return 30;
85         }
86
87         text_base = header.e_entry;
88         section_header_base = header.e_shoff;
89         section_header_size = header.e_shentsize * header.e_shnum;
90
91         sh_table = malloc(section_header_size);
92         if (!sh_table) {
93                 fprintf(stderr, "%s: Cannot allocate space for section header\n",
94                         argv[0]);
95                 fclose(felf);
96                 return 26;
97         }
98
99         ret = fseek(felf, section_header_base, SEEK_SET);
100         if (ret) {
101                 fprintf(stderr, "%s: Can't set pointer to section header: %x/%lx\n",
102                         argv[0], ret, section_header_base);
103                 free(sh_table);
104                 fclose(felf);
105                 return 26;
106         }
107
108         size = fread(sh_table, 1, section_header_size, felf);
109         if (size != section_header_size) {
110                 fprintf(stderr, "%s: Can't read section header: %lx/%lx\n",
111                         argv[0], size, section_header_size);
112                 free(sh_table);
113                 fclose(felf);
114                 return 27;
115         }
116
117         sh_size = sh_table[header.e_shstrndx].sh_size;
118         debug("e_shstrndx\t0x%08x\n", header.e_shstrndx);
119         debug("sh_size\t\t0x%08lx\n", sh_size);
120
121         sh_str = malloc(sh_size);
122         if (!sh_str) {
123                 fprintf(stderr, "malloc failed\n");
124                 free(sh_table);
125                 fclose(felf);
126                 return 28;
127         }
128
129         /*
130          * Specifies the byte offset from the beginning of the file
131          * to the first byte in the section.
132          */
133         sh_offset = sh_table[header.e_shstrndx].sh_offset;
134
135         debug("sh_offset\t0x%08x\n", header.e_shnum);
136
137         ret = fseek(felf, sh_offset, SEEK_SET);
138         if (ret) {
139                 fprintf(stderr, "Setting up sh_offset failed\n");
140                 free(sh_str);
141                 free(sh_table);
142                 fclose(felf);
143                 return 29;
144         }
145
146         size = fread(sh_str, 1, sh_size, felf);
147         if (size != sh_size) {
148                 fprintf(stderr, "%s: Can't read section: %lx/%lx\n",
149                         argv[0], size, sh_size);
150                 free(sh_str);
151                 free(sh_table);
152                 fclose(felf);
153                 return 30;
154         }
155
156         for (i = 0; i < header.e_shnum; i++) {
157                 /* fprintf(stderr, "%s\n", sh_str + sh_table[i].sh_name); Debug only */
158                 if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) {
159                         debug("Found section\t\".rela_dyn\"\n");
160                         debug(" at addr\t0x%08x\n",
161                               (unsigned int)sh_table[i].sh_addr);
162                         debug(" at offset\t0x%08x\n",
163                               (unsigned int)sh_table[i].sh_offset);
164                         debug(" of size\t0x%08x\n",
165                               (unsigned int)sh_table[i].sh_size);
166                         rela_start = sh_table[i].sh_addr;
167                         rela_end = rela_start + sh_table[i].sh_size;
168                         break;
169                 }
170         }
171
172         /* Clean up */
173         free(sh_str);
174         free(sh_table);
175         fclose(felf);
176
177         debug("text_base\t0x%08lx\n", text_base);
178         debug("rela_start\t0x%08lx\n", rela_start);
179         debug("rela_end\t0x%08lx\n", rela_end);
180
181         if (!rela_start)
182                 return 1;
183
184         return 0;
185 }
186
187 static int decode_elf32(FILE *felf, char **argv)
188 {
189         size_t size;
190         Elf32_Ehdr header;
191         uint64_t section_header_base, section_header_size, sh_offset, sh_size;
192         Elf32_Shdr *sh_table; /* Elf symbol table */
193         int ret, i, machine;
194         char *sh_str;
195
196         debug("32bit version\n");
197
198         /* Make sure we are at start */
199         rewind(felf);
200
201         size = fread(&header, 1, sizeof(header), felf);
202         if (size != sizeof(header)) {
203                 fclose(felf);
204                 return 25;
205         }
206
207         machine = header.e_machine;
208         debug("Machine %d\n", machine);
209
210         if (machine != EM_MICROBLAZE) {
211                 fprintf(stderr, "%s: Not supported machine type\n", argv[0]);
212                 return 30;
213         }
214
215         text_base = header.e_entry;
216         section_header_base = header.e_shoff;
217
218         debug("Section header base %x\n", section_header_base);
219
220         section_header_size = header.e_shentsize * header.e_shnum;
221
222         debug("Section header size %d\n", section_header_size);
223
224         sh_table = malloc(section_header_size);
225         if (!sh_table) {
226                 fprintf(stderr, "%s: Cannot allocate space for section header\n",
227                         argv[0]);
228                 fclose(felf);
229                 return 26;
230         }
231
232         ret = fseek(felf, section_header_base, SEEK_SET);
233         if (ret) {
234                 fprintf(stderr, "%s: Can't set pointer to section header: %x/%lx\n",
235                         argv[0], ret, section_header_base);
236                 free(sh_table);
237                 fclose(felf);
238                 return 26;
239         }
240
241         size = fread(sh_table, 1, section_header_size, felf);
242         if (size != section_header_size) {
243                 fprintf(stderr, "%s: Can't read section header: %lx/%lx\n",
244                         argv[0], size, section_header_size);
245                 free(sh_table);
246                 fclose(felf);
247                 return 27;
248         }
249
250         sh_size = sh_table[header.e_shstrndx].sh_size;
251         debug("e_shstrndx %x, sh_size %lx\n", header.e_shstrndx, sh_size);
252
253         sh_str = malloc(sh_size);
254         if (!sh_str) {
255                 fprintf(stderr, "malloc failed\n");
256                 free(sh_table);
257                 fclose(felf);
258                 return 28;
259         }
260
261         /*
262          * Specifies the byte offset from the beginning of the file
263          * to the first byte in the section.
264          */
265         sh_offset = sh_table[header.e_shstrndx].sh_offset;
266
267         debug("sh_offset %x\n", header.e_shnum);
268
269         ret = fseek(felf, sh_offset, SEEK_SET);
270         if (ret) {
271                 fprintf(stderr, "Setting up sh_offset failed\n");
272                 free(sh_str);
273                 free(sh_table);
274                 fclose(felf);
275                 return 29;
276         }
277
278         size = fread(sh_str, 1, sh_size, felf);
279         if (size != sh_size) {
280                 fprintf(stderr, "%s: Can't read section: %lx/%lx\n",
281                         argv[0], size, sh_size);
282                 free(sh_str);
283                 free(sh_table);
284                 fclose(felf);
285                 return 30;
286         }
287
288         for (i = 0; i < header.e_shnum; i++) {
289                 debug("%s\n", sh_str + sh_table[i].sh_name);
290                 if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) {
291                         debug("Found section\t\".rela_dyn\"\n");
292                         debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr);
293                         debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset);
294                         debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size);
295                         rela_start = sh_table[i].sh_addr;
296                         rela_end = rela_start + sh_table[i].sh_size;
297                 }
298                 if (!strcmp(".dynsym", (sh_str + sh_table[i].sh_name))) {
299                         debug("Found section\t\".dynsym\"\n");
300                         debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr);
301                         debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset);
302                         debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size);
303                         dyn_start = sh_table[i].sh_addr;
304                 }
305         }
306
307         /* Clean up */
308         free(sh_str);
309         free(sh_table);
310         fclose(felf);
311
312         debug("text_base\t0x%08lx\n", text_base);
313         debug("rela_start\t0x%08lx\n", rela_start);
314         debug("rela_end\t0x%08lx\n", rela_end);
315         debug("dyn_start\t0x%08lx\n", dyn_start);
316
317         if (!rela_start)
318                 return 1;
319
320         return 0;
321 }
322
323 static int decode_elf(char **argv)
324 {
325         FILE *felf;
326         size_t size;
327         unsigned char e_ident[EI_NIDENT];
328
329         felf = fopen(argv[2], "r+b");
330         if (!felf) {
331                 fprintf(stderr, "%s: Cannot open %s: %s\n",
332                         argv[0], argv[5], strerror(errno));
333                 return 2;
334         }
335
336         size = fread(e_ident, 1, EI_NIDENT, felf);
337         if (size != EI_NIDENT) {
338                 fclose(felf);
339                 return 25;
340         }
341
342         /* Check if this is really ELF file */
343         if (e_ident[0] != 0x7f &&
344             e_ident[1] != 'E' &&
345             e_ident[2] != 'L' &&
346             e_ident[3] != 'F') {
347                 fclose(felf);
348                 return 1;
349         }
350
351         ei_class = e_ident[4];
352         debug("EI_CLASS(1=32bit, 2=64bit) %d\n", ei_class);
353
354         if (ei_class == 2)
355                 return decode_elf64(felf, argv);
356
357         return decode_elf32(felf, argv);
358 }
359
360 static int rela_elf64(char **argv, FILE *f)
361 {
362         int i, num;
363
364         if ((rela_end - rela_start) % sizeof(Elf64_Rela)) {
365                 fprintf(stderr, "%s: rela size isn't a multiple of Elf64_Rela\n", argv[0]);
366                 return 3;
367         }
368
369         num = (rela_end - rela_start) / sizeof(Elf64_Rela);
370
371         for (i = 0; i < num; i++) {
372                 Elf64_Rela rela, swrela;
373                 uint64_t pos = rela_start + sizeof(Elf64_Rela) * i;
374                 uint64_t addr;
375
376                 if (fseek(f, pos, SEEK_SET) < 0) {
377                         fprintf(stderr, "%s: %s: seek to %" PRIx64
378                                         " failed: %s\n",
379                                 argv[0], argv[1], pos, strerror(errno));
380                 }
381
382                 if (fread(&rela, sizeof(rela), 1, f) != 1) {
383                         fprintf(stderr, "%s: %s: read rela failed at %"
384                                         PRIx64 "\n",
385                                 argv[0], argv[1], pos);
386                         return 4;
387                 }
388
389                 swrela.r_offset = cpu_to_le64(rela.r_offset);
390                 swrela.r_info = cpu_to_le64(rela.r_info);
391                 swrela.r_addend = cpu_to_le64(rela.r_addend);
392
393                 if (!supported_rela(&swrela))
394                         continue;
395
396                 debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n",
397                       swrela.r_offset, swrela.r_info, swrela.r_addend);
398
399                 if (swrela.r_offset < text_base) {
400                         fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n",
401                                 argv[0], argv[1], pos);
402                         return 4;
403                 }
404
405                 addr = swrela.r_offset - text_base;
406
407                 if (fseek(f, addr, SEEK_SET) < 0) {
408                         fprintf(stderr, "%s: %s: seek to %"
409                                         PRIx64 " failed: %s\n",
410                                 argv[0], argv[1], addr, strerror(errno));
411                 }
412
413                 if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) {
414                         fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n",
415                                 argv[0], argv[1], addr);
416                         return 4;
417                 }
418         }
419
420         return 0;
421 }
422
423 static bool supported_rela32(Elf32_Rela *rela, uint32_t *type)
424 {
425         uint32_t mask = 0xffULL; /* would be different on 32-bit */
426         *type = rela->r_info & mask;
427
428         debug("Type:\t");
429
430         switch (*type) {
431         case R_MICROBLAZE_32:
432                 debug("R_MICROBLAZE_32\n");
433                 return true;
434         case R_MICROBLAZE_GLOB_DAT:
435                 debug("R_MICROBLAZE_GLOB_DAT\n");
436                 return true;
437         case R_MICROBLAZE_NONE:
438                 debug("R_MICROBLAZE_NONE - ignoring - do nothing\n");
439                 return false;
440         case R_MICROBLAZE_REL:
441                 debug("R_MICROBLAZE_REL\n");
442                 return true;
443         default:
444                 fprintf(stderr, "warning: unsupported relocation type %"
445                         PRIu32 " at %" PRIx32 "\n", *type, rela->r_offset);
446
447                 return false;
448         }
449 }
450
451 static int rela_elf32(char **argv, FILE *f)
452 {
453         int i, num, index;
454         uint32_t value, type;
455
456         if ((rela_end - rela_start) % sizeof(Elf32_Rela)) {
457                 fprintf(stderr, "%s: rela size isn't a multiple of Elf32_Rela\n", argv[0]);
458                 return 3;
459         }
460
461         num = (rela_end - rela_start) / sizeof(Elf32_Rela);
462
463         debug("Number of entries: %u\n", num);
464
465         for (i = 0; i < num; i++) {
466                 Elf32_Rela rela, swrela;
467                 Elf32_Sym symbols;
468                 uint32_t pos = rela_start + sizeof(Elf32_Rela) * i;
469                 uint32_t addr, pos_dyn;
470
471                 debug("\nPossition:\t%d/0x%x\n", i, pos);
472
473                 if (fseek(f, pos, SEEK_SET) < 0) {
474                         fprintf(stderr, "%s: %s: seek to %" PRIx32
475                                         " failed: %s\n",
476                                 argv[0], argv[1], pos, strerror(errno));
477                 }
478
479                 if (fread(&rela, sizeof(rela), 1, f) != 1) {
480                         fprintf(stderr, "%s: %s: read rela failed at %"
481                                         PRIx32 "\n",
482                                 argv[0], argv[1], pos);
483                         return 4;
484                 }
485
486                 debug("Rela:\toffset:\t%" PRIx32 " r_info:\t%"
487                       PRIu32 " r_addend:\t%" PRIx32 "\n",
488                       rela.r_offset, rela.r_info, rela.r_addend);
489
490                 swrela.r_offset = cpu_to_le32(rela.r_offset);
491                 swrela.r_info = cpu_to_le32(rela.r_info);
492                 swrela.r_addend = cpu_to_le32(rela.r_addend);
493
494                 debug("SWRela:\toffset:\t%" PRIx32 " r_info:\t%"
495                       PRIu32 " r_addend:\t%" PRIx32 "\n",
496                       swrela.r_offset, swrela.r_info, swrela.r_addend);
497
498                 if (!supported_rela32(&swrela, &type))
499                         continue;
500
501                 if (swrela.r_offset < text_base) {
502                         fprintf(stderr, "%s: %s: bad rela at %" PRIx32 "\n",
503                                 argv[0], argv[1], pos);
504                         return 4;
505                 }
506
507                 addr = swrela.r_offset - text_base;
508
509                 debug("Addr:\t0x%" PRIx32 "\n", addr);
510
511                 switch (type) {
512                 case R_MICROBLAZE_REL:
513                         if (fseek(f, addr, SEEK_SET) < 0) {
514                                 fprintf(stderr, "%s: %s: seek to %"
515                                         PRIx32 " failed: %s\n",
516                                         argv[0], argv[1], addr, strerror(errno));
517                                 return 5;
518                         }
519
520                         debug("Write addend\n");
521
522                         if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) {
523                                 fprintf(stderr, "%s: %s: write failed at %" PRIx32 "\n",
524                                         argv[0], argv[1], addr);
525                                 return 4;
526                         }
527                         break;
528                 case R_MICROBLAZE_32:
529                 case R_MICROBLAZE_GLOB_DAT:
530                         /* global symbols read it and add reloc offset */
531                         index = swrela.r_info >> 8;
532                         pos_dyn = dyn_start + sizeof(Elf32_Sym) * index;
533
534                         debug("Index:\t%d\n", index);
535                         debug("Pos_dyn:\t0x%x\n", pos_dyn);
536
537                         if (fseek(f, pos_dyn, SEEK_SET) < 0) {
538                                 fprintf(stderr, "%s: %s: seek to %"
539                                         PRIx32 " failed: %s\n",
540                                         argv[0], argv[1], pos_dyn, strerror(errno));
541                                 return 5;
542                         }
543
544                         if (fread(&symbols, sizeof(symbols), 1, f) != 1) {
545                                 fprintf(stderr, "%s: %s: read symbols failed at %"
546                                                 PRIx32 "\n",
547                                         argv[0], argv[1], pos_dyn);
548                                 return 4;
549                         }
550
551                         debug("Symbol description:\n");
552                         debug(" st_name:\t0x%x\n", symbols.st_name);
553                         debug(" st_value:\t0x%x\n", symbols.st_value);
554                         debug(" st_size:\t0x%x\n", symbols.st_size);
555
556                         value = swrela.r_addend + symbols.st_value;
557
558                         debug("Value:\t0x%x\n", value);
559
560                         if (fseek(f, addr, SEEK_SET) < 0) {
561                                 fprintf(stderr, "%s: %s: seek to %"
562                                         PRIx32 " failed: %s\n",
563                                         argv[0], argv[1], addr, strerror(errno));
564                                 return 5;
565                         }
566
567                         if (fwrite(&value, sizeof(rela.r_addend), 1, f) != 1) {
568                                 fprintf(stderr, "%s: %s: write failed at %" PRIx32 "\n",
569                                         argv[0], argv[1], addr);
570                                 return 4;
571                         }
572
573                         break;
574                 case R_MICROBLAZE_NONE:
575                         debug("R_MICROBLAZE_NONE - skip\n");
576                         break;
577                 default:
578                         fprintf(stderr, "warning: unsupported relocation type %"
579                                 PRIu32 " at %" PRIx32 "\n",
580                                 type, rela.r_offset);
581                 }
582         }
583
584         return 0;
585 }
586
587 int main(int argc, char **argv)
588 {
589         FILE *f;
590         int ret;
591         uint64_t file_size;
592
593         if (argc != 3) {
594                 fprintf(stderr, "Statically apply ELF rela relocations\n");
595                 fprintf(stderr, "Usage: %s <bin file> <u-boot ELF>\n",
596                         argv[0]);
597                 return 1;
598         }
599
600         ret = decode_elf(argv);
601         if (ret) {
602                 fprintf(stderr, "ELF decoding failed\n");
603                 return ret;
604         }
605
606         if (rela_start > rela_end || rela_start < text_base) {
607                 fprintf(stderr, "%s: bad rela bounds\n", argv[0]);
608                 return 3;
609         }
610
611         rela_start -= text_base;
612         rela_end -= text_base;
613         dyn_start -= text_base;
614
615         f = fopen(argv[1], "r+b");
616         if (!f) {
617                 fprintf(stderr, "%s: Cannot open %s: %s\n",
618                         argv[0], argv[1], strerror(errno));
619                 return 2;
620         }
621
622         fseek(f, 0, SEEK_END);
623         file_size = ftell(f);
624         rewind(f);
625
626         if (rela_end > file_size) {
627                 // Most likely compiler inserted some section that didn't get
628                 // objcopy-ed into the final binary
629                 rela_end = file_size;
630         }
631
632         if (ei_class == 2)
633                 ret = rela_elf64(argv, f);
634         else
635                 ret = rela_elf32(argv, f);
636
637         if (fclose(f) < 0) {
638                 fprintf(stderr, "%s: %s: close failed: %s\n",
639                         argv[0], argv[1], strerror(errno));
640                 return 4;
641         }
642
643         return ret;
644 }