Back to index

cell-binutils  2.17cvs20070401
elf32-openrisc.c
Go to the documentation of this file.
00001 /* OpenRISC-specific support for 32-bit ELF.
00002    Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
00003    Free Software Foundation, Inc.
00004    Contributed by Johan Rydberg, jrydberg@opencores.org
00005 
00006    This file is part of BFD, the Binary File Descriptor library.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
00021    USA.  */
00022 
00023 #include "bfd.h"
00024 #include "sysdep.h"
00025 #include "libbfd.h"
00026 #include "elf-bfd.h"
00027 #include "elf/openrisc.h"
00028 #include "libiberty.h"
00029 
00030 static reloc_howto_type openrisc_elf_howto_table[] =
00031 {
00032   /* This reloc does nothing.  */
00033   HOWTO (R_OPENRISC_NONE,   /* type */
00034         0,                  /* rightshift */
00035         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00036         32,                 /* bitsize */
00037         FALSE,                     /* pc_relative */
00038         0,                  /* bitpos */
00039         complain_overflow_bitfield, /* complain_on_overflow */
00040         bfd_elf_generic_reloc,     /* special_function */
00041         "R_OPENRISC_NONE",  /* name */
00042         FALSE,                     /* partial_inplace */
00043         0,                  /* src_mask */
00044         0,                  /* dst_mask */
00045         FALSE),             /* pcrel_offset */
00046 
00047   /* A PC relative 26 bit relocation, right shifted by 2.  */
00048   HOWTO (R_OPENRISC_INSN_REL_26, /* type */
00049         2,                  /* rightshift */
00050         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00051         26,                 /* bitsize */
00052         TRUE,               /* pc_relative */
00053         0,                  /* bitpos */
00054         complain_overflow_signed, /* complain_on_overflow */
00055         bfd_elf_generic_reloc,     /* special_function */
00056         "R_OPENRISC_INSN_REL_26", /* name */
00057         FALSE,                     /* partial_inplace */
00058         0x00000000,         /* src_mask */
00059         0x03ffffff,         /* dst_mask */
00060         FALSE),             /* pcrel_offset */
00061 
00062   /* A absolute 26 bit relocation, right shifted by 2.  */
00063   HOWTO (R_OPENRISC_INSN_ABS_26, /* type */
00064         2,                  /* rightshift */
00065         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00066         26,                 /* bitsize */
00067         FALSE,                     /* pc_relative */
00068         0,                  /* bitpos */
00069         complain_overflow_signed, /* complain_on_overflow */
00070         bfd_elf_generic_reloc,     /* special_function */
00071         "R_OPENRISC_INSN_ABS_26", /* name */
00072         FALSE,                     /* partial_inplace */
00073         0x00000000,         /* src_mask */
00074         0x03ffffff,         /* dst_mask */
00075         FALSE),             /* pcrel_offset */
00076 
00077   HOWTO (R_OPENRISC_LO_16_IN_INSN, /* type */
00078         0,                  /* rightshift */
00079         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00080         16,                 /* bitsize */
00081         FALSE,                     /* pc_relative */
00082         0,                  /* bitpos */
00083         complain_overflow_dont, /* complain_on_overflow */
00084         bfd_elf_generic_reloc,     /* special_function */
00085         "R_OPENRISC_LO_16_IN_INSN", /* name */
00086         FALSE,                     /* partial_inplace */
00087         0,                  /* src_mask */
00088         0x0000ffff,         /* dst_mask */
00089         FALSE),             /* pcrel_offset */
00090 
00091   HOWTO (R_OPENRISC_HI_16_IN_INSN, /* type */
00092         16,                 /* rightshift */
00093         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00094         16,                 /* bitsize */
00095         FALSE,                     /* pc_relative */
00096         0,                  /* bitpos */
00097         complain_overflow_dont,    /* complain_on_overflow */
00098         bfd_elf_generic_reloc,     /* special_function */
00099         "R_OPENRISC_HI_16_IN_INSN",       /* name */
00100         FALSE,                     /* partial_inplace */
00101         0,                  /* src_mask */
00102         0x0000ffff,         /* dst_mask */
00103         FALSE),             /* pcrel_offset */
00104 
00105   /* An 8 bit absolute relocation.  */
00106   HOWTO (R_OPENRISC_8,             /* type */
00107         0,                  /* rightshift */
00108         0,                  /* size (0 = byte, 1 = short, 2 = long) */
00109         8,                  /* bitsize */
00110         FALSE,                     /* pc_relative */
00111         0,                  /* bitpos */
00112         complain_overflow_bitfield, /* complain_on_overflow */
00113         bfd_elf_generic_reloc,     /* special_function */
00114         "R_OPENRISC_8",     /* name */
00115         TRUE,               /* partial_inplace */
00116         0x0000,             /* src_mask */
00117         0x00ff,             /* dst_mask */
00118         FALSE),             /* pcrel_offset */
00119 
00120   /* A 16 bit absolute relocation.  */
00121   HOWTO (R_OPENRISC_16,            /* type */
00122         0,                  /* rightshift */
00123         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00124         16,                 /* bitsize */
00125         FALSE,                     /* pc_relative */
00126         0,                  /* bitpos */
00127         complain_overflow_bitfield, /* complain_on_overflow */
00128         bfd_elf_generic_reloc,     /* special_function */
00129         "R_OPENRISC_16",    /* name */
00130         TRUE,               /* partial_inplace */
00131         0x00000000,         /* src_mask */
00132         0x0000ffff,         /* dst_mask */
00133         FALSE),             /* pcrel_offset */
00134 
00135   /* A 32 bit absolute relocation.  */
00136   HOWTO (R_OPENRISC_32,            /* type */
00137         0,                  /* rightshift */
00138         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00139         32,                 /* bitsize */
00140         FALSE,                     /* pc_relative */
00141         0,                  /* bitpos */
00142         complain_overflow_bitfield, /* complain_on_overflow */
00143         bfd_elf_generic_reloc,     /* special_function */
00144         "R_OPENRISC_32",    /* name */
00145         TRUE,               /* partial_inplace */
00146         0x00000000,         /* src_mask */
00147         0xffffffff,         /* dst_mask */
00148         FALSE),             /* pcrel_offset */
00149 
00150   /* GNU extension to record C++ vtable hierarchy.  */
00151   HOWTO (R_OPENRISC_GNU_VTINHERIT, /* type */
00152         0,                  /* rightshift */
00153         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00154         0,                  /* bitsize */
00155         FALSE,                     /* pc_relative */
00156         0,                  /* bitpos */
00157         complain_overflow_dont, /* complain_on_overflow */
00158         NULL,               /* special_function */
00159         "R_OPENRISC_GNU_VTINHERIT", /* name */
00160         FALSE,                     /* partial_inplace */
00161         0,                  /* src_mask */
00162         0,                  /* dst_mask */
00163         FALSE),             /* pcrel_offset */
00164 
00165   /* GNU extension to record C++ vtable member usage.  */
00166   HOWTO (R_OPENRISC_GNU_VTENTRY, /* type */
00167         0,                  /* rightshift */
00168         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00169         0,                  /* bitsize */
00170         FALSE,                     /* pc_relative */
00171         0,                  /* bitpos */
00172         complain_overflow_dont, /* complain_on_overflow */
00173         _bfd_elf_rel_vtable_reloc_fn, /* special_function */
00174         "R_OPENRISC_GNU_VTENTRY", /* name */
00175         FALSE,                     /* partial_inplace */
00176         0,                  /* src_mask */
00177         0,                  /* dst_mask */
00178         FALSE),             /* pcrel_offset */
00179 };
00180 
00181 /* Map BFD reloc types to OpenRISC ELF reloc types.  */
00182 
00183 struct openrisc_reloc_map
00184 {
00185   bfd_reloc_code_real_type bfd_reloc_val;
00186   unsigned int openrisc_reloc_val;
00187 };
00188 
00189 static const struct openrisc_reloc_map openrisc_reloc_map[] =
00190 {
00191   { BFD_RELOC_NONE,         R_OPENRISC_NONE },
00192   { BFD_RELOC_32,           R_OPENRISC_32 },
00193   { BFD_RELOC_16,           R_OPENRISC_16 },
00194   { BFD_RELOC_8,            R_OPENRISC_8 },
00195   { BFD_RELOC_OPENRISC_REL_26,     R_OPENRISC_INSN_REL_26 },
00196   { BFD_RELOC_OPENRISC_ABS_26,     R_OPENRISC_INSN_ABS_26 },
00197   { BFD_RELOC_HI16,         R_OPENRISC_HI_16_IN_INSN },
00198   { BFD_RELOC_LO16,         R_OPENRISC_LO_16_IN_INSN },
00199   { BFD_RELOC_VTABLE_INHERIT,      R_OPENRISC_GNU_VTINHERIT },
00200   { BFD_RELOC_VTABLE_ENTRY,        R_OPENRISC_GNU_VTENTRY }
00201 };
00202 
00203 static reloc_howto_type *
00204 openrisc_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
00205                          bfd_reloc_code_real_type code)
00206 {
00207   unsigned int i;
00208 
00209   for (i = ARRAY_SIZE (openrisc_reloc_map); --i;)
00210     if (openrisc_reloc_map[i].bfd_reloc_val == code)
00211       return & openrisc_elf_howto_table[openrisc_reloc_map[i].
00212                                    openrisc_reloc_val];
00213 
00214   return NULL;
00215 }
00216 
00217 static reloc_howto_type *
00218 openrisc_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00219                          const char *r_name)
00220 {
00221   unsigned int i;
00222 
00223   for (i = 0;
00224        i < (sizeof (openrisc_elf_howto_table)
00225            / sizeof (openrisc_elf_howto_table[0]));
00226        i++)
00227     if (openrisc_elf_howto_table[i].name != NULL
00228        && strcasecmp (openrisc_elf_howto_table[i].name, r_name) == 0)
00229       return &openrisc_elf_howto_table[i];
00230 
00231   return NULL;
00232 }
00233 
00234 /* Set the howto pointer for an OpenRISC ELF reloc.  */
00235 
00236 static void
00237 openrisc_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED,
00238                           arelent * cache_ptr,
00239                           Elf_Internal_Rela * dst)
00240 {
00241   unsigned int r_type;
00242 
00243   r_type = ELF32_R_TYPE (dst->r_info);
00244   BFD_ASSERT (r_type < (unsigned int) R_OPENRISC_max);
00245   cache_ptr->howto = & openrisc_elf_howto_table[r_type];
00246 }
00247 
00248 /* Perform a single relocation.  By default we use the standard BFD
00249    routines, but a few relocs, we have to do them ourselves.  */
00250 
00251 static bfd_reloc_status_type
00252 openrisc_final_link_relocate (reloc_howto_type *howto,
00253                            bfd *input_bfd,
00254                            asection *input_section,
00255                            bfd_byte *contents,
00256                            Elf_Internal_Rela *rel,
00257                            bfd_vma relocation)
00258 {
00259   bfd_reloc_status_type r = bfd_reloc_ok;
00260 
00261   switch (howto->type)
00262     {
00263     case R_OPENRISC_LO_16_IN_INSN:
00264       relocation &= 0xffff;
00265       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
00266                                 contents, rel->r_offset,
00267                                 relocation, rel->r_addend);
00268       break;
00269 
00270     default:
00271       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
00272                                 contents, rel->r_offset,
00273                                 relocation, rel->r_addend);
00274     }
00275 
00276   return r;
00277 }
00278 
00279 /* Relocate an OpenRISC ELF section.
00280 
00281    The RELOCATE_SECTION function is called by the new ELF backend linker
00282    to handle the relocations for a section.
00283 
00284    The relocs are always passed as Rela structures; if the section
00285    actually uses Rel structures, the r_addend field will always be
00286    zero.
00287 
00288    This function is responsible for adjusting the section contents as
00289    necessary, and (if using Rela relocs and generating a relocatable
00290    output file) adjusting the reloc addend as necessary.
00291 
00292    This function does not have to worry about setting the reloc
00293    address or the reloc symbol index.
00294 
00295    LOCAL_SYMS is a pointer to the swapped in local symbols.
00296 
00297    LOCAL_SECTIONS is an array giving the section in the input file
00298    corresponding to the st_shndx field of each local symbol.
00299 
00300    The global hash table entry for the global symbols can be found
00301    via elf_sym_hashes (input_bfd).
00302 
00303    When generating relocatable output, this function must handle
00304    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
00305    going to be the section symbol corresponding to the output
00306    section, which means that the addend must be adjusted
00307    accordingly.  */
00308 
00309 static bfd_boolean
00310 openrisc_elf_relocate_section (bfd *output_bfd,
00311                             struct bfd_link_info *info,
00312                             bfd *input_bfd,
00313                             asection *input_section,
00314                             bfd_byte *contents,
00315                             Elf_Internal_Rela *relocs,
00316                             Elf_Internal_Sym *local_syms,
00317                             asection **local_sections)
00318 {
00319   Elf_Internal_Shdr *symtab_hdr;
00320   struct elf_link_hash_entry **sym_hashes;
00321   Elf_Internal_Rela *rel;
00322   Elf_Internal_Rela *relend;
00323 
00324   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
00325   sym_hashes = elf_sym_hashes (input_bfd);
00326   relend = relocs + input_section->reloc_count;
00327 
00328   for (rel = relocs; rel < relend; rel++)
00329     {
00330       reloc_howto_type *howto;
00331       unsigned long r_symndx;
00332       Elf_Internal_Sym *sym;
00333       asection *sec;
00334       struct elf_link_hash_entry *h;
00335       bfd_vma relocation;
00336       bfd_reloc_status_type r;
00337       const char *name = NULL;
00338       int r_type;
00339 
00340       r_type = ELF32_R_TYPE (rel->r_info);
00341       r_symndx = ELF32_R_SYM (rel->r_info);
00342 
00343       if (r_type == R_OPENRISC_GNU_VTINHERIT
00344          || r_type == R_OPENRISC_GNU_VTENTRY)
00345        continue;
00346 
00347       if ((unsigned int) r_type >
00348          (sizeof openrisc_elf_howto_table / sizeof (reloc_howto_type)))
00349        abort ();
00350 
00351       howto = openrisc_elf_howto_table + ELF32_R_TYPE (rel->r_info);
00352       h = NULL;
00353       sym = NULL;
00354       sec = NULL;
00355 
00356       if (r_symndx < symtab_hdr->sh_info)
00357        {
00358          sym = local_syms + r_symndx;
00359          sec = local_sections[r_symndx];
00360          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
00361 
00362          name = bfd_elf_string_from_elf_section
00363            (input_bfd, symtab_hdr->sh_link, sym->st_name);
00364          name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
00365        }
00366       else
00367        {
00368          bfd_boolean unresolved_reloc, warned;
00369 
00370          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
00371                                r_symndx, symtab_hdr, sym_hashes,
00372                                h, sec, relocation,
00373                                unresolved_reloc, warned);
00374        }
00375 
00376       if (sec != NULL && elf_discarded_section (sec))
00377        {
00378          /* For relocs against symbols from removed linkonce sections,
00379             or sections discarded by a linker script, we just want the
00380             section contents zeroed.  Avoid any special processing.  */
00381          _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
00382          rel->r_info = 0;
00383          rel->r_addend = 0;
00384          continue;
00385        }
00386 
00387       if (info->relocatable)
00388        continue;
00389 
00390       r = openrisc_final_link_relocate (howto, input_bfd, input_section,
00391                                    contents, rel, relocation);
00392 
00393       if (r != bfd_reloc_ok)
00394        {
00395          const char *msg = NULL;
00396 
00397          switch (r)
00398            {
00399            case bfd_reloc_overflow:
00400              r = info->callbacks->reloc_overflow
00401               (info, (h ? &h->root : NULL), name, howto->name,
00402                (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
00403              break;
00404 
00405            case bfd_reloc_undefined:
00406              r = info->callbacks->undefined_symbol
00407               (info, name, input_bfd, input_section, rel->r_offset, TRUE);
00408              break;
00409 
00410            case bfd_reloc_outofrange:
00411              msg = _("internal error: out of range error");
00412              break;
00413 
00414            case bfd_reloc_notsupported:
00415              msg = _("internal error: unsupported relocation error");
00416              break;
00417 
00418            case bfd_reloc_dangerous:
00419              msg = _("internal error: dangerous relocation");
00420              break;
00421 
00422            default:
00423              msg = _("internal error: unknown error");
00424              break;
00425            }
00426 
00427          if (msg)
00428            r = info->callbacks->warning
00429              (info, msg, name, input_bfd, input_section, rel->r_offset);
00430 
00431          if (!r)
00432            return FALSE;
00433        }
00434     }
00435 
00436   return TRUE;
00437 }
00438 
00439 /* Return the section that should be marked against GC for a given
00440    relocation.  */
00441 
00442 static asection *
00443 openrisc_elf_gc_mark_hook (asection *sec,
00444                         struct bfd_link_info *info,
00445                         Elf_Internal_Rela *rel,
00446                         struct elf_link_hash_entry *h,
00447                         Elf_Internal_Sym *sym)
00448 {
00449   if (h != NULL)
00450     switch (ELF32_R_TYPE (rel->r_info))
00451       {
00452       case R_OPENRISC_GNU_VTINHERIT:
00453       case R_OPENRISC_GNU_VTENTRY:
00454        return NULL;
00455       }
00456 
00457   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
00458 }
00459 
00460 /* Look through the relocs for a section during the first phase.
00461    Since we don't do .gots or .plts, we just need to consider the
00462    virtual table relocs for gc.  */
00463 
00464 static bfd_boolean
00465 openrisc_elf_check_relocs (bfd *abfd,
00466                         struct bfd_link_info *info,
00467                         asection *sec,
00468                         const Elf_Internal_Rela *relocs)
00469 {
00470   Elf_Internal_Shdr *symtab_hdr;
00471   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
00472   const Elf_Internal_Rela *rel;
00473   const Elf_Internal_Rela *rel_end;
00474 
00475   if (info->relocatable)
00476     return TRUE;
00477 
00478   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
00479   sym_hashes = elf_sym_hashes (abfd);
00480   sym_hashes_end =
00481     sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
00482   if (!elf_bad_symtab (abfd))
00483     sym_hashes_end -= symtab_hdr->sh_info;
00484 
00485   rel_end = relocs + sec->reloc_count;
00486   for (rel = relocs; rel < rel_end; rel++)
00487     {
00488       struct elf_link_hash_entry *h;
00489       unsigned long r_symndx;
00490 
00491       r_symndx = ELF32_R_SYM (rel->r_info);
00492       if (r_symndx < symtab_hdr->sh_info)
00493        h = NULL;
00494       else
00495        {
00496          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
00497          while (h->root.type == bfd_link_hash_indirect
00498                || h->root.type == bfd_link_hash_warning)
00499            h = (struct elf_link_hash_entry *) h->root.u.i.link;
00500        }
00501 
00502       switch (ELF32_R_TYPE (rel->r_info))
00503        {
00504          /* This relocation describes the C++ object vtable hierarchy.
00505             Reconstruct it for later use during GC.  */
00506        case R_OPENRISC_GNU_VTINHERIT:
00507          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
00508            return FALSE;
00509          break;
00510 
00511          /* This relocation describes which C++ vtable entries are actually
00512             used.  Record for later use during GC.  */
00513        case R_OPENRISC_GNU_VTENTRY:
00514          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
00515            return FALSE;
00516          break;
00517        }
00518     }
00519 
00520   return TRUE;
00521 }
00522 
00523 /* Set the right machine number.  */
00524 
00525 static bfd_boolean
00526 openrisc_elf_object_p (bfd *abfd)
00527 {
00528   bfd_default_set_arch_mach (abfd, bfd_arch_openrisc, 0);
00529   return TRUE;
00530 }
00531 
00532 /* Store the machine number in the flags field.  */
00533 
00534 static void
00535 openrisc_elf_final_write_processing (bfd *abfd,
00536                                  bfd_boolean linker ATTRIBUTE_UNUSED)
00537 {
00538   unsigned long val;
00539 
00540   switch (bfd_get_mach (abfd))
00541     {
00542     default:
00543       val = 0;
00544       break;
00545     }
00546 
00547   elf_elfheader (abfd)->e_flags &= ~0xf;
00548   elf_elfheader (abfd)->e_flags |= val;
00549 }
00550 
00551 
00552 #define ELF_ARCH                   bfd_arch_openrisc
00553 #define ELF_MACHINE_CODE           EM_OPENRISC
00554 #define ELF_MACHINE_ALT1           EM_OPENRISC_OLD
00555 #define ELF_MAXPAGESIZE                   0x1000
00556 
00557 #define TARGET_BIG_SYM                    bfd_elf32_openrisc_vec
00558 #define TARGET_BIG_NAME                   "elf32-openrisc"
00559 
00560 #define elf_info_to_howto_rel             NULL
00561 #define elf_info_to_howto          openrisc_info_to_howto_rela
00562 #define elf_backend_relocate_section      openrisc_elf_relocate_section
00563 #define elf_backend_gc_mark_hook   openrisc_elf_gc_mark_hook
00564 #define elf_backend_check_relocs   openrisc_elf_check_relocs
00565 
00566 #define elf_backend_can_gc_sections       1
00567 #define elf_backend_rela_normal           1
00568 
00569 #define bfd_elf32_bfd_reloc_type_lookup openrisc_reloc_type_lookup
00570 #define bfd_elf32_bfd_reloc_name_lookup openrisc_reloc_name_lookup
00571 
00572 #define elf_backend_object_p                openrisc_elf_object_p
00573 #define elf_backend_final_write_processing  openrisc_elf_final_write_processing
00574 
00575 #include "elf32-target.h"