Coverage Report

Created: 2026-07-25 10:20

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