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