Back to index

cell-binutils  2.17cvs20070401
elf32-fr30.c
Go to the documentation of this file.
00001 /* FR30-specific support for 32-bit ELF.
00002    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
00003    Free Software Foundation, Inc.
00004 
00005 This file is part of BFD, the Binary File Descriptor library.
00006 
00007 This program is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 This program is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00020 
00021 #include "bfd.h"
00022 #include "sysdep.h"
00023 #include "libbfd.h"
00024 #include "elf-bfd.h"
00025 #include "elf/fr30.h"
00026 
00027 /* Forward declarations.  */
00028 static bfd_reloc_status_type fr30_elf_i20_reloc
00029   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
00030 static bfd_reloc_status_type fr30_elf_i32_reloc
00031   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
00032 static reloc_howto_type * fr30_reloc_type_lookup
00033   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
00034 static void fr30_info_to_howto_rela
00035   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
00036 static bfd_boolean fr30_elf_relocate_section
00037   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
00038           Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
00039 static bfd_reloc_status_type fr30_final_link_relocate
00040   PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
00041           Elf_Internal_Rela *, bfd_vma));
00042 static bfd_boolean fr30_elf_check_relocs
00043   PARAMS ((bfd *, struct bfd_link_info *, asection *,
00044           const Elf_Internal_Rela *));
00045 
00046 static reloc_howto_type fr30_elf_howto_table [] =
00047 {
00048   /* This reloc does nothing.  */
00049   HOWTO (R_FR30_NONE,              /* type */
00050         0,                  /* rightshift */
00051         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00052         32,                 /* bitsize */
00053         FALSE,                     /* pc_relative */
00054         0,                  /* bitpos */
00055         complain_overflow_bitfield, /* complain_on_overflow */
00056         bfd_elf_generic_reloc,     /* special_function */
00057         "R_FR30_NONE",             /* name */
00058         FALSE,                     /* partial_inplace */
00059         0,                  /* src_mask */
00060         0,                  /* dst_mask */
00061         FALSE),             /* pcrel_offset */
00062 
00063   /* An 8 bit absolute relocation.  */
00064   HOWTO (R_FR30_8,          /* type */
00065         0,                  /* rightshift */
00066         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00067         8,                  /* bitsize */
00068         FALSE,                     /* pc_relative */
00069         4,                  /* bitpos */
00070         complain_overflow_bitfield, /* complain_on_overflow */
00071         bfd_elf_generic_reloc,     /* special_function */
00072         "R_FR30_8",         /* name */
00073         TRUE,               /* partial_inplace */
00074         0x0000,             /* src_mask */
00075         0x0ff0,             /* dst_mask */
00076         FALSE),             /* pcrel_offset */
00077 
00078   /* A 20 bit absolute relocation.  */
00079   HOWTO (R_FR30_20,         /* type */
00080         0,                  /* rightshift */
00081         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00082         20,                 /* bitsize */
00083         FALSE,                     /* pc_relative */
00084         0,                  /* bitpos */
00085         complain_overflow_bitfield, /* complain_on_overflow */
00086         fr30_elf_i20_reloc, /* special_function */
00087         "R_FR30_20",        /* name */
00088         TRUE,               /* partial_inplace */
00089         0x00000000,         /* src_mask */
00090         0x00f0ffff,         /* dst_mask */
00091         FALSE),             /* pcrel_offset */
00092 
00093   /* A 32 bit absolute relocation.  */
00094   HOWTO (R_FR30_32,         /* type */
00095         0,                  /* rightshift */
00096         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00097         32,                 /* bitsize */
00098         FALSE,                     /* pc_relative */
00099         0,                  /* bitpos */
00100         complain_overflow_bitfield, /* complain_on_overflow */
00101         bfd_elf_generic_reloc,     /* special_function */
00102         "R_FR30_32",        /* name */
00103         TRUE,               /* partial_inplace */
00104         0x00000000,         /* src_mask */
00105         0xffffffff,         /* dst_mask */
00106         FALSE),             /* pcrel_offset */
00107 
00108   /* A 32 bit into 48 bits absolute relocation.  */
00109   HOWTO (R_FR30_48,         /* type */
00110         0,                  /* rightshift */
00111         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00112         32,                 /* bitsize */
00113         FALSE,                     /* pc_relative */
00114         0,                  /* bitpos */
00115         complain_overflow_bitfield, /* complain_on_overflow */
00116         fr30_elf_i32_reloc, /* special_function */
00117         "R_FR30_48",        /* name */
00118         TRUE,               /* partial_inplace */
00119         0x00000000,         /* src_mask */
00120         0xffffffff,         /* dst_mask */
00121         FALSE),             /* pcrel_offset */
00122 
00123   /* A 6 bit absolute relocation.  */
00124   HOWTO (R_FR30_6_IN_4,            /* type */
00125         2,                  /* rightshift */
00126         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00127         6,                  /* bitsize */
00128         FALSE,                     /* pc_relative */
00129         4,                  /* bitpos */
00130         complain_overflow_unsigned, /* complain_on_overflow */
00131         bfd_elf_generic_reloc,     /* special_function */
00132         "R_FR30_6_IN_4",    /* name */
00133         TRUE,               /* partial_inplace */
00134         0x0000,             /* src_mask */
00135         0x00f0,             /* dst_mask */
00136         FALSE),             /* pcrel_offset */
00137 
00138   /* An 8 bit absolute relocation.  */
00139   HOWTO (R_FR30_8_IN_8,            /* type */
00140         0,                  /* rightshift */
00141         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00142         8,                  /* bitsize */
00143         FALSE,                     /* pc_relative */
00144         4,                  /* bitpos */
00145         complain_overflow_signed, /* complain_on_overflow */
00146         bfd_elf_generic_reloc,/* special_function */
00147         "R_FR30_8_IN_8",    /* name */
00148         TRUE,               /* partial_inplace */
00149         0x0000,             /* src_mask */
00150         0x0ff0,             /* dst_mask */
00151         FALSE),             /* pcrel_offset */
00152 
00153   /* A 9 bit absolute relocation.  */
00154   HOWTO (R_FR30_9_IN_8,            /* type */
00155         1,                  /* rightshift */
00156         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00157         9,                  /* bitsize */
00158         FALSE,                     /* pc_relative */
00159         4,                  /* bitpos */
00160         complain_overflow_signed, /* complain_on_overflow */
00161         bfd_elf_generic_reloc,/* special_function */
00162         "R_FR30_9_IN_8",    /* name */
00163         TRUE,               /* partial_inplace */
00164         0x0000,             /* src_mask */
00165         0x0ff0,             /* dst_mask */
00166         FALSE),             /* pcrel_offset */
00167 
00168   /* A 10 bit absolute relocation.  */
00169   HOWTO (R_FR30_10_IN_8,    /* type */
00170         2,                  /* rightshift */
00171         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00172         10,                 /* bitsize */
00173         FALSE,                     /* pc_relative */
00174         4,                  /* bitpos */
00175         complain_overflow_signed, /* complain_on_overflow */
00176         bfd_elf_generic_reloc,/* special_function */
00177         "R_FR30_10_IN_8",   /* name */
00178         TRUE,               /* partial_inplace */
00179         0x0000,             /* src_mask */
00180         0x0ff0,             /* dst_mask */
00181         FALSE),             /* pcrel_offset */
00182 
00183   /* A PC relative 9 bit relocation, right shifted by 1.  */
00184   HOWTO (R_FR30_9_PCREL,    /* type */
00185         1,                  /* rightshift */
00186         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00187         9,                  /* bitsize */
00188         TRUE,               /* pc_relative */
00189         0,                  /* bitpos */
00190         complain_overflow_signed, /* complain_on_overflow */
00191         bfd_elf_generic_reloc, /* special_function */
00192         "R_FR30_9_PCREL",   /* name */
00193         FALSE,                     /* partial_inplace */
00194         0x0000,             /* src_mask */
00195         0x00ff,             /* dst_mask */
00196         FALSE),             /* pcrel_offset */
00197 
00198   /* A PC relative 12 bit relocation, right shifted by 1.  */
00199   HOWTO (R_FR30_12_PCREL,   /* type */
00200         1,                  /* rightshift */
00201         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00202         12,                 /* bitsize */
00203         TRUE,               /* pc_relative */
00204         0,                  /* bitpos */
00205         complain_overflow_signed, /* complain_on_overflow */
00206         bfd_elf_generic_reloc, /* special_function */
00207         "R_FR30_12_PCREL",  /* name */
00208         FALSE,                     /* partial_inplace */
00209         0x0000,             /* src_mask */
00210         0x07ff,             /* dst_mask */
00211         FALSE),             /* pcrel_offset */
00212   /* GNU extension to record C++ vtable hierarchy */
00213   HOWTO (R_FR30_GNU_VTINHERIT, /* type */
00214          0,                     /* rightshift */
00215          2,                     /* size (0 = byte, 1 = short, 2 = long) */
00216          0,                     /* bitsize */
00217          FALSE,                 /* pc_relative */
00218          0,                     /* bitpos */
00219          complain_overflow_dont, /* complain_on_overflow */
00220          NULL,                  /* special_function */
00221          "R_FR30_GNU_VTINHERIT", /* name */
00222          FALSE,                 /* partial_inplace */
00223          0,                     /* src_mask */
00224          0,                     /* dst_mask */
00225          FALSE),                /* pcrel_offset */
00226 
00227   /* GNU extension to record C++ vtable member usage */
00228   HOWTO (R_FR30_GNU_VTENTRY,     /* type */
00229          0,                     /* rightshift */
00230          2,                     /* size (0 = byte, 1 = short, 2 = long) */
00231          0,                     /* bitsize */
00232          FALSE,                 /* pc_relative */
00233          0,                     /* bitpos */
00234          complain_overflow_dont, /* complain_on_overflow */
00235          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
00236          "R_FR30_GNU_VTENTRY",   /* name */
00237          FALSE,                 /* partial_inplace */
00238          0,                     /* src_mask */
00239          0,                     /* dst_mask */
00240          FALSE),                /* pcrel_offset */
00241 };
00242 
00243 /* Utility to actually perform an R_FR30_20 reloc.  */
00244 
00245 static bfd_reloc_status_type
00246 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
00247                   input_section, output_bfd, error_message)
00248      bfd *abfd;
00249      arelent *reloc_entry;
00250      asymbol *symbol;
00251      PTR data;
00252      asection *input_section;
00253      bfd *output_bfd;
00254      char **error_message ATTRIBUTE_UNUSED;
00255 {
00256   bfd_vma relocation;
00257   unsigned long x;
00258 
00259   /* This part is from bfd_elf_generic_reloc.  */
00260   if (output_bfd != (bfd *) NULL
00261       && (symbol->flags & BSF_SECTION_SYM) == 0
00262       && (! reloc_entry->howto->partial_inplace
00263          || reloc_entry->addend == 0))
00264     {
00265       reloc_entry->address += input_section->output_offset;
00266       return bfd_reloc_ok;
00267     }
00268 
00269   if (output_bfd != NULL)
00270     /* FIXME: See bfd_perform_relocation.  Is this right?  */
00271     return bfd_reloc_ok;
00272 
00273   relocation =
00274     symbol->value
00275     + symbol->section->output_section->vma
00276     + symbol->section->output_offset
00277     + reloc_entry->addend;
00278 
00279   if (relocation > (((bfd_vma) 1 << 20) - 1))
00280     return bfd_reloc_overflow;
00281 
00282   x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
00283   x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
00284   bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
00285 
00286   return bfd_reloc_ok;
00287 }
00288 
00289 /* Utility to actually perform a R_FR30_48 reloc.  */
00290 
00291 static bfd_reloc_status_type
00292 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
00293                   input_section, output_bfd, error_message)
00294      bfd *abfd;
00295      arelent *reloc_entry;
00296      asymbol *symbol;
00297      PTR data;
00298      asection *input_section;
00299      bfd *output_bfd;
00300      char **error_message ATTRIBUTE_UNUSED;
00301 {
00302   bfd_vma relocation;
00303 
00304   /* This part is from bfd_elf_generic_reloc.  */
00305   if (output_bfd != (bfd *) NULL
00306       && (symbol->flags & BSF_SECTION_SYM) == 0
00307       && (! reloc_entry->howto->partial_inplace
00308          || reloc_entry->addend == 0))
00309     {
00310       reloc_entry->address += input_section->output_offset;
00311       return bfd_reloc_ok;
00312     }
00313 
00314   if (output_bfd != NULL)
00315     /* FIXME: See bfd_perform_relocation.  Is this right?  */
00316     return bfd_reloc_ok;
00317 
00318   relocation =
00319     symbol->value
00320     + symbol->section->output_section->vma
00321     + symbol->section->output_offset
00322     + reloc_entry->addend;
00323 
00324   bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
00325 
00326   return bfd_reloc_ok;
00327 }
00328 
00329 /* Map BFD reloc types to FR30 ELF reloc types.  */
00330 
00331 struct fr30_reloc_map
00332 {
00333   bfd_reloc_code_real_type bfd_reloc_val;
00334   unsigned int fr30_reloc_val;
00335 };
00336 
00337 static const struct fr30_reloc_map fr30_reloc_map [] =
00338 {
00339   { BFD_RELOC_NONE,           R_FR30_NONE },
00340   { BFD_RELOC_8,              R_FR30_8 },
00341   { BFD_RELOC_FR30_20,        R_FR30_20 },
00342   { BFD_RELOC_32,             R_FR30_32 },
00343   { BFD_RELOC_FR30_48,        R_FR30_48 },
00344   { BFD_RELOC_FR30_6_IN_4,    R_FR30_6_IN_4 },
00345   { BFD_RELOC_FR30_8_IN_8,    R_FR30_8_IN_8 },
00346   { BFD_RELOC_FR30_9_IN_8,    R_FR30_9_IN_8 },
00347   { BFD_RELOC_FR30_10_IN_8,   R_FR30_10_IN_8 },
00348   { BFD_RELOC_FR30_9_PCREL,   R_FR30_9_PCREL },
00349   { BFD_RELOC_FR30_12_PCREL,  R_FR30_12_PCREL },
00350   { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
00351   { BFD_RELOC_VTABLE_ENTRY,   R_FR30_GNU_VTENTRY },
00352 };
00353 
00354 static reloc_howto_type *
00355 fr30_reloc_type_lookup (abfd, code)
00356      bfd *abfd ATTRIBUTE_UNUSED;
00357      bfd_reloc_code_real_type code;
00358 {
00359   unsigned int i;
00360 
00361   for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
00362        --i;)
00363     if (fr30_reloc_map [i].bfd_reloc_val == code)
00364       return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
00365 
00366   return NULL;
00367 }
00368 
00369 static reloc_howto_type *
00370 fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
00371 {
00372   unsigned int i;
00373 
00374   for (i = 0;
00375        i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
00376        i++)
00377     if (fr30_elf_howto_table[i].name != NULL
00378        && strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0)
00379       return &fr30_elf_howto_table[i];
00380 
00381   return NULL;
00382 }
00383 
00384 /* Set the howto pointer for an FR30 ELF reloc.  */
00385 
00386 static void
00387 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
00388      bfd *abfd ATTRIBUTE_UNUSED;
00389      arelent *cache_ptr;
00390      Elf_Internal_Rela *dst;
00391 {
00392   unsigned int r_type;
00393 
00394   r_type = ELF32_R_TYPE (dst->r_info);
00395   BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
00396   cache_ptr->howto = & fr30_elf_howto_table [r_type];
00397 }
00398 
00399 /* Perform a single relocation.  By default we use the standard BFD
00400    routines, but a few relocs, we have to do them ourselves.  */
00401 
00402 static bfd_reloc_status_type
00403 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel,
00404                        relocation)
00405      reloc_howto_type *howto;
00406      bfd *input_bfd;
00407      asection *input_section;
00408      bfd_byte *contents;
00409      Elf_Internal_Rela *rel;
00410      bfd_vma relocation;
00411 {
00412   bfd_reloc_status_type r = bfd_reloc_ok;
00413   bfd_vma x;
00414   bfd_signed_vma srel;
00415 
00416   switch (howto->type)
00417     {
00418     case R_FR30_20:
00419       contents   += rel->r_offset;
00420       relocation += rel->r_addend;
00421 
00422       if (relocation > ((1 << 20) - 1))
00423        return bfd_reloc_overflow;
00424 
00425       x = bfd_get_32 (input_bfd, contents);
00426       x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
00427       bfd_put_32 (input_bfd, x, contents);
00428       break;
00429 
00430     case R_FR30_48:
00431       contents   += rel->r_offset + 2;
00432       relocation += rel->r_addend;
00433       bfd_put_32 (input_bfd, relocation, contents);
00434       break;
00435 
00436     case R_FR30_9_PCREL:
00437       contents   += rel->r_offset + 1;
00438       srel = (bfd_signed_vma) relocation;
00439       srel += rel->r_addend;
00440       srel -= rel->r_offset;
00441       srel -= 2;  /* Branch instructions add 2 to the PC...  */
00442       srel -= (input_section->output_section->vma +
00443                    input_section->output_offset);
00444 
00445       if (srel & 1)
00446        return bfd_reloc_outofrange;
00447       if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
00448        return bfd_reloc_overflow;
00449 
00450       bfd_put_8 (input_bfd, srel >> 1, contents);
00451       break;
00452 
00453     case R_FR30_12_PCREL:
00454       contents   += rel->r_offset;
00455       srel = (bfd_signed_vma) relocation;
00456       srel += rel->r_addend;
00457       srel -= rel->r_offset;
00458       srel -= 2; /* Branch instructions add 2 to the PC...  */
00459       srel -= (input_section->output_section->vma +
00460                    input_section->output_offset);
00461 
00462       if (srel & 1)
00463        return bfd_reloc_outofrange;
00464       if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
00465          return bfd_reloc_overflow;
00466 
00467       x = bfd_get_16 (input_bfd, contents);
00468       x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
00469       bfd_put_16 (input_bfd, x, contents);
00470       break;
00471 
00472     default:
00473       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
00474                                 contents, rel->r_offset,
00475                                 relocation, rel->r_addend);
00476     }
00477 
00478   return r;
00479 }
00480 
00481 /* Relocate an FR30 ELF section.
00482 
00483    The RELOCATE_SECTION function is called by the new ELF backend linker
00484    to handle the relocations for a section.
00485 
00486    The relocs are always passed as Rela structures; if the section
00487    actually uses Rel structures, the r_addend field will always be
00488    zero.
00489 
00490    This function is responsible for adjusting the section contents as
00491    necessary, and (if using Rela relocs and generating a relocatable
00492    output file) adjusting the reloc addend as necessary.
00493 
00494    This function does not have to worry about setting the reloc
00495    address or the reloc symbol index.
00496 
00497    LOCAL_SYMS is a pointer to the swapped in local symbols.
00498 
00499    LOCAL_SECTIONS is an array giving the section in the input file
00500    corresponding to the st_shndx field of each local symbol.
00501 
00502    The global hash table entry for the global symbols can be found
00503    via elf_sym_hashes (input_bfd).
00504 
00505    When generating relocatable output, this function must handle
00506    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
00507    going to be the section symbol corresponding to the output
00508    section, which means that the addend must be adjusted
00509    accordingly.  */
00510 
00511 static bfd_boolean
00512 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
00513                         contents, relocs, local_syms, local_sections)
00514      bfd *output_bfd;
00515      struct bfd_link_info *info;
00516      bfd *input_bfd;
00517      asection *input_section;
00518      bfd_byte *contents;
00519      Elf_Internal_Rela *relocs;
00520      Elf_Internal_Sym *local_syms;
00521      asection **local_sections;
00522 {
00523   Elf_Internal_Shdr *symtab_hdr;
00524   struct elf_link_hash_entry **sym_hashes;
00525   Elf_Internal_Rela *rel;
00526   Elf_Internal_Rela *relend;
00527 
00528   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
00529   sym_hashes = elf_sym_hashes (input_bfd);
00530   relend     = relocs + input_section->reloc_count;
00531 
00532   for (rel = relocs; rel < relend; rel ++)
00533     {
00534       reloc_howto_type *howto;
00535       unsigned long r_symndx;
00536       Elf_Internal_Sym *sym;
00537       asection *sec;
00538       struct elf_link_hash_entry *h;
00539       bfd_vma relocation;
00540       bfd_reloc_status_type r;
00541       const char *name;
00542       int r_type;
00543 
00544       r_type = ELF32_R_TYPE (rel->r_info);
00545 
00546       if (   r_type == R_FR30_GNU_VTINHERIT
00547          || r_type == R_FR30_GNU_VTENTRY)
00548        continue;
00549 
00550       r_symndx = ELF32_R_SYM (rel->r_info);
00551 
00552       howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
00553       h      = NULL;
00554       sym    = NULL;
00555       sec    = NULL;
00556 
00557       if (r_symndx < symtab_hdr->sh_info)
00558        {
00559          sym = local_syms + r_symndx;
00560          sec = local_sections [r_symndx];
00561          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
00562 
00563          name = bfd_elf_string_from_elf_section
00564            (input_bfd, symtab_hdr->sh_link, sym->st_name);
00565          name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
00566        }
00567       else
00568        {
00569          bfd_boolean unresolved_reloc, warned;
00570 
00571          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
00572                                r_symndx, symtab_hdr, sym_hashes,
00573                                h, sec, relocation,
00574                                unresolved_reloc, warned);
00575 
00576          name = h->root.root.string;
00577        }
00578 
00579       if (sec != NULL && elf_discarded_section (sec))
00580        {
00581          /* For relocs against symbols from removed linkonce sections,
00582             or sections discarded by a linker script, we just want the
00583             section contents zeroed.  Avoid any special processing.  */
00584          _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
00585          rel->r_info = 0;
00586          rel->r_addend = 0;
00587          continue;
00588        }
00589 
00590       if (info->relocatable)
00591        continue;
00592 
00593       r = fr30_final_link_relocate (howto, input_bfd, input_section,
00594                                  contents, rel, relocation);
00595 
00596       if (r != bfd_reloc_ok)
00597        {
00598          const char * msg = (const char *) NULL;
00599 
00600          switch (r)
00601            {
00602            case bfd_reloc_overflow:
00603              r = info->callbacks->reloc_overflow
00604               (info, (h ? &h->root : NULL), name, howto->name,
00605                (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
00606              break;
00607 
00608            case bfd_reloc_undefined:
00609              r = info->callbacks->undefined_symbol
00610               (info, name, input_bfd, input_section, rel->r_offset,
00611                TRUE);
00612              break;
00613 
00614            case bfd_reloc_outofrange:
00615              msg = _("internal error: out of range error");
00616              break;
00617 
00618            case bfd_reloc_notsupported:
00619              msg = _("internal error: unsupported relocation error");
00620              break;
00621 
00622            case bfd_reloc_dangerous:
00623              msg = _("internal error: dangerous relocation");
00624              break;
00625 
00626            default:
00627              msg = _("internal error: unknown error");
00628              break;
00629            }
00630 
00631          if (msg)
00632            r = info->callbacks->warning
00633              (info, msg, name, input_bfd, input_section, rel->r_offset);
00634 
00635          if (! r)
00636            return FALSE;
00637        }
00638     }
00639 
00640   return TRUE;
00641 }
00642 
00643 /* Return the section that should be marked against GC for a given
00644    relocation.  */
00645 
00646 static asection *
00647 fr30_elf_gc_mark_hook (asection *sec,
00648                      struct bfd_link_info *info,
00649                      Elf_Internal_Rela *rel,
00650                      struct elf_link_hash_entry *h,
00651                      Elf_Internal_Sym *sym)
00652 {
00653   if (h != NULL)
00654     switch (ELF32_R_TYPE (rel->r_info))
00655       {
00656       case R_FR30_GNU_VTINHERIT:
00657       case R_FR30_GNU_VTENTRY:
00658        return NULL;
00659       }
00660 
00661   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
00662 }
00663 
00664 /* Look through the relocs for a section during the first phase.
00665    Since we don't do .gots or .plts, we just need to consider the
00666    virtual table relocs for gc.  */
00667 
00668 static bfd_boolean
00669 fr30_elf_check_relocs (abfd, info, sec, relocs)
00670      bfd *abfd;
00671      struct bfd_link_info *info;
00672      asection *sec;
00673      const Elf_Internal_Rela *relocs;
00674 {
00675   Elf_Internal_Shdr *symtab_hdr;
00676   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
00677   const Elf_Internal_Rela *rel;
00678   const Elf_Internal_Rela *rel_end;
00679 
00680   if (info->relocatable)
00681     return TRUE;
00682 
00683   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
00684   sym_hashes = elf_sym_hashes (abfd);
00685   sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
00686   if (!elf_bad_symtab (abfd))
00687     sym_hashes_end -= symtab_hdr->sh_info;
00688 
00689   rel_end = relocs + sec->reloc_count;
00690   for (rel = relocs; rel < rel_end; rel++)
00691     {
00692       struct elf_link_hash_entry *h;
00693       unsigned long r_symndx;
00694 
00695       r_symndx = ELF32_R_SYM (rel->r_info);
00696       if (r_symndx < symtab_hdr->sh_info)
00697         h = NULL;
00698       else
00699        {
00700          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
00701          while (h->root.type == bfd_link_hash_indirect
00702                || h->root.type == bfd_link_hash_warning)
00703            h = (struct elf_link_hash_entry *) h->root.u.i.link;
00704        }
00705 
00706       switch (ELF32_R_TYPE (rel->r_info))
00707         {
00708         /* This relocation describes the C++ object vtable hierarchy.
00709            Reconstruct it for later use during GC.  */
00710         case R_FR30_GNU_VTINHERIT:
00711           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
00712             return FALSE;
00713           break;
00714 
00715         /* This relocation describes which C++ vtable entries are actually
00716            used.  Record for later use during GC.  */
00717         case R_FR30_GNU_VTENTRY:
00718           if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
00719             return FALSE;
00720           break;
00721         }
00722     }
00723 
00724   return TRUE;
00725 }
00726 
00727 #define ELF_ARCH            bfd_arch_fr30
00728 #define ELF_MACHINE_CODE    EM_FR30
00729 #define ELF_MACHINE_ALT1    EM_CYGNUS_FR30
00730 #define ELF_MAXPAGESIZE            0x1000
00731 
00732 #define TARGET_BIG_SYM          bfd_elf32_fr30_vec
00733 #define TARGET_BIG_NAME            "elf32-fr30"
00734 
00735 #define elf_info_to_howto_rel                    NULL
00736 #define elf_info_to_howto                 fr30_info_to_howto_rela
00737 #define elf_backend_relocate_section             fr30_elf_relocate_section
00738 #define elf_backend_gc_mark_hook          fr30_elf_gc_mark_hook
00739 #define elf_backend_check_relocs                fr30_elf_check_relocs
00740 
00741 #define elf_backend_can_gc_sections              1
00742 #define elf_backend_rela_normal                  1
00743 
00744 #define bfd_elf32_bfd_reloc_type_lookup          fr30_reloc_type_lookup
00745 #define bfd_elf32_bfd_reloc_name_lookup   fr30_reloc_name_lookup
00746 
00747 #include "elf32-target.h"