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
71static int ei_class;
72static int ei_data;
73static int machine;
74
75static uint64_t rela_start, rela_end, text_base, dyn_start;
76
77static const bool debug_en;
78
79static 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
90static 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
98static 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
106static 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
114static 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
131static 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
265static 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
414static 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
454static 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
517static 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
564static 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
704int 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}
762