Back to index

cell-binutils  2.17cvs20070401
elf32-or32.c
Go to the documentation of this file.
00001 /* OR32-specific support for 32-bit ELF
00002    Copyright 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
00003    Contributed by Ivan Guzvinec  <ivang@opencores.org>
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/or32.h"
00026 #include "libiberty.h"
00027 
00028 /* Try to minimize the amount of space occupied by relocation tables
00029    on the ROM (not that the ROM won't be swamped by other ELF overhead).  */
00030 #define USE_REL      1
00031 
00032 /* Set the right machine number for an OR32 ELF file.  */
00033 
00034 static bfd_boolean
00035 or32_elf_object_p (bfd *abfd)
00036 {
00037   (void) bfd_default_set_arch_mach (abfd, bfd_arch_or32, 0);
00038   return TRUE;
00039 }
00040 
00041 /* The final processing done just before writing out an OR32 ELF object file.
00042    This gets the OR32 architecture right based on the machine number.  */
00043 
00044 static void
00045 or32_elf_final_write_processing (bfd *abfd,
00046                              bfd_boolean linker ATTRIBUTE_UNUSED)
00047 {
00048   elf_elfheader (abfd)->e_flags &=~ EF_OR32_MACH;
00049 }
00050 
00051 static bfd_reloc_status_type
00052 or32_elf_32_reloc (bfd *abfd,
00053                  arelent *reloc_entry,
00054                  asymbol *symbol,
00055                  void * data,
00056                  asection *input_section,
00057                  bfd *output_bfd,
00058                  char **error_message ATTRIBUTE_UNUSED)
00059 {
00060   if (output_bfd != NULL)
00061     {
00062       unsigned long insn;
00063       bfd_size_type addr = reloc_entry->address;
00064 
00065       reloc_entry->address += input_section->output_offset;
00066 
00067       insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
00068       insn += symbol->section->output_section->vma;
00069       insn += symbol->section->output_offset;
00070       insn += symbol->value;
00071       bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
00072 
00073       return bfd_reloc_ok;
00074     }
00075 
00076   return bfd_reloc_continue;
00077 }
00078 
00079 static bfd_reloc_status_type
00080 or32_elf_16_reloc (bfd *abfd,
00081                  arelent *reloc_entry,
00082                  asymbol *symbol,
00083                  void * data,
00084                  asection *input_section,
00085                  bfd *output_bfd,
00086                  char **error_message ATTRIBUTE_UNUSED)
00087 {
00088   if (output_bfd != NULL)
00089     {
00090       unsigned short insn;
00091       bfd_size_type addr = reloc_entry->address;
00092 
00093       reloc_entry->address += input_section->output_offset;
00094 
00095       insn = bfd_get_16 (abfd, (bfd_byte *) data + addr);
00096       insn += symbol->section->output_section->vma;
00097       insn += symbol->section->output_offset;
00098       insn += symbol->value;
00099       bfd_put_16 (abfd, insn, (bfd_byte *) data + addr);
00100 
00101       return bfd_reloc_ok;
00102     }
00103 
00104   return bfd_reloc_continue;
00105 }
00106 
00107 static bfd_reloc_status_type
00108 or32_elf_8_reloc (bfd *abfd ATTRIBUTE_UNUSED,
00109                 arelent *reloc_entry,
00110                 asymbol *symbol,
00111                 void * data,
00112                 asection *input_section,
00113                 bfd *output_bfd,
00114                 char **error_message ATTRIBUTE_UNUSED)
00115 {
00116   if (output_bfd != NULL)
00117     {
00118       unsigned char insn;
00119       bfd_size_type addr = reloc_entry->address;
00120 
00121       reloc_entry->address += input_section->output_offset;
00122 
00123       insn = bfd_get_8 (abfd, (bfd_byte *) data + addr);
00124       insn += symbol->section->output_section->vma;
00125       insn += symbol->section->output_offset;
00126       insn += symbol->value;
00127       bfd_put_8 (abfd, insn, (bfd_byte *) data + addr);
00128 
00129       return bfd_reloc_ok;
00130     }
00131 
00132   return bfd_reloc_continue;
00133 }
00134 
00135 /* Do a R_OR32_CONSTH relocation.  This has to be done in combination
00136    with a R_OR32_CONST reloc, because there is a carry from the LO16 to
00137    the HI16.  Here we just save the information we need; we do the
00138    actual relocation when we see the LO16.  OR32 ELF requires that the
00139    LO16 immediately follow the HI16.  As a GNU extension, we permit an
00140    arbitrary number of HI16 relocs to be associated with a single LO16
00141    reloc.  This extension permits gcc to output the HI and LO relocs
00142    itself. This code is copied from the elf32-mips.c.  */
00143 
00144 struct or32_consth
00145 {
00146   struct or32_consth *next;
00147   bfd_byte *addr;
00148   bfd_vma addend;
00149 };
00150 
00151 /* FIXME: This should not be a static variable.  */
00152 
00153 static struct or32_consth *or32_consth_list;
00154 
00155 static bfd_reloc_status_type
00156 or32_elf_consth_reloc (bfd *abfd ATTRIBUTE_UNUSED,
00157                      arelent *reloc_entry,
00158                      asymbol *symbol,
00159                      void * data,
00160                      asection *input_section,
00161                      bfd *output_bfd,
00162                      char **error_message ATTRIBUTE_UNUSED)
00163 {
00164   bfd_reloc_status_type ret;
00165   bfd_vma relocation;
00166   struct or32_consth *n;
00167 
00168   ret = bfd_reloc_ok;
00169 
00170   if (bfd_is_und_section (symbol->section)
00171       && output_bfd == NULL)
00172     ret = bfd_reloc_undefined;
00173 
00174   if (bfd_is_com_section (symbol->section))
00175     relocation = 0;
00176   else
00177     relocation = symbol->value;
00178 
00179   relocation += symbol->section->output_section->vma;
00180   relocation += symbol->section->output_offset;
00181   relocation += reloc_entry->addend;
00182 
00183   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
00184     return bfd_reloc_outofrange;
00185 
00186   /* Save the information, and let LO16 do the actual relocation.  */
00187   n = bfd_malloc (sizeof *n);
00188   if (n == NULL)
00189     return bfd_reloc_outofrange;
00190   n->addr = (bfd_byte *) data + reloc_entry->address;
00191   n->addend = relocation;
00192   n->next = or32_consth_list;
00193   or32_consth_list = n;
00194 
00195   if (output_bfd != NULL)
00196     reloc_entry->address += input_section->output_offset;
00197 
00198   return ret;
00199 }
00200 
00201 /* Do a R_OR32_CONST relocation.  This is a straightforward 16 bit
00202    inplace relocation; this function exists in order to do the
00203    R_OR32_CONSTH relocation described above.  */
00204 
00205 static bfd_reloc_status_type
00206 or32_elf_const_reloc (bfd *abfd,
00207                     arelent *reloc_entry,
00208                     asymbol *symbol,
00209                     void * data,
00210                     asection *input_section,
00211                     bfd *output_bfd,
00212                     char **error_message)
00213 {
00214   if (or32_consth_list != NULL)
00215     {
00216       struct or32_consth *l;
00217 
00218       l = or32_consth_list;
00219       while (l != NULL)
00220        {
00221          unsigned long insn;
00222          unsigned long val;
00223           unsigned long vallo;
00224          struct or32_consth *next;
00225 
00226          /* Do the HI16 relocation.  Note that we actually don't need
00227             to know anything about the LO16 itself, except where to
00228             find the low 16 bits of the addend needed by the LO16.  */
00229          insn = bfd_get_32 (abfd, l->addr);
00230          vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
00231                  & 0xffff);
00232          val = ((insn & 0xffff) << 16) + vallo;
00233          val += l->addend;
00234 
00235          insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff);
00236          bfd_put_32 (abfd, insn, l->addr);
00237 
00238          next = l->next;
00239          free (l);
00240          l = next;
00241        }
00242 
00243       or32_consth_list = NULL;
00244     }
00245 
00246   if (output_bfd != NULL)
00247     {
00248       unsigned long insn, tmp;
00249       bfd_size_type addr = reloc_entry->address;
00250 
00251       reloc_entry->address += input_section->output_offset;
00252 
00253       insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
00254       tmp = insn & 0x0000ffff;
00255       tmp += symbol->section->output_section->vma;
00256       tmp += symbol->section->output_offset;
00257       tmp += symbol->value;
00258       insn = (insn & 0xffff0000) | (tmp & 0x0000ffff);
00259       bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
00260 
00261       return bfd_reloc_ok;
00262     }
00263 
00264   /* Now do the LO16 reloc in the usual way.  */
00265   return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
00266                             input_section, output_bfd, error_message);
00267 }
00268 
00269 static bfd_reloc_status_type
00270 or32_elf_jumptarg_reloc (bfd *abfd,
00271                       arelent *reloc_entry,
00272                       asymbol *symbol ATTRIBUTE_UNUSED,
00273                       void * data,
00274                       asection *input_section,
00275                       bfd *output_bfd,
00276                       char **error_message ATTRIBUTE_UNUSED)
00277 {
00278   if (output_bfd != NULL)
00279     {
00280       unsigned long insn, tmp;
00281       bfd_size_type addr = reloc_entry->address;
00282 
00283       reloc_entry->address += input_section->output_offset;
00284 
00285       insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
00286       tmp = insn | 0xfc000000;
00287       tmp -= (input_section->output_offset >> 2);
00288       insn = (insn & 0xfc000000) | (tmp & 0x03ffffff);
00289       bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
00290 
00291       return bfd_reloc_ok;
00292     }
00293 
00294   return bfd_reloc_continue;
00295 }
00296 
00297 static reloc_howto_type elf_or32_howto_table[] =
00298 {
00299   /* This reloc does nothing.  */
00300   HOWTO (R_OR32_NONE,              /* type */
00301         0,                  /* rightshift */
00302         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00303         32,                 /* bitsize */
00304         FALSE,                     /* pc_relative */
00305         0,                  /* bitpos */
00306         complain_overflow_bitfield, /* complain_on_overflow */
00307         bfd_elf_generic_reloc,     /* special_function */
00308         "R_OR32_NONE",             /* name */
00309         FALSE,                     /* partial_inplace */
00310         0,                  /* src_mask */
00311         0,                  /* dst_mask */
00312         FALSE),             /* pcrel_offset */
00313 
00314   /* A standard 32 bit relocation.  */
00315   HOWTO (R_OR32_32,         /* type */
00316         0,                    /* rightshift */
00317         2,                    /* size (0 = byte, 1 = short, 2 = long) */
00318         32,                   /* bitsize */
00319         FALSE,                       /* pc_relative */
00320         0,                    /* bitpos */
00321         complain_overflow_bitfield, /* complain_on_overflow */
00322         or32_elf_32_reloc,  /* special_function */
00323         "R_OR32_32",        /* name */
00324         FALSE,                       /* partial_inplace */
00325         0xffffffff,          /* src_mask */
00326         0xffffffff,                /* dst_mask */
00327         FALSE),                /* pcrel_offset */
00328 
00329   /* A standard 16 bit relocation.  */
00330   HOWTO (R_OR32_16,         /* type */
00331         0,                    /* rightshift */
00332         1,                    /* size (0 = byte, 1 = short, 2 = long) */
00333         16,                   /* bitsize */
00334         FALSE,                       /* pc_relative */
00335         0,                    /* bitpos */
00336         complain_overflow_bitfield, /* complain_on_overflow */
00337         or32_elf_16_reloc,  /* special_function */
00338         "R_OR32_16",        /* name */
00339         FALSE,                       /* partial_inplace */
00340         0x0000ffff,          /* src_mask */
00341         0x0000ffff,                /* dst_mask */
00342         FALSE),                /* pcrel_offset */
00343 
00344   /* A standard 8 bit relocation.  */
00345   HOWTO (R_OR32_8,          /* type */
00346         0,                    /* rightshift */
00347         0,                    /* size (0 = byte, 1 = short, 2 = long) */
00348         8,                    /* bitsize */
00349         FALSE,                       /* pc_relative */
00350         0,                    /* bitpos */
00351         complain_overflow_bitfield, /* complain_on_overflow */
00352         or32_elf_8_reloc,   /* special_function */
00353         "R_OR32_8",         /* name */
00354         FALSE,                       /* partial_inplace */
00355         0x000000ff,          /* src_mask */
00356         0x000000ff,                /* dst_mask */
00357         FALSE),                /* pcrel_offset */
00358 
00359   /* A standard low 16 bit relocation.  */
00360   HOWTO (R_OR32_CONST,             /* type */
00361         0,                  /* rightshift */
00362         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00363         16,                 /* bitsize */
00364         FALSE,                     /* pc_relative */
00365         0,                  /* bitpos */
00366         complain_overflow_dont, /* complain_on_overflow */
00367         or32_elf_const_reloc,      /* special_function */
00368         "R_OR32_CONST",     /* name */
00369         FALSE,                     /* partial_inplace */
00370         0x0000ffff,         /* src_mask */
00371         0x0000ffff,         /* dst_mask */
00372         FALSE),             /* pcrel_offset */
00373 
00374   /* A standard high 16 bit relocation.  */
00375   HOWTO (R_OR32_CONSTH,            /* type */
00376         16,                 /* rightshift */
00377         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00378         16,                 /* bitsize */
00379         TRUE,               /* pc_relative */
00380         0,                  /* bitpos */
00381         complain_overflow_dont, /* complain_on_overflow */
00382         or32_elf_consth_reloc,     /* special_function */
00383         "R_OR32_CONSTH",    /* name */
00384         FALSE,                     /* partial_inplace */
00385         0xffff0000,         /* src_mask */
00386         0x0000ffff,         /* dst_mask */
00387         FALSE),             /* pcrel_offset */
00388 
00389   /* A standard branch relocation.  */
00390   HOWTO (R_OR32_JUMPTARG,   /* type */
00391         2,                  /* rightshift */
00392         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00393         28,                 /* bitsize */
00394         TRUE,               /* pc_relative */
00395         0,                  /* bitpos */
00396         complain_overflow_signed, /* complain_on_overflow */
00397         or32_elf_jumptarg_reloc,/* special_function */
00398         "R_OR32_JUMPTARG",  /* name */
00399         FALSE,                     /* partial_inplace */
00400         0,                  /* src_mask */
00401         0x03ffffff,         /* dst_mask */
00402         TRUE),              /* pcrel_offset */
00403 
00404   /* GNU extension to record C++ vtable hierarchy.  */
00405   HOWTO (R_OR32_GNU_VTINHERIT, /* type */
00406          0,                     /* rightshift */
00407          2,                     /* size (0 = byte, 1 = short, 2 = long) */
00408          0,                     /* bitsize */
00409          FALSE,                 /* pc_relative */
00410          0,                     /* bitpos */
00411          complain_overflow_dont, /* complain_on_overflow */
00412          NULL,                  /* special_function */
00413          "R_OR32_GNU_VTINHERIT", /* name */
00414          FALSE,                 /* partial_inplace */
00415          0,                     /* src_mask */
00416          0,                     /* dst_mask */
00417          FALSE),                /* pcrel_offset */
00418 
00419   /* GNU extension to record C++ vtable member usage.  */
00420   HOWTO (R_OR32_GNU_VTENTRY,     /* type */
00421          0,                     /* rightshift */
00422          2,                     /* size (0 = byte, 1 = short, 2 = long) */
00423          0,                     /* bitsize */
00424          FALSE,                 /* pc_relative */
00425          0,                     /* bitpos */
00426          complain_overflow_dont, /* complain_on_overflow */
00427          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
00428          "R_OR32_GNU_VTENTRY",   /* name */
00429          FALSE,                 /* partial_inplace */
00430          0,                     /* src_mask */
00431          0,                     /* dst_mask */
00432          FALSE),                /* pcrel_offset */
00433 };
00434 
00435 /* Map BFD reloc types to OR32 ELF reloc types.  */
00436 
00437 struct or32_reloc_map
00438 {
00439   bfd_reloc_code_real_type  bfd_reloc_val;
00440   unsigned char             elf_reloc_val;
00441 };
00442 
00443 static const struct or32_reloc_map or32_reloc_map[] =
00444 {
00445   { BFD_RELOC_NONE, R_OR32_NONE },
00446   { BFD_RELOC_32, R_OR32_32 },
00447   { BFD_RELOC_16, R_OR32_16 },
00448   { BFD_RELOC_8, R_OR32_8 },
00449   { BFD_RELOC_LO16, R_OR32_CONST },
00450   { BFD_RELOC_HI16, R_OR32_CONSTH },
00451   { BFD_RELOC_32_GOT_PCREL, R_OR32_JUMPTARG },
00452   { BFD_RELOC_VTABLE_INHERIT, R_OR32_GNU_VTINHERIT },
00453   { BFD_RELOC_VTABLE_ENTRY, R_OR32_GNU_VTENTRY },
00454 };
00455 
00456 static reloc_howto_type *
00457 bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00458                              bfd_reloc_code_real_type code)
00459 {
00460   unsigned int i;
00461 
00462   for (i = ARRAY_SIZE (or32_reloc_map); i--;)
00463     if (or32_reloc_map[i].bfd_reloc_val == code)
00464       return &elf_or32_howto_table[or32_reloc_map[i].elf_reloc_val];
00465 
00466   return NULL;
00467 }
00468 
00469 static reloc_howto_type *
00470 bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00471                              const char *r_name)
00472 {
00473   unsigned int i;
00474 
00475   for (i = 0;
00476        i < sizeof (elf_or32_howto_table) / sizeof (elf_or32_howto_table[0]);
00477        i++)
00478     if (elf_or32_howto_table[i].name != NULL
00479        && strcasecmp (elf_or32_howto_table[i].name, r_name) == 0)
00480       return &elf_or32_howto_table[i];
00481 
00482   return NULL;
00483 }
00484 
00485 /* Set the howto pointer for an OR32 ELF reloc.  */
00486 
00487 static void
00488 or32_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
00489                      arelent *cache_ptr,
00490                      Elf_Internal_Rela *dst)
00491 {
00492   unsigned int r_type;
00493 
00494   r_type = ELF32_R_TYPE (dst->r_info);
00495   BFD_ASSERT (r_type < (unsigned int) R_OR32_max);
00496   cache_ptr->howto = &elf_or32_howto_table[r_type];
00497 }
00498 
00499 #define TARGET_LITTLE_SYM   bfd_elf32_or32_little_vec
00500 #define TARGET_LITTLE_NAME  "elf32-littleor32"
00501 #define TARGET_BIG_SYM             bfd_elf32_or32_big_vec
00502 #define TARGET_BIG_NAME            "elf32-or32"
00503 #define ELF_ARCH            bfd_arch_or32
00504 #define ELF_MACHINE_CODE    EM_OR32
00505 #define ELF_MAXPAGESIZE            0x1000
00506 
00507 #define elf_info_to_howto   0
00508 #define elf_info_to_howto_rel      or32_info_to_howto_rel
00509 #define elf_backend_object_p       or32_elf_object_p
00510 #define elf_backend_final_write_processing \
00511                             or32_elf_final_write_processing
00512 
00513 #include "elf32-target.h"