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