1/* FR30-specific support for 32-bit ELF.
2   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
3   Free Software Foundation, Inc.
4
5This file is part of BFD, the Binary File Descriptor library.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, 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.  */
28static bfd_reloc_status_type fr30_elf_i20_reloc
29  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
30static bfd_reloc_status_type fr30_elf_i32_reloc
31  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
32static reloc_howto_type * fr30_reloc_type_lookup
33  PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
34static void fr30_info_to_howto_rela
35  PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
36static 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 **));
39static bfd_reloc_status_type fr30_final_link_relocate
40  PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
41	   Elf_Internal_Rela *, bfd_vma));
42static bfd_boolean fr30_elf_gc_sweep_hook
43  PARAMS ((bfd *, struct bfd_link_info *, asection *,
44	   const Elf_Internal_Rela *));
45static 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 *));
48static bfd_boolean fr30_elf_check_relocs
49  PARAMS ((bfd *, struct bfd_link_info *, asection *,
50	   const Elf_Internal_Rela *));
51
52static 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
251static bfd_reloc_status_type
252fr30_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
297static bfd_reloc_status_type
298fr30_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
337struct fr30_reloc_map
338{
339  bfd_reloc_code_real_type bfd_reloc_val;
340  unsigned int fr30_reloc_val;
341};
342
343static 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
360static reloc_howto_type *
361fr30_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
377static void
378fr30_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
393static bfd_reloc_status_type
394fr30_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
502static bfd_boolean
503fr30_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
626static asection *
627fr30_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
665static bfd_boolean
666fr30_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
679static bfd_boolean
680fr30_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