PR 3958
[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
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   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
514   sym_hashes = elf_sym_hashes (input_bfd);
515   relend     = relocs + input_section->reloc_count;
516
517   for (rel = relocs; rel < relend; rel ++)
518     {
519       reloc_howto_type *howto;
520       unsigned long r_symndx;
521       Elf_Internal_Sym *sym;
522       asection *sec;
523       struct elf_link_hash_entry *h;
524       bfd_vma relocation;
525       bfd_reloc_status_type r;
526       const char *name;
527       int r_type;
528
529       r_type = ELF32_R_TYPE (rel->r_info);
530
531       if (   r_type == R_FR30_GNU_VTINHERIT
532           || r_type == R_FR30_GNU_VTENTRY)
533         continue;
534
535       r_symndx = ELF32_R_SYM (rel->r_info);
536
537       howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
538       h      = NULL;
539       sym    = NULL;
540       sec    = NULL;
541
542       if (r_symndx < symtab_hdr->sh_info)
543         {
544           sym = local_syms + r_symndx;
545           sec = local_sections [r_symndx];
546           relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
547
548           name = bfd_elf_string_from_elf_section
549             (input_bfd, symtab_hdr->sh_link, sym->st_name);
550           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
551         }
552       else
553         {
554           bfd_boolean unresolved_reloc, warned;
555
556           RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
557                                    r_symndx, symtab_hdr, sym_hashes,
558                                    h, sec, relocation,
559                                    unresolved_reloc, warned);
560
561           name = h->root.root.string;
562         }
563
564       if (sec != NULL && elf_discarded_section (sec))
565         {
566           /* For relocs against symbols from removed linkonce sections,
567              or sections discarded by a linker script, we just want the
568              section contents zeroed.  Avoid any special processing.  */
569           _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
570           rel->r_info = 0;
571           rel->r_addend = 0;
572           continue;
573         }
574
575       if (info->relocatable)
576         continue;
577
578       r = fr30_final_link_relocate (howto, input_bfd, input_section,
579                                      contents, rel, relocation);
580
581       if (r != bfd_reloc_ok)
582         {
583           const char * msg = (const char *) NULL;
584
585           switch (r)
586             {
587             case bfd_reloc_overflow:
588               r = info->callbacks->reloc_overflow
589                 (info, (h ? &h->root : NULL), name, howto->name,
590                  (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
591               break;
592
593             case bfd_reloc_undefined:
594               r = info->callbacks->undefined_symbol
595                 (info, name, input_bfd, input_section, rel->r_offset,
596                  TRUE);
597               break;
598
599             case bfd_reloc_outofrange:
600               msg = _("internal error: out of range error");
601               break;
602
603             case bfd_reloc_notsupported:
604               msg = _("internal error: unsupported relocation error");
605               break;
606
607             case bfd_reloc_dangerous:
608               msg = _("internal error: dangerous relocation");
609               break;
610
611             default:
612               msg = _("internal error: unknown error");
613               break;
614             }
615
616           if (msg)
617             r = info->callbacks->warning
618               (info, msg, name, input_bfd, input_section, rel->r_offset);
619
620           if (! r)
621             return FALSE;
622         }
623     }
624
625   return TRUE;
626 }
627 \f
628 /* Return the section that should be marked against GC for a given
629    relocation.  */
630
631 static asection *
632 fr30_elf_gc_mark_hook (asection *sec,
633                        struct bfd_link_info *info,
634                        Elf_Internal_Rela *rel,
635                        struct elf_link_hash_entry *h,
636                        Elf_Internal_Sym *sym)
637 {
638   if (h != NULL)
639     switch (ELF32_R_TYPE (rel->r_info))
640       {
641       case R_FR30_GNU_VTINHERIT:
642       case R_FR30_GNU_VTENTRY:
643         return NULL;
644       }
645
646   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
647 }
648
649 /* Look through the relocs for a section during the first phase.
650    Since we don't do .gots or .plts, we just need to consider the
651    virtual table relocs for gc.  */
652
653 static bfd_boolean
654 fr30_elf_check_relocs (abfd, info, sec, relocs)
655      bfd *abfd;
656      struct bfd_link_info *info;
657      asection *sec;
658      const Elf_Internal_Rela *relocs;
659 {
660   Elf_Internal_Shdr *symtab_hdr;
661   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
662   const Elf_Internal_Rela *rel;
663   const Elf_Internal_Rela *rel_end;
664
665   if (info->relocatable)
666     return TRUE;
667
668   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
669   sym_hashes = elf_sym_hashes (abfd);
670   sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
671   if (!elf_bad_symtab (abfd))
672     sym_hashes_end -= symtab_hdr->sh_info;
673
674   rel_end = relocs + sec->reloc_count;
675   for (rel = relocs; rel < rel_end; rel++)
676     {
677       struct elf_link_hash_entry *h;
678       unsigned long r_symndx;
679
680       r_symndx = ELF32_R_SYM (rel->r_info);
681       if (r_symndx < symtab_hdr->sh_info)
682         h = NULL;
683       else
684         {
685           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
686           while (h->root.type == bfd_link_hash_indirect
687                  || h->root.type == bfd_link_hash_warning)
688             h = (struct elf_link_hash_entry *) h->root.u.i.link;
689         }
690
691       switch (ELF32_R_TYPE (rel->r_info))
692         {
693         /* This relocation describes the C++ object vtable hierarchy.
694            Reconstruct it for later use during GC.  */
695         case R_FR30_GNU_VTINHERIT:
696           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
697             return FALSE;
698           break;
699
700         /* This relocation describes which C++ vtable entries are actually
701            used.  Record for later use during GC.  */
702         case R_FR30_GNU_VTENTRY:
703           if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
704             return FALSE;
705           break;
706         }
707     }
708
709   return TRUE;
710 }
711 \f
712 #define ELF_ARCH                bfd_arch_fr30
713 #define ELF_MACHINE_CODE        EM_FR30
714 #define ELF_MACHINE_ALT1        EM_CYGNUS_FR30
715 #define ELF_MAXPAGESIZE         0x1000
716
717 #define TARGET_BIG_SYM          bfd_elf32_fr30_vec
718 #define TARGET_BIG_NAME         "elf32-fr30"
719
720 #define elf_info_to_howto_rel                   NULL
721 #define elf_info_to_howto                       fr30_info_to_howto_rela
722 #define elf_backend_relocate_section            fr30_elf_relocate_section
723 #define elf_backend_gc_mark_hook                fr30_elf_gc_mark_hook
724 #define elf_backend_check_relocs                fr30_elf_check_relocs
725
726 #define elf_backend_can_gc_sections             1
727 #define elf_backend_rela_normal                 1
728
729 #define bfd_elf32_bfd_reloc_type_lookup         fr30_reloc_type_lookup
730
731 #include "elf32-target.h"