]>
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+
19 #include <asm/relocs.h>
21 #define hdr_field(pfx, idx, field) ({ \
26 _val = pfx##hdr64[idx].field; \
27 _size = sizeof(pfx##hdr64[0].field); \
29 _val = pfx##hdr32[idx].field; \
30 _size = sizeof(pfx##hdr32[0].field); \
37 _val = is_be ? be16toh(_val) : le16toh(_val); \
40 _val = is_be ? be32toh(_val) : le32toh(_val); \
43 _val = is_be ? be64toh(_val) : le64toh(_val); \
50 #define set_hdr_field(pfx, idx, field, val) ({ \
55 _size = sizeof(pfx##hdr64[0].field); \
57 _size = sizeof(pfx##hdr32[0].field); \
64 _val = is_be ? htobe16(val) : htole16(val); \
67 _val = is_be ? htobe32(val) : htole32(val); \
70 _val = is_be ? htobe64(val) : htole64(val); \
75 pfx##hdr64[idx].field = _val; \
77 pfx##hdr32[idx].field = _val; \
80 #define ehdr_field(field) \
81 hdr_field(e, 0, field)
82 #define phdr_field(idx, field) \
83 hdr_field(p, idx, field)
84 #define shdr_field(idx, field) \
85 hdr_field(s, idx, field)
87 #define set_phdr_field(idx, field, val) \
88 set_hdr_field(p, idx, field, val)
89 #define set_shdr_field(idx, field, val) \
90 set_hdr_field(s, idx, field, val)
92 #define shstr(idx) (&shstrtab[idx])
101 size_t relocs_sz
, relocs_idx
;
103 static int add_reloc(unsigned int type
, uint64_t off
)
105 struct mips_reloc
*new;
116 /* Skip these relocs */
123 if (relocs_idx
== relocs_sz
) {
124 new_sz
= relocs_sz
? relocs_sz
* 2 : 128;
125 new = realloc(relocs
, new_sz
* sizeof(*relocs
));
127 fprintf(stderr
, "Out of memory\n");
135 relocs
[relocs_idx
++] = (struct mips_reloc
){
143 static int parse_mips32_rel(const void *_rel
)
145 const Elf32_Rel
*rel
= _rel
;
148 off
= is_be
? be32toh(rel
->r_offset
) : le32toh(rel
->r_offset
);
151 type
= is_be
? be32toh(rel
->r_info
) : le32toh(rel
->r_info
);
152 type
= ELF32_R_TYPE(type
);
154 return add_reloc(type
, off
);
157 static int parse_mips64_rela(const void *_rel
)
159 const Elf64_Rela
*rel
= _rel
;
162 off
= is_be
? be64toh(rel
->r_offset
) : le64toh(rel
->r_offset
);
165 type
= rel
->r_info
>> (64 - 8);
167 return add_reloc(type
, off
);
170 static void output_uint(uint8_t **buf
, uint64_t val
)
182 static int compare_relocs(const void *a
, const void *b
)
184 const struct mips_reloc
*ra
= a
, *rb
= b
;
186 return ra
->offset
- rb
->offset
;
189 int main(int argc
, char *argv
[])
191 unsigned int i
, j
, i_rel_shdr
, sh_type
, sh_entsize
, sh_entries
;
192 size_t rel_size
, rel_actual_size
, load_sz
;
193 const char *shstrtab
, *sh_name
, *rel_pfx
;
194 int (*parse_fn
)(const void *rel
);
195 uint8_t *buf_start
, *buf
;
196 const Elf32_Ehdr
*ehdr32
;
197 const Elf64_Ehdr
*ehdr64
;
208 fd
= open(argv
[1], O_RDWR
);
210 fprintf(stderr
, "Unable to open input file %s\n", argv
[1]);
215 err
= fstat(fd
, &st
);
217 fprintf(stderr
, "Unable to fstat() input file\n");
221 elf
= mmap(NULL
, st
.st_size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
222 if (elf
== MAP_FAILED
) {
223 fprintf(stderr
, "Unable to mmap() input file\n");
231 if (memcmp(&ehdr32
->e_ident
[EI_MAG0
], ELFMAG
, SELFMAG
)) {
232 fprintf(stderr
, "Input file is not an ELF\n");
234 goto out_free_relocs
;
237 if (ehdr32
->e_ident
[EI_VERSION
] != EV_CURRENT
) {
238 fprintf(stderr
, "Unrecognised ELF version\n");
240 goto out_free_relocs
;
243 switch (ehdr32
->e_ident
[EI_CLASS
]) {
251 fprintf(stderr
, "Unrecognised ELF class\n");
253 goto out_free_relocs
;
256 switch (ehdr32
->e_ident
[EI_DATA
]) {
264 fprintf(stderr
, "Unrecognised ELF data encoding\n");
266 goto out_free_relocs
;
269 if (ehdr_field(e_type
) != ET_EXEC
) {
270 fprintf(stderr
, "Input ELF is not an executable\n");
271 printf("type 0x%lx\n", ehdr_field(e_type
));
273 goto out_free_relocs
;
276 if (ehdr_field(e_machine
) != EM_MIPS
) {
277 fprintf(stderr
, "Input ELF does not target MIPS\n");
279 goto out_free_relocs
;
282 phdr32
= elf
+ ehdr_field(e_phoff
);
283 phdr64
= elf
+ ehdr_field(e_phoff
);
284 shdr32
= elf
+ ehdr_field(e_shoff
);
285 shdr64
= elf
+ ehdr_field(e_shoff
);
286 shstrtab
= elf
+ shdr_field(ehdr_field(e_shstrndx
), sh_offset
);
288 i_rel_shdr
= UINT_MAX
;
289 for (i
= 0; i
< ehdr_field(e_shnum
); i
++) {
290 sh_name
= shstr(shdr_field(i
, sh_name
));
292 if (!strcmp(sh_name
, ".rel")) {
297 if (!strcmp(sh_name
, ".text")) {
298 text_base
= shdr_field(i
, sh_addr
);
302 if (i_rel_shdr
== UINT_MAX
) {
303 fprintf(stderr
, "Unable to find .rel section\n");
305 goto out_free_relocs
;
308 fprintf(stderr
, "Unable to find .text base address\n");
310 goto out_free_relocs
;
313 rel_pfx
= is_64
? ".rela." : ".rel.";
315 for (i
= 0; i
< ehdr_field(e_shnum
); i
++) {
316 sh_type
= shdr_field(i
, sh_type
);
317 if ((sh_type
!= SHT_REL
) && (sh_type
!= SHT_RELA
))
320 sh_name
= shstr(shdr_field(i
, sh_name
));
321 if (strncmp(sh_name
, rel_pfx
, strlen(rel_pfx
))) {
322 if (strcmp(sh_name
, ".rel") && strcmp(sh_name
, ".rel.dyn"))
323 fprintf(stderr
, "WARNING: Unexpected reloc section name '%s'\n", sh_name
);
328 * Skip reloc sections which either don't correspond to another
329 * section in the ELF, or whose corresponding section isn't
330 * loaded as part of the U-Boot binary (ie. doesn't have the
334 for (j
= 0; j
< ehdr_field(e_shnum
); j
++) {
335 if (strcmp(&sh_name
[strlen(rel_pfx
) - 1], shstr(shdr_field(j
, sh_name
))))
338 skip
= !(shdr_field(j
, sh_flags
) & SHF_ALLOC
);
344 sh_offset
= shdr_field(i
, sh_offset
);
345 sh_entsize
= shdr_field(i
, sh_entsize
);
346 sh_entries
= shdr_field(i
, sh_size
) / sh_entsize
;
348 if (sh_type
== SHT_REL
) {
350 fprintf(stderr
, "REL-style reloc in MIPS64 ELF?\n");
352 goto out_free_relocs
;
354 parse_fn
= parse_mips32_rel
;
358 parse_fn
= parse_mips64_rela
;
360 fprintf(stderr
, "RELA-style reloc in MIPS32 ELF?\n");
362 goto out_free_relocs
;
366 for (j
= 0; j
< sh_entries
; j
++) {
367 err
= parse_fn(elf
+ sh_offset
+ (j
* sh_entsize
));
369 goto out_free_relocs
;
373 /* Sort relocs in ascending order of offset */
374 qsort(relocs
, relocs_idx
, sizeof(*relocs
), compare_relocs
);
376 /* Make reloc offsets relative to their predecessor */
377 for (i
= relocs_idx
- 1; i
> 0; i
--)
378 relocs
[i
].offset
-= relocs
[i
- 1].offset
;
380 /* Write the relocations to the .rel section */
381 buf
= buf_start
= elf
+ shdr_field(i_rel_shdr
, sh_offset
);
382 for (i
= 0; i
< relocs_idx
; i
++) {
383 output_uint(&buf
, relocs
[i
].type
);
384 output_uint(&buf
, relocs
[i
].offset
>> 2);
387 /* Write a terminating R_MIPS_NONE (0) */
388 output_uint(&buf
, R_MIPS_NONE
);
390 /* Ensure the relocs didn't overflow the .rel section */
391 rel_size
= shdr_field(i_rel_shdr
, sh_size
);
392 rel_actual_size
= buf
- buf_start
;
393 if (rel_actual_size
> rel_size
) {
394 fprintf(stderr
, "Relocs overflowed .rel section\n");
398 /* Update the .rel section's size */
399 set_shdr_field(i_rel_shdr
, sh_size
, rel_actual_size
);
401 /* Shrink the PT_LOAD program header filesz (ie. shrink u-boot.bin) */
402 for (i
= 0; i
< ehdr_field(e_phnum
); i
++) {
403 if (phdr_field(i
, p_type
) != PT_LOAD
)
406 load_sz
= phdr_field(i
, p_filesz
);
407 load_sz
-= rel_size
- rel_actual_size
;
408 set_phdr_field(i
, p_filesz
, load_sz
);
412 /* Make sure data is written back to the file */
413 err
= msync(elf
, st
.st_size
, MS_SYNC
);
415 fprintf(stderr
, "Failed to msync: %d\n", errno
);
416 goto out_free_relocs
;
421 munmap(elf
, st
.st_size
);