Coverage Report

Created: 2025-06-24 06:45

/src/binutils-gdb/bfd/elf32-pru.c
Line
Count
Source (jump to first uncovered line)
1
/* 32-bit ELF support for TI PRU.
2
   Copyright (C) 2014-2025 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
47
{
302
47
  static bool initialized = false;
303
47
  int i;
304
47
  int howto_tbl_size = (int) (sizeof (elf_pru_howto_table_rel)
305
47
            / sizeof (elf_pru_howto_table_rel[0]));
306
307
47
  if (! initialized)
308
1
    {
309
1
      initialized = true;
310
1
      memset (elf_code_to_howto_index, 0xff,
311
1
        sizeof (elf_code_to_howto_index));
312
17
      for (i = 0; i < howto_tbl_size; i++)
313
16
  elf_code_to_howto_index[elf_pru_howto_table_rel[i].type] = i;
314
1
    }
315
316
47
  if (rtype > R_PRU_ILLEGAL)
317
0
    return NULL;
318
47
  i = elf_code_to_howto_index[rtype];
319
47
  if (i >= howto_tbl_size)
320
6
    return NULL;
321
41
  return elf_pru_howto_table_rel + i;
322
47
}
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
48
{
417
48
  unsigned int r_type;
418
419
48
  r_type = ELF32_R_TYPE (dst->r_info);
420
48
  if (r_type >= R_PRU_ILLEGAL)
421
1
    {
422
      /* xgettext:c-format */
423
1
      _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, r_type);
424
1
      bfd_set_error (bfd_error_bad_value);
425
1
      return false;
426
1
    }
427
428
47
  cache_ptr->howto = lookup_howto (r_type);
429
47
  return cache_ptr->howto != NULL;
430
48
}
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, howto, 0, contents);
754
755
      /* Nothing more to do unless this is a final link.  */
756
0
      if (bfd_link_relocatable (info))
757
0
  continue;
758
759
0
      if (howto)
760
0
  {
761
0
    switch (howto->type)
762
0
      {
763
0
      case R_PRU_NONE:
764
        /* We don't need to find a value for this symbol.  It's just a
765
     marker.  */
766
0
        r = bfd_reloc_ok;
767
0
        break;
768
769
0
      case R_PRU_U16:
770
0
        if (is_rel_reloc)
771
0
    {
772
0
      unsigned long insn;
773
0
      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
774
0
      addend = GET_INSN_FIELD (IMM16, insn);
775
0
    }
776
0
        else
777
0
    addend = rel->r_addend;
778
0
        r = _bfd_final_link_relocate (howto, input_bfd,
779
0
              input_section, contents,
780
0
              rel->r_offset, relocation,
781
0
              addend);
782
0
        break;
783
784
0
      case R_PRU_U16_PMEMIMM:
785
0
      case R_PRU_32_PMEM:
786
0
      case R_PRU_16_PMEM:
787
0
        if (is_rel_reloc && howto->type == R_PRU_U16_PMEMIMM)
788
0
    {
789
0
      unsigned long insn;
790
0
      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
791
0
      addend = GET_INSN_FIELD (IMM16, insn) << 2;
792
0
    }
793
0
        else if (is_rel_reloc && howto->type == R_PRU_32_PMEM)
794
0
    {
795
0
      addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
796
0
      addend <<= 2;
797
0
    }
798
0
        else if (is_rel_reloc && howto->type == R_PRU_16_PMEM)
799
0
    {
800
0
      addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
801
0
      addend <<= 2;
802
0
    }
803
0
        else
804
0
    {
805
0
      BFD_ASSERT (!is_rel_reloc);
806
0
      addend = rel->r_addend;
807
0
    }
808
0
        r = pru_elf32_do_pmem_relocate (input_bfd, howto,
809
0
            input_section,
810
0
            contents, rel->r_offset,
811
0
            relocation, addend);
812
0
        break;
813
0
      case R_PRU_S10_PCREL:
814
0
        BFD_ASSERT (! is_rel_reloc);
815
0
        r = pru_elf32_do_s10_pcrel_relocate (input_bfd, howto,
816
0
                  input_section,
817
0
                  contents,
818
0
                  rel->r_offset,
819
0
                  relocation,
820
0
                  rel->r_addend);
821
0
        break;
822
0
      case R_PRU_U8_PCREL:
823
0
        BFD_ASSERT (! is_rel_reloc);
824
0
        r = pru_elf32_do_u8_pcrel_relocate (input_bfd, howto,
825
0
                  input_section,
826
0
                  contents,
827
0
                  rel->r_offset,
828
0
                  relocation,
829
0
                  rel->r_addend);
830
0
        break;
831
0
      case R_PRU_LDI32:
832
0
        if (is_rel_reloc)
833
0
    {
834
0
      unsigned long in1, in2;
835
0
      in1 = bfd_get_32 (input_bfd, contents + rel->r_offset);
836
0
      in2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
837
0
      addend = (GET_INSN_FIELD (IMM16, in1) << 16)
838
0
          | GET_INSN_FIELD (IMM16, in2);
839
0
    }
840
0
        else
841
0
    {
842
0
      addend = rel->r_addend;
843
0
    }
844
0
        r = pru_elf32_do_ldi32_relocate (input_bfd, howto,
845
0
                 input_section,
846
0
                 contents,
847
0
                 rel->r_offset,
848
0
                 relocation,
849
0
                 addend);
850
0
        break;
851
0
      case R_PRU_GNU_DIFF8:
852
0
      case R_PRU_GNU_DIFF16:
853
0
      case R_PRU_GNU_DIFF32:
854
0
      case R_PRU_GNU_DIFF16_PMEM:
855
0
      case R_PRU_GNU_DIFF32_PMEM:
856
        /* GNU extensions support only rela.  */
857
0
        BFD_ASSERT (! is_rel_reloc);
858
        /* Nothing to do here, as contents already contain the
859
     diff value.  */
860
0
        r = bfd_reloc_ok;
861
0
        break;
862
863
0
      case R_PRU_BFD_RELOC_16:
864
0
        if (is_rel_reloc)
865
0
    addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
866
0
        else
867
0
    addend = rel->r_addend;
868
0
        r = _bfd_final_link_relocate (howto, input_bfd,
869
0
              input_section, contents,
870
0
              rel->r_offset, relocation,
871
0
              addend);
872
0
        break;
873
874
0
      case R_PRU_BFD_RELOC_32:
875
0
        if (is_rel_reloc)
876
0
    addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
877
0
        else
878
0
    addend = rel->r_addend;
879
0
        r = _bfd_final_link_relocate (howto, input_bfd,
880
0
              input_section, contents,
881
0
              rel->r_offset, relocation,
882
0
              addend);
883
0
        break;
884
885
0
      case R_PRU_GNU_BFD_RELOC_8:
886
0
        BFD_ASSERT (! is_rel_reloc);
887
0
        r = _bfd_final_link_relocate (howto, input_bfd,
888
0
              input_section, contents,
889
0
              rel->r_offset, relocation,
890
0
              rel->r_addend);
891
0
        break;
892
893
0
      default:
894
0
        BFD_ASSERT (0);
895
0
        break;
896
0
      }
897
0
  }
898
0
      else
899
0
  r = bfd_reloc_notsupported;
900
901
0
      if (r != bfd_reloc_ok)
902
0
  {
903
0
    if (h != NULL)
904
0
      name = h->root.root.string;
905
0
    else
906
0
      {
907
0
        name = bfd_elf_string_from_elf_section (input_bfd,
908
0
                  symtab_hdr->sh_link,
909
0
                  sym->st_name);
910
0
        if (name == NULL || *name == '\0')
911
0
    name = bfd_section_name (sec);
912
0
      }
913
914
0
    switch (r)
915
0
      {
916
0
      case bfd_reloc_overflow:
917
0
        (*info->callbacks->reloc_overflow) (info, NULL, name,
918
0
              howto->name, (bfd_vma) 0,
919
0
              input_bfd, input_section,
920
0
              rel->r_offset);
921
0
        break;
922
923
0
      case bfd_reloc_undefined:
924
0
        (*info->callbacks->undefined_symbol) (info, name, input_bfd,
925
0
                input_section,
926
0
                rel->r_offset, true);
927
0
        break;
928
929
0
      case bfd_reloc_outofrange:
930
0
        if (msg == NULL)
931
0
    msg = _("relocation out of range");
932
0
        break;
933
934
0
      case bfd_reloc_notsupported:
935
0
        if (msg == NULL)
936
0
    msg = _("unsupported relocation");
937
0
        break;
938
939
0
      case bfd_reloc_dangerous:
940
0
        if (msg == NULL)
941
0
    msg = _("dangerous relocation");
942
0
        break;
943
944
0
      default:
945
0
        if (msg == NULL)
946
0
    msg = _("unknown error");
947
0
        break;
948
0
      }
949
950
0
    if (msg)
951
0
      {
952
0
        (*info->callbacks->warning) (info, msg, name, input_bfd,
953
0
             input_section, rel->r_offset);
954
0
        return false;
955
0
      }
956
0
  }
957
0
    }
958
0
  return true;
959
0
}
960
961

962
/* Perform a diff relocation.  Nothing to do, as the difference value is
963
   already written into the section's contents.  */
964
965
static bfd_reloc_status_type
966
bfd_elf_pru_diff_relocate (bfd *abfd ATTRIBUTE_UNUSED,
967
         arelent *reloc_entry ATTRIBUTE_UNUSED,
968
         asymbol *symbol ATTRIBUTE_UNUSED,
969
         void *data ATTRIBUTE_UNUSED,
970
         asection *input_section ATTRIBUTE_UNUSED,
971
         bfd *output_bfd ATTRIBUTE_UNUSED,
972
         char **error_message ATTRIBUTE_UNUSED)
973
0
{
974
0
  return bfd_reloc_ok;
975
0
}
976
977
978
/* Returns whether the relocation type passed is a diff reloc.  */
979
980
static bool
981
elf32_pru_is_diff_reloc (Elf_Internal_Rela *irel)
982
0
{
983
0
  return (ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF8
984
0
    || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16
985
0
    || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32
986
0
    || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16_PMEM
987
0
    || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32_PMEM);
988
0
}
989
990
/* Reduce the diff value written in the section by count if the shrinked
991
   insn address happens to fall between the two symbols for which this
992
   diff reloc was emitted.  */
993
994
static void
995
elf32_pru_adjust_diff_reloc_value (bfd *abfd,
996
           struct bfd_section *isec,
997
           Elf_Internal_Rela *irel,
998
           bfd_vma symval,
999
           bfd_vma shrinked_insn_address,
1000
           int count)
1001
0
{
1002
0
  unsigned char *reloc_contents = NULL;
1003
0
  unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
1004
0
  if (isec_contents == NULL)
1005
0
  {
1006
0
    if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
1007
0
      return;
1008
1009
0
    elf_section_data (isec)->this_hdr.contents = isec_contents;
1010
0
  }
1011
1012
0
  reloc_contents = isec_contents + irel->r_offset;
1013
1014
  /* Read value written in object file.  */
1015
0
  bfd_signed_vma x = 0;
1016
0
  switch (ELF32_R_TYPE (irel->r_info))
1017
0
  {
1018
0
  case R_PRU_GNU_DIFF8:
1019
0
    {
1020
0
      x = bfd_get_signed_8 (abfd, reloc_contents);
1021
0
      break;
1022
0
    }
1023
0
  case R_PRU_GNU_DIFF16:
1024
0
    {
1025
0
      x = bfd_get_signed_16 (abfd, reloc_contents);
1026
0
      break;
1027
0
    }
1028
0
  case R_PRU_GNU_DIFF32:
1029
0
    {
1030
0
      x = bfd_get_signed_32 (abfd, reloc_contents);
1031
0
      break;
1032
0
    }
1033
0
  case R_PRU_GNU_DIFF16_PMEM:
1034
0
    {
1035
0
      x = bfd_get_signed_16 (abfd, reloc_contents) * 4;
1036
0
      break;
1037
0
    }
1038
0
  case R_PRU_GNU_DIFF32_PMEM:
1039
0
    {
1040
0
      x = bfd_get_signed_32 (abfd, reloc_contents) * 4;
1041
0
      break;
1042
0
    }
1043
0
  default:
1044
0
    {
1045
0
      BFD_FAIL ();
1046
0
    }
1047
0
  }
1048
1049
  /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
1050
     into the object file at the reloc offset.  sym2's logical value is
1051
     symval (<start_of_section>) + reloc addend.  Compute the start and end
1052
     addresses and check if the shrinked insn falls between sym1 and sym2.  */
1053
1054
0
  bfd_vma end_address = symval + irel->r_addend;
1055
0
  bfd_vma start_address = end_address - x;
1056
1057
  /* Shrink the absolute DIFF value (get the to labels "closer"
1058
     together), because we have removed data between labels.  */
1059
0
  if (x < 0)
1060
0
    {
1061
0
      x += count;
1062
      /* In case the signed x is negative, restore order.  */
1063
0
      SWAP_VALS (end_address, start_address);
1064
0
    }
1065
0
  else
1066
0
    {
1067
0
      x -= count;
1068
0
    }
1069
1070
  /* Reduce the diff value by count bytes and write it back into section
1071
    contents.  */
1072
1073
0
  if (shrinked_insn_address >= start_address
1074
0
      && shrinked_insn_address <= end_address)
1075
0
  {
1076
0
    switch (ELF32_R_TYPE (irel->r_info))
1077
0
    {
1078
0
    case R_PRU_GNU_DIFF8:
1079
0
      {
1080
0
  bfd_put_signed_8 (abfd, x & 0xFF, reloc_contents);
1081
0
  break;
1082
0
      }
1083
0
    case R_PRU_GNU_DIFF16:
1084
0
      {
1085
0
  bfd_put_signed_16 (abfd, x & 0xFFFF, reloc_contents);
1086
0
  break;
1087
0
      }
1088
0
    case R_PRU_GNU_DIFF32:
1089
0
      {
1090
0
  bfd_put_signed_32 (abfd, x & 0xFFFFFFFF, reloc_contents);
1091
0
  break;
1092
0
      }
1093
0
    case R_PRU_GNU_DIFF16_PMEM:
1094
0
      {
1095
0
  bfd_put_signed_16 (abfd, (x / 4) & 0xFFFF, reloc_contents);
1096
0
  break;
1097
0
      }
1098
0
    case R_PRU_GNU_DIFF32_PMEM:
1099
0
      {
1100
0
  bfd_put_signed_32 (abfd, (x / 4) & 0xFFFFFFFF, reloc_contents);
1101
0
  break;
1102
0
      }
1103
0
    default:
1104
0
      {
1105
0
  BFD_FAIL ();
1106
0
      }
1107
0
    }
1108
1109
0
  }
1110
0
}
1111
1112
/* Delete some bytes from a section while changing the size of an instruction.
1113
   The parameter "addr" denotes the section-relative offset pointing just
1114
   behind the shrinked instruction. "addr+count" point at the first
1115
   byte just behind the original unshrinked instruction.
1116
1117
   Idea copied from the AVR port.  */
1118
1119
static bool
1120
pru_elf_relax_delete_bytes (bfd *abfd,
1121
          asection *sec,
1122
          bfd_vma addr,
1123
          int count)
1124
0
{
1125
0
  Elf_Internal_Shdr *symtab_hdr;
1126
0
  unsigned int sec_shndx;
1127
0
  bfd_byte *contents;
1128
0
  Elf_Internal_Rela *irel, *irelend;
1129
0
  Elf_Internal_Sym *isym;
1130
0
  Elf_Internal_Sym *isymbuf = NULL;
1131
0
  bfd_vma toaddr;
1132
0
  struct elf_link_hash_entry **sym_hashes;
1133
0
  struct elf_link_hash_entry **end_hashes;
1134
0
  unsigned int symcount;
1135
1136
0
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1137
0
  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
1138
0
  contents = elf_section_data (sec)->this_hdr.contents;
1139
1140
0
  toaddr = sec->size;
1141
1142
0
  irel = elf_section_data (sec)->relocs;
1143
0
  irelend = irel + sec->reloc_count;
1144
1145
  /* Actually delete the bytes.  */
1146
0
  if (toaddr - addr - count > 0)
1147
0
    memmove (contents + addr, contents + addr + count,
1148
0
       (size_t) (toaddr - addr - count));
1149
0
  sec->size -= count;
1150
1151
  /* Adjust all the reloc addresses.  */
1152
0
  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
1153
0
    {
1154
0
      bfd_vma old_reloc_address;
1155
1156
0
      old_reloc_address = (sec->output_section->vma
1157
0
         + sec->output_offset + irel->r_offset);
1158
1159
      /* Get the new reloc address.  */
1160
0
      if ((irel->r_offset > addr
1161
0
     && irel->r_offset < toaddr))
1162
0
  {
1163
0
    if (debug_relax)
1164
0
      printf ("Relocation at address 0x%x needs to be moved.\n"
1165
0
        "Old section offset: 0x%x, New section offset: 0x%x \n",
1166
0
        (unsigned int) old_reloc_address,
1167
0
        (unsigned int) irel->r_offset,
1168
0
        (unsigned int) ((irel->r_offset) - count));
1169
1170
0
    irel->r_offset -= count;
1171
0
  }
1172
1173
0
    }
1174
1175
   /* The reloc's own addresses are now ok.  However, we need to readjust
1176
      the reloc's addend, i.e. the reloc's value if two conditions are met:
1177
      1.) the reloc is relative to a symbol in this section that
1178
    is located in front of the shrinked instruction
1179
      2.) symbol plus addend end up behind the shrinked instruction.
1180
1181
      The most common case where this happens are relocs relative to
1182
      the section-start symbol.
1183
1184
      This step needs to be done for all of the sections of the bfd.  */
1185
1186
0
  {
1187
0
    struct bfd_section *isec;
1188
1189
0
    for (isec = abfd->sections; isec; isec = isec->next)
1190
0
     {
1191
0
       bfd_vma symval;
1192
0
       bfd_vma shrinked_insn_address;
1193
1194
0
       if (isec->reloc_count == 0)
1195
0
   continue;
1196
1197
0
       shrinked_insn_address = (sec->output_section->vma
1198
0
        + sec->output_offset + addr);
1199
1200
0
       irel = elf_section_data (isec)->relocs;
1201
       /* PR 12161: Read in the relocs for this section if necessary.  */
1202
0
       if (irel == NULL)
1203
0
   irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, true);
1204
1205
0
       for (irelend = irel + isec->reloc_count;
1206
0
      irel < irelend;
1207
0
      irel++)
1208
0
   {
1209
     /* Read this BFD's local symbols if we haven't done
1210
        so already.  */
1211
0
     if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1212
0
       {
1213
0
         isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1214
0
         if (isymbuf == NULL)
1215
0
     isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1216
0
             symtab_hdr->sh_info, 0,
1217
0
             NULL, NULL, NULL);
1218
0
         if (isymbuf == NULL)
1219
0
     return false;
1220
0
       }
1221
1222
     /* Get the value of the symbol referred to by the reloc.  */
1223
0
     if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1224
0
       {
1225
         /* A local symbol.  */
1226
0
         asection *sym_sec;
1227
1228
0
         isym = isymbuf + ELF32_R_SYM (irel->r_info);
1229
0
         sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1230
0
         symval = isym->st_value;
1231
         /* If the reloc is absolute, it will not have
1232
      a symbol or section associated with it.  */
1233
0
         if (sym_sec == sec)
1234
0
     {
1235
0
       symval += sym_sec->output_section->vma
1236
0
         + sym_sec->output_offset;
1237
1238
0
       if (debug_relax)
1239
0
         printf ("Checking if the relocation's "
1240
0
           "addend needs corrections.\n"
1241
0
           "Address of anchor symbol: 0x%x \n"
1242
0
           "Address of relocation target: 0x%x \n"
1243
0
           "Address of relaxed insn: 0x%x \n",
1244
0
           (unsigned int) symval,
1245
0
           (unsigned int) (symval + irel->r_addend),
1246
0
           (unsigned int) shrinked_insn_address);
1247
1248
       /* Shrink the special DIFF relocations.  */
1249
0
       if (elf32_pru_is_diff_reloc (irel))
1250
0
         {
1251
0
           elf32_pru_adjust_diff_reloc_value (abfd, isec, irel,
1252
0
                symval,
1253
0
                shrinked_insn_address,
1254
0
                count);
1255
0
         }
1256
1257
       /* Fix the addend, if it is affected.  */
1258
0
       if (symval <= shrinked_insn_address
1259
0
           && (symval + irel->r_addend) > shrinked_insn_address)
1260
0
         {
1261
1262
0
           irel->r_addend -= count;
1263
1264
0
           if (debug_relax)
1265
0
       printf ("Relocation's addend needed to be fixed \n");
1266
0
         }
1267
0
     }
1268
         /* else...Reference symbol is absolute.
1269
      No adjustment needed.  */
1270
0
       }
1271
     /* else...Reference symbol is extern.  No need for adjusting
1272
        the addend.  */
1273
0
   }
1274
0
     }
1275
0
  }
1276
1277
  /* Adjust the local symbols defined in this section.  */
1278
0
  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
1279
  /* Fix PR 9841, there may be no local symbols.  */
1280
0
  if (isym != NULL)
1281
0
    {
1282
0
      Elf_Internal_Sym *isymend;
1283
1284
0
      isymend = isym + symtab_hdr->sh_info;
1285
0
      for (; isym < isymend; isym++)
1286
0
  {
1287
0
    if (isym->st_shndx == sec_shndx)
1288
0
      {
1289
0
        if (isym->st_value > addr
1290
0
      && isym->st_value <= toaddr)
1291
0
    isym->st_value -= count;
1292
1293
0
        if (isym->st_value <= addr
1294
0
      && isym->st_value + isym->st_size > addr)
1295
0
    {
1296
      /* If this assert fires then we have a symbol that ends
1297
         part way through an instruction.  Does that make
1298
         sense?  */
1299
0
      BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
1300
0
      isym->st_size -= count;
1301
0
    }
1302
0
      }
1303
0
  }
1304
0
    }
1305
1306
  /* Now adjust the global symbols defined in this section.  */
1307
0
  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
1308
0
        - symtab_hdr->sh_info);
1309
0
  sym_hashes = elf_sym_hashes (abfd);
1310
0
  end_hashes = sym_hashes + symcount;
1311
0
  for (; sym_hashes < end_hashes; sym_hashes++)
1312
0
    {
1313
0
      struct elf_link_hash_entry *sym_hash = *sym_hashes;
1314
0
      if ((sym_hash->root.type == bfd_link_hash_defined
1315
0
     || sym_hash->root.type == bfd_link_hash_defweak)
1316
0
    && sym_hash->root.u.def.section == sec)
1317
0
  {
1318
0
    if (sym_hash->root.u.def.value > addr
1319
0
        && sym_hash->root.u.def.value <= toaddr)
1320
0
      sym_hash->root.u.def.value -= count;
1321
1322
0
    if (sym_hash->root.u.def.value <= addr
1323
0
        && (sym_hash->root.u.def.value + sym_hash->size > addr))
1324
0
      {
1325
        /* If this assert fires then we have a symbol that ends
1326
     part way through an instruction.  Does that make
1327
     sense?  */
1328
0
        BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size
1329
0
        >= addr + count);
1330
0
        sym_hash->size -= count;
1331
0
      }
1332
0
  }
1333
0
    }
1334
1335
0
  return true;
1336
0
}
1337
1338
static bool
1339
pru_elf32_relax_section (bfd *abfd, asection *sec,
1340
       struct bfd_link_info *link_info,
1341
       bool *again)
1342
0
{
1343
0
  Elf_Internal_Shdr * symtab_hdr;
1344
0
  Elf_Internal_Rela * internal_relocs;
1345
0
  Elf_Internal_Rela * irel;
1346
0
  Elf_Internal_Rela * irelend;
1347
0
  bfd_byte *        contents = NULL;
1348
0
  Elf_Internal_Sym *  isymbuf = NULL;
1349
1350
  /* Assume nothing changes.  */
1351
0
  *again = false;
1352
1353
  /* We don't have to do anything for a relocatable link, if
1354
     this section does not have relocs, or if this is not a
1355
     code section.  */
1356
0
  if (bfd_link_relocatable (link_info)
1357
0
      || sec->reloc_count == 0
1358
0
      || (sec->flags & SEC_RELOC) == 0
1359
0
      || (sec->flags & SEC_HAS_CONTENTS) == 0
1360
0
      || (sec->flags & SEC_CODE) == 0)
1361
0
    return true;
1362
1363
0
  symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
1364
1365
  /* Get a copy of the native relocations.  */
1366
0
  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
1367
0
                 link_info->keep_memory);
1368
0
  if (internal_relocs == NULL)
1369
0
    goto error_return;
1370
1371
  /* Walk through them looking for relaxing opportunities.  */
1372
0
  irelend = internal_relocs + sec->reloc_count;
1373
1374
0
  for (irel = internal_relocs; irel < irelend; irel++)
1375
0
    {
1376
0
      bfd_vma symval;
1377
1378
      /* Get the section contents if we haven't done so already.  */
1379
0
      if (contents == NULL)
1380
0
  {
1381
    /* Get cached copy if it exists.  */
1382
0
    if (elf_section_data (sec)->this_hdr.contents != NULL)
1383
0
      contents = elf_section_data (sec)->this_hdr.contents;
1384
0
    else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
1385
0
      goto error_return;
1386
0
  }
1387
1388
      /* Read this BFD's local symbols if we haven't done so already.  */
1389
0
      if (isymbuf == NULL && symtab_hdr->sh_info != 0)
1390
0
  {
1391
0
    isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1392
0
    if (isymbuf == NULL)
1393
0
      isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1394
0
              symtab_hdr->sh_info, 0,
1395
0
              NULL, NULL, NULL);
1396
0
    if (isymbuf == NULL)
1397
0
      goto error_return;
1398
0
  }
1399
1400
      /* Get the value of the symbol referred to by the reloc.  */
1401
0
      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
1402
0
  {
1403
    /* A local symbol.  */
1404
0
    Elf_Internal_Sym *isym;
1405
0
    asection *sym_sec;
1406
1407
0
    isym = isymbuf + ELF32_R_SYM (irel->r_info);
1408
0
    if (isym->st_shndx == SHN_UNDEF)
1409
0
      sym_sec = bfd_und_section_ptr;
1410
0
    else if (isym->st_shndx == SHN_ABS)
1411
0
      sym_sec = bfd_abs_section_ptr;
1412
0
    else if (isym->st_shndx == SHN_COMMON)
1413
0
      sym_sec = bfd_com_section_ptr;
1414
0
    else
1415
0
      sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
1416
0
    symval = (isym->st_value
1417
0
        + sym_sec->output_section->vma + sym_sec->output_offset);
1418
0
  }
1419
0
      else
1420
0
  {
1421
0
    unsigned long indx;
1422
0
    struct elf_link_hash_entry *h;
1423
1424
    /* An external symbol.  */
1425
0
    indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
1426
0
    h = elf_sym_hashes (abfd)[indx];
1427
0
    BFD_ASSERT (h != NULL);
1428
1429
0
    if (h->root.type != bfd_link_hash_defined
1430
0
        && h->root.type != bfd_link_hash_defweak)
1431
      /* This appears to be a reference to an undefined
1432
         symbol.  Just ignore it--it will be caught by the
1433
         regular reloc processing.  */
1434
0
      continue;
1435
1436
0
    symval = (h->root.u.def.value
1437
0
        + h->root.u.def.section->output_section->vma
1438
0
        + h->root.u.def.section->output_offset);
1439
0
  }
1440
1441
      /* For simplicity of coding, we are going to modify the section
1442
   contents, the section relocs, and the BFD symbol table.  We
1443
   must tell the rest of the code not to free up this
1444
   information.  It would be possible to instead create a table
1445
   of changes which have to be made, as is done in coff-mips.c;
1446
   that would be more work, but would require less memory when
1447
   the linker is run.  */
1448
1449
      /* Check if we can remove an LDI instruction from the LDI32
1450
   pseudo instruction if the upper 16 operand bits are zero.  */
1451
0
      if (ELF32_R_TYPE (irel->r_info) == (int) R_PRU_LDI32)
1452
0
  {
1453
0
    bfd_vma value = symval + irel->r_addend;
1454
1455
0
    if (debug_relax)
1456
0
      printf ("R_PRU_LDI32 with value=0x%lx\n", (long) value);
1457
1458
0
    if ((long) value >> 16 == 0)
1459
0
      {
1460
0
        unsigned long insn;
1461
1462
        /* Note that we've changed the relocs, section contents.  */
1463
0
        elf_section_data (sec)->relocs = internal_relocs;
1464
0
        elf_section_data (sec)->this_hdr.contents = contents;
1465
0
        symtab_hdr->contents = (unsigned char *) isymbuf;
1466
1467
        /* Make the second instruction load the 16-bit constant
1468
     into the full 32-bit register.  */
1469
0
        insn = bfd_get_32 (abfd, contents + irel->r_offset + 4);
1470
1471
        /* Old GAS and LD versions have a bug, where the two
1472
     LDI instructions are swapped.  Detect such object
1473
     files and bail.  */
1474
0
        if (GET_INSN_FIELD (RDSEL, insn) != RSEL_15_0)
1475
0
    {
1476
      /* xgettext:c-format */
1477
0
      _bfd_error_handler (_("error: %pB: old incompatible object file detected"),
1478
0
              abfd);
1479
0
      goto error_return;
1480
0
    }
1481
1482
0
        SET_INSN_FIELD (RDSEL, insn, RSEL_31_0);
1483
0
        bfd_put_32 (abfd, insn, contents + irel->r_offset + 4);
1484
1485
        /* Delete the first LDI instruction.  Note that there should
1486
     be no relocations or symbols pointing to the second LDI
1487
     instruction.  */
1488
0
        if (!pru_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 4))
1489
0
    goto error_return;
1490
1491
        /* We're done with deletion of the first instruction.
1492
     Set a regular LDI relocation for the second instruction
1493
     we left to load the 16-bit value into the 32-bit
1494
     register.  */
1495
0
        irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1496
0
             R_PRU_U16);
1497
1498
        /* That will change things, so, we should relax again.
1499
     Note that this is not required, and it may be slow.  */
1500
0
        *again = true;
1501
0
      }
1502
0
  }
1503
0
    }
1504
1505
0
  if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
1506
0
    {
1507
0
      if (!link_info->keep_memory)
1508
0
  free (isymbuf);
1509
0
      else
1510
0
  {
1511
    /* Cache the symbols for elf_link_input_bfd.  */
1512
0
    symtab_hdr->contents = (unsigned char *) isymbuf;
1513
0
  }
1514
0
    }
1515
1516
0
  if (contents != NULL
1517
0
      && elf_section_data (sec)->this_hdr.contents != contents)
1518
0
    {
1519
0
      if (!link_info->keep_memory)
1520
0
  free (contents);
1521
0
      else
1522
0
  {
1523
    /* Cache the section contents for elf_link_input_bfd.  */
1524
0
    elf_section_data (sec)->this_hdr.contents = contents;
1525
0
  }
1526
0
    }
1527
1528
0
  if (elf_section_data (sec)->relocs != internal_relocs)
1529
0
    free (internal_relocs);
1530
1531
0
  return true;
1532
1533
0
 error_return:
1534
0
  if (symtab_hdr->contents != (unsigned char *) isymbuf)
1535
0
    free (isymbuf);
1536
0
  if (elf_section_data (sec)->this_hdr.contents != contents)
1537
0
    free (contents);
1538
0
  if (elf_section_data (sec)->relocs != internal_relocs)
1539
0
    free (internal_relocs);
1540
1541
0
  return false;
1542
0
}
1543
1544
/* Free the derived linker hash table.  */
1545
static void
1546
pru_elf32_link_hash_table_free (bfd *obfd)
1547
0
{
1548
0
  _bfd_elf_link_hash_table_free (obfd);
1549
0
}
1550
1551
/* Implement bfd_elf32_bfd_link_hash_table_create.  */
1552
static struct bfd_link_hash_table *
1553
pru_elf32_link_hash_table_create (bfd *abfd)
1554
0
{
1555
0
  struct elf_link_hash_table *ret;
1556
0
  size_t amt = sizeof (struct elf_link_hash_table);
1557
1558
0
  ret = bfd_zmalloc (amt);
1559
0
  if (ret == NULL)
1560
0
    return NULL;
1561
1562
0
  if (!_bfd_elf_link_hash_table_init (ret, abfd, link_hash_newfunc,
1563
0
              sizeof (struct elf_link_hash_entry)))
1564
0
    {
1565
0
      free (ret);
1566
0
      return NULL;
1567
0
    }
1568
1569
0
  ret->root.hash_table_free = pru_elf32_link_hash_table_free;
1570
1571
0
  return &ret->root;
1572
0
}
1573
1574
#define ELF_ARCH      bfd_arch_pru
1575
#define ELF_TARGET_ID     PRU_ELF_DATA
1576
#define ELF_MACHINE_CODE    EM_TI_PRU
1577
1578
#define ELF_MAXPAGESIZE     1
1579
1580
#define bfd_elf32_bfd_link_hash_table_create \
1581
            pru_elf32_link_hash_table_create
1582
1583
/* Relocation table lookup macros.  */
1584
1585
#define bfd_elf32_bfd_reloc_type_lookup   pru_elf32_bfd_reloc_type_lookup
1586
#define bfd_elf32_bfd_reloc_name_lookup   pru_elf32_bfd_reloc_name_lookup
1587
1588
#define elf_info_to_howto   pru_elf32_info_to_howto
1589
#define elf_info_to_howto_rel   NULL
1590
1591
/* elf backend functions.  */
1592
1593
/* TI folks like to use a mix of REL and RELA relocations.  See also
1594
   the MSP430 and TI C6X backends.  */
1595
#define elf_backend_may_use_rel_p  1
1596
#define elf_backend_may_use_rela_p 1
1597
#define elf_backend_default_use_rela_p 1
1598
1599
#define elf_backend_rela_normal   1
1600
1601
#define elf_backend_relocate_section  pru_elf32_relocate_section
1602
#define bfd_elf32_bfd_relax_section pru_elf32_relax_section
1603
#define elf_backend_can_gc_sections 1
1604
1605
#define elf_backend_default_execstack 0
1606
1607
#define TARGET_LITTLE_SYM   pru_elf32_vec
1608
#define TARGET_LITTLE_NAME    "elf32-pru"
1609
1610
#include "elf32-target.h"