elf32-pru.c revision 1.1.1.5 1 1.1 christos /* 32-bit ELF support for TI PRU.
2 1.1.1.5 christos Copyright (C) 2014-2024 Free Software Foundation, Inc.
3 1.1 christos Contributed by Dimitar Dimitrov <dimitar (at) dinux.eu>
4 1.1 christos Based on elf32-nios2.c
5 1.1 christos
6 1.1 christos This file is part of BFD, the Binary File Descriptor library.
7 1.1 christos
8 1.1 christos This program is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3 of the License, or
11 1.1 christos (at your option) any later version.
12 1.1 christos
13 1.1 christos This program is distributed in the hope that it will be useful,
14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 1.1 christos GNU General Public License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this program; if not, write to the Free Software
20 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 1.1 christos MA 02110-1301, USA. */
22 1.1 christos
23 1.1 christos /* This file handles TI PRU ELF targets. */
24 1.1 christos
25 1.1 christos #include "sysdep.h"
26 1.1 christos #include "bfd.h"
27 1.1 christos #include "libbfd.h"
28 1.1 christos #include "bfdlink.h"
29 1.1 christos #include "genlink.h"
30 1.1 christos #include "elf-bfd.h"
31 1.1 christos #include "elf/pru.h"
32 1.1 christos #include "opcode/pru.h"
33 1.1.1.2 christos #include "libiberty.h"
34 1.1 christos
35 1.1.1.3 christos /* All users of this file have bfd_octets_per_byte (abfd, sec) == 1. */
36 1.1.1.3 christos #define OCTETS_PER_BYTE(ABFD, SEC) 1
37 1.1.1.3 christos
38 1.1 christos #define SWAP_VALS(A,B) \
39 1.1 christos do { \
40 1.1 christos (A) ^= (B); \
41 1.1 christos (B) ^= (A); \
42 1.1 christos (A) ^= (B); \
43 1.1 christos } while (0)
44 1.1 christos
45 1.1 christos /* Enable debugging printout at stdout with this variable. */
46 1.1.1.4 christos static bool debug_relax = false;
47 1.1 christos
48 1.1 christos /* Forward declarations. */
49 1.1 christos static bfd_reloc_status_type pru_elf32_pmem_relocate
50 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
51 1.1 christos static bfd_reloc_status_type pru_elf32_s10_pcrel_relocate
52 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
53 1.1 christos static bfd_reloc_status_type pru_elf32_u8_pcrel_relocate
54 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
55 1.1 christos static bfd_reloc_status_type pru_elf32_ldi32_relocate
56 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
57 1.1 christos static bfd_reloc_status_type bfd_elf_pru_diff_relocate
58 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
59 1.1 christos
60 1.1 christos /* Target vector. */
61 1.1 christos extern const bfd_target pru_elf32_vec;
62 1.1 christos
63 1.1 christos /* The relocation table used for SHT_REL sections. */
64 1.1 christos static reloc_howto_type elf_pru_howto_table_rel[] = {
65 1.1 christos /* No relocation. */
66 1.1 christos HOWTO (R_PRU_NONE, /* type */
67 1.1 christos 0, /* rightshift */
68 1.1.1.4 christos 0, /* size */
69 1.1.1.4 christos 0, /* bitsize */
70 1.1.1.4 christos false, /* pc_relative */
71 1.1 christos 0, /* bitpos */
72 1.1 christos complain_overflow_dont,/* complain_on_overflow */
73 1.1 christos bfd_elf_generic_reloc, /* special_function */
74 1.1 christos "R_PRU_NONE", /* name */
75 1.1.1.4 christos false, /* partial_inplace */
76 1.1 christos 0, /* src_mask */
77 1.1 christos 0, /* dst_mask */
78 1.1.1.4 christos false), /* pcrel_offset */
79 1.1 christos
80 1.1 christos HOWTO (R_PRU_16_PMEM,
81 1.1 christos 2,
82 1.1.1.4 christos 2, /* short */
83 1.1 christos 32,
84 1.1.1.4 christos false,
85 1.1 christos 0,
86 1.1 christos complain_overflow_dont,
87 1.1 christos bfd_elf_generic_reloc,
88 1.1 christos "R_PRU_16_PMEM",
89 1.1.1.4 christos false,
90 1.1 christos 0, /* src_mask */
91 1.1 christos 0xffff,
92 1.1.1.4 christos false),
93 1.1 christos
94 1.1 christos HOWTO (R_PRU_U16_PMEMIMM,
95 1.1 christos 2,
96 1.1.1.4 christos 4,
97 1.1 christos 32,
98 1.1.1.4 christos false,
99 1.1 christos 8,
100 1.1 christos complain_overflow_unsigned,
101 1.1 christos pru_elf32_pmem_relocate,
102 1.1 christos "R_PRU_U16_PMEMIMM",
103 1.1.1.4 christos false,
104 1.1 christos 0, /* src_mask */
105 1.1 christos 0x00ffff00,
106 1.1.1.4 christos false),
107 1.1 christos
108 1.1 christos HOWTO (R_PRU_BFD_RELOC_16,
109 1.1 christos 0,
110 1.1.1.4 christos 2, /* short */
111 1.1 christos 16,
112 1.1.1.4 christos false,
113 1.1 christos 0,
114 1.1 christos complain_overflow_bitfield,
115 1.1 christos bfd_elf_generic_reloc,
116 1.1 christos "R_PRU_BFD_RELOC16",
117 1.1.1.4 christos false,
118 1.1 christos 0, /* src_mask */
119 1.1 christos 0x0000ffff,
120 1.1.1.4 christos false),
121 1.1 christos
122 1.1 christos /* 16-bit unsigned immediate relocation. */
123 1.1 christos HOWTO (R_PRU_U16, /* type */
124 1.1 christos 0, /* rightshift */
125 1.1.1.4 christos 4, /* size */
126 1.1 christos 16, /* bitsize */
127 1.1.1.4 christos false, /* pc_relative */
128 1.1 christos 8, /* bitpos */
129 1.1 christos complain_overflow_unsigned, /* complain on overflow */
130 1.1 christos bfd_elf_generic_reloc, /* special function */
131 1.1 christos "R_PRU_U16", /* name */
132 1.1.1.4 christos false, /* partial_inplace */
133 1.1 christos 0, /* src_mask */
134 1.1 christos 0x00ffff00, /* dest_mask */
135 1.1.1.4 christos false), /* pcrel_offset */
136 1.1 christos
137 1.1 christos HOWTO (R_PRU_32_PMEM,
138 1.1 christos 2,
139 1.1.1.4 christos 4, /* long */
140 1.1 christos 32,
141 1.1.1.4 christos false,
142 1.1 christos 0,
143 1.1 christos complain_overflow_dont,
144 1.1 christos pru_elf32_pmem_relocate,
145 1.1 christos "R_PRU_32_PMEM",
146 1.1.1.4 christos false,
147 1.1 christos 0, /* src_mask */
148 1.1 christos 0xffffffff,
149 1.1.1.4 christos false),
150 1.1 christos
151 1.1 christos HOWTO (R_PRU_BFD_RELOC_32,
152 1.1 christos 0,
153 1.1.1.4 christos 4, /* long */
154 1.1 christos 32,
155 1.1.1.4 christos false,
156 1.1 christos 0,
157 1.1 christos complain_overflow_dont,
158 1.1 christos bfd_elf_generic_reloc,
159 1.1 christos "R_PRU_BFD_RELOC32",
160 1.1.1.4 christos false,
161 1.1 christos 0, /* src_mask */
162 1.1 christos 0xffffffff,
163 1.1.1.4 christos false),
164 1.1 christos
165 1.1 christos HOWTO (R_PRU_S10_PCREL,
166 1.1 christos 2,
167 1.1.1.4 christos 4,
168 1.1 christos 10,
169 1.1.1.4 christos true,
170 1.1 christos 0,
171 1.1 christos complain_overflow_bitfield,
172 1.1 christos pru_elf32_s10_pcrel_relocate,
173 1.1 christos "R_PRU_S10_PCREL",
174 1.1.1.4 christos false,
175 1.1 christos 0, /* src_mask */
176 1.1 christos 0x060000ff,
177 1.1.1.4 christos true),
178 1.1 christos
179 1.1 christos HOWTO (R_PRU_U8_PCREL,
180 1.1 christos 2,
181 1.1.1.4 christos 4,
182 1.1 christos 8,
183 1.1.1.4 christos true,
184 1.1 christos 0,
185 1.1 christos complain_overflow_unsigned,
186 1.1 christos pru_elf32_u8_pcrel_relocate,
187 1.1 christos "R_PRU_U8_PCREL",
188 1.1.1.4 christos false,
189 1.1 christos 0, /* src_mask */
190 1.1 christos 0x000000ff,
191 1.1.1.4 christos true),
192 1.1 christos
193 1.1 christos HOWTO (R_PRU_LDI32,
194 1.1 christos 0, /* rightshift */
195 1.1.1.4 christos 8, /* size */
196 1.1 christos 32, /* bitsize */
197 1.1.1.4 christos false, /* pc_relative */
198 1.1 christos 0, /* bitpos */
199 1.1 christos complain_overflow_unsigned, /* complain on overflow */
200 1.1 christos pru_elf32_ldi32_relocate, /* special function */
201 1.1 christos "R_PRU_LDI32", /* name */
202 1.1.1.4 christos false, /* partial_inplace */
203 1.1 christos 0, /* src_mask */
204 1.1 christos 0xffffffff, /* dest_mask */
205 1.1.1.4 christos false), /* pcrel_offset */
206 1.1 christos
207 1.1 christos /* GNU-specific relocations. */
208 1.1 christos HOWTO (R_PRU_GNU_BFD_RELOC_8,
209 1.1 christos 0,
210 1.1.1.4 christos 1, /* byte */
211 1.1 christos 8,
212 1.1.1.4 christos false,
213 1.1 christos 0,
214 1.1 christos complain_overflow_bitfield,
215 1.1 christos bfd_elf_generic_reloc,
216 1.1 christos "R_PRU_BFD_RELOC8",
217 1.1.1.4 christos false,
218 1.1 christos 0, /* src_mask */
219 1.1 christos 0x000000ff,
220 1.1.1.4 christos false),
221 1.1 christos
222 1.1 christos HOWTO (R_PRU_GNU_DIFF8, /* type */
223 1.1 christos 0, /* rightshift */
224 1.1.1.4 christos 1, /* size */
225 1.1.1.2 christos 8, /* bitsize */
226 1.1.1.4 christos false, /* pc_relative */
227 1.1 christos 0, /* bitpos */
228 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
229 1.1 christos bfd_elf_pru_diff_relocate, /* special_function */
230 1.1.1.2 christos "R_PRU_DIFF8", /* name */
231 1.1.1.4 christos false, /* partial_inplace */
232 1.1 christos 0, /* src_mask */
233 1.1 christos 0xff, /* dst_mask */
234 1.1.1.4 christos false), /* pcrel_offset */
235 1.1 christos
236 1.1.1.2 christos HOWTO (R_PRU_GNU_DIFF16, /* type */
237 1.1 christos 0, /* rightshift */
238 1.1.1.4 christos 2, /* size */
239 1.1 christos 16, /* bitsize */
240 1.1.1.4 christos false, /* pc_relative */
241 1.1 christos 0, /* bitpos */
242 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
243 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */
244 1.1.1.2 christos "R_PRU_DIFF16", /* name */
245 1.1.1.4 christos false, /* partial_inplace */
246 1.1 christos 0, /* src_mask */
247 1.1 christos 0xffff, /* dst_mask */
248 1.1.1.4 christos false), /* pcrel_offset */
249 1.1 christos
250 1.1.1.2 christos HOWTO (R_PRU_GNU_DIFF32, /* type */
251 1.1 christos 0, /* rightshift */
252 1.1.1.4 christos 4, /* size */
253 1.1 christos 32, /* bitsize */
254 1.1.1.4 christos false, /* pc_relative */
255 1.1 christos 0, /* bitpos */
256 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
257 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */
258 1.1.1.2 christos "R_PRU_DIFF32", /* name */
259 1.1.1.4 christos false, /* partial_inplace */
260 1.1 christos 0, /* src_mask */
261 1.1.1.2 christos 0xffffffff, /* dst_mask */
262 1.1.1.4 christos false), /* pcrel_offset */
263 1.1 christos
264 1.1 christos HOWTO (R_PRU_GNU_DIFF16_PMEM, /* type */
265 1.1 christos 0, /* rightshift */
266 1.1.1.4 christos 2, /* size */
267 1.1 christos 16, /* bitsize */
268 1.1.1.4 christos false, /* pc_relative */
269 1.1 christos 0, /* bitpos */
270 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
271 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */
272 1.1.1.2 christos "R_PRU_DIFF16_PMEM", /* name */
273 1.1.1.4 christos false, /* partial_inplace */
274 1.1 christos 0, /* src_mask */
275 1.1 christos 0xffff, /* dst_mask */
276 1.1.1.4 christos false), /* pcrel_offset */
277 1.1 christos
278 1.1 christos HOWTO (R_PRU_GNU_DIFF32_PMEM, /* type */
279 1.1 christos 0, /* rightshift */
280 1.1.1.4 christos 4, /* size */
281 1.1 christos 32, /* bitsize */
282 1.1.1.4 christos false, /* pc_relative */
283 1.1 christos 0, /* bitpos */
284 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
285 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */
286 1.1.1.2 christos "R_PRU_DIFF32_PMEM", /* name */
287 1.1.1.4 christos false, /* partial_inplace */
288 1.1 christos 0, /* src_mask */
289 1.1 christos 0xffffffff, /* dst_mask */
290 1.1.1.4 christos false), /* pcrel_offset */
291 1.1 christos
292 1.1 christos /* Add other relocations here. */
293 1.1 christos };
294 1.1 christos
295 1.1 christos static unsigned char elf_code_to_howto_index[R_PRU_ILLEGAL + 1];
296 1.1 christos
297 1.1 christos /* Return the howto for relocation RTYPE. */
298 1.1.1.2 christos
299 1.1 christos static reloc_howto_type *
300 1.1 christos lookup_howto (unsigned int rtype)
301 1.1 christos {
302 1.1.1.4 christos static bool initialized = false;
303 1.1 christos int i;
304 1.1 christos int howto_tbl_size = (int) (sizeof (elf_pru_howto_table_rel)
305 1.1 christos / sizeof (elf_pru_howto_table_rel[0]));
306 1.1 christos
307 1.1.1.2 christos if (! initialized)
308 1.1 christos {
309 1.1.1.4 christos initialized = true;
310 1.1 christos memset (elf_code_to_howto_index, 0xff,
311 1.1 christos sizeof (elf_code_to_howto_index));
312 1.1 christos for (i = 0; i < howto_tbl_size; i++)
313 1.1 christos elf_code_to_howto_index[elf_pru_howto_table_rel[i].type] = i;
314 1.1 christos }
315 1.1 christos
316 1.1.1.2 christos if (rtype > R_PRU_ILLEGAL)
317 1.1.1.2 christos return NULL;
318 1.1 christos i = elf_code_to_howto_index[rtype];
319 1.1 christos if (i >= howto_tbl_size)
320 1.1.1.2 christos return NULL;
321 1.1 christos return elf_pru_howto_table_rel + i;
322 1.1 christos }
323 1.1 christos
324 1.1 christos /* Map for converting BFD reloc types to PRU reloc types. */
325 1.1.1.2 christos
326 1.1 christos struct elf_reloc_map
327 1.1 christos {
328 1.1 christos bfd_reloc_code_real_type bfd_val;
329 1.1 christos enum elf_pru_reloc_type elf_val;
330 1.1 christos };
331 1.1 christos
332 1.1.1.2 christos static const struct elf_reloc_map pru_reloc_map[] =
333 1.1.1.2 christos {
334 1.1 christos {BFD_RELOC_NONE, R_PRU_NONE},
335 1.1 christos {BFD_RELOC_PRU_16_PMEM, R_PRU_16_PMEM},
336 1.1 christos {BFD_RELOC_PRU_U16_PMEMIMM, R_PRU_U16_PMEMIMM},
337 1.1 christos {BFD_RELOC_16, R_PRU_BFD_RELOC_16},
338 1.1 christos {BFD_RELOC_PRU_U16, R_PRU_U16},
339 1.1 christos {BFD_RELOC_PRU_32_PMEM, R_PRU_32_PMEM},
340 1.1 christos {BFD_RELOC_32, R_PRU_BFD_RELOC_32},
341 1.1 christos {BFD_RELOC_PRU_S10_PCREL, R_PRU_S10_PCREL},
342 1.1 christos {BFD_RELOC_PRU_U8_PCREL, R_PRU_U8_PCREL},
343 1.1 christos {BFD_RELOC_PRU_LDI32, R_PRU_LDI32},
344 1.1 christos
345 1.1 christos {BFD_RELOC_8, R_PRU_GNU_BFD_RELOC_8},
346 1.1 christos {BFD_RELOC_PRU_GNU_DIFF8, R_PRU_GNU_DIFF8},
347 1.1 christos {BFD_RELOC_PRU_GNU_DIFF16, R_PRU_GNU_DIFF16},
348 1.1 christos {BFD_RELOC_PRU_GNU_DIFF32, R_PRU_GNU_DIFF32},
349 1.1 christos {BFD_RELOC_PRU_GNU_DIFF16_PMEM, R_PRU_GNU_DIFF16_PMEM},
350 1.1 christos {BFD_RELOC_PRU_GNU_DIFF32_PMEM, R_PRU_GNU_DIFF32_PMEM},
351 1.1 christos };
352 1.1 christos
353 1.1 christos
354 1.1 christos /* Assorted hash table functions. */
355 1.1 christos
356 1.1 christos /* Create an entry in a PRU ELF linker hash table. */
357 1.1.1.2 christos
358 1.1 christos static struct bfd_hash_entry *
359 1.1 christos link_hash_newfunc (struct bfd_hash_entry *entry,
360 1.1 christos struct bfd_hash_table *table, const char *string)
361 1.1 christos {
362 1.1 christos /* Allocate the structure if it has not already been allocated by a
363 1.1 christos subclass. */
364 1.1 christos if (entry == NULL)
365 1.1 christos {
366 1.1 christos entry = bfd_hash_allocate (table,
367 1.1 christos sizeof (struct elf_link_hash_entry));
368 1.1 christos if (entry == NULL)
369 1.1 christos return entry;
370 1.1 christos }
371 1.1 christos
372 1.1 christos /* Call the allocation method of the superclass. */
373 1.1 christos entry = _bfd_elf_link_hash_newfunc (entry, table, string);
374 1.1 christos
375 1.1 christos return entry;
376 1.1 christos }
377 1.1 christos
378 1.1 christos /* Implement bfd_elf32_bfd_reloc_type_lookup:
379 1.1 christos Given a BFD reloc type, return a howto structure. */
380 1.1.1.2 christos
381 1.1 christos static reloc_howto_type *
382 1.1 christos pru_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
383 1.1 christos bfd_reloc_code_real_type code)
384 1.1 christos {
385 1.1.1.2 christos unsigned int i;
386 1.1.1.2 christos
387 1.1.1.2 christos for (i = 0; i < ARRAY_SIZE (pru_reloc_map); ++i)
388 1.1 christos if (pru_reloc_map[i].bfd_val == code)
389 1.1 christos return lookup_howto ((unsigned int) pru_reloc_map[i].elf_val);
390 1.1 christos return NULL;
391 1.1 christos }
392 1.1 christos
393 1.1 christos /* Implement bfd_elf32_bfd_reloc_name_lookup:
394 1.1 christos Given a reloc name, return a howto structure. */
395 1.1.1.2 christos
396 1.1 christos static reloc_howto_type *
397 1.1 christos pru_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
398 1.1 christos const char *r_name)
399 1.1 christos {
400 1.1 christos unsigned int i;
401 1.1.1.2 christos
402 1.1.1.2 christos for (i = 0; i < ARRAY_SIZE (elf_pru_howto_table_rel); i++)
403 1.1 christos if (elf_pru_howto_table_rel[i].name
404 1.1 christos && strcasecmp (elf_pru_howto_table_rel[i].name, r_name) == 0)
405 1.1 christos return &elf_pru_howto_table_rel[i];
406 1.1 christos
407 1.1 christos return NULL;
408 1.1 christos }
409 1.1 christos
410 1.1 christos /* Implement elf_info_to_howto:
411 1.1 christos Given a ELF32 relocation, fill in a arelent structure. */
412 1.1.1.2 christos
413 1.1.1.4 christos static bool
414 1.1.1.2 christos pru_elf32_info_to_howto (bfd *abfd, arelent *cache_ptr,
415 1.1 christos Elf_Internal_Rela *dst)
416 1.1 christos {
417 1.1 christos unsigned int r_type;
418 1.1 christos
419 1.1 christos r_type = ELF32_R_TYPE (dst->r_info);
420 1.1.1.2 christos if (r_type >= R_PRU_ILLEGAL)
421 1.1.1.2 christos {
422 1.1.1.2 christos /* xgettext:c-format */
423 1.1.1.2 christos _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, r_type);
424 1.1.1.2 christos bfd_set_error (bfd_error_bad_value);
425 1.1.1.4 christos return false;
426 1.1.1.2 christos }
427 1.1.1.3 christos
428 1.1 christos cache_ptr->howto = lookup_howto (r_type);
429 1.1.1.2 christos return cache_ptr->howto != NULL;
430 1.1 christos }
431 1.1 christos
432 1.1 christos /* Do the relocations that require special handling. */
433 1.1 christos /* Produce a word address for program memory. Linker scripts will put .text
434 1.1 christos at a high offset in order to differentiate it from .data. So here we also
435 1.1 christos mask the high bits of PMEM address.
436 1.1 christos
437 1.1 christos But why 1MB when internal Program Memory much smaller? We want to catch
438 1.1 christos unintended overflows.
439 1.1 christos
440 1.1 christos Why not use (1<<31) as an offset and a mask? Sitara DDRAM usually resides
441 1.1 christos there, and users might want to put some shared carveout memory region in
442 1.1 christos their linker scripts. So 0x80000000 might be a valid .data address.
443 1.1 christos
444 1.1 christos Note that we still keep and pass down the original howto. This way we
445 1.1 christos can reuse this function for several different relocations. */
446 1.1 christos static bfd_reloc_status_type
447 1.1 christos pru_elf32_do_pmem_relocate (bfd *abfd, reloc_howto_type *howto,
448 1.1 christos asection *input_section,
449 1.1 christos bfd_byte *data, bfd_vma offset,
450 1.1 christos bfd_vma symbol_value, bfd_vma addend)
451 1.1 christos {
452 1.1 christos symbol_value = symbol_value + addend;
453 1.1 christos addend = 0;
454 1.1 christos symbol_value &= 0x3fffff;
455 1.1 christos return _bfd_final_link_relocate (howto, abfd, input_section,
456 1.1 christos data, offset, symbol_value, addend);
457 1.1 christos }
458 1.1 christos
459 1.1 christos /* Direct copy of _bfd_final_link_relocate, but with special
460 1.1 christos "fill-in". This copy-paste mumbo jumbo is only needed because BFD
461 1.1 christos cannot deal correctly with non-contiguous bit fields. */
462 1.1 christos static bfd_reloc_status_type
463 1.1 christos pru_elf32_do_s10_pcrel_relocate (bfd *input_bfd, reloc_howto_type *howto,
464 1.1 christos asection *input_section,
465 1.1 christos bfd_byte *contents, bfd_vma address,
466 1.1 christos bfd_vma relocation, bfd_vma addend)
467 1.1 christos {
468 1.1 christos bfd_byte *location;
469 1.1 christos bfd_vma x = 0;
470 1.1 christos bfd_vma qboff;
471 1.1 christos bfd_reloc_status_type flag = bfd_reloc_ok;
472 1.1 christos
473 1.1 christos /* Sanity check the address. */
474 1.1 christos if (address > bfd_get_section_limit (input_bfd, input_section))
475 1.1 christos return bfd_reloc_outofrange;
476 1.1 christos
477 1.1 christos BFD_ASSERT (howto->pc_relative);
478 1.1 christos BFD_ASSERT (howto->pcrel_offset);
479 1.1 christos
480 1.1 christos relocation = relocation + addend - (input_section->output_section->vma
481 1.1 christos + input_section->output_offset) - address;
482 1.1 christos
483 1.1 christos location = contents + address;
484 1.1 christos
485 1.1 christos /* Get the value we are going to relocate. */
486 1.1 christos BFD_ASSERT (bfd_get_reloc_size (howto) == 4);
487 1.1 christos x = bfd_get_32 (input_bfd, location);
488 1.1 christos
489 1.1 christos qboff = GET_BROFF_SIGNED (x) << howto->rightshift;
490 1.1 christos relocation += qboff;
491 1.1 christos
492 1.1 christos BFD_ASSERT (howto->complain_on_overflow == complain_overflow_bitfield);
493 1.1 christos
494 1.1 christos if (relocation > 2047 && relocation < (bfd_vma)-2048l)
495 1.1 christos flag = bfd_reloc_overflow;
496 1.1 christos
497 1.1 christos /* Check that target address is word-aligned. */
498 1.1 christos if (relocation & ((1 << howto->rightshift) - 1))
499 1.1 christos flag = bfd_reloc_outofrange;
500 1.1 christos
501 1.1 christos relocation >>= (bfd_vma) howto->rightshift;
502 1.1 christos
503 1.1 christos /* Fill-in the RELOCATION to the right bits of X. */
504 1.1 christos SET_BROFF_URAW (x, relocation);
505 1.1 christos
506 1.1 christos bfd_put_32 (input_bfd, x, location);
507 1.1 christos
508 1.1 christos return flag;
509 1.1 christos }
510 1.1 christos
511 1.1 christos static bfd_reloc_status_type
512 1.1 christos pru_elf32_do_u8_pcrel_relocate (bfd *abfd, reloc_howto_type *howto,
513 1.1 christos asection *input_section,
514 1.1 christos bfd_byte *data, bfd_vma offset,
515 1.1 christos bfd_vma symbol_value, bfd_vma addend)
516 1.1 christos {
517 1.1 christos bfd_vma relocation;
518 1.1 christos
519 1.1 christos BFD_ASSERT (howto->pc_relative);
520 1.1 christos BFD_ASSERT (howto->pcrel_offset);
521 1.1 christos
522 1.1 christos relocation = symbol_value + addend - (input_section->output_section->vma
523 1.1 christos + input_section->output_offset) - offset;
524 1.1 christos relocation >>= howto->rightshift;
525 1.1 christos
526 1.1 christos /* 0 and 1 are invalid target labels for LOOP. We cannot
527 1.1 christos encode this info in HOWTO, so catch such cases here. */
528 1.1 christos if (relocation < 2)
529 1.1 christos return bfd_reloc_outofrange;
530 1.1 christos
531 1.1 christos return _bfd_final_link_relocate (howto, abfd, input_section,
532 1.1 christos data, offset, symbol_value, addend);
533 1.1 christos }
534 1.1 christos
535 1.1 christos /* Idea and code taken from elf32-d30v. */
536 1.1 christos static bfd_reloc_status_type
537 1.1 christos pru_elf32_do_ldi32_relocate (bfd *abfd, reloc_howto_type *howto,
538 1.1 christos asection *input_section,
539 1.1 christos bfd_byte *data, bfd_vma offset,
540 1.1 christos bfd_vma symbol_value, bfd_vma addend)
541 1.1 christos {
542 1.1.1.3 christos bfd_vma relocation;
543 1.1.1.3 christos bfd_size_type octets = offset * OCTETS_PER_BYTE (abfd, input_section);
544 1.1 christos bfd_byte *location;
545 1.1.1.2 christos unsigned long in1, in2;
546 1.1 christos
547 1.1 christos /* A hacked-up version of _bfd_final_link_relocate() follows. */
548 1.1 christos
549 1.1 christos /* Sanity check the address. */
550 1.1 christos if (octets + bfd_get_reloc_size (howto)
551 1.1 christos > bfd_get_section_limit_octets (abfd, input_section))
552 1.1 christos return bfd_reloc_outofrange;
553 1.1 christos
554 1.1 christos /* This function assumes that we are dealing with a basic relocation
555 1.1 christos against a symbol. We want to compute the value of the symbol to
556 1.1 christos relocate to. This is just VALUE, the value of the symbol, plus
557 1.1 christos ADDEND, any addend associated with the reloc. */
558 1.1 christos relocation = symbol_value + addend;
559 1.1 christos
560 1.1 christos BFD_ASSERT (!howto->pc_relative);
561 1.1 christos
562 1.1 christos /* A hacked-up version of _bfd_relocate_contents() follows. */
563 1.1.1.3 christos location = data + octets;
564 1.1 christos
565 1.1 christos BFD_ASSERT (!howto->pc_relative);
566 1.1 christos
567 1.1 christos in1 = bfd_get_32 (abfd, location);
568 1.1 christos in2 = bfd_get_32 (abfd, location + 4);
569 1.1 christos
570 1.1.1.2 christos SET_INSN_FIELD (IMM16, in1, relocation >> 16);
571 1.1.1.2 christos SET_INSN_FIELD (IMM16, in2, relocation & 0xffff);
572 1.1 christos
573 1.1 christos bfd_put_32 (abfd, in1, location);
574 1.1 christos bfd_put_32 (abfd, in2, location + 4);
575 1.1 christos
576 1.1.1.2 christos /* Old GAS and LD versions have a bug, where the two
577 1.1.1.2 christos LDI instructions are swapped. Detect such object
578 1.1.1.2 christos files and bail. */
579 1.1.1.2 christos if (GET_INSN_FIELD (RDSEL, in1) != RSEL_31_16)
580 1.1.1.2 christos {
581 1.1.1.2 christos /* xgettext:c-format */
582 1.1.1.2 christos _bfd_error_handler (_("error: %pB: old incompatible object file detected"),
583 1.1.1.2 christos abfd);
584 1.1.1.2 christos return bfd_reloc_notsupported;
585 1.1.1.2 christos }
586 1.1.1.2 christos
587 1.1 christos return bfd_reloc_ok;
588 1.1 christos }
589 1.1 christos
590 1.1 christos /* HOWTO handlers for relocations that require special handling. */
591 1.1 christos
592 1.1 christos static bfd_reloc_status_type
593 1.1 christos pru_elf32_pmem_relocate (bfd *abfd, arelent *reloc_entry,
594 1.1 christos asymbol *symbol, void *data,
595 1.1 christos asection *input_section, bfd *output_bfd,
596 1.1 christos char **error_message)
597 1.1 christos {
598 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just
599 1.1 christos call the generic function. Any adjustment will be done at final
600 1.1 christos link time. */
601 1.1 christos if (output_bfd != NULL)
602 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
603 1.1 christos input_section, output_bfd, error_message);
604 1.1 christos
605 1.1.1.2 christos BFD_ASSERT (0);
606 1.1 christos return pru_elf32_do_pmem_relocate (abfd, reloc_entry->howto,
607 1.1 christos input_section,
608 1.1 christos data, reloc_entry->address,
609 1.1 christos (symbol->value
610 1.1 christos + symbol->section->output_section->vma
611 1.1 christos + symbol->section->output_offset),
612 1.1 christos reloc_entry->addend);
613 1.1 christos }
614 1.1 christos
615 1.1 christos static bfd_reloc_status_type
616 1.1 christos pru_elf32_s10_pcrel_relocate (bfd *abfd, arelent *reloc_entry,
617 1.1 christos asymbol *symbol, void *data,
618 1.1 christos asection *input_section, bfd *output_bfd,
619 1.1 christos char **error_message)
620 1.1 christos {
621 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just
622 1.1 christos call the generic function. Any adjustment will be done at final
623 1.1 christos link time. */
624 1.1 christos if (output_bfd != NULL)
625 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
626 1.1 christos input_section, output_bfd, error_message);
627 1.1 christos
628 1.1 christos return pru_elf32_do_s10_pcrel_relocate (abfd, reloc_entry->howto,
629 1.1 christos input_section, data,
630 1.1 christos reloc_entry->address,
631 1.1 christos (symbol->value
632 1.1 christos + symbol->section->output_section->vma
633 1.1 christos + symbol->section->output_offset),
634 1.1 christos reloc_entry->addend);
635 1.1 christos }
636 1.1 christos
637 1.1 christos static bfd_reloc_status_type
638 1.1 christos pru_elf32_u8_pcrel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
639 1.1 christos void *data, asection *input_section,
640 1.1 christos bfd *output_bfd,
641 1.1 christos char **error_message)
642 1.1 christos {
643 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just
644 1.1 christos call the generic function. Any adjustment will be done at final
645 1.1 christos link time. */
646 1.1 christos if (output_bfd != NULL)
647 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
648 1.1 christos input_section, output_bfd, error_message);
649 1.1 christos
650 1.1 christos return pru_elf32_do_u8_pcrel_relocate (abfd, reloc_entry->howto,
651 1.1 christos input_section,
652 1.1 christos data, reloc_entry->address,
653 1.1 christos (symbol->value
654 1.1 christos + symbol->section->output_section->vma
655 1.1 christos + symbol->section->output_offset),
656 1.1 christos reloc_entry->addend);
657 1.1 christos }
658 1.1 christos
659 1.1 christos static bfd_reloc_status_type
660 1.1 christos pru_elf32_ldi32_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
661 1.1 christos void *data, asection *input_section,
662 1.1 christos bfd *output_bfd,
663 1.1 christos char **error_message)
664 1.1 christos {
665 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just
666 1.1 christos call the generic function. Any adjustment will be done at final
667 1.1 christos link time. */
668 1.1 christos if (output_bfd != NULL)
669 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
670 1.1 christos input_section, output_bfd, error_message);
671 1.1 christos
672 1.1 christos return pru_elf32_do_ldi32_relocate (abfd, reloc_entry->howto,
673 1.1 christos input_section,
674 1.1 christos data, reloc_entry->address,
675 1.1 christos (symbol->value
676 1.1 christos + symbol->section->output_section->vma
677 1.1 christos + symbol->section->output_offset),
678 1.1 christos reloc_entry->addend);
679 1.1 christos }
680 1.1 christos
681 1.1 christos
682 1.1 christos /* Implement elf_backend_relocate_section. */
683 1.1.1.4 christos static int
684 1.1 christos pru_elf32_relocate_section (bfd *output_bfd,
685 1.1 christos struct bfd_link_info *info,
686 1.1 christos bfd *input_bfd,
687 1.1 christos asection *input_section,
688 1.1 christos bfd_byte *contents,
689 1.1 christos Elf_Internal_Rela *relocs,
690 1.1 christos Elf_Internal_Sym *local_syms,
691 1.1 christos asection **local_sections)
692 1.1 christos {
693 1.1.1.2 christos struct bfd_elf_section_data * esd = elf_section_data (input_section);
694 1.1 christos Elf_Internal_Shdr *symtab_hdr;
695 1.1 christos struct elf_link_hash_entry **sym_hashes;
696 1.1 christos Elf_Internal_Rela *rel;
697 1.1 christos Elf_Internal_Rela *relend;
698 1.1.1.4 christos bool is_rel_reloc;
699 1.1 christos
700 1.1 christos symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
701 1.1 christos sym_hashes = elf_sym_hashes (input_bfd);
702 1.1 christos relend = relocs + input_section->reloc_count;
703 1.1 christos
704 1.1.1.2 christos /* See if we have a REL type relocation. */
705 1.1.1.2 christos is_rel_reloc = (esd->rel.hdr != NULL);
706 1.1.1.2 christos /* Sanity check - only one type of relocation per section.
707 1.1.1.2 christos FIXME: Theoretically it is possible to have both types,
708 1.1.1.2 christos but if that happens how can we distinguish between the two ? */
709 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc || ! esd->rela.hdr);
710 1.1.1.2 christos
711 1.1 christos for (rel = relocs; rel < relend; rel++)
712 1.1 christos {
713 1.1 christos reloc_howto_type *howto;
714 1.1 christos unsigned long r_symndx;
715 1.1 christos Elf_Internal_Sym *sym;
716 1.1 christos asection *sec;
717 1.1 christos struct elf_link_hash_entry *h;
718 1.1 christos bfd_vma relocation;
719 1.1 christos bfd_reloc_status_type r = bfd_reloc_ok;
720 1.1 christos const char *name = NULL;
721 1.1 christos const char* msg = (const char*) NULL;
722 1.1.1.4 christos bool unresolved_reloc;
723 1.1.1.2 christos bfd_vma addend;
724 1.1.1.2 christos
725 1.1.1.2 christos /* If we are using a REL relocation then the addend should be empty. */
726 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc || rel->r_addend == 0);
727 1.1 christos
728 1.1 christos r_symndx = ELF32_R_SYM (rel->r_info);
729 1.1 christos
730 1.1 christos howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info));
731 1.1 christos h = NULL;
732 1.1 christos sym = NULL;
733 1.1 christos sec = NULL;
734 1.1 christos
735 1.1 christos if (r_symndx < symtab_hdr->sh_info)
736 1.1 christos {
737 1.1 christos sym = local_syms + r_symndx;
738 1.1 christos sec = local_sections[r_symndx];
739 1.1 christos relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
740 1.1 christos }
741 1.1 christos else
742 1.1 christos {
743 1.1.1.4 christos bool warned, ignored;
744 1.1 christos
745 1.1 christos RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
746 1.1 christos r_symndx, symtab_hdr, sym_hashes,
747 1.1 christos h, sec, relocation,
748 1.1 christos unresolved_reloc, warned, ignored);
749 1.1 christos }
750 1.1 christos
751 1.1 christos if (sec && discarded_section (sec))
752 1.1 christos RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
753 1.1 christos rel, 1, relend, howto, 0, contents);
754 1.1 christos
755 1.1 christos /* Nothing more to do unless this is a final link. */
756 1.1 christos if (bfd_link_relocatable (info))
757 1.1 christos continue;
758 1.1 christos
759 1.1 christos if (howto)
760 1.1 christos {
761 1.1 christos switch (howto->type)
762 1.1 christos {
763 1.1 christos case R_PRU_NONE:
764 1.1 christos /* We don't need to find a value for this symbol. It's just a
765 1.1 christos marker. */
766 1.1 christos r = bfd_reloc_ok;
767 1.1 christos break;
768 1.1 christos
769 1.1.1.2 christos case R_PRU_U16:
770 1.1.1.2 christos if (is_rel_reloc)
771 1.1.1.2 christos {
772 1.1.1.2 christos unsigned long insn;
773 1.1.1.2 christos insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
774 1.1.1.2 christos addend = GET_INSN_FIELD (IMM16, insn);
775 1.1.1.2 christos }
776 1.1.1.2 christos else
777 1.1.1.2 christos addend = rel->r_addend;
778 1.1.1.2 christos r = _bfd_final_link_relocate (howto, input_bfd,
779 1.1.1.2 christos input_section, contents,
780 1.1.1.2 christos rel->r_offset, relocation,
781 1.1.1.2 christos addend);
782 1.1.1.2 christos break;
783 1.1.1.2 christos
784 1.1 christos case R_PRU_U16_PMEMIMM:
785 1.1 christos case R_PRU_32_PMEM:
786 1.1 christos case R_PRU_16_PMEM:
787 1.1.1.2 christos if (is_rel_reloc && howto->type == R_PRU_U16_PMEMIMM)
788 1.1.1.2 christos {
789 1.1.1.2 christos unsigned long insn;
790 1.1.1.2 christos insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
791 1.1.1.2 christos addend = GET_INSN_FIELD (IMM16, insn) << 2;
792 1.1.1.2 christos }
793 1.1.1.2 christos else if (is_rel_reloc && howto->type == R_PRU_32_PMEM)
794 1.1.1.2 christos {
795 1.1.1.2 christos addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
796 1.1.1.2 christos addend <<= 2;
797 1.1.1.2 christos }
798 1.1.1.2 christos else if (is_rel_reloc && howto->type == R_PRU_16_PMEM)
799 1.1.1.2 christos {
800 1.1.1.2 christos addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
801 1.1.1.2 christos addend <<= 2;
802 1.1.1.2 christos }
803 1.1.1.2 christos else
804 1.1.1.2 christos {
805 1.1.1.2 christos BFD_ASSERT (!is_rel_reloc);
806 1.1.1.2 christos addend = rel->r_addend;
807 1.1.1.2 christos }
808 1.1 christos r = pru_elf32_do_pmem_relocate (input_bfd, howto,
809 1.1 christos input_section,
810 1.1 christos contents, rel->r_offset,
811 1.1.1.2 christos relocation, addend);
812 1.1 christos break;
813 1.1 christos case R_PRU_S10_PCREL:
814 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc);
815 1.1 christos r = pru_elf32_do_s10_pcrel_relocate (input_bfd, howto,
816 1.1 christos input_section,
817 1.1 christos contents,
818 1.1 christos rel->r_offset,
819 1.1 christos relocation,
820 1.1 christos rel->r_addend);
821 1.1 christos break;
822 1.1 christos case R_PRU_U8_PCREL:
823 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc);
824 1.1 christos r = pru_elf32_do_u8_pcrel_relocate (input_bfd, howto,
825 1.1 christos input_section,
826 1.1 christos contents,
827 1.1 christos rel->r_offset,
828 1.1 christos relocation,
829 1.1 christos rel->r_addend);
830 1.1 christos break;
831 1.1 christos case R_PRU_LDI32:
832 1.1.1.2 christos if (is_rel_reloc)
833 1.1.1.2 christos {
834 1.1.1.2 christos unsigned long in1, in2;
835 1.1.1.2 christos in1 = bfd_get_32 (input_bfd, contents + rel->r_offset);
836 1.1.1.2 christos in2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
837 1.1.1.2 christos addend = (GET_INSN_FIELD (IMM16, in1) << 16)
838 1.1.1.2 christos | GET_INSN_FIELD (IMM16, in2);
839 1.1.1.2 christos }
840 1.1.1.2 christos else
841 1.1.1.2 christos {
842 1.1.1.2 christos addend = rel->r_addend;
843 1.1.1.2 christos }
844 1.1 christos r = pru_elf32_do_ldi32_relocate (input_bfd, howto,
845 1.1 christos input_section,
846 1.1 christos contents,
847 1.1 christos rel->r_offset,
848 1.1 christos relocation,
849 1.1.1.2 christos addend);
850 1.1 christos break;
851 1.1 christos case R_PRU_GNU_DIFF8:
852 1.1 christos case R_PRU_GNU_DIFF16:
853 1.1 christos case R_PRU_GNU_DIFF32:
854 1.1 christos case R_PRU_GNU_DIFF16_PMEM:
855 1.1 christos case R_PRU_GNU_DIFF32_PMEM:
856 1.1.1.2 christos /* GNU extensions support only rela. */
857 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc);
858 1.1 christos /* Nothing to do here, as contents already contain the
859 1.1 christos diff value. */
860 1.1 christos r = bfd_reloc_ok;
861 1.1 christos break;
862 1.1 christos
863 1.1.1.2 christos case R_PRU_BFD_RELOC_16:
864 1.1.1.2 christos if (is_rel_reloc)
865 1.1.1.2 christos addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
866 1.1.1.2 christos else
867 1.1.1.2 christos addend = rel->r_addend;
868 1.1.1.2 christos r = _bfd_final_link_relocate (howto, input_bfd,
869 1.1.1.2 christos input_section, contents,
870 1.1.1.2 christos rel->r_offset, relocation,
871 1.1.1.2 christos addend);
872 1.1.1.2 christos break;
873 1.1.1.2 christos
874 1.1.1.2 christos case R_PRU_BFD_RELOC_32:
875 1.1.1.2 christos if (is_rel_reloc)
876 1.1.1.2 christos addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
877 1.1.1.2 christos else
878 1.1.1.2 christos addend = rel->r_addend;
879 1.1.1.2 christos r = _bfd_final_link_relocate (howto, input_bfd,
880 1.1.1.2 christos input_section, contents,
881 1.1.1.2 christos rel->r_offset, relocation,
882 1.1.1.2 christos addend);
883 1.1.1.2 christos break;
884 1.1.1.2 christos
885 1.1.1.2 christos case R_PRU_GNU_BFD_RELOC_8:
886 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc);
887 1.1 christos r = _bfd_final_link_relocate (howto, input_bfd,
888 1.1 christos input_section, contents,
889 1.1 christos rel->r_offset, relocation,
890 1.1 christos rel->r_addend);
891 1.1 christos break;
892 1.1.1.2 christos
893 1.1.1.2 christos default:
894 1.1.1.2 christos BFD_ASSERT (0);
895 1.1.1.2 christos break;
896 1.1 christos }
897 1.1 christos }
898 1.1 christos else
899 1.1 christos r = bfd_reloc_notsupported;
900 1.1 christos
901 1.1 christos if (r != bfd_reloc_ok)
902 1.1 christos {
903 1.1 christos if (h != NULL)
904 1.1 christos name = h->root.root.string;
905 1.1 christos else
906 1.1 christos {
907 1.1 christos name = bfd_elf_string_from_elf_section (input_bfd,
908 1.1 christos symtab_hdr->sh_link,
909 1.1 christos sym->st_name);
910 1.1 christos if (name == NULL || *name == '\0')
911 1.1.1.3 christos name = bfd_section_name (sec);
912 1.1 christos }
913 1.1 christos
914 1.1 christos switch (r)
915 1.1 christos {
916 1.1 christos case bfd_reloc_overflow:
917 1.1 christos (*info->callbacks->reloc_overflow) (info, NULL, name,
918 1.1 christos howto->name, (bfd_vma) 0,
919 1.1 christos input_bfd, input_section,
920 1.1 christos rel->r_offset);
921 1.1 christos break;
922 1.1 christos
923 1.1 christos case bfd_reloc_undefined:
924 1.1 christos (*info->callbacks->undefined_symbol) (info, name, input_bfd,
925 1.1 christos input_section,
926 1.1.1.4 christos rel->r_offset, true);
927 1.1 christos break;
928 1.1 christos
929 1.1 christos case bfd_reloc_outofrange:
930 1.1 christos if (msg == NULL)
931 1.1 christos msg = _("relocation out of range");
932 1.1 christos break;
933 1.1 christos
934 1.1 christos case bfd_reloc_notsupported:
935 1.1 christos if (msg == NULL)
936 1.1 christos msg = _("unsupported relocation");
937 1.1 christos break;
938 1.1 christos
939 1.1 christos case bfd_reloc_dangerous:
940 1.1 christos if (msg == NULL)
941 1.1 christos msg = _("dangerous relocation");
942 1.1 christos break;
943 1.1 christos
944 1.1 christos default:
945 1.1 christos if (msg == NULL)
946 1.1 christos msg = _("unknown error");
947 1.1 christos break;
948 1.1 christos }
949 1.1 christos
950 1.1 christos if (msg)
951 1.1 christos {
952 1.1 christos (*info->callbacks->warning) (info, msg, name, input_bfd,
953 1.1 christos input_section, rel->r_offset);
954 1.1.1.4 christos return false;
955 1.1 christos }
956 1.1 christos }
957 1.1 christos }
958 1.1.1.4 christos return true;
959 1.1 christos }
960 1.1 christos
961 1.1 christos
962 1.1 christos /* Perform a diff relocation. Nothing to do, as the difference value is
964 1.1 christos already written into the section's contents. */
965 1.1 christos
966 1.1 christos static bfd_reloc_status_type
967 1.1 christos bfd_elf_pru_diff_relocate (bfd *abfd ATTRIBUTE_UNUSED,
968 1.1 christos arelent *reloc_entry ATTRIBUTE_UNUSED,
969 1.1 christos asymbol *symbol ATTRIBUTE_UNUSED,
970 1.1 christos void *data ATTRIBUTE_UNUSED,
971 1.1 christos asection *input_section ATTRIBUTE_UNUSED,
972 1.1 christos bfd *output_bfd ATTRIBUTE_UNUSED,
973 1.1 christos char **error_message ATTRIBUTE_UNUSED)
974 1.1 christos {
975 1.1 christos return bfd_reloc_ok;
976 1.1 christos }
977 1.1 christos
978 1.1 christos
979 1.1 christos /* Returns whether the relocation type passed is a diff reloc. */
980 1.1.1.4 christos
981 1.1 christos static bool
982 1.1 christos elf32_pru_is_diff_reloc (Elf_Internal_Rela *irel)
983 1.1 christos {
984 1.1 christos return (ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF8
985 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16
986 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32
987 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16_PMEM
988 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32_PMEM);
989 1.1 christos }
990 1.1 christos
991 1.1 christos /* Reduce the diff value written in the section by count if the shrinked
992 1.1 christos insn address happens to fall between the two symbols for which this
993 1.1 christos diff reloc was emitted. */
994 1.1 christos
995 1.1 christos static void
996 1.1 christos elf32_pru_adjust_diff_reloc_value (bfd *abfd,
997 1.1 christos struct bfd_section *isec,
998 1.1 christos Elf_Internal_Rela *irel,
999 1.1 christos bfd_vma symval,
1000 1.1 christos bfd_vma shrinked_insn_address,
1001 1.1 christos int count)
1002 1.1 christos {
1003 1.1 christos unsigned char *reloc_contents = NULL;
1004 1.1 christos unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
1005 1.1 christos if (isec_contents == NULL)
1006 1.1 christos {
1007 1.1 christos if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
1008 1.1 christos return;
1009 1.1 christos
1010 1.1 christos elf_section_data (isec)->this_hdr.contents = isec_contents;
1011 1.1 christos }
1012 1.1 christos
1013 1.1 christos reloc_contents = isec_contents + irel->r_offset;
1014 1.1 christos
1015 1.1 christos /* Read value written in object file. */
1016 1.1 christos bfd_signed_vma x = 0;
1017 1.1 christos switch (ELF32_R_TYPE (irel->r_info))
1018 1.1 christos {
1019 1.1 christos case R_PRU_GNU_DIFF8:
1020 1.1 christos {
1021 1.1 christos x = bfd_get_signed_8 (abfd, reloc_contents);
1022 1.1 christos break;
1023 1.1 christos }
1024 1.1 christos case R_PRU_GNU_DIFF16:
1025 1.1 christos {
1026 1.1 christos x = bfd_get_signed_16 (abfd, reloc_contents);
1027 1.1 christos break;
1028 1.1 christos }
1029 1.1 christos case R_PRU_GNU_DIFF32:
1030 1.1 christos {
1031 1.1 christos x = bfd_get_signed_32 (abfd, reloc_contents);
1032 1.1 christos break;
1033 1.1 christos }
1034 1.1 christos case R_PRU_GNU_DIFF16_PMEM:
1035 1.1 christos {
1036 1.1 christos x = bfd_get_signed_16 (abfd, reloc_contents) * 4;
1037 1.1 christos break;
1038 1.1 christos }
1039 1.1 christos case R_PRU_GNU_DIFF32_PMEM:
1040 1.1 christos {
1041 1.1 christos x = bfd_get_signed_32 (abfd, reloc_contents) * 4;
1042 1.1 christos break;
1043 1.1 christos }
1044 1.1 christos default:
1045 1.1 christos {
1046 1.1 christos BFD_FAIL ();
1047 1.1 christos }
1048 1.1 christos }
1049 1.1 christos
1050 1.1 christos /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
1051 1.1 christos into the object file at the reloc offset. sym2's logical value is
1052 1.1 christos symval (<start_of_section>) + reloc addend. Compute the start and end
1053 1.1 christos addresses and check if the shrinked insn falls between sym1 and sym2. */
1054 1.1 christos
1055 1.1 christos bfd_vma end_address = symval + irel->r_addend;
1056 1.1 christos bfd_vma start_address = end_address - x;
1057 1.1 christos
1058 1.1 christos /* Shrink the absolute DIFF value (get the to labels "closer"
1059 1.1 christos together), because we have removed data between labels. */
1060 1.1 christos if (x < 0)
1061 1.1 christos {
1062 1.1 christos x += count;
1063 1.1 christos /* In case the signed x is negative, restore order. */
1064 1.1 christos SWAP_VALS (end_address, start_address);
1065 1.1 christos }
1066 1.1 christos else
1067 1.1 christos {
1068 1.1 christos x -= count;
1069 1.1 christos }
1070 1.1 christos
1071 1.1 christos /* Reduce the diff value by count bytes and write it back into section
1072 1.1 christos contents. */
1073 1.1 christos
1074 1.1 christos if (shrinked_insn_address >= start_address
1075 1.1 christos && shrinked_insn_address <= end_address)
1076 1.1 christos {
1077 1.1 christos switch (ELF32_R_TYPE (irel->r_info))
1078 1.1 christos {
1079 1.1 christos case R_PRU_GNU_DIFF8:
1080 1.1 christos {
1081 1.1 christos bfd_put_signed_8 (abfd, x & 0xFF, reloc_contents);
1082 1.1 christos break;
1083 1.1 christos }
1084 1.1 christos case R_PRU_GNU_DIFF16:
1085 1.1 christos {
1086 1.1 christos bfd_put_signed_16 (abfd, x & 0xFFFF, reloc_contents);
1087 1.1 christos break;
1088 1.1 christos }
1089 1.1 christos case R_PRU_GNU_DIFF32:
1090 1.1 christos {
1091 1.1 christos bfd_put_signed_32 (abfd, x & 0xFFFFFFFF, reloc_contents);
1092 1.1 christos break;
1093 1.1 christos }
1094 1.1 christos case R_PRU_GNU_DIFF16_PMEM:
1095 1.1 christos {
1096 1.1 christos bfd_put_signed_16 (abfd, (x / 4) & 0xFFFF, reloc_contents);
1097 1.1 christos break;
1098 1.1 christos }
1099 1.1 christos case R_PRU_GNU_DIFF32_PMEM:
1100 1.1 christos {
1101 1.1 christos bfd_put_signed_32 (abfd, (x / 4) & 0xFFFFFFFF, reloc_contents);
1102 1.1 christos break;
1103 1.1 christos }
1104 1.1 christos default:
1105 1.1 christos {
1106 1.1 christos BFD_FAIL ();
1107 1.1 christos }
1108 1.1 christos }
1109 1.1 christos
1110 1.1 christos }
1111 1.1 christos }
1112 1.1 christos
1113 1.1 christos /* Delete some bytes from a section while changing the size of an instruction.
1114 1.1 christos The parameter "addr" denotes the section-relative offset pointing just
1115 1.1 christos behind the shrinked instruction. "addr+count" point at the first
1116 1.1 christos byte just behind the original unshrinked instruction.
1117 1.1 christos
1118 1.1 christos Idea copied from the AVR port. */
1119 1.1.1.4 christos
1120 1.1 christos static bool
1121 1.1 christos pru_elf_relax_delete_bytes (bfd *abfd,
1122 1.1 christos asection *sec,
1123 1.1 christos bfd_vma addr,
1124 1.1 christos int count)
1125 1.1 christos {
1126 1.1 christos Elf_Internal_Shdr *symtab_hdr;
1127 1.1 christos unsigned int sec_shndx;
1128 1.1 christos bfd_byte *contents;
1129 1.1 christos Elf_Internal_Rela *irel, *irelend;
1130 1.1 christos Elf_Internal_Sym *isym;
1131 1.1 christos Elf_Internal_Sym *isymbuf = NULL;
1132 1.1 christos bfd_vma toaddr;
1133 1.1 christos struct elf_link_hash_entry **sym_hashes;
1134 1.1 christos struct elf_link_hash_entry **end_hashes;
1135 1.1 christos unsigned int symcount;
1136 1.1 christos
1137 1.1 christos symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1138 1.1 christos sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
1139 1.1 christos contents = elf_section_data (sec)->this_hdr.contents;
1140 1.1 christos
1141 1.1 christos toaddr = sec->size;
1142 1.1 christos
1143 1.1 christos irel = elf_section_data (sec)->relocs;
1144 1.1 christos irelend = irel + sec->reloc_count;
1145 1.1 christos
1146 1.1 christos /* Actually delete the bytes. */
1147 1.1 christos if (toaddr - addr - count > 0)
1148 1.1 christos memmove (contents + addr, contents + addr + count,
1149 1.1 christos (size_t) (toaddr - addr - count));
1150 1.1 christos sec->size -= count;
1151 1.1 christos
1152 1.1 christos /* Adjust all the reloc addresses. */
1153 1.1 christos for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
1154 1.1 christos {
1155 1.1 christos bfd_vma old_reloc_address;
1156 1.1 christos
1157 1.1 christos old_reloc_address = (sec->output_section->vma
1158 1.1 christos + sec->output_offset + irel->r_offset);
1159 1.1 christos
1160 1.1 christos /* Get the new reloc address. */
1161 1.1 christos if ((irel->r_offset > addr
1162 1.1 christos && irel->r_offset < toaddr))
1163 1.1 christos {
1164 1.1 christos if (debug_relax)
1165 1.1 christos printf ("Relocation at address 0x%x needs to be moved.\n"
1166 1.1 christos "Old section offset: 0x%x, New section offset: 0x%x \n",
1167 1.1 christos (unsigned int) old_reloc_address,
1168 1.1 christos (unsigned int) irel->r_offset,
1169 1.1 christos (unsigned int) ((irel->r_offset) - count));
1170 1.1 christos
1171 1.1 christos irel->r_offset -= count;
1172 1.1 christos }
1173 1.1 christos
1174 1.1 christos }
1175 1.1 christos
1176 1.1 christos /* The reloc's own addresses are now ok. However, we need to readjust
1177 1.1 christos the reloc's addend, i.e. the reloc's value if two conditions are met:
1178 1.1 christos 1.) the reloc is relative to a symbol in this section that
1179 1.1 christos is located in front of the shrinked instruction
1180 1.1 christos 2.) symbol plus addend end up behind the shrinked instruction.
1181 1.1 christos
1182 1.1 christos The most common case where this happens are relocs relative to
1183 1.1 christos the section-start symbol.
1184 1.1 christos
1185 1.1 christos This step needs to be done for all of the sections of the bfd. */
1186 1.1 christos
1187 1.1 christos {
1188 1.1 christos struct bfd_section *isec;
1189 1.1 christos
1190 1.1 christos for (isec = abfd->sections; isec; isec = isec->next)
1191 1.1 christos {
1192 1.1 christos bfd_vma symval;
1193 1.1 christos bfd_vma shrinked_insn_address;
1194 1.1 christos
1195 1.1 christos if (isec->reloc_count == 0)
1196 1.1 christos continue;
1197 1.1 christos
1198 1.1.1.2 christos shrinked_insn_address = (sec->output_section->vma
1199 1.1 christos + sec->output_offset + addr);
1200 1.1 christos
1201 1.1 christos irel = elf_section_data (isec)->relocs;
1202 1.1 christos /* PR 12161: Read in the relocs for this section if necessary. */
1203 1.1.1.4 christos if (irel == NULL)
1204 1.1 christos irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, true);
1205 1.1 christos
1206 1.1 christos for (irelend = irel + isec->reloc_count;
1207 1.1 christos irel < irelend;
1208 1.1 christos irel++)
1209 1.1 christos {
1210 1.1 christos /* Read this BFD's local symbols if we haven't done
1211 1.1 christos so already. */
1212 1.1 christos if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1213 1.1 christos {
1214 1.1 christos isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1215 1.1 christos if (isymbuf == NULL)
1216 1.1 christos isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1217 1.1 christos symtab_hdr->sh_info, 0,
1218 1.1 christos NULL, NULL, NULL);
1219 1.1.1.4 christos if (isymbuf == NULL)
1220 1.1 christos return false;
1221 1.1 christos }
1222 1.1 christos
1223 1.1 christos /* Get the value of the symbol referred to by the reloc. */
1224 1.1 christos if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1225 1.1 christos {
1226 1.1 christos /* A local symbol. */
1227 1.1 christos asection *sym_sec;
1228 1.1 christos
1229 1.1 christos isym = isymbuf + ELF32_R_SYM (irel->r_info);
1230 1.1 christos sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1231 1.1 christos symval = isym->st_value;
1232 1.1 christos /* If the reloc is absolute, it will not have
1233 1.1 christos a symbol or section associated with it. */
1234 1.1 christos if (sym_sec == sec)
1235 1.1 christos {
1236 1.1 christos symval += sym_sec->output_section->vma
1237 1.1 christos + sym_sec->output_offset;
1238 1.1 christos
1239 1.1 christos if (debug_relax)
1240 1.1 christos printf ("Checking if the relocation's "
1241 1.1 christos "addend needs corrections.\n"
1242 1.1 christos "Address of anchor symbol: 0x%x \n"
1243 1.1 christos "Address of relocation target: 0x%x \n"
1244 1.1 christos "Address of relaxed insn: 0x%x \n",
1245 1.1 christos (unsigned int) symval,
1246 1.1 christos (unsigned int) (symval + irel->r_addend),
1247 1.1 christos (unsigned int) shrinked_insn_address);
1248 1.1 christos
1249 1.1 christos /* Shrink the special DIFF relocations. */
1250 1.1 christos if (elf32_pru_is_diff_reloc (irel))
1251 1.1 christos {
1252 1.1 christos elf32_pru_adjust_diff_reloc_value (abfd, isec, irel,
1253 1.1 christos symval,
1254 1.1 christos shrinked_insn_address,
1255 1.1 christos count);
1256 1.1 christos }
1257 1.1 christos
1258 1.1 christos /* Fix the addend, if it is affected. */
1259 1.1 christos if (symval <= shrinked_insn_address
1260 1.1 christos && (symval + irel->r_addend) > shrinked_insn_address)
1261 1.1 christos {
1262 1.1 christos
1263 1.1 christos irel->r_addend -= count;
1264 1.1 christos
1265 1.1 christos if (debug_relax)
1266 1.1 christos printf ("Relocation's addend needed to be fixed \n");
1267 1.1 christos }
1268 1.1 christos }
1269 1.1 christos /* else...Reference symbol is absolute.
1270 1.1 christos No adjustment needed. */
1271 1.1 christos }
1272 1.1 christos /* else...Reference symbol is extern. No need for adjusting
1273 1.1 christos the addend. */
1274 1.1 christos }
1275 1.1 christos }
1276 1.1 christos }
1277 1.1 christos
1278 1.1 christos /* Adjust the local symbols defined in this section. */
1279 1.1 christos isym = (Elf_Internal_Sym *) symtab_hdr->contents;
1280 1.1 christos /* Fix PR 9841, there may be no local symbols. */
1281 1.1 christos if (isym != NULL)
1282 1.1 christos {
1283 1.1 christos Elf_Internal_Sym *isymend;
1284 1.1 christos
1285 1.1 christos isymend = isym + symtab_hdr->sh_info;
1286 1.1 christos for (; isym < isymend; isym++)
1287 1.1 christos {
1288 1.1 christos if (isym->st_shndx == sec_shndx)
1289 1.1 christos {
1290 1.1 christos if (isym->st_value > addr
1291 1.1 christos && isym->st_value <= toaddr)
1292 1.1 christos isym->st_value -= count;
1293 1.1 christos
1294 1.1 christos if (isym->st_value <= addr
1295 1.1 christos && isym->st_value + isym->st_size > addr)
1296 1.1 christos {
1297 1.1 christos /* If this assert fires then we have a symbol that ends
1298 1.1 christos part way through an instruction. Does that make
1299 1.1 christos sense? */
1300 1.1 christos BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
1301 1.1 christos isym->st_size -= count;
1302 1.1 christos }
1303 1.1 christos }
1304 1.1 christos }
1305 1.1 christos }
1306 1.1 christos
1307 1.1 christos /* Now adjust the global symbols defined in this section. */
1308 1.1 christos symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
1309 1.1 christos - symtab_hdr->sh_info);
1310 1.1 christos sym_hashes = elf_sym_hashes (abfd);
1311 1.1 christos end_hashes = sym_hashes + symcount;
1312 1.1 christos for (; sym_hashes < end_hashes; sym_hashes++)
1313 1.1 christos {
1314 1.1 christos struct elf_link_hash_entry *sym_hash = *sym_hashes;
1315 1.1 christos if ((sym_hash->root.type == bfd_link_hash_defined
1316 1.1 christos || sym_hash->root.type == bfd_link_hash_defweak)
1317 1.1 christos && sym_hash->root.u.def.section == sec)
1318 1.1 christos {
1319 1.1 christos if (sym_hash->root.u.def.value > addr
1320 1.1 christos && sym_hash->root.u.def.value <= toaddr)
1321 1.1 christos sym_hash->root.u.def.value -= count;
1322 1.1 christos
1323 1.1 christos if (sym_hash->root.u.def.value <= addr
1324 1.1 christos && (sym_hash->root.u.def.value + sym_hash->size > addr))
1325 1.1 christos {
1326 1.1 christos /* If this assert fires then we have a symbol that ends
1327 1.1 christos part way through an instruction. Does that make
1328 1.1 christos sense? */
1329 1.1 christos BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size
1330 1.1 christos >= addr + count);
1331 1.1 christos sym_hash->size -= count;
1332 1.1 christos }
1333 1.1 christos }
1334 1.1 christos }
1335 1.1.1.4 christos
1336 1.1 christos return true;
1337 1.1 christos }
1338 1.1.1.4 christos
1339 1.1.1.4 christos static bool
1340 1.1.1.4 christos pru_elf32_relax_section (bfd *abfd, asection *sec,
1341 1.1.1.4 christos struct bfd_link_info *link_info,
1342 1.1 christos bool *again)
1343 1.1 christos {
1344 1.1 christos Elf_Internal_Shdr * symtab_hdr;
1345 1.1 christos Elf_Internal_Rela * internal_relocs;
1346 1.1 christos Elf_Internal_Rela * irel;
1347 1.1 christos Elf_Internal_Rela * irelend;
1348 1.1 christos bfd_byte * contents = NULL;
1349 1.1 christos Elf_Internal_Sym * isymbuf = NULL;
1350 1.1 christos
1351 1.1.1.4 christos /* Assume nothing changes. */
1352 1.1 christos *again = false;
1353 1.1 christos
1354 1.1 christos /* We don't have to do anything for a relocatable link, if
1355 1.1 christos this section does not have relocs, or if this is not a
1356 1.1 christos code section. */
1357 1.1.1.5 christos if (bfd_link_relocatable (link_info)
1358 1.1.1.5 christos || sec->reloc_count == 0
1359 1.1.1.5 christos || (sec->flags & SEC_RELOC) == 0
1360 1.1.1.5 christos || (sec->flags & SEC_HAS_CONTENTS) == 0
1361 1.1.1.4 christos || (sec->flags & SEC_CODE) == 0)
1362 1.1 christos return true;
1363 1.1 christos
1364 1.1 christos symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
1365 1.1 christos
1366 1.1 christos /* Get a copy of the native relocations. */
1367 1.1 christos internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
1368 1.1 christos link_info->keep_memory);
1369 1.1 christos if (internal_relocs == NULL)
1370 1.1 christos goto error_return;
1371 1.1 christos
1372 1.1 christos /* Walk through them looking for relaxing opportunities. */
1373 1.1 christos irelend = internal_relocs + sec->reloc_count;
1374 1.1 christos
1375 1.1 christos for (irel = internal_relocs; irel < irelend; irel++)
1376 1.1 christos {
1377 1.1 christos bfd_vma symval;
1378 1.1 christos
1379 1.1 christos /* Get the section contents if we haven't done so already. */
1380 1.1 christos if (contents == NULL)
1381 1.1 christos {
1382 1.1 christos /* Get cached copy if it exists. */
1383 1.1 christos if (elf_section_data (sec)->this_hdr.contents != NULL)
1384 1.1 christos contents = elf_section_data (sec)->this_hdr.contents;
1385 1.1 christos else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
1386 1.1 christos goto error_return;
1387 1.1 christos }
1388 1.1 christos
1389 1.1 christos /* Read this BFD's local symbols if we haven't done so already. */
1390 1.1 christos if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1391 1.1 christos {
1392 1.1 christos isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1393 1.1 christos if (isymbuf == NULL)
1394 1.1 christos isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1395 1.1 christos symtab_hdr->sh_info, 0,
1396 1.1 christos NULL, NULL, NULL);
1397 1.1 christos if (isymbuf == NULL)
1398 1.1 christos goto error_return;
1399 1.1 christos }
1400 1.1 christos
1401 1.1 christos /* Get the value of the symbol referred to by the reloc. */
1402 1.1 christos if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1403 1.1 christos {
1404 1.1 christos /* A local symbol. */
1405 1.1 christos Elf_Internal_Sym *isym;
1406 1.1 christos asection *sym_sec;
1407 1.1 christos
1408 1.1 christos isym = isymbuf + ELF32_R_SYM (irel->r_info);
1409 1.1 christos if (isym->st_shndx == SHN_UNDEF)
1410 1.1 christos sym_sec = bfd_und_section_ptr;
1411 1.1 christos else if (isym->st_shndx == SHN_ABS)
1412 1.1 christos sym_sec = bfd_abs_section_ptr;
1413 1.1 christos else if (isym->st_shndx == SHN_COMMON)
1414 1.1 christos sym_sec = bfd_com_section_ptr;
1415 1.1 christos else
1416 1.1 christos sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1417 1.1 christos symval = (isym->st_value
1418 1.1 christos + sym_sec->output_section->vma + sym_sec->output_offset);
1419 1.1 christos }
1420 1.1 christos else
1421 1.1 christos {
1422 1.1 christos unsigned long indx;
1423 1.1 christos struct elf_link_hash_entry *h;
1424 1.1 christos
1425 1.1 christos /* An external symbol. */
1426 1.1 christos indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
1427 1.1 christos h = elf_sym_hashes (abfd)[indx];
1428 1.1 christos BFD_ASSERT (h != NULL);
1429 1.1 christos
1430 1.1 christos if (h->root.type != bfd_link_hash_defined
1431 1.1 christos && h->root.type != bfd_link_hash_defweak)
1432 1.1 christos /* This appears to be a reference to an undefined
1433 1.1 christos symbol. Just ignore it--it will be caught by the
1434 1.1 christos regular reloc processing. */
1435 1.1 christos continue;
1436 1.1 christos
1437 1.1 christos symval = (h->root.u.def.value
1438 1.1 christos + h->root.u.def.section->output_section->vma
1439 1.1 christos + h->root.u.def.section->output_offset);
1440 1.1 christos }
1441 1.1 christos
1442 1.1 christos /* For simplicity of coding, we are going to modify the section
1443 1.1 christos contents, the section relocs, and the BFD symbol table. We
1444 1.1 christos must tell the rest of the code not to free up this
1445 1.1 christos information. It would be possible to instead create a table
1446 1.1 christos of changes which have to be made, as is done in coff-mips.c;
1447 1.1 christos that would be more work, but would require less memory when
1448 1.1 christos the linker is run. */
1449 1.1 christos
1450 1.1 christos /* Check if we can remove an LDI instruction from the LDI32
1451 1.1 christos pseudo instruction if the upper 16 operand bits are zero. */
1452 1.1 christos if (ELF32_R_TYPE (irel->r_info) == (int) R_PRU_LDI32)
1453 1.1 christos {
1454 1.1 christos bfd_vma value = symval + irel->r_addend;
1455 1.1 christos
1456 1.1 christos if (debug_relax)
1457 1.1 christos printf ("R_PRU_LDI32 with value=0x%lx\n", (long) value);
1458 1.1 christos
1459 1.1 christos if ((long) value >> 16 == 0)
1460 1.1.1.2 christos {
1461 1.1.1.2 christos unsigned long insn;
1462 1.1 christos
1463 1.1 christos /* Note that we've changed the relocs, section contents. */
1464 1.1 christos elf_section_data (sec)->relocs = internal_relocs;
1465 1.1 christos elf_section_data (sec)->this_hdr.contents = contents;
1466 1.1 christos symtab_hdr->contents = (unsigned char *) isymbuf;
1467 1.1.1.2 christos
1468 1.1.1.2 christos /* Make the second instruction load the 16-bit constant
1469 1.1.1.2 christos into the full 32-bit register. */
1470 1.1.1.2 christos insn = bfd_get_32 (abfd, contents + irel->r_offset + 4);
1471 1.1.1.2 christos
1472 1.1.1.2 christos /* Old GAS and LD versions have a bug, where the two
1473 1.1.1.2 christos LDI instructions are swapped. Detect such object
1474 1.1.1.2 christos files and bail. */
1475 1.1.1.2 christos if (GET_INSN_FIELD (RDSEL, insn) != RSEL_15_0)
1476 1.1.1.2 christos {
1477 1.1.1.2 christos /* xgettext:c-format */
1478 1.1.1.2 christos _bfd_error_handler (_("error: %pB: old incompatible object file detected"),
1479 1.1.1.2 christos abfd);
1480 1.1.1.2 christos goto error_return;
1481 1.1.1.2 christos }
1482 1.1.1.2 christos
1483 1.1.1.2 christos SET_INSN_FIELD (RDSEL, insn, RSEL_31_0);
1484 1.1.1.2 christos bfd_put_32 (abfd, insn, contents + irel->r_offset + 4);
1485 1.1.1.2 christos
1486 1.1.1.2 christos /* Delete the first LDI instruction. Note that there should
1487 1.1.1.2 christos be no relocations or symbols pointing to the second LDI
1488 1.1.1.2 christos instruction. */
1489 1.1 christos if (!pru_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 4))
1490 1.1 christos goto error_return;
1491 1.1.1.2 christos
1492 1.1.1.2 christos /* We're done with deletion of the first instruction.
1493 1.1 christos Set a regular LDI relocation for the second instruction
1494 1.1 christos we left to load the 16-bit value into the 32-bit
1495 1.1 christos register. */
1496 1.1 christos irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1497 1.1 christos R_PRU_U16);
1498 1.1 christos
1499 1.1 christos /* That will change things, so, we should relax again.
1500 1.1.1.4 christos Note that this is not required, and it may be slow. */
1501 1.1 christos *again = true;
1502 1.1 christos }
1503 1.1 christos }
1504 1.1 christos }
1505 1.1 christos
1506 1.1 christos if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
1507 1.1 christos {
1508 1.1 christos if (!link_info->keep_memory)
1509 1.1 christos free (isymbuf);
1510 1.1 christos else
1511 1.1 christos {
1512 1.1 christos /* Cache the symbols for elf_link_input_bfd. */
1513 1.1 christos symtab_hdr->contents = (unsigned char *) isymbuf;
1514 1.1 christos }
1515 1.1 christos }
1516 1.1 christos
1517 1.1 christos if (contents != NULL
1518 1.1 christos && elf_section_data (sec)->this_hdr.contents != contents)
1519 1.1 christos {
1520 1.1 christos if (!link_info->keep_memory)
1521 1.1 christos free (contents);
1522 1.1 christos else
1523 1.1 christos {
1524 1.1 christos /* Cache the section contents for elf_link_input_bfd. */
1525 1.1 christos elf_section_data (sec)->this_hdr.contents = contents;
1526 1.1 christos }
1527 1.1 christos }
1528 1.1.1.3 christos
1529 1.1 christos if (elf_section_data (sec)->relocs != internal_relocs)
1530 1.1 christos free (internal_relocs);
1531 1.1.1.4 christos
1532 1.1 christos return true;
1533 1.1.1.3 christos
1534 1.1.1.3 christos error_return:
1535 1.1 christos if (symtab_hdr->contents != (unsigned char *) isymbuf)
1536 1.1.1.3 christos free (isymbuf);
1537 1.1 christos if (elf_section_data (sec)->this_hdr.contents != contents)
1538 1.1.1.3 christos free (contents);
1539 1.1 christos if (elf_section_data (sec)->relocs != internal_relocs)
1540 1.1 christos free (internal_relocs);
1541 1.1.1.4 christos
1542 1.1 christos return false;
1543 1.1 christos }
1544 1.1 christos
1545 1.1 christos /* Free the derived linker hash table. */
1546 1.1 christos static void
1547 1.1 christos pru_elf32_link_hash_table_free (bfd *obfd)
1548 1.1 christos {
1549 1.1 christos _bfd_elf_link_hash_table_free (obfd);
1550 1.1 christos }
1551 1.1 christos
1552 1.1 christos /* Implement bfd_elf32_bfd_link_hash_table_create. */
1553 1.1 christos static struct bfd_link_hash_table *
1554 1.1 christos pru_elf32_link_hash_table_create (bfd *abfd)
1555 1.1 christos {
1556 1.1.1.3 christos struct elf_link_hash_table *ret;
1557 1.1 christos size_t amt = sizeof (struct elf_link_hash_table);
1558 1.1 christos
1559 1.1 christos ret = bfd_zmalloc (amt);
1560 1.1 christos if (ret == NULL)
1561 1.1 christos return NULL;
1562 1.1 christos
1563 1.1 christos if (!_bfd_elf_link_hash_table_init (ret, abfd,
1564 1.1 christos link_hash_newfunc,
1565 1.1 christos sizeof (struct
1566 1.1 christos elf_link_hash_entry),
1567 1.1 christos PRU_ELF_DATA))
1568 1.1 christos {
1569 1.1 christos free (ret);
1570 1.1 christos return NULL;
1571 1.1 christos }
1572 1.1 christos
1573 1.1 christos ret->root.hash_table_free = pru_elf32_link_hash_table_free;
1574 1.1 christos
1575 1.1 christos return &ret->root;
1576 1.1 christos }
1577 1.1 christos
1578 1.1 christos #define ELF_ARCH bfd_arch_pru
1579 1.1 christos #define ELF_TARGET_ID PRU_ELF_DATA
1580 1.1 christos #define ELF_MACHINE_CODE EM_TI_PRU
1581 1.1 christos
1582 1.1 christos #define ELF_MAXPAGESIZE 1
1583 1.1 christos
1584 1.1 christos #define bfd_elf32_bfd_link_hash_table_create \
1585 1.1 christos pru_elf32_link_hash_table_create
1586 1.1 christos
1587 1.1 christos /* Relocation table lookup macros. */
1588 1.1 christos
1589 1.1 christos #define bfd_elf32_bfd_reloc_type_lookup pru_elf32_bfd_reloc_type_lookup
1590 1.1 christos #define bfd_elf32_bfd_reloc_name_lookup pru_elf32_bfd_reloc_name_lookup
1591 1.1 christos
1592 1.1.1.2 christos #define elf_info_to_howto pru_elf32_info_to_howto
1593 1.1 christos #define elf_info_to_howto_rel NULL
1594 1.1 christos
1595 1.1 christos /* elf backend functions. */
1596 1.1.1.2 christos
1597 1.1.1.2 christos /* TI folks like to use a mix of REL and RELA relocations. See also
1598 1.1.1.2 christos the MSP430 and TI C6X backends. */
1599 1.1.1.2 christos #define elf_backend_may_use_rel_p 1
1600 1.1.1.2 christos #define elf_backend_may_use_rela_p 1
1601 1.1.1.2 christos #define elf_backend_default_use_rela_p 1
1602 1.1 christos
1603 1.1 christos #define elf_backend_rela_normal 1
1604 1.1 christos
1605 1.1 christos #define elf_backend_relocate_section pru_elf32_relocate_section
1606 1.1.1.4 christos #define bfd_elf32_bfd_relax_section pru_elf32_relax_section
1607 1.1.1.4 christos #define elf_backend_can_gc_sections 1
1608 1.1.1.4 christos
1609 1.1 christos #define elf_backend_default_execstack 0
1610 1.1 christos
1611 1.1 christos #define TARGET_LITTLE_SYM pru_elf32_vec
1612 1.1 christos #define TARGET_LITTLE_NAME "elf32-pru"
1613 1.1 christos
1614 #include "elf32-target.h"
1615