OSDN Git Service

f2b4b445cffa3ce01496785c6e714c15f63ca007
[pf3gnuchains/pf3gnuchains3x.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 };
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 ATTRIBUTE_UNUSED;
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 > (((bfd_vma) 1 << 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 ATTRIBUTE_UNUSED;
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 ATTRIBUTE_UNUSED;
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 ATTRIBUTE_UNUSED;
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 ATTRIBUTE_UNUSED;
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, true)))
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                  true);
648               break;
649
650             case bfd_reloc_outofrange:
651               msg = _("internal error: out of range error");
652               break;
653
654             case bfd_reloc_notsupported:
655               msg = _("internal error: unsupported relocation error");
656               break;
657
658             case bfd_reloc_dangerous:
659               msg = _("internal error: dangerous relocation");
660               break;
661
662             default:
663               msg = _("internal error: unknown error");
664               break;
665             }
666
667           if (msg)
668             r = info->callbacks->warning
669               (info, msg, name, input_bfd, input_section, rel->r_offset);
670
671           if (! r)
672             return false;
673         }
674     }
675
676   return true;
677 }
678 \f
679 /* Return the section that should be marked against GC for a given
680    relocation.  */
681
682 static asection *
683 fr30_elf_gc_mark_hook (abfd, info, rel, h, sym)
684      bfd *                        abfd;
685      struct bfd_link_info *       info ATTRIBUTE_UNUSED;
686      Elf_Internal_Rela *          rel;
687      struct elf_link_hash_entry * h;
688      Elf_Internal_Sym *           sym;
689 {
690   if (h != NULL)
691     {
692       switch (ELF32_R_TYPE (rel->r_info))
693         {
694         case R_FR30_GNU_VTINHERIT:
695         case R_FR30_GNU_VTENTRY:
696           break;
697
698         default:
699           switch (h->root.type)
700             {
701             case bfd_link_hash_defined:
702             case bfd_link_hash_defweak:
703               return h->root.u.def.section;
704
705             case bfd_link_hash_common:
706               return h->root.u.c.p->section;
707
708             default:
709               break;
710             }
711         }
712     }
713   else
714     {
715       if (!(elf_bad_symtab (abfd)
716             && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
717           && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
718                 && sym->st_shndx != SHN_COMMON))
719         {
720           return bfd_section_from_elf_index (abfd, sym->st_shndx);
721         }
722     }
723
724   return NULL;
725 }
726
727 /* Update the got entry reference counts for the section being removed.  */
728
729 static boolean
730 fr30_elf_gc_sweep_hook (abfd, info, sec, relocs)
731      bfd *                     abfd ATTRIBUTE_UNUSED;
732      struct bfd_link_info *    info ATTRIBUTE_UNUSED;
733      asection *                sec ATTRIBUTE_UNUSED;
734      const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
735 {
736   return true;
737 }
738
739 /* Look through the relocs for a section during the first phase.
740    Since we don't do .gots or .plts, we just need to consider the
741    virtual table relocs for gc.  */
742
743 static boolean
744 fr30_elf_check_relocs (abfd, info, sec, relocs)
745      bfd *abfd;
746      struct bfd_link_info *info;
747      asection *sec;
748      const Elf_Internal_Rela *relocs;
749 {
750   Elf_Internal_Shdr *symtab_hdr;
751   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
752   const Elf_Internal_Rela *rel;
753   const Elf_Internal_Rela *rel_end;
754
755   if (info->relocateable)
756     return true;
757
758   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
759   sym_hashes = elf_sym_hashes (abfd);
760   sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
761   if (!elf_bad_symtab (abfd))
762     sym_hashes_end -= symtab_hdr->sh_info;
763
764   rel_end = relocs + sec->reloc_count;
765   for (rel = relocs; rel < rel_end; rel++)
766     {
767       struct elf_link_hash_entry *h;
768       unsigned long r_symndx;
769
770       r_symndx = ELF32_R_SYM (rel->r_info);
771       if (r_symndx < symtab_hdr->sh_info)
772         h = NULL;
773       else
774         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
775
776       switch (ELF32_R_TYPE (rel->r_info))
777         {
778         /* This relocation describes the C++ object vtable hierarchy.
779            Reconstruct it for later use during GC.  */
780         case R_FR30_GNU_VTINHERIT:
781           if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
782             return false;
783           break;
784
785         /* This relocation describes which C++ vtable entries are actually
786            used.  Record for later use during GC.  */
787         case R_FR30_GNU_VTENTRY:
788           if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
789             return false;
790           break;
791         }
792     }
793
794   return true;
795 }
796 \f
797 #define ELF_ARCH                bfd_arch_fr30
798 #define ELF_MACHINE_CODE        EM_CYGNUS_FR30
799 #define ELF_MAXPAGESIZE         0x1000
800
801 #define TARGET_BIG_SYM          bfd_elf32_fr30_vec
802 #define TARGET_BIG_NAME         "elf32-fr30"
803
804 #define elf_info_to_howto_rel                   NULL
805 #define elf_info_to_howto                       fr30_info_to_howto_rela
806 #define elf_backend_relocate_section            fr30_elf_relocate_section
807 #define elf_backend_gc_mark_hook                fr30_elf_gc_mark_hook
808 #define elf_backend_gc_sweep_hook               fr30_elf_gc_sweep_hook
809 #define elf_backend_check_relocs                fr30_elf_check_relocs
810
811 #define elf_backend_can_gc_sections             1
812
813 #define bfd_elf32_bfd_reloc_type_lookup         fr30_reloc_type_lookup
814
815 #include "elf32-target.h"