]>
git.ipfire.org Git - people/ms/u-boot.git/blob - tools/mips-relocs.c
2 * MIPS Relocation Data Generator
4 * Copyright (c) 2017 Imagination Technologies Ltd.
6 * SPDX-License-Identifier: GPL-2.0+
21 #include <asm/relocs.h>
23 #define hdr_field(pfx, idx, field) ({ \
28 _val = pfx##hdr64[idx].field; \
29 _size = sizeof(pfx##hdr64[0].field); \
31 _val = pfx##hdr32[idx].field; \
32 _size = sizeof(pfx##hdr32[0].field); \
39 _val = is_be ? be16toh(_val) : le16toh(_val); \
42 _val = is_be ? be32toh(_val) : le32toh(_val); \
45 _val = is_be ? be64toh(_val) : le64toh(_val); \
52 #define set_hdr_field(pfx, idx, field, val) ({ \
57 _size = sizeof(pfx##hdr64[0].field); \
59 _size = sizeof(pfx##hdr32[0].field); \
66 _val = is_be ? htobe16(val) : htole16(val); \
69 _val = is_be ? htobe32(val) : htole32(val); \
72 _val = is_be ? htobe64(val) : htole64(val); \
75 /* We should never reach here */ \
82 pfx##hdr64[idx].field = _val; \
84 pfx##hdr32[idx].field = _val; \
87 #define ehdr_field(field) \
88 hdr_field(e, 0, field)
89 #define phdr_field(idx, field) \
90 hdr_field(p, idx, field)
91 #define shdr_field(idx, field) \
92 hdr_field(s, idx, field)
94 #define set_phdr_field(idx, field, val) \
95 set_hdr_field(p, idx, field, val)
96 #define set_shdr_field(idx, field, val) \
97 set_hdr_field(s, idx, field, val)
99 #define shstr(idx) (&shstrtab[idx])
108 size_t relocs_sz
, relocs_idx
;
110 static int add_reloc(unsigned int type
, uint64_t off
)
112 struct mips_reloc
*new;
123 /* Skip these relocs */
130 if (relocs_idx
== relocs_sz
) {
131 new_sz
= relocs_sz
? relocs_sz
* 2 : 128;
132 new = realloc(relocs
, new_sz
* sizeof(*relocs
));
134 fprintf(stderr
, "Out of memory\n");
142 relocs
[relocs_idx
++] = (struct mips_reloc
){
150 static int parse_mips32_rel(const void *_rel
)
152 const Elf32_Rel
*rel
= _rel
;
155 off
= is_be
? be32toh(rel
->r_offset
) : le32toh(rel
->r_offset
);
158 type
= is_be
? be32toh(rel
->r_info
) : le32toh(rel
->r_info
);
159 type
= ELF32_R_TYPE(type
);
161 return add_reloc(type
, off
);
164 static int parse_mips64_rela(const void *_rel
)
166 const Elf64_Rela
*rel
= _rel
;
169 off
= is_be
? be64toh(rel
->r_offset
) : le64toh(rel
->r_offset
);
172 type
= rel
->r_info
>> (64 - 8);
174 return add_reloc(type
, off
);
177 static void output_uint(uint8_t **buf
, uint64_t val
)
189 static int compare_relocs(const void *a
, const void *b
)
191 const struct mips_reloc
*ra
= a
, *rb
= b
;
193 return ra
->offset
- rb
->offset
;
196 int main(int argc
, char *argv
[])
198 unsigned int i
, j
, i_rel_shdr
, sh_type
, sh_entsize
, sh_entries
;
199 size_t rel_size
, rel_actual_size
, load_sz
;
200 const char *shstrtab
, *sh_name
, *rel_pfx
;
201 int (*parse_fn
)(const void *rel
);
202 uint8_t *buf_start
, *buf
;
203 const Elf32_Ehdr
*ehdr32
;
204 const Elf64_Ehdr
*ehdr64
;
215 fd
= open(argv
[1], O_RDWR
);
217 fprintf(stderr
, "Unable to open input file %s\n", argv
[1]);
222 err
= fstat(fd
, &st
);
224 fprintf(stderr
, "Unable to fstat() input file\n");
228 elf
= mmap(NULL
, st
.st_size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
229 if (elf
== MAP_FAILED
) {
230 fprintf(stderr
, "Unable to mmap() input file\n");
238 if (memcmp(&ehdr32
->e_ident
[EI_MAG0
], ELFMAG
, SELFMAG
)) {
239 fprintf(stderr
, "Input file is not an ELF\n");
241 goto out_free_relocs
;
244 if (ehdr32
->e_ident
[EI_VERSION
] != EV_CURRENT
) {
245 fprintf(stderr
, "Unrecognised ELF version\n");
247 goto out_free_relocs
;
250 switch (ehdr32
->e_ident
[EI_CLASS
]) {
258 fprintf(stderr
, "Unrecognised ELF class\n");
260 goto out_free_relocs
;
263 switch (ehdr32
->e_ident
[EI_DATA
]) {
271 fprintf(stderr
, "Unrecognised ELF data encoding\n");
273 goto out_free_relocs
;
276 if (ehdr_field(e_type
) != ET_EXEC
) {
277 fprintf(stderr
, "Input ELF is not an executable\n");
278 printf("type 0x%lx\n", ehdr_field(e_type
));
280 goto out_free_relocs
;
283 if (ehdr_field(e_machine
) != EM_MIPS
) {
284 fprintf(stderr
, "Input ELF does not target MIPS\n");
286 goto out_free_relocs
;
289 phdr32
= elf
+ ehdr_field(e_phoff
);
290 phdr64
= elf
+ ehdr_field(e_phoff
);
291 shdr32
= elf
+ ehdr_field(e_shoff
);
292 shdr64
= elf
+ ehdr_field(e_shoff
);
293 shstrtab
= elf
+ shdr_field(ehdr_field(e_shstrndx
), sh_offset
);
295 i_rel_shdr
= UINT_MAX
;
296 for (i
= 0; i
< ehdr_field(e_shnum
); i
++) {
297 sh_name
= shstr(shdr_field(i
, sh_name
));
299 if (!strcmp(sh_name
, ".rel")) {
304 if (!strcmp(sh_name
, ".text")) {
305 text_base
= shdr_field(i
, sh_addr
);
309 if (i_rel_shdr
== UINT_MAX
) {
310 fprintf(stderr
, "Unable to find .rel section\n");
312 goto out_free_relocs
;
315 fprintf(stderr
, "Unable to find .text base address\n");
317 goto out_free_relocs
;
320 rel_pfx
= is_64
? ".rela." : ".rel.";
322 for (i
= 0; i
< ehdr_field(e_shnum
); i
++) {
323 sh_type
= shdr_field(i
, sh_type
);
324 if ((sh_type
!= SHT_REL
) && (sh_type
!= SHT_RELA
))
327 sh_name
= shstr(shdr_field(i
, sh_name
));
328 if (strncmp(sh_name
, rel_pfx
, strlen(rel_pfx
))) {
329 if (strcmp(sh_name
, ".rel") && strcmp(sh_name
, ".rel.dyn"))
330 fprintf(stderr
, "WARNING: Unexpected reloc section name '%s'\n", sh_name
);
335 * Skip reloc sections which either don't correspond to another
336 * section in the ELF, or whose corresponding section isn't
337 * loaded as part of the U-Boot binary (ie. doesn't have the
341 for (j
= 0; j
< ehdr_field(e_shnum
); j
++) {
342 if (strcmp(&sh_name
[strlen(rel_pfx
) - 1], shstr(shdr_field(j
, sh_name
))))
345 skip
= !(shdr_field(j
, sh_flags
) & SHF_ALLOC
);
351 sh_offset
= shdr_field(i
, sh_offset
);
352 sh_entsize
= shdr_field(i
, sh_entsize
);
353 sh_entries
= shdr_field(i
, sh_size
) / sh_entsize
;
355 if (sh_type
== SHT_REL
) {
357 fprintf(stderr
, "REL-style reloc in MIPS64 ELF?\n");
359 goto out_free_relocs
;
361 parse_fn
= parse_mips32_rel
;
365 parse_fn
= parse_mips64_rela
;
367 fprintf(stderr
, "RELA-style reloc in MIPS32 ELF?\n");
369 goto out_free_relocs
;
373 for (j
= 0; j
< sh_entries
; j
++) {
374 err
= parse_fn(elf
+ sh_offset
+ (j
* sh_entsize
));
376 goto out_free_relocs
;
380 /* Sort relocs in ascending order of offset */
381 qsort(relocs
, relocs_idx
, sizeof(*relocs
), compare_relocs
);
383 /* Make reloc offsets relative to their predecessor */
384 for (i
= relocs_idx
- 1; i
> 0; i
--)
385 relocs
[i
].offset
-= relocs
[i
- 1].offset
;
387 /* Write the relocations to the .rel section */
388 buf
= buf_start
= elf
+ shdr_field(i_rel_shdr
, sh_offset
);
389 for (i
= 0; i
< relocs_idx
; i
++) {
390 output_uint(&buf
, relocs
[i
].type
);
391 output_uint(&buf
, relocs
[i
].offset
>> 2);
394 /* Write a terminating R_MIPS_NONE (0) */
395 output_uint(&buf
, R_MIPS_NONE
);
397 /* Ensure the relocs didn't overflow the .rel section */
398 rel_size
= shdr_field(i_rel_shdr
, sh_size
);
399 rel_actual_size
= buf
- buf_start
;
400 if (rel_actual_size
> rel_size
) {
401 fprintf(stderr
, "Relocs overflowed .rel section\n");
405 /* Update the .rel section's size */
406 set_shdr_field(i_rel_shdr
, sh_size
, rel_actual_size
);
408 /* Shrink the PT_LOAD program header filesz (ie. shrink u-boot.bin) */
409 for (i
= 0; i
< ehdr_field(e_phnum
); i
++) {
410 if (phdr_field(i
, p_type
) != PT_LOAD
)
413 load_sz
= phdr_field(i
, p_filesz
);
414 load_sz
-= rel_size
- rel_actual_size
;
415 set_phdr_field(i
, p_filesz
, load_sz
);
419 /* Make sure data is written back to the file */
420 err
= msync(elf
, st
.st_size
, MS_SYNC
);
422 fprintf(stderr
, "Failed to msync: %d\n", errno
);
423 goto out_free_relocs
;
428 munmap(elf
, st
.st_size
);