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