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