1 /* FR30-specific support for 32-bit ELF.
2    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
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_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 
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 
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 
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 
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 
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 	}
561       else
562 	{
563 	  bfd_boolean unresolved_reloc, warned;
564 
565 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
566 				   r_symndx, symtab_hdr, sym_hashes,
567 				   h, sec, relocation,
568 				   unresolved_reloc, warned);
569 
570 	  name = h->root.root.string;
571 	}
572 
573       r = fr30_final_link_relocate (howto, input_bfd, input_section,
574 				     contents, rel, relocation);
575 
576       if (r != bfd_reloc_ok)
577 	{
578 	  const char * msg = (const char *) NULL;
579 
580 	  switch (r)
581 	    {
582 	    case bfd_reloc_overflow:
583 	      r = info->callbacks->reloc_overflow
584 		(info, (h ? &h->root : NULL), name, howto->name,
585 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
586 	      break;
587 
588 	    case bfd_reloc_undefined:
589 	      r = info->callbacks->undefined_symbol
590 		(info, name, input_bfd, input_section, rel->r_offset,
591 		 TRUE);
592 	      break;
593 
594 	    case bfd_reloc_outofrange:
595 	      msg = _("internal error: out of range error");
596 	      break;
597 
598 	    case bfd_reloc_notsupported:
599 	      msg = _("internal error: unsupported relocation error");
600 	      break;
601 
602 	    case bfd_reloc_dangerous:
603 	      msg = _("internal error: dangerous relocation");
604 	      break;
605 
606 	    default:
607 	      msg = _("internal error: unknown error");
608 	      break;
609 	    }
610 
611 	  if (msg)
612 	    r = info->callbacks->warning
613 	      (info, msg, name, input_bfd, input_section, rel->r_offset);
614 
615 	  if (! r)
616 	    return FALSE;
617 	}
618     }
619 
620   return TRUE;
621 }
622 
623 /* Return the section that should be marked against GC for a given
624    relocation.  */
625 
626 static asection *
627 fr30_elf_gc_mark_hook (sec, info, rel, h, sym)
628      asection *sec;
629      struct bfd_link_info *info ATTRIBUTE_UNUSED;
630      Elf_Internal_Rela *rel;
631      struct elf_link_hash_entry *h;
632      Elf_Internal_Sym * sym;
633 {
634   if (h != NULL)
635     {
636       switch (ELF32_R_TYPE (rel->r_info))
637 	{
638 	case R_FR30_GNU_VTINHERIT:
639 	case R_FR30_GNU_VTENTRY:
640 	  break;
641 
642 	default:
643 	  switch (h->root.type)
644 	    {
645 	    case bfd_link_hash_defined:
646 	    case bfd_link_hash_defweak:
647 	      return h->root.u.def.section;
648 
649 	    case bfd_link_hash_common:
650 	      return h->root.u.c.p->section;
651 
652 	    default:
653 	      break;
654 	    }
655 	}
656     }
657   else
658     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
659 
660   return NULL;
661 }
662 
663 /* Update the got entry reference counts for the section being removed.  */
664 
665 static bfd_boolean
666 fr30_elf_gc_sweep_hook (abfd, info, sec, relocs)
667      bfd *abfd ATTRIBUTE_UNUSED;
668      struct bfd_link_info *info ATTRIBUTE_UNUSED;
669      asection *sec ATTRIBUTE_UNUSED;
670      const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
671 {
672   return TRUE;
673 }
674 
675 /* Look through the relocs for a section during the first phase.
676    Since we don't do .gots or .plts, we just need to consider the
677    virtual table relocs for gc.  */
678 
679 static bfd_boolean
680 fr30_elf_check_relocs (abfd, info, sec, relocs)
681      bfd *abfd;
682      struct bfd_link_info *info;
683      asection *sec;
684      const Elf_Internal_Rela *relocs;
685 {
686   Elf_Internal_Shdr *symtab_hdr;
687   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
688   const Elf_Internal_Rela *rel;
689   const Elf_Internal_Rela *rel_end;
690 
691   if (info->relocatable)
692     return TRUE;
693 
694   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
695   sym_hashes = elf_sym_hashes (abfd);
696   sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
697   if (!elf_bad_symtab (abfd))
698     sym_hashes_end -= symtab_hdr->sh_info;
699 
700   rel_end = relocs + sec->reloc_count;
701   for (rel = relocs; rel < rel_end; rel++)
702     {
703       struct elf_link_hash_entry *h;
704       unsigned long r_symndx;
705 
706       r_symndx = ELF32_R_SYM (rel->r_info);
707       if (r_symndx < symtab_hdr->sh_info)
708         h = NULL;
709       else
710 	{
711 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
712 	  while (h->root.type == bfd_link_hash_indirect
713 		 || h->root.type == bfd_link_hash_warning)
714 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
715 	}
716 
717       switch (ELF32_R_TYPE (rel->r_info))
718         {
719         /* This relocation describes the C++ object vtable hierarchy.
720            Reconstruct it for later use during GC.  */
721         case R_FR30_GNU_VTINHERIT:
722           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
723             return FALSE;
724           break;
725 
726         /* This relocation describes which C++ vtable entries are actually
727            used.  Record for later use during GC.  */
728         case R_FR30_GNU_VTENTRY:
729           if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
730             return FALSE;
731           break;
732         }
733     }
734 
735   return TRUE;
736 }
737 
738 #define ELF_ARCH		bfd_arch_fr30
739 #define ELF_MACHINE_CODE	EM_FR30
740 #define ELF_MACHINE_ALT1	EM_CYGNUS_FR30
741 #define ELF_MAXPAGESIZE		0x1000
742 
743 #define TARGET_BIG_SYM          bfd_elf32_fr30_vec
744 #define TARGET_BIG_NAME		"elf32-fr30"
745 
746 #define elf_info_to_howto_rel			NULL
747 #define elf_info_to_howto			fr30_info_to_howto_rela
748 #define elf_backend_relocate_section		fr30_elf_relocate_section
749 #define elf_backend_gc_mark_hook		fr30_elf_gc_mark_hook
750 #define elf_backend_gc_sweep_hook		fr30_elf_gc_sweep_hook
751 #define elf_backend_check_relocs                fr30_elf_check_relocs
752 
753 #define elf_backend_can_gc_sections		1
754 #define elf_backend_rela_normal			1
755 
756 #define bfd_elf32_bfd_reloc_type_lookup		fr30_reloc_type_lookup
757 
758 #include "elf32-target.h"
759