Coverage Report

Created: 2026-03-10 08:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/bfd/elf32-pru.c
Line
Count
Source
1
/* 32-bit ELF support for TI PRU.
2
   Copyright (C) 2014-2026 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
0
#define OCTETS_PER_BYTE(ABFD, SEC) 1
37
38
#define SWAP_VALS(A,B)          \
39
0
  do {             \
40
0
      (A) ^= (B);         \
41
0
      (B) ^= (A);         \
42
0
      (A) ^= (B);         \
43
0
  } 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 *
300
lookup_howto (unsigned int rtype)
301
0
{
302
0
  static bool initialized = false;
303
0
  int i;
304
0
  int howto_tbl_size = (int) (sizeof (elf_pru_howto_table_rel)
305
0
            / sizeof (elf_pru_howto_table_rel[0]));
306
307
0
  if (! initialized)
308
0
    {
309
0
      initialized = true;
310
0
      memset (elf_code_to_howto_index, 0xff,
311
0
        sizeof (elf_code_to_howto_index));
312
0
      for (i = 0; i < howto_tbl_size; i++)
313
0
  elf_code_to_howto_index[elf_pru_howto_table_rel[i].type] = i;
314
0
    }
315
316
0
  if (rtype > R_PRU_ILLEGAL)
317
0
    return NULL;
318
0
  i = elf_code_to_howto_index[rtype];
319
0
  if (i >= howto_tbl_size)
320
0
    return NULL;
321
0
  return elf_pru_howto_table_rel + i;
322
0
}
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 *
359
link_hash_newfunc (struct bfd_hash_entry *entry,
360
       struct bfd_hash_table *table, const char *string)
361
0
{
362
  /* Allocate the structure if it has not already been allocated by a
363
     subclass.  */
364
0
  if (entry == NULL)
365
0
    {
366
0
      entry = bfd_hash_allocate (table,
367
0
         sizeof (struct elf_link_hash_entry));
368
0
      if (entry == NULL)
369
0
  return entry;
370
0
    }
371
372
  /* Call the allocation method of the superclass.  */
373
0
  entry = _bfd_elf_link_hash_newfunc (entry, table, string);
374
375
0
  return entry;
376
0
}
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 *
382
pru_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
383
           bfd_reloc_code_real_type code)
384
0
{
385
0
  unsigned int i;
386
387
0
  for (i = 0; i < ARRAY_SIZE (pru_reloc_map); ++i)
388
0
    if (pru_reloc_map[i].bfd_val == code)
389
0
      return lookup_howto ((unsigned int) pru_reloc_map[i].elf_val);
390
0
  return NULL;
391
0
}
392
393
/* Implement bfd_elf32_bfd_reloc_name_lookup:
394
   Given a reloc name, return a howto structure.  */
395
396
static reloc_howto_type *
397
pru_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
398
           const char *r_name)
399
0
{
400
0
  unsigned int i;
401
402
0
  for (i = 0; i < ARRAY_SIZE (elf_pru_howto_table_rel); i++)
403
0
    if (elf_pru_howto_table_rel[i].name
404
0
  && strcasecmp (elf_pru_howto_table_rel[i].name, r_name) == 0)
405
0
      return &elf_pru_howto_table_rel[i];
406
407
0
  return NULL;
408
0
}
409
410
/* Implement elf_info_to_howto:
411
   Given a ELF32 relocation, fill in a arelent structure.  */
412
413
static bool
414
pru_elf32_info_to_howto (bfd *abfd, arelent *cache_ptr,
415
       Elf_Internal_Rela *dst)
416
0
{
417
0
  unsigned int r_type;
418
419
0
  r_type = ELF32_R_TYPE (dst->r_info);
420
0
  if (r_type >= R_PRU_ILLEGAL)
421
0
    {
422
      /* xgettext:c-format */
423
0
      _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, r_type);
424
0
      bfd_set_error (bfd_error_bad_value);
425
0
      return false;
426
0
    }
427
428
0
  cache_ptr->howto = lookup_howto (r_type);
429
0
  return cache_ptr->howto != NULL;
430
0
}
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
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
0
{
452
0
  symbol_value = symbol_value + addend;
453
0
  addend = 0;
454
0
  symbol_value &= 0x3fffff;
455
0
  return _bfd_final_link_relocate (howto, abfd, input_section,
456
0
           data, offset, symbol_value, addend);
457
0
}
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
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
0
{
468
0
  bfd_byte *location;
469
0
  bfd_vma x = 0;
470
0
  bfd_vma qboff;
471
0
  bfd_reloc_status_type flag = bfd_reloc_ok;
472
473
  /* Sanity check the address.  */
474
0
  if (address > bfd_get_section_limit (input_bfd, input_section))
475
0
    return bfd_reloc_outofrange;
476
477
0
  BFD_ASSERT (howto->pc_relative);
478
0
  BFD_ASSERT (howto->pcrel_offset);
479
480
0
  relocation = relocation + addend - (input_section->output_section->vma
481
0
    + input_section->output_offset) - address;
482
483
0
  location = contents + address;
484
485
  /* Get the value we are going to relocate.  */
486
0
  BFD_ASSERT (bfd_get_reloc_size (howto) == 4);
487
0
  x = bfd_get_32 (input_bfd, location);
488
489
0
  qboff = GET_BROFF_SIGNED (x) << howto->rightshift;
490
0
  relocation += qboff;
491
492
0
  BFD_ASSERT (howto->complain_on_overflow == complain_overflow_bitfield);
493
494
0
  if (relocation > 2047 && relocation < (bfd_vma)-2048l)
495
0
    flag = bfd_reloc_overflow;
496
497
  /* Check that target address is word-aligned.  */
498
0
  if (relocation & ((1 << howto->rightshift) - 1))
499
0
    flag = bfd_reloc_outofrange;
500
501
0
  relocation >>= (bfd_vma) howto->rightshift;
502
503
  /* Fill-in the RELOCATION to the right bits of X.  */
504
0
  SET_BROFF_URAW (x, relocation);
505
506
0
  bfd_put_32 (input_bfd, x, location);
507
508
0
  return flag;
509
0
}
510
511
static bfd_reloc_status_type
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
0
{
517
0
  bfd_vma relocation;
518
519
0
  BFD_ASSERT (howto->pc_relative);
520
0
  BFD_ASSERT (howto->pcrel_offset);
521
522
0
  relocation = symbol_value + addend - (input_section->output_section->vma
523
0
    + input_section->output_offset) - offset;
524
0
  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
0
  if (relocation < 2)
529
0
      return bfd_reloc_outofrange;
530
531
0
  return _bfd_final_link_relocate (howto, abfd, input_section,
532
0
           data, offset, symbol_value, addend);
533
0
}
534
535
/* Idea and code taken from elf32-d30v.  */
536
static bfd_reloc_status_type
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
0
{
542
0
  bfd_vma relocation;
543
0
  bfd_size_type octets = offset * OCTETS_PER_BYTE (abfd, input_section);
544
0
  bfd_byte *location;
545
0
  unsigned long in1, in2;
546
547
  /* A hacked-up version of _bfd_final_link_relocate() follows.  */
548
549
  /* Sanity check the address.  */
550
0
  if (octets + bfd_get_reloc_size (howto)
551
0
      > bfd_get_section_limit_octets (abfd, input_section))
552
0
    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
0
  relocation = symbol_value + addend;
559
560
0
  BFD_ASSERT (!howto->pc_relative);
561
562
  /* A hacked-up version of _bfd_relocate_contents() follows.  */
563
0
  location = data + octets;
564
565
0
  BFD_ASSERT (!howto->pc_relative);
566
567
0
  in1 = bfd_get_32 (abfd, location);
568
0
  in2 = bfd_get_32 (abfd, location + 4);
569
570
0
  SET_INSN_FIELD (IMM16, in1, relocation >> 16);
571
0
  SET_INSN_FIELD (IMM16, in2, relocation & 0xffff);
572
573
0
  bfd_put_32 (abfd, in1, location);
574
0
  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
0
  if (GET_INSN_FIELD (RDSEL, in1) != RSEL_31_16)
580
0
    {
581
      /* xgettext:c-format */
582
0
      _bfd_error_handler (_("error: %pB: old incompatible object file detected"),
583
0
        abfd);
584
0
      return bfd_reloc_notsupported;
585
0
    }
586
587
0
  return bfd_reloc_ok;
588
0
}
589
590
/* HOWTO handlers for relocations that require special handling.  */
591
592
static bfd_reloc_status_type
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
0
{
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
0
  if (output_bfd != NULL)
602
0
    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
603
0
          input_section, output_bfd, error_message);
604
605
0
  BFD_ASSERT (0);
606
0
  return pru_elf32_do_pmem_relocate (abfd, reloc_entry->howto,
607
0
             input_section,
608
0
             data, reloc_entry->address,
609
0
             (symbol->value
610
0
              + symbol->section->output_section->vma
611
0
              + symbol->section->output_offset),
612
0
             reloc_entry->addend);
613
0
}
614
615
static bfd_reloc_status_type
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
0
{
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
0
  if (output_bfd != NULL)
625
0
    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
626
0
          input_section, output_bfd, error_message);
627
628
0
  return pru_elf32_do_s10_pcrel_relocate (abfd, reloc_entry->howto,
629
0
            input_section, data,
630
0
            reloc_entry->address,
631
0
            (symbol->value
632
0
             + symbol->section->output_section->vma
633
0
             + symbol->section->output_offset),
634
0
            reloc_entry->addend);
635
0
}
636
637
static bfd_reloc_status_type
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
0
{
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
0
  if (output_bfd != NULL)
647
0
    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
648
0
          input_section, output_bfd, error_message);
649
650
0
  return pru_elf32_do_u8_pcrel_relocate (abfd, reloc_entry->howto,
651
0
           input_section,
652
0
           data, reloc_entry->address,
653
0
           (symbol->value
654
0
            + symbol->section->output_section->vma
655
0
            + symbol->section->output_offset),
656
0
           reloc_entry->addend);
657
0
}
658
659
static bfd_reloc_status_type
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
0
{
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
0
  if (output_bfd != NULL)
669
0
    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
670
0
          input_section, output_bfd, error_message);
671
672
0
  return pru_elf32_do_ldi32_relocate (abfd, reloc_entry->howto,
673
0
              input_section,
674
0
              data, reloc_entry->address,
675
0
              (symbol->value
676
0
               + symbol->section->output_section->vma
677
0
               + symbol->section->output_offset),
678
0
              reloc_entry->addend);
679
0
}
680
681
682
/* Implement elf_backend_relocate_section.  */
683
static int
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
0
{
693
0
  struct bfd_elf_section_data * esd = elf_section_data (input_section);
694
0
  Elf_Internal_Shdr *symtab_hdr;
695
0
  struct elf_link_hash_entry **sym_hashes;
696
0
  Elf_Internal_Rela *rel;
697
0
  Elf_Internal_Rela *relend;
698
0
  bool is_rel_reloc;
699
700
0
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
701
0
  sym_hashes = elf_sym_hashes (input_bfd);
702
0
  relend = relocs + input_section->reloc_count;
703
704
  /* See if we have a REL type relocation.  */
705
0
  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
0
  BFD_ASSERT (! is_rel_reloc || ! esd->rela.hdr);
710
711
0
  for (rel = relocs; rel < relend; rel++)
712
0
    {
713
0
      reloc_howto_type *howto;
714
0
      unsigned long r_symndx;
715
0
      Elf_Internal_Sym *sym;
716
0
      asection *sec;
717
0
      struct elf_link_hash_entry *h;
718
0
      bfd_vma relocation;
719
0
      bfd_reloc_status_type r = bfd_reloc_ok;
720
0
      const char *name = NULL;
721
0
      const char* msg = (const char*) NULL;
722
0
      bool unresolved_reloc;
723
0
      bfd_vma addend;
724
725
      /* If we are using a REL relocation then the addend should be empty.  */
726
0
      BFD_ASSERT (! is_rel_reloc || rel->r_addend == 0);
727
728
0
      r_symndx = ELF32_R_SYM (rel->r_info);
729
730
0
      howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info));
731
0
      h = NULL;
732
0
      sym = NULL;
733
0
      sec = NULL;
734
735
0
      if (r_symndx < symtab_hdr->sh_info)
736
0
  {
737
0
    sym = local_syms + r_symndx;
738
0
    sec = local_sections[r_symndx];
739
0
    relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
740
0
  }
741
0
      else
742
0
  {
743
0
    bool warned, ignored;
744
745
0
    RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
746
0
           r_symndx, symtab_hdr, sym_hashes,
747
0
           h, sec, relocation,
748
0
           unresolved_reloc, warned, ignored);
749
0
  }
750
751
0
      if (sec && discarded_section (sec))
752
0
  RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
753
0
           rel, 1, relend, R_PRU_NONE,
754
0
           howto, 0, contents);
755
756
      /* Nothing more to do unless this is a final link.  */
757
0
      if (bfd_link_relocatable (info))
758
0
  continue;
759
760
0
      if (howto)
761
0
  {
762
0
    switch (howto->type)
763
0
      {
764
0
      case R_PRU_NONE:
765
        /* We don't need to find a value for this symbol.  It's just a
766
     marker.  */
767
0
        r = bfd_reloc_ok;
768
0
        break;
769
770
0
      case R_PRU_U16:
771
0
        if (is_rel_reloc)
772
0
    {
773
0
      unsigned long insn;
774
0
      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
775
0
      addend = GET_INSN_FIELD (IMM16, insn);
776
0
    }
777
0
        else
778
0
    addend = rel->r_addend;
779
0
        r = _bfd_final_link_relocate (howto, input_bfd,
780
0
              input_section, contents,
781
0
              rel->r_offset, relocation,
782
0
              addend);
783
0
        break;
784
785
0
      case R_PRU_U16_PMEMIMM:
786
0
      case R_PRU_32_PMEM:
787
0
      case R_PRU_16_PMEM:
788
0
        if (is_rel_reloc && howto->type == R_PRU_U16_PMEMIMM)
789
0
    {
790
0
      unsigned long insn;
791
0
      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
792
0
      addend = GET_INSN_FIELD (IMM16, insn) << 2;
793
0
    }
794
0
        else if (is_rel_reloc && howto->type == R_PRU_32_PMEM)
795
0
    {
796
0
      addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
797
0
      addend <<= 2;
798
0
    }
799
0
        else if (is_rel_reloc && howto->type == R_PRU_16_PMEM)
800
0
    {
801
0
      addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
802
0
      addend <<= 2;
803
0
    }
804
0
        else
805
0
    {
806
0
      BFD_ASSERT (!is_rel_reloc);
807
0
      addend = rel->r_addend;
808
0
    }
809
0
        r = pru_elf32_do_pmem_relocate (input_bfd, howto,
810
0
            input_section,
811
0
            contents, rel->r_offset,
812
0
            relocation, addend);
813
0
        break;
814
0
      case R_PRU_S10_PCREL:
815
0
        BFD_ASSERT (! is_rel_reloc);
816
0
        r = pru_elf32_do_s10_pcrel_relocate (input_bfd, howto,
817
0
                  input_section,
818
0
                  contents,
819
0
                  rel->r_offset,
820
0
                  relocation,
821
0
                  rel->r_addend);
822
0
        break;
823
0
      case R_PRU_U8_PCREL:
824
0
        BFD_ASSERT (! is_rel_reloc);
825
0
        r = pru_elf32_do_u8_pcrel_relocate (input_bfd, howto,
826
0
                  input_section,
827
0
                  contents,
828
0
                  rel->r_offset,
829
0
                  relocation,
830
0
                  rel->r_addend);
831
0
        break;
832
0
      case R_PRU_LDI32:
833
0
        if (is_rel_reloc)
834
0
    {
835
0
      unsigned long in1, in2;
836
0
      in1 = bfd_get_32 (input_bfd, contents + rel->r_offset);
837
0
      in2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
838
0
      addend = (GET_INSN_FIELD (IMM16, in1) << 16)
839
0
          | GET_INSN_FIELD (IMM16, in2);
840
0
    }
841
0
        else
842
0
    {
843
0
      addend = rel->r_addend;
844
0
    }
845
0
        r = pru_elf32_do_ldi32_relocate (input_bfd, howto,
846
0
                 input_section,
847
0
                 contents,
848
0
                 rel->r_offset,
849
0
                 relocation,
850
0
                 addend);
851
0
        break;
852
0
      case R_PRU_GNU_DIFF8:
853
0
      case R_PRU_GNU_DIFF16:
854
0
      case R_PRU_GNU_DIFF32:
855
0
      case R_PRU_GNU_DIFF16_PMEM:
856
0
      case R_PRU_GNU_DIFF32_PMEM:
857
        /* GNU extensions support only rela.  */
858
0
        BFD_ASSERT (! is_rel_reloc);
859
        /* Nothing to do here, as contents already contain the
860
     diff value.  */
861
0
        r = bfd_reloc_ok;
862
0
        break;
863
864
0
      case R_PRU_BFD_RELOC_16:
865
0
        if (is_rel_reloc)
866
0
    addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
867
0
        else
868
0
    addend = rel->r_addend;
869
0
        r = _bfd_final_link_relocate (howto, input_bfd,
870
0
              input_section, contents,
871
0
              rel->r_offset, relocation,
872
0
              addend);
873
0
        break;
874
875
0
      case R_PRU_BFD_RELOC_32:
876
0
        if (is_rel_reloc)
877
0
    addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
878
0
        else
879
0
    addend = rel->r_addend;
880
0
        r = _bfd_final_link_relocate (howto, input_bfd,
881
0
              input_section, contents,
882
0
              rel->r_offset, relocation,
883
0
              addend);
884
0
        break;
885
886
0
      case R_PRU_GNU_BFD_RELOC_8:
887
0
        BFD_ASSERT (! is_rel_reloc);
888
0
        r = _bfd_final_link_relocate (howto, input_bfd,
889
0
              input_section, contents,
890
0
              rel->r_offset, relocation,
891
0
              rel->r_addend);
892
0
        break;
893
894
0
      default:
895
0
        BFD_ASSERT (0);
896
0
        break;
897
0
      }
898
0
  }
899
0
      else
900
0
  r = bfd_reloc_notsupported;
901
902
0
      if (r != bfd_reloc_ok)
903
0
  {
904
0
    if (h != NULL)
905
0
      name = h->root.root.string;
906
0
    else
907
0
      {
908
0
        name = bfd_elf_string_from_elf_section (input_bfd,
909
0
                  symtab_hdr->sh_link,
910
0
                  sym->st_name);
911
0
        if (name == NULL || *name == '\0')
912
0
    name = bfd_section_name (sec);
913
0
      }
914
915
0
    switch (r)
916
0
      {
917
0
      case bfd_reloc_overflow:
918
0
        (*info->callbacks->reloc_overflow) (info, NULL, name,
919
0
              howto->name, (bfd_vma) 0,
920
0
              input_bfd, input_section,
921
0
              rel->r_offset);
922
0
        break;
923
924
0
      case bfd_reloc_undefined:
925
0
        (*info->callbacks->undefined_symbol) (info, name, input_bfd,
926
0
                input_section,
927
0
                rel->r_offset, true);
928
0
        break;
929
930
0
      case bfd_reloc_outofrange:
931
0
        if (msg == NULL)
932
0
    msg = _("relocation out of range");
933
0
        break;
934
935
0
      case bfd_reloc_notsupported:
936
0
        if (msg == NULL)
937
0
    msg = _("unsupported relocation");
938
0
        break;
939
940
0
      case bfd_reloc_dangerous:
941
0
        if (msg == NULL)
942
0
    msg = _("dangerous relocation");
943
0
        break;
944
945
0
      default:
946
0
        if (msg == NULL)
947
0
    msg = _("unknown error");
948
0
        break;
949
0
      }
950
951
0
    if (msg)
952
0
      {
953
0
        (*info->callbacks->warning) (info, msg, name, input_bfd,
954
0
             input_section, rel->r_offset);
955
0
        return false;
956
0
      }
957
0
  }
958
0
    }
959
0
  return true;
960
0
}
961
962

963
/* Perform a diff relocation.  Nothing to do, as the difference value is
964
   already written into the section's contents.  */
965
966
static bfd_reloc_status_type
967
bfd_elf_pru_diff_relocate (bfd *abfd ATTRIBUTE_UNUSED,
968
         arelent *reloc_entry ATTRIBUTE_UNUSED,
969
         asymbol *symbol ATTRIBUTE_UNUSED,
970
         void *data ATTRIBUTE_UNUSED,
971
         asection *input_section ATTRIBUTE_UNUSED,
972
         bfd *output_bfd ATTRIBUTE_UNUSED,
973
         char **error_message ATTRIBUTE_UNUSED)
974
0
{
975
0
  return bfd_reloc_ok;
976
0
}
977
978
979
/* Returns whether the relocation type passed is a diff reloc.  */
980
981
static bool
982
elf32_pru_is_diff_reloc (Elf_Internal_Rela *irel)
983
0
{
984
0
  return (ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF8
985
0
    || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16
986
0
    || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32
987
0
    || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16_PMEM
988
0
    || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32_PMEM);
989
0
}
990
991
/* Reduce the diff value written in the section by count if the shrinked
992
   insn address happens to fall between the two symbols for which this
993
   diff reloc was emitted.  */
994
995
static void
996
elf32_pru_adjust_diff_reloc_value (bfd *abfd,
997
           struct bfd_section *isec,
998
           Elf_Internal_Rela *irel,
999
           bfd_vma symval,
1000
           bfd_vma shrinked_insn_address,
1001
           int count)
1002
0
{
1003
0
  unsigned char *reloc_contents = NULL;
1004
0
  unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
1005
0
  if (isec_contents == NULL)
1006
0
  {
1007
0
    if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
1008
0
      return;
1009
1010
0
    elf_section_data (isec)->this_hdr.contents = isec_contents;
1011
0
  }
1012
1013
0
  reloc_contents = isec_contents + irel->r_offset;
1014
1015
  /* Read value written in object file.  */
1016
0
  bfd_signed_vma x = 0;
1017
0
  switch (ELF32_R_TYPE (irel->r_info))
1018
0
  {
1019
0
  case R_PRU_GNU_DIFF8:
1020
0
    {
1021
0
      x = bfd_get_signed_8 (abfd, reloc_contents);
1022
0
      break;
1023
0
    }
1024
0
  case R_PRU_GNU_DIFF16:
1025
0
    {
1026
0
      x = bfd_get_signed_16 (abfd, reloc_contents);
1027
0
      break;
1028
0
    }
1029
0
  case R_PRU_GNU_DIFF32:
1030
0
    {
1031
0
      x = bfd_get_signed_32 (abfd, reloc_contents);
1032
0
      break;
1033
0
    }
1034
0
  case R_PRU_GNU_DIFF16_PMEM:
1035
0
    {
1036
0
      x = bfd_get_signed_16 (abfd, reloc_contents) * 4;
1037
0
      break;
1038
0
    }
1039
0
  case R_PRU_GNU_DIFF32_PMEM:
1040
0
    {
1041
0
      x = bfd_get_signed_32 (abfd, reloc_contents) * 4;
1042
0
      break;
1043
0
    }
1044
0
  default:
1045
0
    {
1046
0
      BFD_FAIL ();
1047
0
    }
1048
0
  }
1049
1050
  /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
1051
     into the object file at the reloc offset.  sym2's logical value is
1052
     symval (<start_of_section>) + reloc addend.  Compute the start and end
1053
     addresses and check if the shrinked insn falls between sym1 and sym2.  */
1054
1055
0
  bfd_vma end_address = symval + irel->r_addend;
1056
0
  bfd_vma start_address = end_address - x;
1057
1058
  /* Shrink the absolute DIFF value (get the to labels "closer"
1059
     together), because we have removed data between labels.  */
1060
0
  if (x < 0)
1061
0
    {
1062
0
      x += count;
1063
      /* In case the signed x is negative, restore order.  */
1064
0
      SWAP_VALS (end_address, start_address);
1065
0
    }
1066
0
  else
1067
0
    {
1068
0
      x -= count;
1069
0
    }
1070
1071
  /* Reduce the diff value by count bytes and write it back into section
1072
    contents.  */
1073
1074
0
  if (shrinked_insn_address >= start_address
1075
0
      && shrinked_insn_address <= end_address)
1076
0
  {
1077
0
    switch (ELF32_R_TYPE (irel->r_info))
1078
0
    {
1079
0
    case R_PRU_GNU_DIFF8:
1080
0
      {
1081
0
  bfd_put_signed_8 (abfd, x & 0xFF, reloc_contents);
1082
0
  break;
1083
0
      }
1084
0
    case R_PRU_GNU_DIFF16:
1085
0
      {
1086
0
  bfd_put_signed_16 (abfd, x & 0xFFFF, reloc_contents);
1087
0
  break;
1088
0
      }
1089
0
    case R_PRU_GNU_DIFF32:
1090
0
      {
1091
0
  bfd_put_signed_32 (abfd, x & 0xFFFFFFFF, reloc_contents);
1092
0
  break;
1093
0
      }
1094
0
    case R_PRU_GNU_DIFF16_PMEM:
1095
0
      {
1096
0
  bfd_put_signed_16 (abfd, (x / 4) & 0xFFFF, reloc_contents);
1097
0
  break;
1098
0
      }
1099
0
    case R_PRU_GNU_DIFF32_PMEM:
1100
0
      {
1101
0
  bfd_put_signed_32 (abfd, (x / 4) & 0xFFFFFFFF, reloc_contents);
1102
0
  break;
1103
0
      }
1104
0
    default:
1105
0
      {
1106
0
  BFD_FAIL ();
1107
0
      }
1108
0
    }
1109
1110
0
  }
1111
0
}
1112
1113
/* Delete some bytes from a section while changing the size of an instruction.
1114
   The parameter "addr" denotes the section-relative offset pointing just
1115
   behind the shrinked instruction. "addr+count" point at the first
1116
   byte just behind the original unshrinked instruction.
1117
1118
   Idea copied from the AVR port.  */
1119
1120
static bool
1121
pru_elf_relax_delete_bytes (bfd *abfd,
1122
          asection *sec,
1123
          bfd_vma addr,
1124
          int count)
1125
0
{
1126
0
  Elf_Internal_Shdr *symtab_hdr;
1127
0
  unsigned int sec_shndx;
1128
0
  bfd_byte *contents;
1129
0
  Elf_Internal_Rela *irel, *irelend;
1130
0
  Elf_Internal_Sym *isym;
1131
0
  Elf_Internal_Sym *isymbuf = NULL;
1132
0
  bfd_vma toaddr;
1133
0
  struct elf_link_hash_entry **sym_hashes;
1134
0
  struct elf_link_hash_entry **end_hashes;
1135
0
  unsigned int symcount;
1136
1137
0
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1138
0
  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
1139
0
  contents = elf_section_data (sec)->this_hdr.contents;
1140
1141
0
  toaddr = sec->size;
1142
1143
0
  irel = elf_section_data (sec)->relocs;
1144
0
  irelend = irel + sec->reloc_count;
1145
1146
  /* Actually delete the bytes.  */
1147
0
  if (toaddr - addr - count > 0)
1148
0
    memmove (contents + addr, contents + addr + count,
1149
0
       (size_t) (toaddr - addr - count));
1150
0
  sec->size -= count;
1151
1152
  /* Adjust all the reloc addresses.  */
1153
0
  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
1154
0
    {
1155
0
      bfd_vma old_reloc_address;
1156
1157
0
      old_reloc_address = (sec->output_section->vma
1158
0
         + sec->output_offset + irel->r_offset);
1159
1160
      /* Get the new reloc address.  */
1161
0
      if ((irel->r_offset > addr
1162
0
     && irel->r_offset < toaddr))
1163
0
  {
1164
0
    if (debug_relax)
1165
0
      printf ("Relocation at address 0x%x needs to be moved.\n"
1166
0
        "Old section offset: 0x%x, New section offset: 0x%x \n",
1167
0
        (unsigned int) old_reloc_address,
1168
0
        (unsigned int) irel->r_offset,
1169
0
        (unsigned int) ((irel->r_offset) - count));
1170
1171
0
    irel->r_offset -= count;
1172
0
  }
1173
1174
0
    }
1175
1176
   /* The reloc's own addresses are now ok.  However, we need to readjust
1177
      the reloc's addend, i.e. the reloc's value if two conditions are met:
1178
      1.) the reloc is relative to a symbol in this section that
1179
    is located in front of the shrinked instruction
1180
      2.) symbol plus addend end up behind the shrinked instruction.
1181
1182
      The most common case where this happens are relocs relative to
1183
      the section-start symbol.
1184
1185
      This step needs to be done for all of the sections of the bfd.  */
1186
1187
0
  {
1188
0
    struct bfd_section *isec;
1189
1190
0
    for (isec = abfd->sections; isec; isec = isec->next)
1191
0
     {
1192
0
       bfd_vma symval;
1193
0
       bfd_vma shrinked_insn_address;
1194
1195
0
       if (isec->reloc_count == 0)
1196
0
   continue;
1197
1198
0
       shrinked_insn_address = (sec->output_section->vma
1199
0
        + sec->output_offset + addr);
1200
1201
0
       irel = elf_section_data (isec)->relocs;
1202
       /* PR 12161: Read in the relocs for this section if necessary.  */
1203
0
       if (irel == NULL)
1204
0
   irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, true);
1205
1206
0
       for (irelend = irel + isec->reloc_count;
1207
0
      irel < irelend;
1208
0
      irel++)
1209
0
   {
1210
     /* Read this BFD's local symbols if we haven't done
1211
        so already.  */
1212
0
     if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1213
0
       {
1214
0
         isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1215
0
         if (isymbuf == NULL)
1216
0
     isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1217
0
             symtab_hdr->sh_info, 0,
1218
0
             NULL, NULL, NULL);
1219
0
         if (isymbuf == NULL)
1220
0
     return false;
1221
0
       }
1222
1223
     /* Get the value of the symbol referred to by the reloc.  */
1224
0
     if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1225
0
       {
1226
         /* A local symbol.  */
1227
0
         asection *sym_sec;
1228
1229
0
         isym = isymbuf + ELF32_R_SYM (irel->r_info);
1230
0
         sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1231
0
         symval = isym->st_value;
1232
         /* If the reloc is absolute, it will not have
1233
      a symbol or section associated with it.  */
1234
0
         if (sym_sec == sec)
1235
0
     {
1236
0
       symval += sym_sec->output_section->vma
1237
0
         + sym_sec->output_offset;
1238
1239
0
       if (debug_relax)
1240
0
         printf ("Checking if the relocation's "
1241
0
           "addend needs corrections.\n"
1242
0
           "Address of anchor symbol: 0x%x \n"
1243
0
           "Address of relocation target: 0x%x \n"
1244
0
           "Address of relaxed insn: 0x%x \n",
1245
0
           (unsigned int) symval,
1246
0
           (unsigned int) (symval + irel->r_addend),
1247
0
           (unsigned int) shrinked_insn_address);
1248
1249
       /* Shrink the special DIFF relocations.  */
1250
0
       if (elf32_pru_is_diff_reloc (irel))
1251
0
         {
1252
0
           elf32_pru_adjust_diff_reloc_value (abfd, isec, irel,
1253
0
                symval,
1254
0
                shrinked_insn_address,
1255
0
                count);
1256
0
         }
1257
1258
       /* Fix the addend, if it is affected.  */
1259
0
       if (symval <= shrinked_insn_address
1260
0
           && (symval + irel->r_addend) > shrinked_insn_address)
1261
0
         {
1262
1263
0
           irel->r_addend -= count;
1264
1265
0
           if (debug_relax)
1266
0
       printf ("Relocation's addend needed to be fixed \n");
1267
0
         }
1268
0
     }
1269
         /* else...Reference symbol is absolute.
1270
      No adjustment needed.  */
1271
0
       }
1272
     /* else...Reference symbol is extern.  No need for adjusting
1273
        the addend.  */
1274
0
   }
1275
0
     }
1276
0
  }
1277
1278
  /* Adjust the local symbols defined in this section.  */
1279
0
  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
1280
  /* Fix PR 9841, there may be no local symbols.  */
1281
0
  if (isym != NULL)
1282
0
    {
1283
0
      Elf_Internal_Sym *isymend;
1284
1285
0
      isymend = isym + symtab_hdr->sh_info;
1286
0
      for (; isym < isymend; isym++)
1287
0
  {
1288
0
    if (isym->st_shndx == sec_shndx)
1289
0
      {
1290
0
        if (isym->st_value > addr
1291
0
      && isym->st_value <= toaddr)
1292
0
    isym->st_value -= count;
1293
1294
0
        if (isym->st_value <= addr
1295
0
      && isym->st_value + isym->st_size > addr)
1296
0
    {
1297
      /* If this assert fires then we have a symbol that ends
1298
         part way through an instruction.  Does that make
1299
         sense?  */
1300
0
      BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
1301
0
      isym->st_size -= count;
1302
0
    }
1303
0
      }
1304
0
  }
1305
0
    }
1306
1307
  /* Now adjust the global symbols defined in this section.  */
1308
0
  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
1309
0
        - symtab_hdr->sh_info);
1310
0
  sym_hashes = elf_sym_hashes (abfd);
1311
0
  end_hashes = sym_hashes + symcount;
1312
0
  for (; sym_hashes < end_hashes; sym_hashes++)
1313
0
    {
1314
0
      struct elf_link_hash_entry *sym_hash = *sym_hashes;
1315
0
      if ((sym_hash->root.type == bfd_link_hash_defined
1316
0
     || sym_hash->root.type == bfd_link_hash_defweak)
1317
0
    && sym_hash->root.u.def.section == sec)
1318
0
  {
1319
0
    if (sym_hash->root.u.def.value > addr
1320
0
        && sym_hash->root.u.def.value <= toaddr)
1321
0
      sym_hash->root.u.def.value -= count;
1322
1323
0
    if (sym_hash->root.u.def.value <= addr
1324
0
        && (sym_hash->root.u.def.value + sym_hash->size > addr))
1325
0
      {
1326
        /* If this assert fires then we have a symbol that ends
1327
     part way through an instruction.  Does that make
1328
     sense?  */
1329
0
        BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size
1330
0
        >= addr + count);
1331
0
        sym_hash->size -= count;
1332
0
      }
1333
0
  }
1334
0
    }
1335
1336
0
  return true;
1337
0
}
1338
1339
static bool
1340
pru_elf32_relax_section (bfd *abfd, asection *sec,
1341
       struct bfd_link_info *link_info,
1342
       bool *again)
1343
0
{
1344
0
  Elf_Internal_Shdr * symtab_hdr;
1345
0
  Elf_Internal_Rela * internal_relocs;
1346
0
  Elf_Internal_Rela * irel;
1347
0
  Elf_Internal_Rela * irelend;
1348
0
  bfd_byte *        contents = NULL;
1349
0
  Elf_Internal_Sym *  isymbuf = NULL;
1350
1351
  /* Assume nothing changes.  */
1352
0
  *again = false;
1353
1354
  /* We don't have to do anything for a relocatable link, if
1355
     this section does not have relocs, or if this is not a
1356
     code section.  */
1357
0
  if (bfd_link_relocatable (link_info)
1358
0
      || sec->reloc_count == 0
1359
0
      || (sec->flags & SEC_RELOC) == 0
1360
0
      || (sec->flags & SEC_HAS_CONTENTS) == 0
1361
0
      || (sec->flags & SEC_CODE) == 0)
1362
0
    return true;
1363
1364
0
  symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
1365
1366
  /* Get a copy of the native relocations.  */
1367
0
  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
1368
0
                 link_info->keep_memory);
1369
0
  if (internal_relocs == NULL)
1370
0
    goto error_return;
1371
1372
  /* Walk through them looking for relaxing opportunities.  */
1373
0
  irelend = internal_relocs + sec->reloc_count;
1374
1375
0
  for (irel = internal_relocs; irel < irelend; irel++)
1376
0
    {
1377
0
      bfd_vma symval;
1378
1379
      /* Get the section contents if we haven't done so already.  */
1380
0
      if (contents == NULL)
1381
0
  {
1382
    /* Get cached copy if it exists.  */
1383
0
    if (elf_section_data (sec)->this_hdr.contents != NULL)
1384
0
      contents = elf_section_data (sec)->this_hdr.contents;
1385
0
    else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
1386
0
      goto error_return;
1387
0
  }
1388
1389
      /* Read this BFD's local symbols if we haven't done so already.  */
1390
0
      if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1391
0
  {
1392
0
    isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1393
0
    if (isymbuf == NULL)
1394
0
      isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1395
0
              symtab_hdr->sh_info, 0,
1396
0
              NULL, NULL, NULL);
1397
0
    if (isymbuf == NULL)
1398
0
      goto error_return;
1399
0
  }
1400
1401
      /* Get the value of the symbol referred to by the reloc.  */
1402
0
      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1403
0
  {
1404
    /* A local symbol.  */
1405
0
    Elf_Internal_Sym *isym;
1406
0
    asection *sym_sec;
1407
1408
0
    isym = isymbuf + ELF32_R_SYM (irel->r_info);
1409
0
    if (isym->st_shndx == SHN_UNDEF)
1410
0
      sym_sec = bfd_und_section_ptr;
1411
0
    else if (isym->st_shndx == SHN_ABS)
1412
0
      sym_sec = bfd_abs_section_ptr;
1413
0
    else if (isym->st_shndx == SHN_COMMON)
1414
0
      sym_sec = bfd_com_section_ptr;
1415
0
    else
1416
0
      sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1417
0
    symval = (isym->st_value
1418
0
        + sym_sec->output_section->vma + sym_sec->output_offset);
1419
0
  }
1420
0
      else
1421
0
  {
1422
0
    unsigned long indx;
1423
0
    struct elf_link_hash_entry *h;
1424
1425
    /* An external symbol.  */
1426
0
    indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
1427
0
    h = elf_sym_hashes (abfd)[indx];
1428
0
    BFD_ASSERT (h != NULL);
1429
1430
0
    if (h->root.type != bfd_link_hash_defined
1431
0
        && h->root.type != bfd_link_hash_defweak)
1432
      /* This appears to be a reference to an undefined
1433
         symbol.  Just ignore it--it will be caught by the
1434
         regular reloc processing.  */
1435
0
      continue;
1436
1437
0
    symval = (h->root.u.def.value
1438
0
        + h->root.u.def.section->output_section->vma
1439
0
        + h->root.u.def.section->output_offset);
1440
0
  }
1441
1442
      /* For simplicity of coding, we are going to modify the section
1443
   contents, the section relocs, and the BFD symbol table.  We
1444
   must tell the rest of the code not to free up this
1445
   information.  It would be possible to instead create a table
1446
   of changes which have to be made, as is done in coff-mips.c;
1447
   that would be more work, but would require less memory when
1448
   the linker is run.  */
1449
1450
      /* Check if we can remove an LDI instruction from the LDI32
1451
   pseudo instruction if the upper 16 operand bits are zero.  */
1452
0
      if (ELF32_R_TYPE (irel->r_info) == (int) R_PRU_LDI32)
1453
0
  {
1454
0
    bfd_vma value = symval + irel->r_addend;
1455
1456
0
    if (debug_relax)
1457
0
      printf ("R_PRU_LDI32 with value=0x%lx\n", (long) value);
1458
1459
0
    if ((long) value >> 16 == 0)
1460
0
      {
1461
0
        unsigned long insn;
1462
1463
        /* Note that we've changed the relocs, section contents.  */
1464
0
        elf_section_data (sec)->relocs = internal_relocs;
1465
0
        elf_section_data (sec)->this_hdr.contents = contents;
1466
0
        symtab_hdr->contents = (unsigned char *) isymbuf;
1467
1468
        /* Make the second instruction load the 16-bit constant
1469
     into the full 32-bit register.  */
1470
0
        insn = bfd_get_32 (abfd, contents + irel->r_offset + 4);
1471
1472
        /* Old GAS and LD versions have a bug, where the two
1473
     LDI instructions are swapped.  Detect such object
1474
     files and bail.  */
1475
0
        if (GET_INSN_FIELD (RDSEL, insn) != RSEL_15_0)
1476
0
    {
1477
      /* xgettext:c-format */
1478
0
      _bfd_error_handler (_("error: %pB: old incompatible object file detected"),
1479
0
              abfd);
1480
0
      goto error_return;
1481
0
    }
1482
1483
0
        SET_INSN_FIELD (RDSEL, insn, RSEL_31_0);
1484
0
        bfd_put_32 (abfd, insn, contents + irel->r_offset + 4);
1485
1486
        /* Delete the first LDI instruction.  Note that there should
1487
     be no relocations or symbols pointing to the second LDI
1488
     instruction.  */
1489
0
        if (!pru_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 4))
1490
0
    goto error_return;
1491
1492
        /* We're done with deletion of the first instruction.
1493
     Set a regular LDI relocation for the second instruction
1494
     we left to load the 16-bit value into the 32-bit
1495
     register.  */
1496
0
        irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1497
0
             R_PRU_U16);
1498
1499
        /* That will change things, so, we should relax again.
1500
     Note that this is not required, and it may be slow.  */
1501
0
        *again = true;
1502
0
      }
1503
0
  }
1504
0
    }
1505
1506
0
  if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
1507
0
    {
1508
0
      if (!link_info->keep_memory)
1509
0
  free (isymbuf);
1510
0
      else
1511
0
  {
1512
    /* Cache the symbols for elf_link_input_bfd.  */
1513
0
    symtab_hdr->contents = (unsigned char *) isymbuf;
1514
0
  }
1515
0
    }
1516
1517
0
  if (contents != NULL
1518
0
      && elf_section_data (sec)->this_hdr.contents != contents)
1519
0
    {
1520
0
      if (!link_info->keep_memory)
1521
0
  free (contents);
1522
0
      else
1523
0
  {
1524
    /* Cache the section contents for elf_link_input_bfd.  */
1525
0
    elf_section_data (sec)->this_hdr.contents = contents;
1526
0
  }
1527
0
    }
1528
1529
0
  if (elf_section_data (sec)->relocs != internal_relocs)
1530
0
    free (internal_relocs);
1531
1532
0
  return true;
1533
1534
0
 error_return:
1535
0
  if (symtab_hdr->contents != (unsigned char *) isymbuf)
1536
0
    free (isymbuf);
1537
0
  if (elf_section_data (sec)->this_hdr.contents != contents)
1538
0
    free (contents);
1539
0
  if (elf_section_data (sec)->relocs != internal_relocs)
1540
0
    free (internal_relocs);
1541
1542
0
  return false;
1543
0
}
1544
1545
/* Free the derived linker hash table.  */
1546
static void
1547
pru_elf32_link_hash_table_free (bfd *obfd)
1548
0
{
1549
0
  _bfd_elf_link_hash_table_free (obfd);
1550
0
}
1551
1552
/* Implement bfd_elf32_bfd_link_hash_table_create.  */
1553
static struct bfd_link_hash_table *
1554
pru_elf32_link_hash_table_create (bfd *abfd)
1555
0
{
1556
0
  struct elf_link_hash_table *ret;
1557
0
  size_t amt = sizeof (struct elf_link_hash_table);
1558
1559
0
  ret = bfd_zmalloc (amt);
1560
0
  if (ret == NULL)
1561
0
    return NULL;
1562
1563
0
  if (!_bfd_elf_link_hash_table_init (ret, abfd, link_hash_newfunc,
1564
0
              sizeof (struct elf_link_hash_entry)))
1565
0
    {
1566
0
      free (ret);
1567
0
      return NULL;
1568
0
    }
1569
1570
0
  ret->root.hash_table_free = pru_elf32_link_hash_table_free;
1571
1572
0
  return &ret->root;
1573
0
}
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 elf_backend_default_execstack 0
1607
1608
#define TARGET_LITTLE_SYM   pru_elf32_vec
1609
#define TARGET_LITTLE_NAME    "elf32-pru"
1610
1611
#include "elf32-target.h"