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