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