OSDN Git Service

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