183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2703ec9ddSPaul Burton /*
3703ec9ddSPaul Burton * MIPS Relocation Data Generator
4703ec9ddSPaul Burton *
5703ec9ddSPaul Burton * Copyright (c) 2017 Imagination Technologies Ltd.
6703ec9ddSPaul Burton */
7703ec9ddSPaul Burton
8e94136bdSPaul Burton #include <assert.h>
9703ec9ddSPaul Burton #include <elf.h>
10703ec9ddSPaul Burton #include <errno.h>
11703ec9ddSPaul Burton #include <fcntl.h>
12703ec9ddSPaul Burton #include <limits.h>
13d2bf1152SMasahiro Yamada #include <stdbool.h>
14703ec9ddSPaul Burton #include <stdio.h>
15703ec9ddSPaul Burton #include <stdlib.h>
16703ec9ddSPaul Burton #include <sys/mman.h>
17703ec9ddSPaul Burton #include <sys/stat.h>
18703ec9ddSPaul Burton #include <unistd.h>
19703ec9ddSPaul Burton
20703ec9ddSPaul Burton #include <asm/relocs.h>
21703ec9ddSPaul Burton
22703ec9ddSPaul Burton #define hdr_field(pfx, idx, field) ({ \
23703ec9ddSPaul Burton uint64_t _val; \
24703ec9ddSPaul Burton unsigned int _size; \
25703ec9ddSPaul Burton \
26703ec9ddSPaul Burton if (is_64) { \
27703ec9ddSPaul Burton _val = pfx##hdr64[idx].field; \
28703ec9ddSPaul Burton _size = sizeof(pfx##hdr64[0].field); \
29703ec9ddSPaul Burton } else { \
30703ec9ddSPaul Burton _val = pfx##hdr32[idx].field; \
31703ec9ddSPaul Burton _size = sizeof(pfx##hdr32[0].field); \
32703ec9ddSPaul Burton } \
33703ec9ddSPaul Burton \
34703ec9ddSPaul Burton switch (_size) { \
35703ec9ddSPaul Burton case 1: \
36703ec9ddSPaul Burton break; \
37703ec9ddSPaul Burton case 2: \
38703ec9ddSPaul Burton _val = is_be ? be16toh(_val) : le16toh(_val); \
39703ec9ddSPaul Burton break; \
40703ec9ddSPaul Burton case 4: \
41703ec9ddSPaul Burton _val = is_be ? be32toh(_val) : le32toh(_val); \
42703ec9ddSPaul Burton break; \
43703ec9ddSPaul Burton case 8: \
44703ec9ddSPaul Burton _val = is_be ? be64toh(_val) : le64toh(_val); \
45703ec9ddSPaul Burton break; \
46703ec9ddSPaul Burton } \
47703ec9ddSPaul Burton \
48703ec9ddSPaul Burton _val; \
49703ec9ddSPaul Burton })
50703ec9ddSPaul Burton
51703ec9ddSPaul Burton #define set_hdr_field(pfx, idx, field, val) ({ \
52703ec9ddSPaul Burton uint64_t _val; \
53703ec9ddSPaul Burton unsigned int _size; \
54703ec9ddSPaul Burton \
55703ec9ddSPaul Burton if (is_64) \
56703ec9ddSPaul Burton _size = sizeof(pfx##hdr64[0].field); \
57703ec9ddSPaul Burton else \
58703ec9ddSPaul Burton _size = sizeof(pfx##hdr32[0].field); \
59703ec9ddSPaul Burton \
60703ec9ddSPaul Burton switch (_size) { \
61703ec9ddSPaul Burton case 1: \
62703ec9ddSPaul Burton _val = val; \
63703ec9ddSPaul Burton break; \
64703ec9ddSPaul Burton case 2: \
65703ec9ddSPaul Burton _val = is_be ? htobe16(val) : htole16(val); \
66703ec9ddSPaul Burton break; \
67703ec9ddSPaul Burton case 4: \
68703ec9ddSPaul Burton _val = is_be ? htobe32(val) : htole32(val); \
69703ec9ddSPaul Burton break; \
70703ec9ddSPaul Burton case 8: \
71703ec9ddSPaul Burton _val = is_be ? htobe64(val) : htole64(val); \
72703ec9ddSPaul Burton break; \
73e94136bdSPaul Burton default: \
74e94136bdSPaul Burton /* We should never reach here */ \
75e94136bdSPaul Burton _val = 0; \
76e94136bdSPaul Burton assert(0); \
77e94136bdSPaul Burton break; \
78703ec9ddSPaul Burton } \
79703ec9ddSPaul Burton \
80703ec9ddSPaul Burton if (is_64) \
81703ec9ddSPaul Burton pfx##hdr64[idx].field = _val; \
82703ec9ddSPaul Burton else \
83703ec9ddSPaul Burton pfx##hdr32[idx].field = _val; \
84703ec9ddSPaul Burton })
85703ec9ddSPaul Burton
86703ec9ddSPaul Burton #define ehdr_field(field) \
87703ec9ddSPaul Burton hdr_field(e, 0, field)
88703ec9ddSPaul Burton #define phdr_field(idx, field) \
89703ec9ddSPaul Burton hdr_field(p, idx, field)
90703ec9ddSPaul Burton #define shdr_field(idx, field) \
91703ec9ddSPaul Burton hdr_field(s, idx, field)
92703ec9ddSPaul Burton
93703ec9ddSPaul Burton #define set_phdr_field(idx, field, val) \
94703ec9ddSPaul Burton set_hdr_field(p, idx, field, val)
95703ec9ddSPaul Burton #define set_shdr_field(idx, field, val) \
96703ec9ddSPaul Burton set_hdr_field(s, idx, field, val)
97703ec9ddSPaul Burton
98703ec9ddSPaul Burton #define shstr(idx) (&shstrtab[idx])
99703ec9ddSPaul Burton
100703ec9ddSPaul Burton bool is_64, is_be;
101703ec9ddSPaul Burton uint64_t text_base;
102703ec9ddSPaul Burton
103703ec9ddSPaul Burton struct mips_reloc {
104703ec9ddSPaul Burton uint8_t type;
105703ec9ddSPaul Burton uint64_t offset;
106703ec9ddSPaul Burton } *relocs;
107703ec9ddSPaul Burton size_t relocs_sz, relocs_idx;
108703ec9ddSPaul Burton
add_reloc(unsigned int type,uint64_t off)109703ec9ddSPaul Burton static int add_reloc(unsigned int type, uint64_t off)
110703ec9ddSPaul Burton {
111703ec9ddSPaul Burton struct mips_reloc *new;
112703ec9ddSPaul Burton size_t new_sz;
113703ec9ddSPaul Burton
114703ec9ddSPaul Burton switch (type) {
115703ec9ddSPaul Burton case R_MIPS_NONE:
116703ec9ddSPaul Burton case R_MIPS_LO16:
117703ec9ddSPaul Burton case R_MIPS_PC16:
118703ec9ddSPaul Burton case R_MIPS_HIGHER:
119703ec9ddSPaul Burton case R_MIPS_HIGHEST:
120703ec9ddSPaul Burton case R_MIPS_PC21_S2:
121703ec9ddSPaul Burton case R_MIPS_PC26_S2:
122703ec9ddSPaul Burton /* Skip these relocs */
123703ec9ddSPaul Burton return 0;
124703ec9ddSPaul Burton
125703ec9ddSPaul Burton default:
126703ec9ddSPaul Burton break;
127703ec9ddSPaul Burton }
128703ec9ddSPaul Burton
129703ec9ddSPaul Burton if (relocs_idx == relocs_sz) {
130703ec9ddSPaul Burton new_sz = relocs_sz ? relocs_sz * 2 : 128;
131703ec9ddSPaul Burton new = realloc(relocs, new_sz * sizeof(*relocs));
132703ec9ddSPaul Burton if (!new) {
133703ec9ddSPaul Burton fprintf(stderr, "Out of memory\n");
134703ec9ddSPaul Burton return -ENOMEM;
135703ec9ddSPaul Burton }
136703ec9ddSPaul Burton
137703ec9ddSPaul Burton relocs = new;
138703ec9ddSPaul Burton relocs_sz = new_sz;
139703ec9ddSPaul Burton }
140703ec9ddSPaul Burton
141703ec9ddSPaul Burton relocs[relocs_idx++] = (struct mips_reloc){
142703ec9ddSPaul Burton .type = type,
143703ec9ddSPaul Burton .offset = off,
144703ec9ddSPaul Burton };
145703ec9ddSPaul Burton
146703ec9ddSPaul Burton return 0;
147703ec9ddSPaul Burton }
148703ec9ddSPaul Burton
parse_mips32_rel(const void * _rel)149703ec9ddSPaul Burton static int parse_mips32_rel(const void *_rel)
150703ec9ddSPaul Burton {
151703ec9ddSPaul Burton const Elf32_Rel *rel = _rel;
152703ec9ddSPaul Burton uint32_t off, type;
153703ec9ddSPaul Burton
154703ec9ddSPaul Burton off = is_be ? be32toh(rel->r_offset) : le32toh(rel->r_offset);
155703ec9ddSPaul Burton off -= text_base;
156703ec9ddSPaul Burton
157703ec9ddSPaul Burton type = is_be ? be32toh(rel->r_info) : le32toh(rel->r_info);
158703ec9ddSPaul Burton type = ELF32_R_TYPE(type);
159703ec9ddSPaul Burton
160703ec9ddSPaul Burton return add_reloc(type, off);
161703ec9ddSPaul Burton }
162703ec9ddSPaul Burton
parse_mips64_rela(const void * _rel)163703ec9ddSPaul Burton static int parse_mips64_rela(const void *_rel)
164703ec9ddSPaul Burton {
165703ec9ddSPaul Burton const Elf64_Rela *rel = _rel;
166703ec9ddSPaul Burton uint64_t off, type;
167703ec9ddSPaul Burton
168703ec9ddSPaul Burton off = is_be ? be64toh(rel->r_offset) : le64toh(rel->r_offset);
169703ec9ddSPaul Burton off -= text_base;
170703ec9ddSPaul Burton
171703ec9ddSPaul Burton type = rel->r_info >> (64 - 8);
172703ec9ddSPaul Burton
173703ec9ddSPaul Burton return add_reloc(type, off);
174703ec9ddSPaul Burton }
175703ec9ddSPaul Burton
output_uint(uint8_t ** buf,uint64_t val)176703ec9ddSPaul Burton static void output_uint(uint8_t **buf, uint64_t val)
177703ec9ddSPaul Burton {
178703ec9ddSPaul Burton uint64_t tmp;
179703ec9ddSPaul Burton
180703ec9ddSPaul Burton do {
181703ec9ddSPaul Burton tmp = val & 0x7f;
182703ec9ddSPaul Burton val >>= 7;
183703ec9ddSPaul Burton tmp |= !!val << 7;
184703ec9ddSPaul Burton *(*buf)++ = tmp;
185703ec9ddSPaul Burton } while (val);
186703ec9ddSPaul Burton }
187703ec9ddSPaul Burton
compare_relocs(const void * a,const void * b)188703ec9ddSPaul Burton static int compare_relocs(const void *a, const void *b)
189703ec9ddSPaul Burton {
190703ec9ddSPaul Burton const struct mips_reloc *ra = a, *rb = b;
191703ec9ddSPaul Burton
192703ec9ddSPaul Burton return ra->offset - rb->offset;
193703ec9ddSPaul Burton }
194703ec9ddSPaul Burton
main(int argc,char * argv[])195703ec9ddSPaul Burton int main(int argc, char *argv[])
196703ec9ddSPaul Burton {
197703ec9ddSPaul Burton unsigned int i, j, i_rel_shdr, sh_type, sh_entsize, sh_entries;
198*96301464SDaniel Schwierzeck size_t rel_size, rel_actual_size;
199703ec9ddSPaul Burton const char *shstrtab, *sh_name, *rel_pfx;
200703ec9ddSPaul Burton int (*parse_fn)(const void *rel);
201703ec9ddSPaul Burton uint8_t *buf_start, *buf;
202703ec9ddSPaul Burton const Elf32_Ehdr *ehdr32;
203703ec9ddSPaul Burton const Elf64_Ehdr *ehdr64;
204703ec9ddSPaul Burton uintptr_t sh_offset;
205703ec9ddSPaul Burton Elf32_Shdr *shdr32;
206703ec9ddSPaul Burton Elf64_Shdr *shdr64;
207703ec9ddSPaul Burton struct stat st;
208703ec9ddSPaul Burton int err, fd;
209703ec9ddSPaul Burton void *elf;
210703ec9ddSPaul Burton bool skip;
211703ec9ddSPaul Burton
212703ec9ddSPaul Burton fd = open(argv[1], O_RDWR);
213703ec9ddSPaul Burton if (fd == -1) {
214703ec9ddSPaul Burton fprintf(stderr, "Unable to open input file %s\n", argv[1]);
215703ec9ddSPaul Burton err = errno;
216703ec9ddSPaul Burton goto out_ret;
217703ec9ddSPaul Burton }
218703ec9ddSPaul Burton
219703ec9ddSPaul Burton err = fstat(fd, &st);
220703ec9ddSPaul Burton if (err) {
221703ec9ddSPaul Burton fprintf(stderr, "Unable to fstat() input file\n");
222703ec9ddSPaul Burton goto out_close_fd;
223703ec9ddSPaul Burton }
224703ec9ddSPaul Burton
225703ec9ddSPaul Burton elf = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
226703ec9ddSPaul Burton if (elf == MAP_FAILED) {
227703ec9ddSPaul Burton fprintf(stderr, "Unable to mmap() input file\n");
228703ec9ddSPaul Burton err = errno;
229703ec9ddSPaul Burton goto out_close_fd;
230703ec9ddSPaul Burton }
231703ec9ddSPaul Burton
232703ec9ddSPaul Burton ehdr32 = elf;
233703ec9ddSPaul Burton ehdr64 = elf;
234703ec9ddSPaul Burton
235703ec9ddSPaul Burton if (memcmp(&ehdr32->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {
236703ec9ddSPaul Burton fprintf(stderr, "Input file is not an ELF\n");
237703ec9ddSPaul Burton err = -EINVAL;
238703ec9ddSPaul Burton goto out_free_relocs;
239703ec9ddSPaul Burton }
240703ec9ddSPaul Burton
241703ec9ddSPaul Burton if (ehdr32->e_ident[EI_VERSION] != EV_CURRENT) {
242703ec9ddSPaul Burton fprintf(stderr, "Unrecognised ELF version\n");
243703ec9ddSPaul Burton err = -EINVAL;
244703ec9ddSPaul Burton goto out_free_relocs;
245703ec9ddSPaul Burton }
246703ec9ddSPaul Burton
247703ec9ddSPaul Burton switch (ehdr32->e_ident[EI_CLASS]) {
248703ec9ddSPaul Burton case ELFCLASS32:
249703ec9ddSPaul Burton is_64 = false;
250703ec9ddSPaul Burton break;
251703ec9ddSPaul Burton case ELFCLASS64:
252703ec9ddSPaul Burton is_64 = true;
253703ec9ddSPaul Burton break;
254703ec9ddSPaul Burton default:
255703ec9ddSPaul Burton fprintf(stderr, "Unrecognised ELF class\n");
256703ec9ddSPaul Burton err = -EINVAL;
257703ec9ddSPaul Burton goto out_free_relocs;
258703ec9ddSPaul Burton }
259703ec9ddSPaul Burton
260703ec9ddSPaul Burton switch (ehdr32->e_ident[EI_DATA]) {
261703ec9ddSPaul Burton case ELFDATA2LSB:
262703ec9ddSPaul Burton is_be = false;
263703ec9ddSPaul Burton break;
264703ec9ddSPaul Burton case ELFDATA2MSB:
265703ec9ddSPaul Burton is_be = true;
266703ec9ddSPaul Burton break;
267703ec9ddSPaul Burton default:
268703ec9ddSPaul Burton fprintf(stderr, "Unrecognised ELF data encoding\n");
269703ec9ddSPaul Burton err = -EINVAL;
270703ec9ddSPaul Burton goto out_free_relocs;
271703ec9ddSPaul Burton }
272703ec9ddSPaul Burton
273703ec9ddSPaul Burton if (ehdr_field(e_type) != ET_EXEC) {
274703ec9ddSPaul Burton fprintf(stderr, "Input ELF is not an executable\n");
275703ec9ddSPaul Burton printf("type 0x%lx\n", ehdr_field(e_type));
276703ec9ddSPaul Burton err = -EINVAL;
277703ec9ddSPaul Burton goto out_free_relocs;
278703ec9ddSPaul Burton }
279703ec9ddSPaul Burton
280703ec9ddSPaul Burton if (ehdr_field(e_machine) != EM_MIPS) {
281703ec9ddSPaul Burton fprintf(stderr, "Input ELF does not target MIPS\n");
282703ec9ddSPaul Burton err = -EINVAL;
283703ec9ddSPaul Burton goto out_free_relocs;
284703ec9ddSPaul Burton }
285703ec9ddSPaul Burton
286703ec9ddSPaul Burton shdr32 = elf + ehdr_field(e_shoff);
287703ec9ddSPaul Burton shdr64 = elf + ehdr_field(e_shoff);
288703ec9ddSPaul Burton shstrtab = elf + shdr_field(ehdr_field(e_shstrndx), sh_offset);
289703ec9ddSPaul Burton
290703ec9ddSPaul Burton i_rel_shdr = UINT_MAX;
291703ec9ddSPaul Burton for (i = 0; i < ehdr_field(e_shnum); i++) {
292703ec9ddSPaul Burton sh_name = shstr(shdr_field(i, sh_name));
293703ec9ddSPaul Burton
294*96301464SDaniel Schwierzeck if (!strcmp(sh_name, ".data.reloc")) {
295703ec9ddSPaul Burton i_rel_shdr = i;
296703ec9ddSPaul Burton continue;
297703ec9ddSPaul Burton }
298703ec9ddSPaul Burton
299703ec9ddSPaul Burton if (!strcmp(sh_name, ".text")) {
300703ec9ddSPaul Burton text_base = shdr_field(i, sh_addr);
301703ec9ddSPaul Burton continue;
302703ec9ddSPaul Burton }
303703ec9ddSPaul Burton }
304703ec9ddSPaul Burton if (i_rel_shdr == UINT_MAX) {
305703ec9ddSPaul Burton fprintf(stderr, "Unable to find .rel section\n");
306703ec9ddSPaul Burton err = -EINVAL;
307703ec9ddSPaul Burton goto out_free_relocs;
308703ec9ddSPaul Burton }
309703ec9ddSPaul Burton if (!text_base) {
310703ec9ddSPaul Burton fprintf(stderr, "Unable to find .text base address\n");
311703ec9ddSPaul Burton err = -EINVAL;
312703ec9ddSPaul Burton goto out_free_relocs;
313703ec9ddSPaul Burton }
314703ec9ddSPaul Burton
315703ec9ddSPaul Burton rel_pfx = is_64 ? ".rela." : ".rel.";
316703ec9ddSPaul Burton
317703ec9ddSPaul Burton for (i = 0; i < ehdr_field(e_shnum); i++) {
318703ec9ddSPaul Burton sh_type = shdr_field(i, sh_type);
319703ec9ddSPaul Burton if ((sh_type != SHT_REL) && (sh_type != SHT_RELA))
320703ec9ddSPaul Burton continue;
321703ec9ddSPaul Burton
322703ec9ddSPaul Burton sh_name = shstr(shdr_field(i, sh_name));
323703ec9ddSPaul Burton if (strncmp(sh_name, rel_pfx, strlen(rel_pfx))) {
324703ec9ddSPaul Burton if (strcmp(sh_name, ".rel") && strcmp(sh_name, ".rel.dyn"))
325703ec9ddSPaul Burton fprintf(stderr, "WARNING: Unexpected reloc section name '%s'\n", sh_name);
326703ec9ddSPaul Burton continue;
327703ec9ddSPaul Burton }
328703ec9ddSPaul Burton
329703ec9ddSPaul Burton /*
330703ec9ddSPaul Burton * Skip reloc sections which either don't correspond to another
331703ec9ddSPaul Burton * section in the ELF, or whose corresponding section isn't
332703ec9ddSPaul Burton * loaded as part of the U-Boot binary (ie. doesn't have the
333703ec9ddSPaul Burton * alloc flags set).
334703ec9ddSPaul Burton */
335703ec9ddSPaul Burton skip = true;
336703ec9ddSPaul Burton for (j = 0; j < ehdr_field(e_shnum); j++) {
337703ec9ddSPaul Burton if (strcmp(&sh_name[strlen(rel_pfx) - 1], shstr(shdr_field(j, sh_name))))
338703ec9ddSPaul Burton continue;
339703ec9ddSPaul Burton
340703ec9ddSPaul Burton skip = !(shdr_field(j, sh_flags) & SHF_ALLOC);
341703ec9ddSPaul Burton break;
342703ec9ddSPaul Burton }
343703ec9ddSPaul Burton if (skip)
344703ec9ddSPaul Burton continue;
345703ec9ddSPaul Burton
346703ec9ddSPaul Burton sh_offset = shdr_field(i, sh_offset);
347703ec9ddSPaul Burton sh_entsize = shdr_field(i, sh_entsize);
348703ec9ddSPaul Burton sh_entries = shdr_field(i, sh_size) / sh_entsize;
349703ec9ddSPaul Burton
350703ec9ddSPaul Burton if (sh_type == SHT_REL) {
351703ec9ddSPaul Burton if (is_64) {
352703ec9ddSPaul Burton fprintf(stderr, "REL-style reloc in MIPS64 ELF?\n");
353703ec9ddSPaul Burton err = -EINVAL;
354703ec9ddSPaul Burton goto out_free_relocs;
355703ec9ddSPaul Burton } else {
356703ec9ddSPaul Burton parse_fn = parse_mips32_rel;
357703ec9ddSPaul Burton }
358703ec9ddSPaul Burton } else {
359703ec9ddSPaul Burton if (is_64) {
360703ec9ddSPaul Burton parse_fn = parse_mips64_rela;
361703ec9ddSPaul Burton } else {
362703ec9ddSPaul Burton fprintf(stderr, "RELA-style reloc in MIPS32 ELF?\n");
363703ec9ddSPaul Burton err = -EINVAL;
364703ec9ddSPaul Burton goto out_free_relocs;
365703ec9ddSPaul Burton }
366703ec9ddSPaul Burton }
367703ec9ddSPaul Burton
368703ec9ddSPaul Burton for (j = 0; j < sh_entries; j++) {
369703ec9ddSPaul Burton err = parse_fn(elf + sh_offset + (j * sh_entsize));
370703ec9ddSPaul Burton if (err)
371703ec9ddSPaul Burton goto out_free_relocs;
372703ec9ddSPaul Burton }
373703ec9ddSPaul Burton }
374703ec9ddSPaul Burton
375703ec9ddSPaul Burton /* Sort relocs in ascending order of offset */
376703ec9ddSPaul Burton qsort(relocs, relocs_idx, sizeof(*relocs), compare_relocs);
377703ec9ddSPaul Burton
378703ec9ddSPaul Burton /* Make reloc offsets relative to their predecessor */
379703ec9ddSPaul Burton for (i = relocs_idx - 1; i > 0; i--)
380703ec9ddSPaul Burton relocs[i].offset -= relocs[i - 1].offset;
381703ec9ddSPaul Burton
382703ec9ddSPaul Burton /* Write the relocations to the .rel section */
383703ec9ddSPaul Burton buf = buf_start = elf + shdr_field(i_rel_shdr, sh_offset);
384703ec9ddSPaul Burton for (i = 0; i < relocs_idx; i++) {
385703ec9ddSPaul Burton output_uint(&buf, relocs[i].type);
386703ec9ddSPaul Burton output_uint(&buf, relocs[i].offset >> 2);
387703ec9ddSPaul Burton }
388703ec9ddSPaul Burton
389703ec9ddSPaul Burton /* Write a terminating R_MIPS_NONE (0) */
390703ec9ddSPaul Burton output_uint(&buf, R_MIPS_NONE);
391703ec9ddSPaul Burton
392703ec9ddSPaul Burton /* Ensure the relocs didn't overflow the .rel section */
393703ec9ddSPaul Burton rel_size = shdr_field(i_rel_shdr, sh_size);
394703ec9ddSPaul Burton rel_actual_size = buf - buf_start;
395703ec9ddSPaul Burton if (rel_actual_size > rel_size) {
396*96301464SDaniel Schwierzeck fprintf(stderr, "Relocations overflow available space of 0x%lx (required 0x%lx)!\n",
397*96301464SDaniel Schwierzeck rel_size, rel_actual_size);
398*96301464SDaniel Schwierzeck fprintf(stderr, "Please adjust CONFIG_MIPS_RELOCATION_TABLE_SIZE to at least 0x%lx\n",
399*96301464SDaniel Schwierzeck (rel_actual_size + 0x100) & ~0xFF);
400*96301464SDaniel Schwierzeck err = -ENOMEM;
401*96301464SDaniel Schwierzeck goto out_free_relocs;
402703ec9ddSPaul Burton }
403703ec9ddSPaul Burton
404703ec9ddSPaul Burton /* Make sure data is written back to the file */
405703ec9ddSPaul Burton err = msync(elf, st.st_size, MS_SYNC);
406703ec9ddSPaul Burton if (err) {
407703ec9ddSPaul Burton fprintf(stderr, "Failed to msync: %d\n", errno);
408703ec9ddSPaul Burton goto out_free_relocs;
409703ec9ddSPaul Burton }
410703ec9ddSPaul Burton
411703ec9ddSPaul Burton out_free_relocs:
412703ec9ddSPaul Burton free(relocs);
413703ec9ddSPaul Burton munmap(elf, st.st_size);
414703ec9ddSPaul Burton out_close_fd:
415703ec9ddSPaul Burton close(fd);
416703ec9ddSPaul Burton out_ret:
417703ec9ddSPaul Burton return err;
418703ec9ddSPaul Burton }
419