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