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