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