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-fr30.c
Line
Count
Source
1
/* FR30-specific support for 32-bit ELF.
2
   Copyright (C) 1998-2026 Free Software Foundation, Inc.
3
4
   This file is part of BFD, the Binary File Descriptor library.
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19
   MA 02110-1301, USA.  */
20
21
#include "sysdep.h"
22
#include "bfd.h"
23
#include "libbfd.h"
24
#include "elf-bfd.h"
25
#include "elf/fr30.h"
26
27
/* Forward declarations.  */
28
static bfd_reloc_status_type
29
fr30_elf_i20_reloc (bfd *, arelent *, asymbol *, void * data,
30
        asection *, bfd *, char **error_message);
31
static bfd_reloc_status_type
32
fr30_elf_i32_reloc (bfd *, arelent *, asymbol *, void *,
33
        asection *, bfd *, char **);
34
35
static reloc_howto_type fr30_elf_howto_table [] =
36
{
37
  /* This reloc does nothing.  */
38
  HOWTO (R_FR30_NONE,   /* type */
39
   0,     /* rightshift */
40
   0,     /* size */
41
   0,     /* bitsize */
42
   false,     /* pc_relative */
43
   0,     /* bitpos */
44
   complain_overflow_dont, /* complain_on_overflow */
45
   bfd_elf_generic_reloc, /* special_function */
46
   "R_FR30_NONE",   /* name */
47
   false,     /* partial_inplace */
48
   0,     /* src_mask */
49
   0,     /* dst_mask */
50
   false),    /* pcrel_offset */
51
52
  /* An 8 bit absolute relocation.  */
53
  HOWTO (R_FR30_8,    /* type */
54
   0,     /* rightshift */
55
   2,     /* size */
56
   8,     /* bitsize */
57
   false,     /* pc_relative */
58
   4,     /* bitpos */
59
   complain_overflow_bitfield, /* complain_on_overflow */
60
   bfd_elf_generic_reloc, /* special_function */
61
   "R_FR30_8",    /* name */
62
   false,     /* partial_inplace */
63
   0x0000,    /* src_mask */
64
   0x0ff0,    /* dst_mask */
65
   false),    /* pcrel_offset */
66
67
  /* A 20 bit absolute relocation.  */
68
  HOWTO (R_FR30_20,   /* type */
69
   0,     /* rightshift */
70
   4,     /* size */
71
   20,      /* bitsize */
72
   false,     /* pc_relative */
73
   0,     /* bitpos */
74
   complain_overflow_bitfield, /* complain_on_overflow */
75
   fr30_elf_i20_reloc,  /* special_function */
76
   "R_FR30_20",   /* name */
77
   false,     /* partial_inplace */
78
   0x00000000,    /* src_mask */
79
   0x00f0ffff,    /* dst_mask */
80
   false),    /* pcrel_offset */
81
82
  /* A 32 bit absolute relocation.  */
83
  HOWTO (R_FR30_32,   /* type */
84
   0,     /* rightshift */
85
   4,     /* size */
86
   32,      /* bitsize */
87
   false,     /* pc_relative */
88
   0,     /* bitpos */
89
   complain_overflow_bitfield, /* complain_on_overflow */
90
   bfd_elf_generic_reloc, /* special_function */
91
   "R_FR30_32",   /* name */
92
   false,     /* partial_inplace */
93
   0x00000000,    /* src_mask */
94
   0xffffffff,    /* dst_mask */
95
   false),    /* pcrel_offset */
96
97
  /* A 32 bit into 48 bits absolute relocation.  */
98
  HOWTO (R_FR30_48,   /* type */
99
   0,     /* rightshift */
100
   4,     /* size */
101
   32,      /* bitsize */
102
   false,     /* pc_relative */
103
   0,     /* bitpos */
104
   complain_overflow_bitfield, /* complain_on_overflow */
105
   fr30_elf_i32_reloc,  /* special_function */
106
   "R_FR30_48",   /* name */
107
   false,     /* partial_inplace */
108
   0x00000000,    /* src_mask */
109
   0xffffffff,    /* dst_mask */
110
   false),    /* pcrel_offset */
111
112
  /* A 6 bit absolute relocation.  */
113
  HOWTO (R_FR30_6_IN_4,   /* type */
114
   2,     /* rightshift */
115
   2,     /* size */
116
   6,     /* bitsize */
117
   false,     /* pc_relative */
118
   4,     /* bitpos */
119
   complain_overflow_unsigned, /* complain_on_overflow */
120
   bfd_elf_generic_reloc, /* special_function */
121
   "R_FR30_6_IN_4", /* name */
122
   false,     /* partial_inplace */
123
   0x0000,    /* src_mask */
124
   0x00f0,    /* dst_mask */
125
   false),    /* pcrel_offset */
126
127
  /* An 8 bit absolute relocation.  */
128
  HOWTO (R_FR30_8_IN_8,   /* type */
129
   0,     /* rightshift */
130
   2,     /* size */
131
   8,     /* bitsize */
132
   false,     /* pc_relative */
133
   4,     /* bitpos */
134
   complain_overflow_signed, /* complain_on_overflow */
135
   bfd_elf_generic_reloc,/* special_function */
136
   "R_FR30_8_IN_8", /* name */
137
   false,     /* partial_inplace */
138
   0x0000,    /* src_mask */
139
   0x0ff0,    /* dst_mask */
140
   false),    /* pcrel_offset */
141
142
  /* A 9 bit absolute relocation.  */
143
  HOWTO (R_FR30_9_IN_8,   /* type */
144
   1,     /* rightshift */
145
   2,     /* size */
146
   9,     /* bitsize */
147
   false,     /* pc_relative */
148
   4,     /* bitpos */
149
   complain_overflow_signed, /* complain_on_overflow */
150
   bfd_elf_generic_reloc,/* special_function */
151
   "R_FR30_9_IN_8", /* name */
152
   false,     /* partial_inplace */
153
   0x0000,    /* src_mask */
154
   0x0ff0,    /* dst_mask */
155
   false),    /* pcrel_offset */
156
157
  /* A 10 bit absolute relocation.  */
158
  HOWTO (R_FR30_10_IN_8,  /* type */
159
   2,     /* rightshift */
160
   2,     /* size */
161
   10,      /* bitsize */
162
   false,     /* pc_relative */
163
   4,     /* bitpos */
164
   complain_overflow_signed, /* complain_on_overflow */
165
   bfd_elf_generic_reloc,/* special_function */
166
   "R_FR30_10_IN_8",  /* name */
167
   false,     /* partial_inplace */
168
   0x0000,    /* src_mask */
169
   0x0ff0,    /* dst_mask */
170
   false),    /* pcrel_offset */
171
172
  /* A PC relative 9 bit relocation, right shifted by 1.  */
173
  HOWTO (R_FR30_9_PCREL,  /* type */
174
   1,     /* rightshift */
175
   2,     /* size */
176
   9,     /* bitsize */
177
   true,      /* pc_relative */
178
   0,     /* bitpos */
179
   complain_overflow_signed, /* complain_on_overflow */
180
   bfd_elf_generic_reloc, /* special_function */
181
   "R_FR30_9_PCREL",  /* name */
182
   false,     /* partial_inplace */
183
   0x0000,    /* src_mask */
184
   0x00ff,    /* dst_mask */
185
   false),    /* pcrel_offset */
186
187
  /* A PC relative 12 bit relocation, right shifted by 1.  */
188
  HOWTO (R_FR30_12_PCREL, /* type */
189
   1,     /* rightshift */
190
   2,     /* size */
191
   12,      /* bitsize */
192
   true,      /* pc_relative */
193
   0,     /* bitpos */
194
   complain_overflow_signed, /* complain_on_overflow */
195
   bfd_elf_generic_reloc, /* special_function */
196
   "R_FR30_12_PCREL", /* name */
197
   false,     /* partial_inplace */
198
   0x0000,    /* src_mask */
199
   0x07ff,    /* dst_mask */
200
   false),    /* pcrel_offset */
201
  /* GNU extension to record C++ vtable hierarchy */
202
  HOWTO (R_FR30_GNU_VTINHERIT, /* type */
203
   0,     /* rightshift */
204
   4,     /* size */
205
   0,     /* bitsize */
206
   false,     /* pc_relative */
207
   0,     /* bitpos */
208
   complain_overflow_dont, /* complain_on_overflow */
209
   NULL,      /* special_function */
210
   "R_FR30_GNU_VTINHERIT", /* name */
211
   false,     /* partial_inplace */
212
   0,     /* src_mask */
213
   0,     /* dst_mask */
214
   false),    /* pcrel_offset */
215
216
  /* GNU extension to record C++ vtable member usage */
217
  HOWTO (R_FR30_GNU_VTENTRY,   /* type */
218
   0,     /* rightshift */
219
   4,     /* size */
220
   0,     /* bitsize */
221
   false,     /* pc_relative */
222
   0,     /* bitpos */
223
   complain_overflow_dont, /* complain_on_overflow */
224
   _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
225
   "R_FR30_GNU_VTENTRY",   /* name */
226
   false,     /* partial_inplace */
227
   0,     /* src_mask */
228
   0,     /* dst_mask */
229
   false),    /* pcrel_offset */
230
};
231

232
/* Utility to actually perform an R_FR30_20 reloc.  */
233
234
static bfd_reloc_status_type
235
fr30_elf_i20_reloc (bfd *abfd,
236
        arelent *reloc_entry,
237
        asymbol *symbol,
238
        void * data,
239
        asection *input_section,
240
        bfd *output_bfd,
241
        char **error_message)
242
0
{
243
0
  bfd_vma relocation;
244
0
  unsigned long x;
245
246
0
  if (output_bfd != NULL)
247
0
    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
248
0
          input_section, output_bfd, error_message);
249
250
0
  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
251
0
          input_section, reloc_entry->address))
252
0
    return bfd_reloc_outofrange;
253
254
0
  relocation =
255
0
    symbol->value
256
0
    + symbol->section->output_section->vma
257
0
    + symbol->section->output_offset
258
0
    + reloc_entry->addend;
259
260
0
  if (relocation > (((bfd_vma) 1 << 20) - 1))
261
0
    return bfd_reloc_overflow;
262
263
0
  x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
264
0
  x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
265
0
  bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
266
267
0
  return bfd_reloc_ok;
268
0
}
269

270
/* Utility to actually perform a R_FR30_48 reloc.  */
271
272
static bfd_reloc_status_type
273
fr30_elf_i32_reloc (bfd *abfd,
274
        arelent *reloc_entry,
275
        asymbol *symbol,
276
        void * data,
277
        asection *input_section,
278
        bfd *output_bfd,
279
        char **error_message)
280
0
{
281
0
  bfd_vma relocation;
282
283
0
  if (output_bfd != NULL)
284
0
    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
285
0
          input_section, output_bfd, error_message);
286
287
0
  if (reloc_entry->address + 2 < 2
288
0
      || !bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
289
0
             input_section, reloc_entry->address + 2))
290
0
    return bfd_reloc_outofrange;
291
292
0
  relocation =
293
0
    symbol->value
294
0
    + symbol->section->output_section->vma
295
0
    + symbol->section->output_offset
296
0
    + reloc_entry->addend;
297
298
0
  bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
299
300
0
  return bfd_reloc_ok;
301
0
}
302

303
/* Map BFD reloc types to FR30 ELF reloc types.  */
304
305
struct fr30_reloc_map
306
{
307
  bfd_reloc_code_real_type bfd_reloc_val;
308
  unsigned int fr30_reloc_val;
309
};
310
311
static const struct fr30_reloc_map fr30_reloc_map [] =
312
{
313
  { BFD_RELOC_NONE,       R_FR30_NONE },
314
  { BFD_RELOC_8,        R_FR30_8 },
315
  { BFD_RELOC_FR30_20,        R_FR30_20 },
316
  { BFD_RELOC_32,       R_FR30_32 },
317
  { BFD_RELOC_FR30_48,        R_FR30_48 },
318
  { BFD_RELOC_FR30_6_IN_4,    R_FR30_6_IN_4 },
319
  { BFD_RELOC_FR30_8_IN_8,    R_FR30_8_IN_8 },
320
  { BFD_RELOC_FR30_9_IN_8,    R_FR30_9_IN_8 },
321
  { BFD_RELOC_FR30_10_IN_8,   R_FR30_10_IN_8 },
322
  { BFD_RELOC_FR30_9_PCREL,   R_FR30_9_PCREL },
323
  { BFD_RELOC_FR30_12_PCREL,  R_FR30_12_PCREL },
324
  { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
325
  { BFD_RELOC_VTABLE_ENTRY,   R_FR30_GNU_VTENTRY },
326
};
327
328
static reloc_howto_type *
329
fr30_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
330
      bfd_reloc_code_real_type code)
331
0
{
332
0
  unsigned int i;
333
334
0
  for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
335
0
       i--;)
336
0
    if (fr30_reloc_map [i].bfd_reloc_val == code)
337
0
      return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
338
339
0
  return NULL;
340
0
}
341
342
static reloc_howto_type *
343
fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
344
0
{
345
0
  unsigned int i;
346
347
0
  for (i = 0;
348
0
       i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
349
0
       i++)
350
0
    if (fr30_elf_howto_table[i].name != NULL
351
0
  && strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0)
352
0
      return &fr30_elf_howto_table[i];
353
354
0
  return NULL;
355
0
}
356
357
/* Set the howto pointer for an FR30 ELF reloc.  */
358
359
static bool
360
fr30_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
361
       arelent *cache_ptr,
362
       Elf_Internal_Rela *dst)
363
25
{
364
25
  unsigned int r_type;
365
366
25
  r_type = ELF32_R_TYPE (dst->r_info);
367
25
  if (r_type >= (unsigned int) R_FR30_max)
368
3
    {
369
      /* xgettext:c-format */
370
3
      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
371
3
        abfd, r_type);
372
3
      bfd_set_error (bfd_error_bad_value);
373
3
      return false;
374
3
    }
375
22
  cache_ptr->howto = & fr30_elf_howto_table [r_type];
376
22
  return true;
377
25
}
378

379
/* Perform a single relocation.  By default we use the standard BFD
380
   routines, but a few relocs, we have to do them ourselves.  */
381
382
static bfd_reloc_status_type
383
fr30_final_link_relocate (reloc_howto_type *howto,
384
        bfd *input_bfd,
385
        asection *input_section,
386
        bfd_byte *contents,
387
        Elf_Internal_Rela *rel,
388
        bfd_vma relocation)
389
0
{
390
0
  bfd_reloc_status_type r = bfd_reloc_ok;
391
0
  bfd_vma x;
392
0
  bfd_signed_vma srel;
393
394
0
  switch (howto->type)
395
0
    {
396
0
    case R_FR30_20:
397
0
      contents   += rel->r_offset;
398
0
      relocation += rel->r_addend;
399
400
0
      if (relocation > ((1 << 20) - 1))
401
0
  return bfd_reloc_overflow;
402
403
0
      x = bfd_get_32 (input_bfd, contents);
404
0
      x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
405
0
      bfd_put_32 (input_bfd, x, contents);
406
0
      break;
407
408
0
    case R_FR30_48:
409
0
      contents   += rel->r_offset + 2;
410
0
      relocation += rel->r_addend;
411
0
      bfd_put_32 (input_bfd, relocation, contents);
412
0
      break;
413
414
0
    case R_FR30_9_PCREL:
415
0
      contents   += rel->r_offset + 1;
416
0
      srel = (bfd_signed_vma) relocation;
417
0
      srel += rel->r_addend;
418
0
      srel -= rel->r_offset;
419
0
      srel -= 2;  /* Branch instructions add 2 to the PC...  */
420
0
      srel -= (input_section->output_section->vma +
421
0
         input_section->output_offset);
422
423
0
      if (srel & 1)
424
0
  return bfd_reloc_outofrange;
425
0
      if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
426
0
  return bfd_reloc_overflow;
427
428
0
      bfd_put_8 (input_bfd, srel >> 1, contents);
429
0
      break;
430
431
0
    case R_FR30_12_PCREL:
432
0
      contents   += rel->r_offset;
433
0
      srel = (bfd_signed_vma) relocation;
434
0
      srel += rel->r_addend;
435
0
      srel -= rel->r_offset;
436
0
      srel -= 2; /* Branch instructions add 2 to the PC...  */
437
0
      srel -= (input_section->output_section->vma +
438
0
         input_section->output_offset);
439
440
0
      if (srel & 1)
441
0
  return bfd_reloc_outofrange;
442
0
      if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
443
0
    return bfd_reloc_overflow;
444
445
0
      x = bfd_get_16 (input_bfd, contents);
446
0
      x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
447
0
      bfd_put_16 (input_bfd, x, contents);
448
0
      break;
449
450
0
    default:
451
0
      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
452
0
            contents, rel->r_offset,
453
0
            relocation, rel->r_addend);
454
0
    }
455
456
0
  return r;
457
0
}
458

459
/* Relocate an FR30 ELF section.
460
461
   The RELOCATE_SECTION function is called by the new ELF backend linker
462
   to handle the relocations for a section.
463
464
   The relocs are always passed as Rela structures; if the section
465
   actually uses Rel structures, the r_addend field will always be
466
   zero.
467
468
   This function is responsible for adjusting the section contents as
469
   necessary, and (if using Rela relocs and generating a relocatable
470
   output file) adjusting the reloc addend as necessary.
471
472
   This function does not have to worry about setting the reloc
473
   address or the reloc symbol index.
474
475
   LOCAL_SYMS is a pointer to the swapped in local symbols.
476
477
   LOCAL_SECTIONS is an array giving the section in the input file
478
   corresponding to the st_shndx field of each local symbol.
479
480
   The global hash table entry for the global symbols can be found
481
   via elf_sym_hashes (input_bfd).
482
483
   When generating relocatable output, this function must handle
484
   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
485
   going to be the section symbol corresponding to the output
486
   section, which means that the addend must be adjusted
487
   accordingly.  */
488
489
static int
490
fr30_elf_relocate_section (struct bfd_link_info *info,
491
         bfd *input_bfd,
492
         asection *input_section,
493
         bfd_byte *contents,
494
         Elf_Internal_Rela *relocs,
495
         Elf_Internal_Sym *local_syms,
496
         asection **local_sections)
497
0
{
498
0
  Elf_Internal_Shdr *symtab_hdr;
499
0
  struct elf_link_hash_entry **sym_hashes;
500
0
  Elf_Internal_Rela *rel;
501
0
  Elf_Internal_Rela *relend;
502
503
0
  symtab_hdr = &elf_symtab_hdr (input_bfd);
504
0
  sym_hashes = elf_sym_hashes (input_bfd);
505
0
  relend     = relocs + input_section->reloc_count;
506
507
0
  for (rel = relocs; rel < relend; rel ++)
508
0
    {
509
0
      reloc_howto_type *howto;
510
0
      unsigned long r_symndx;
511
0
      Elf_Internal_Sym *sym;
512
0
      asection *sec;
513
0
      struct elf_link_hash_entry *h;
514
0
      bfd_vma relocation;
515
0
      bfd_reloc_status_type r;
516
0
      const char *name;
517
0
      int r_type;
518
519
0
      r_type = ELF32_R_TYPE (rel->r_info);
520
521
0
      if (   r_type == R_FR30_GNU_VTINHERIT
522
0
    || r_type == R_FR30_GNU_VTENTRY)
523
0
  continue;
524
525
0
      r_symndx = ELF32_R_SYM (rel->r_info);
526
527
0
      howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
528
0
      h      = NULL;
529
0
      sym    = NULL;
530
0
      sec    = NULL;
531
532
0
      if (r_symndx < symtab_hdr->sh_info)
533
0
  {
534
0
    sym = local_syms + r_symndx;
535
0
    sec = local_sections [r_symndx];
536
0
    relocation = _bfd_elf_rela_local_sym (info->output_bfd,
537
0
            sym, &sec, rel);
538
539
0
    name = bfd_elf_string_from_elf_section
540
0
      (input_bfd, symtab_hdr->sh_link, sym->st_name);
541
0
    name = name == NULL ? bfd_section_name (sec) : name;
542
0
  }
543
0
      else
544
0
  {
545
0
    bool unresolved_reloc, warned, ignored;
546
547
0
    RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
548
0
           r_symndx, symtab_hdr, sym_hashes,
549
0
           h, sec, relocation,
550
0
           unresolved_reloc, warned, ignored);
551
552
0
    name = h->root.root.string;
553
0
  }
554
555
0
      if (sec != NULL && discarded_section (sec))
556
0
  RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
557
0
           rel, 1, relend, R_FR30_NONE,
558
0
           howto, 0, contents);
559
560
0
      if (bfd_link_relocatable (info))
561
0
  continue;
562
563
0
      r = fr30_final_link_relocate (howto, input_bfd, input_section,
564
0
             contents, rel, relocation);
565
566
0
      if (r != bfd_reloc_ok)
567
0
  {
568
0
    const char * msg = (const char *) NULL;
569
570
0
    switch (r)
571
0
      {
572
0
      case bfd_reloc_overflow:
573
0
        (*info->callbacks->reloc_overflow)
574
0
    (info, (h ? &h->root : NULL), name, howto->name,
575
0
     (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
576
0
        break;
577
578
0
      case bfd_reloc_undefined:
579
0
        (*info->callbacks->undefined_symbol)
580
0
    (info, name, input_bfd, input_section, rel->r_offset, true);
581
0
        break;
582
583
0
      case bfd_reloc_outofrange:
584
0
        msg = _("internal error: out of range error");
585
0
        break;
586
587
0
      case bfd_reloc_notsupported:
588
0
        msg = _("internal error: unsupported relocation error");
589
0
        break;
590
591
0
      case bfd_reloc_dangerous:
592
0
        msg = _("internal error: dangerous relocation");
593
0
        break;
594
595
0
      default:
596
0
        msg = _("internal error: unknown error");
597
0
        break;
598
0
      }
599
600
0
    if (msg)
601
0
      (*info->callbacks->warning) (info, msg, name, input_bfd,
602
0
           input_section, rel->r_offset);
603
0
  }
604
0
    }
605
606
0
  return true;
607
0
}
608

609
/* Return the section that should be marked against GC for a given
610
   relocation.  */
611
612
static asection *
613
fr30_elf_gc_mark_hook (asection *sec,
614
           struct bfd_link_info *info,
615
           struct elf_reloc_cookie *cookie,
616
           struct elf_link_hash_entry *h,
617
           unsigned int symndx)
618
0
{
619
0
  if (h != NULL)
620
0
    switch (ELF32_R_TYPE (cookie->rel->r_info))
621
0
      {
622
0
      case R_FR30_GNU_VTINHERIT:
623
0
      case R_FR30_GNU_VTENTRY:
624
0
  return NULL;
625
0
      }
626
627
0
  return _bfd_elf_gc_mark_hook (sec, info, cookie, h, symndx);
628
0
}
629
630
/* Look through the relocs for a section during the first phase.
631
   Since we don't do .gots or .plts, we just need to consider the
632
   virtual table relocs for gc.  */
633
634
static bool
635
fr30_elf_check_relocs (bfd *abfd,
636
           struct bfd_link_info *info,
637
           asection *sec,
638
           const Elf_Internal_Rela *relocs)
639
0
{
640
0
  Elf_Internal_Shdr *symtab_hdr;
641
0
  struct elf_link_hash_entry **sym_hashes;
642
0
  const Elf_Internal_Rela *rel;
643
0
  const Elf_Internal_Rela *rel_end;
644
645
0
  if (bfd_link_relocatable (info))
646
0
    return true;
647
648
0
  symtab_hdr = &elf_symtab_hdr (abfd);
649
0
  sym_hashes = elf_sym_hashes (abfd);
650
651
0
  rel_end = relocs + sec->reloc_count;
652
0
  for (rel = relocs; rel < rel_end; rel++)
653
0
    {
654
0
      struct elf_link_hash_entry *h;
655
0
      unsigned long r_symndx;
656
657
0
      r_symndx = ELF32_R_SYM (rel->r_info);
658
0
      if (r_symndx < symtab_hdr->sh_info)
659
0
  h = NULL;
660
0
      else
661
0
  {
662
0
    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
663
0
    while (h->root.type == bfd_link_hash_indirect
664
0
     || h->root.type == bfd_link_hash_warning)
665
0
      h = (struct elf_link_hash_entry *) h->root.u.i.link;
666
0
  }
667
668
0
      switch (ELF32_R_TYPE (rel->r_info))
669
0
  {
670
  /* This relocation describes the C++ object vtable hierarchy.
671
     Reconstruct it for later use during GC.  */
672
0
  case R_FR30_GNU_VTINHERIT:
673
0
    if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
674
0
      return false;
675
0
    break;
676
677
  /* This relocation describes which C++ vtable entries are actually
678
     used.  Record for later use during GC.  */
679
0
  case R_FR30_GNU_VTENTRY:
680
0
    if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
681
0
      return false;
682
0
    break;
683
0
  }
684
0
    }
685
686
0
  return true;
687
0
}
688

689
#define ELF_ARCH    bfd_arch_fr30
690
#define ELF_MACHINE_CODE  EM_FR30
691
#define ELF_MACHINE_ALT1  EM_CYGNUS_FR30
692
#define ELF_MAXPAGESIZE   0x1000
693
694
#define TARGET_BIG_SYM    fr30_elf32_vec
695
#define TARGET_BIG_NAME   "elf32-fr30"
696
697
#define elf_info_to_howto_rel     NULL
698
#define elf_info_to_howto     fr30_info_to_howto_rela
699
#define elf_backend_relocate_section    fr30_elf_relocate_section
700
#define elf_backend_gc_mark_hook    fr30_elf_gc_mark_hook
701
#define elf_backend_check_relocs    fr30_elf_check_relocs
702
703
#define elf_backend_can_gc_sections   1
704
#define elf_backend_rela_normal     1
705
706
#define bfd_elf32_bfd_reloc_type_lookup   fr30_reloc_type_lookup
707
#define bfd_elf32_bfd_reloc_name_lookup   fr30_reloc_name_lookup
708
709
#include "elf32-target.h"