formatting fix
[external/binutils.git] / bfd / elf32-fr30.c
1 /* FR30-specific support for 32-bit ELF.
2    Copyright (C) 1998, 1999, 2000 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 \f
241 /* Utility to actually perform an R_FR30_20 reloc.  */
242
243 static bfd_reloc_status_type
244 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
245                     input_section, output_bfd, error_message)
246      bfd *      abfd;
247      arelent *  reloc_entry;
248      asymbol *  symbol;
249      PTR        data;
250      asection * input_section;
251      bfd *      output_bfd;
252      char **    error_message ATTRIBUTE_UNUSED;
253 {
254   bfd_vma       relocation;
255   unsigned long x;
256
257   /* This part is from bfd_elf_generic_reloc.  */
258   if (output_bfd != (bfd *) NULL
259       && (symbol->flags & BSF_SECTION_SYM) == 0
260       && (! reloc_entry->howto->partial_inplace
261           || reloc_entry->addend == 0))
262     {
263       reloc_entry->address += input_section->output_offset;
264       return bfd_reloc_ok;
265     }
266
267   if (output_bfd != NULL)
268     /* FIXME: See bfd_perform_relocation.  Is this right?  */
269     return bfd_reloc_ok;
270
271   relocation =
272     symbol->value
273     + symbol->section->output_section->vma
274     + symbol->section->output_offset
275     + reloc_entry->addend;
276
277   if (relocation > (((bfd_vma) 1 << 20) - 1))
278     return bfd_reloc_overflow;
279
280   x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
281   x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
282   bfd_put_32 (abfd, x, (char *) data + reloc_entry->address);
283
284   return bfd_reloc_ok;
285 }
286
287 \f
288 /* Utility to actually perform a R_FR30_48 reloc.  */
289
290 static bfd_reloc_status_type
291 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
292                     input_section, output_bfd, error_message)
293      bfd *      abfd;
294      arelent *  reloc_entry;
295      asymbol *  symbol;
296      PTR        data;
297      asection * input_section;
298      bfd *      output_bfd;
299      char **    error_message ATTRIBUTE_UNUSED;
300 {
301   bfd_vma       relocation;
302
303   /* This part is from bfd_elf_generic_reloc.  */
304   if (output_bfd != (bfd *) NULL
305       && (symbol->flags & BSF_SECTION_SYM) == 0
306       && (! reloc_entry->howto->partial_inplace
307           || reloc_entry->addend == 0))
308     {
309       reloc_entry->address += input_section->output_offset;
310       return bfd_reloc_ok;
311     }
312
313   if (output_bfd != NULL)
314     /* FIXME: See bfd_perform_relocation.  Is this right?  */
315     return bfd_reloc_ok;
316
317   relocation =
318     symbol->value
319     + symbol->section->output_section->vma
320     + symbol->section->output_offset
321     + reloc_entry->addend;
322
323   bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
324
325   return bfd_reloc_ok;
326 }
327 \f
328 /* Map BFD reloc types to FR30 ELF reloc types.  */
329
330 struct fr30_reloc_map
331 {
332   bfd_reloc_code_real_type bfd_reloc_val;
333   unsigned int fr30_reloc_val;
334 };
335
336 static const struct fr30_reloc_map fr30_reloc_map [] =
337 {
338   { BFD_RELOC_NONE,           R_FR30_NONE },
339   { BFD_RELOC_8,              R_FR30_8 },
340   { BFD_RELOC_FR30_20,        R_FR30_20 },
341   { BFD_RELOC_32,             R_FR30_32 },
342   { BFD_RELOC_FR30_48,        R_FR30_48 },
343   { BFD_RELOC_FR30_6_IN_4,    R_FR30_6_IN_4 },
344   { BFD_RELOC_FR30_8_IN_8,    R_FR30_8_IN_8 },
345   { BFD_RELOC_FR30_9_IN_8,    R_FR30_9_IN_8 },
346   { BFD_RELOC_FR30_10_IN_8,   R_FR30_10_IN_8 },
347   { BFD_RELOC_FR30_9_PCREL,   R_FR30_9_PCREL },
348   { BFD_RELOC_FR30_12_PCREL,  R_FR30_12_PCREL },
349   { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
350   { BFD_RELOC_VTABLE_ENTRY,   R_FR30_GNU_VTENTRY },
351 };
352
353 static reloc_howto_type *
354 fr30_reloc_type_lookup (abfd, code)
355      bfd * abfd ATTRIBUTE_UNUSED;
356      bfd_reloc_code_real_type code;
357 {
358   unsigned int i;
359
360   for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
361        --i;)
362     if (fr30_reloc_map [i].bfd_reloc_val == code)
363       return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
364
365   return NULL;
366 }
367
368 /* Set the howto pointer for an FR30 ELF reloc.  */
369
370 static void
371 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
372      bfd * abfd ATTRIBUTE_UNUSED;
373      arelent * cache_ptr;
374      Elf32_Internal_Rela * dst;
375 {
376   unsigned int r_type;
377
378   r_type = ELF32_R_TYPE (dst->r_info);
379   BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
380   cache_ptr->howto = & fr30_elf_howto_table [r_type];
381 }
382 \f
383 /* Perform a single relocation.  By default we use the standard BFD
384    routines, but a few relocs, we have to do them ourselves.  */
385
386 static bfd_reloc_status_type
387 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
388      reloc_howto_type *  howto;
389      bfd *               input_bfd;
390      asection *          input_section;
391      bfd_byte *          contents;
392      Elf_Internal_Rela * rel;
393      bfd_vma             relocation;
394 {
395   bfd_reloc_status_type r = bfd_reloc_ok;
396   bfd_vma               x;
397   bfd_signed_vma        srel;
398
399   switch (howto->type)
400     {
401     case R_FR30_20:
402       contents   += rel->r_offset;
403       relocation += rel->r_addend;
404
405       if (relocation > ((1 << 20) - 1))
406         return bfd_reloc_overflow;
407
408       x = bfd_get_32 (input_bfd, contents);
409       x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
410       bfd_put_32 (input_bfd, x, contents);
411       break;
412
413     case R_FR30_48:
414       contents   += rel->r_offset + 2;
415       relocation += rel->r_addend;
416       bfd_put_32 (input_bfd, relocation, contents);
417       break;
418
419     case R_FR30_9_PCREL:
420       contents   += rel->r_offset + 1;
421       srel = (bfd_signed_vma) relocation;
422       srel += rel->r_addend;
423       srel -= rel->r_offset;
424       srel -= 2;  /* Branch instructions add 2 to the PC...  */
425       srel -= (input_section->output_section->vma +
426                      input_section->output_offset);
427
428       if (srel & 1)
429         return bfd_reloc_outofrange;
430       if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
431         return bfd_reloc_overflow;
432
433       bfd_put_8 (input_bfd, srel >> 1, contents);
434       break;
435
436     case R_FR30_12_PCREL:
437       contents   += rel->r_offset;
438       srel = (bfd_signed_vma) relocation;
439       srel += rel->r_addend;
440       srel -= rel->r_offset;
441       srel -= 2; /* Branch instructions add 2 to the PC...  */
442       srel -= (input_section->output_section->vma +
443                      input_section->output_offset);
444
445       if (srel & 1)
446         return bfd_reloc_outofrange;
447       if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
448           return bfd_reloc_overflow;
449
450       x = bfd_get_16 (input_bfd, contents);
451       x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
452       bfd_put_16 (input_bfd, x, contents);
453       break;
454
455     default:
456       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
457                                     contents, rel->r_offset,
458                                     relocation, rel->r_addend);
459     }
460
461   return r;
462 }
463
464 \f
465 /* Relocate an FR30 ELF section.
466    There is some attempt to make this function usable for many architectures,
467    both USE_REL and USE_RELA ['twould be nice if such a critter existed],
468    if only to serve as a learning tool.
469
470    The RELOCATE_SECTION function is called by the new ELF backend linker
471    to handle the relocations for a section.
472
473    The relocs are always passed as Rela structures; if the section
474    actually uses Rel structures, the r_addend field will always be
475    zero.
476
477    This function is responsible for adjusting the section contents as
478    necessary, and (if using Rela relocs and generating a relocateable
479    output file) adjusting the reloc addend as necessary.
480
481    This function does not have to worry about setting the reloc
482    address or the reloc symbol index.
483
484    LOCAL_SYMS is a pointer to the swapped in local symbols.
485
486    LOCAL_SECTIONS is an array giving the section in the input file
487    corresponding to the st_shndx field of each local symbol.
488
489    The global hash table entry for the global symbols can be found
490    via elf_sym_hashes (input_bfd).
491
492    When generating relocateable output, this function must handle
493    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
494    going to be the section symbol corresponding to the output
495    section, which means that the addend must be adjusted
496    accordingly.  */
497
498 static boolean
499 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
500                            contents, relocs, local_syms, local_sections)
501      bfd *                   output_bfd ATTRIBUTE_UNUSED;
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 = NULL;
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       if (info->relocateable)
540         {
541           /* This is a relocateable link.  We don't have to change
542              anything, unless the reloc is against a section symbol,
543              in which case we have to adjust according to where the
544              section symbol winds up in the output section.  */
545           if (r_symndx < symtab_hdr->sh_info)
546             {
547               sym = local_syms + r_symndx;
548
549               if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
550                 {
551                   sec = local_sections [r_symndx];
552                   rel->r_addend += sec->output_offset + sym->st_value;
553                 }
554             }
555
556           continue;
557         }
558
559       /* This is a final link.  */
560       howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
561       h      = NULL;
562       sym    = NULL;
563       sec    = NULL;
564
565       if (r_symndx < symtab_hdr->sh_info)
566         {
567           sym = local_syms + r_symndx;
568           sec = local_sections [r_symndx];
569           relocation = (sec->output_section->vma
570                         + sec->output_offset
571                         + sym->st_value);
572
573           name = bfd_elf_string_from_elf_section
574             (input_bfd, symtab_hdr->sh_link, sym->st_name);
575           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
576 #if 0
577           fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
578                    sec->name, name, sym->st_name,
579                    sec->output_section->vma, sec->output_offset,
580                    sym->st_value, rel->r_addend);
581 #endif
582         }
583       else
584         {
585           h = sym_hashes [r_symndx - symtab_hdr->sh_info];
586
587           while (h->root.type == bfd_link_hash_indirect
588                  || h->root.type == bfd_link_hash_warning)
589             h = (struct elf_link_hash_entry *) h->root.u.i.link;
590
591           name = h->root.root.string;
592
593           if (h->root.type == bfd_link_hash_defined
594               || h->root.type == bfd_link_hash_defweak)
595             {
596               sec = h->root.u.def.section;
597               relocation = (h->root.u.def.value
598                             + sec->output_section->vma
599                             + sec->output_offset);
600 #if 0
601               fprintf (stderr,
602                        "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
603                        sec->name, name, h->root.u.def.value,
604                        sec->output_section->vma, sec->output_offset, relocation);
605 #endif
606             }
607           else if (h->root.type == bfd_link_hash_undefweak)
608             {
609 #if 0
610               fprintf (stderr, "undefined: sec: %s, name: %s\n",
611                        sec->name, name);
612 #endif
613               relocation = 0;
614             }
615           else
616             {
617               if (! ((*info->callbacks->undefined_symbol)
618                      (info, h->root.root.string, input_bfd,
619                       input_section, rel->r_offset, true)))
620                 return false;
621 #if 0
622               fprintf (stderr, "unknown: name: %s\n", name);
623 #endif
624               relocation = 0;
625             }
626         }
627
628       r = fr30_final_link_relocate (howto, input_bfd, input_section,
629                                      contents, rel, relocation);
630
631       if (r != bfd_reloc_ok)
632         {
633           const char * msg = (const char *) NULL;
634
635           switch (r)
636             {
637             case bfd_reloc_overflow:
638               r = info->callbacks->reloc_overflow
639                 (info, name, howto->name, (bfd_vma) 0,
640                  input_bfd, input_section, rel->r_offset);
641               break;
642
643             case bfd_reloc_undefined:
644               r = info->callbacks->undefined_symbol
645                 (info, name, input_bfd, input_section, rel->r_offset,
646                  true);
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 ATTRIBUTE_UNUSED;
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             default:
708               break;
709             }
710         }
711     }
712   else
713     {
714       if (!(elf_bad_symtab (abfd)
715             && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
716           && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
717                 && sym->st_shndx != SHN_COMMON))
718         {
719           return bfd_section_from_elf_index (abfd, sym->st_shndx);
720         }
721     }
722
723   return NULL;
724 }
725
726 /* Update the got entry reference counts for the section being removed.  */
727
728 static boolean
729 fr30_elf_gc_sweep_hook (abfd, info, sec, relocs)
730      bfd *                     abfd ATTRIBUTE_UNUSED;
731      struct bfd_link_info *    info ATTRIBUTE_UNUSED;
732      asection *                sec ATTRIBUTE_UNUSED;
733      const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
734 {
735   return true;
736 }
737
738 /* Look through the relocs for a section during the first phase.
739    Since we don't do .gots or .plts, we just need to consider the
740    virtual table relocs for gc.  */
741
742 static boolean
743 fr30_elf_check_relocs (abfd, info, sec, relocs)
744      bfd *abfd;
745      struct bfd_link_info *info;
746      asection *sec;
747      const Elf_Internal_Rela *relocs;
748 {
749   Elf_Internal_Shdr *symtab_hdr;
750   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
751   const Elf_Internal_Rela *rel;
752   const Elf_Internal_Rela *rel_end;
753
754   if (info->relocateable)
755     return true;
756
757   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
758   sym_hashes = elf_sym_hashes (abfd);
759   sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
760   if (!elf_bad_symtab (abfd))
761     sym_hashes_end -= symtab_hdr->sh_info;
762
763   rel_end = relocs + sec->reloc_count;
764   for (rel = relocs; rel < rel_end; rel++)
765     {
766       struct elf_link_hash_entry *h;
767       unsigned long r_symndx;
768
769       r_symndx = ELF32_R_SYM (rel->r_info);
770       if (r_symndx < symtab_hdr->sh_info)
771         h = NULL;
772       else
773         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
774
775       switch (ELF32_R_TYPE (rel->r_info))
776         {
777         /* This relocation describes the C++ object vtable hierarchy.
778            Reconstruct it for later use during GC.  */
779         case R_FR30_GNU_VTINHERIT:
780           if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
781             return false;
782           break;
783
784         /* This relocation describes which C++ vtable entries are actually
785            used.  Record for later use during GC.  */
786         case R_FR30_GNU_VTENTRY:
787           if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
788             return false;
789           break;
790         }
791     }
792
793   return true;
794 }
795 \f
796 #define ELF_ARCH                bfd_arch_fr30
797 #define ELF_MACHINE_CODE        EM_CYGNUS_FR30
798 #define ELF_MAXPAGESIZE         0x1000
799
800 #define TARGET_BIG_SYM          bfd_elf32_fr30_vec
801 #define TARGET_BIG_NAME         "elf32-fr30"
802
803 #define elf_info_to_howto_rel                   NULL
804 #define elf_info_to_howto                       fr30_info_to_howto_rela
805 #define elf_backend_relocate_section            fr30_elf_relocate_section
806 #define elf_backend_gc_mark_hook                fr30_elf_gc_mark_hook
807 #define elf_backend_gc_sweep_hook               fr30_elf_gc_sweep_hook
808 #define elf_backend_check_relocs                fr30_elf_check_relocs
809
810 #define elf_backend_can_gc_sections             1
811
812 #define bfd_elf32_bfd_reloc_type_lookup         fr30_reloc_type_lookup
813
814 #include "elf32-target.h"