Back to index

cell-binutils  2.17cvs20070401
elf32-pj.c
Go to the documentation of this file.
00001 /* picoJava specific support for 32-bit ELF
00002    Copyright 1999, 2000, 2001, 2002, 2005, 2007
00003    Free Software Foundation, Inc.
00004    Contributed by Steve Chamberlan of Transmeta (sac@pobox.com).
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, USA.  */
00021 
00022 #include "bfd.h"
00023 #include "sysdep.h"
00024 #include "bfdlink.h"
00025 #include "libbfd.h"
00026 #include "elf-bfd.h"
00027 #include "elf/pj.h"
00028 
00029 /* This function is used for normal relocs.  This is like the COFF
00030    function, and is almost certainly incorrect for other ELF targets.  */
00031 
00032 static bfd_reloc_status_type
00033 pj_elf_reloc (bfd *abfd,
00034              arelent *reloc_entry,
00035              asymbol *symbol_in,
00036              void * data,
00037              asection *input_section,
00038              bfd *output_bfd,
00039              char **error_message ATTRIBUTE_UNUSED)
00040 {
00041   unsigned long insn;
00042   bfd_vma sym_value;
00043   enum elf_pj_reloc_type r_type;
00044   bfd_vma addr = reloc_entry->address;
00045   bfd_byte *hit_data = addr + (bfd_byte *) data;
00046 
00047   r_type = (enum elf_pj_reloc_type) reloc_entry->howto->type;
00048 
00049   if (output_bfd != NULL)
00050     {
00051       /* Partial linking--do nothing.  */
00052       reloc_entry->address += input_section->output_offset;
00053       return bfd_reloc_ok;
00054     }
00055 
00056   if (symbol_in != NULL
00057       && bfd_is_und_section (symbol_in->section))
00058     return bfd_reloc_undefined;
00059 
00060   if (bfd_is_com_section (symbol_in->section))
00061     sym_value = 0;
00062   else
00063     sym_value = (symbol_in->value +
00064                symbol_in->section->output_section->vma +
00065                symbol_in->section->output_offset);
00066 
00067   switch (r_type)
00068     {
00069     case R_PJ_DATA_DIR32:
00070       insn = bfd_get_32 (abfd, hit_data);
00071       insn += sym_value + reloc_entry->addend;
00072       bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
00073       break;
00074 
00075       /* Relocations in code are always bigendian, no matter what the
00076         data endianness is.  */
00077 
00078     case R_PJ_CODE_DIR32:
00079       insn = bfd_getb32 (hit_data);
00080       insn += sym_value + reloc_entry->addend;
00081       bfd_putb32 ((bfd_vma) insn, hit_data);
00082       break;
00083 
00084     case R_PJ_CODE_REL16:
00085       insn = bfd_getb16 (hit_data);
00086       insn += sym_value + reloc_entry->addend
00087         -  (input_section->output_section->vma
00088             + input_section->output_offset);
00089       bfd_putb16 ((bfd_vma) insn, hit_data);
00090       break;
00091     case R_PJ_CODE_LO16:
00092       insn = bfd_getb16 (hit_data);
00093       insn += sym_value + reloc_entry->addend;
00094       bfd_putb16 ((bfd_vma) insn, hit_data);
00095       break;
00096 
00097     case R_PJ_CODE_HI16:
00098       insn = bfd_getb16 (hit_data);
00099       insn += (sym_value + reloc_entry->addend) >> 16;
00100       bfd_putb16 ((bfd_vma) insn, hit_data);
00101       break;
00102 
00103     default:
00104       abort ();
00105       break;
00106     }
00107 
00108   return bfd_reloc_ok;
00109 }
00110 
00111 static reloc_howto_type pj_elf_howto_table[] =
00112 {
00113   /* No relocation.  */
00114   HOWTO (R_PJ_NONE,         /* type */
00115         0,                  /* rightshift */
00116         0,                  /* size (0 = byte, 1 = short, 2 = long) */
00117         0,                  /* bitsize */
00118         FALSE,                     /* pc_relative */
00119         0,                  /* bitpos */
00120         complain_overflow_dont, /* complain_on_overflow */
00121         pj_elf_reloc,              /* special_function */
00122         "R_PJ_NONE",        /* name */
00123         FALSE,                     /* partial_inplace */
00124         0,                  /* src_mask */
00125         0,                  /* dst_mask */
00126         FALSE),             /* pcrel_offset */
00127 
00128   /* 32 bit absolute relocation.  Setting partial_inplace to TRUE and
00129      src_mask to a non-zero value is similar to the COFF toolchain.  */
00130   HOWTO (R_PJ_DATA_DIR32,   /* type */
00131         0,                  /* rightshift */
00132         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00133         32,                 /* bitsize */
00134         FALSE,                     /* pc_relative */
00135         0,                  /* bitpos */
00136         complain_overflow_bitfield, /* complain_on_overflow */
00137         pj_elf_reloc,              /* special_function */
00138         "R_PJ_DIR32",              /* name */
00139         TRUE,               /* partial_inplace */
00140         0xffffffff,         /* src_mask */
00141         0xffffffff,         /* dst_mask */
00142         FALSE),             /* pcrel_offset */
00143 
00144   /* 32 bit PC relative relocation.  */
00145   HOWTO (R_PJ_CODE_REL32,   /* type */
00146         0,                  /* rightshift */
00147         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00148         32,                 /* bitsize */
00149         TRUE,               /* pc_relative */
00150         0,                  /* bitpos */
00151         complain_overflow_signed, /* complain_on_overflow */
00152         pj_elf_reloc,              /* special_function */
00153         "R_PJ_REL32",              /* name */
00154         FALSE,                     /* partial_inplace */
00155         0,                  /* src_mask */
00156         0xffffffff,         /* dst_mask */
00157         TRUE),                     /* pcrel_offset */
00158 
00159 /* 16 bit PC relative relocation.  */
00160   HOWTO (R_PJ_CODE_REL16,   /* type */
00161         0,                  /* rightshift */
00162         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00163         16,                 /* bitsize */
00164         TRUE,               /* pc_relative */
00165         0,                  /* bitpos */
00166         complain_overflow_signed, /* complain_on_overf6w */
00167         pj_elf_reloc,              /* special_function */
00168         "R_PJ_REL16",              /* name */
00169         FALSE,                     /* partial_inplace */
00170         0xffff,             /* src_mask */
00171         0xffff,             /* dst_mask */
00172         TRUE),                     /* pcrel_offset */
00173   EMPTY_HOWTO (4),
00174   EMPTY_HOWTO (5),
00175   HOWTO (R_PJ_CODE_DIR32,   /* type */
00176         0,                  /* rightshift */
00177         2,                  /* size (0 = byte, 1 = short, 2 = long) */
00178         32,                 /* bitsize */
00179         FALSE,                     /* pc_relative */
00180         0,                  /* bitpos */
00181         complain_overflow_bitfield, /* complain_on_overflow */
00182         pj_elf_reloc,              /* special_function */
00183         "R_PJ_CODE_DIR32",  /* name */
00184         TRUE,               /* partial_inplace */
00185         0xffffffff,         /* src_mask */
00186         0xffffffff,         /* dst_mask */
00187         FALSE),             /* pcrel_offset */
00188 
00189   EMPTY_HOWTO (7),
00190   EMPTY_HOWTO (8),
00191   EMPTY_HOWTO (9),
00192   EMPTY_HOWTO (10),
00193   EMPTY_HOWTO (11),
00194   EMPTY_HOWTO (12),
00195 
00196   HOWTO (R_PJ_CODE_LO16,    /* type */
00197         0,                  /* rightshift */
00198         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00199         16,                 /* bitsize */
00200         FALSE,                     /* pc_relative */
00201         0,                  /* bitpos */
00202         complain_overflow_unsigned, /* complain_on_overflow */
00203         pj_elf_reloc,              /* special_function */
00204         "R_PJ_LO16",        /* name */
00205         FALSE,                     /* partial_inplace */
00206         0xffff,             /* src_mask */
00207         0xffff,             /* dst_mask */
00208         TRUE),                     /* pcrel_offset */
00209 
00210     HOWTO (R_PJ_CODE_HI16,  /* type */
00211         16,                 /* rightshift */
00212         1,                  /* size (0 = byte, 1 = short, 2 = long) */
00213         16,                 /* bitsize */
00214         FALSE,                     /* pc_relative */
00215         0,                  /* bitpos */
00216         complain_overflow_unsigned, /* complain_on_overflow */
00217         pj_elf_reloc,              /* special_function */
00218         "R_PJ_HI16",        /* name */
00219         FALSE,                     /* partial_inplace */
00220         0xffff,             /* src_mask */
00221         0xffff,             /* dst_mask */
00222         TRUE),                     /* pcrel_offset */
00223 
00224   /* GNU extension to record C++ vtable hierarchy.  */
00225   HOWTO (R_PJ_GNU_VTINHERIT,    /* type */
00226          0,                     /* rightshift */
00227          2,                     /* size (0 = byte, 1 = short, 2 = long) */
00228          0,                     /* bitsize */
00229          FALSE,                 /* pc_relative */
00230          0,                     /* bitpos */
00231          complain_overflow_dont, /* complain_on_overflow */
00232          NULL,                  /* special_function */
00233          "R_PJ_GNU_VTINHERIT",  /* name */
00234          FALSE,                 /* partial_inplace */
00235          0,                     /* src_mask */
00236          0,                     /* dst_mask */
00237          FALSE),                /* pcrel_offset */
00238 
00239   /* GNU extension to record C++ vtable member usage.  */
00240   HOWTO (R_PJ_GNU_VTENTRY,     /* type */
00241          0,                     /* rightshift */
00242          2,                     /* size (0 = byte, 1 = short, 2 = long) */
00243          0,                     /* bitsize */
00244          FALSE,                 /* pc_relative */
00245          0,                     /* bitpos */
00246          complain_overflow_dont, /* complain_on_overflow */
00247          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
00248          "R_PJ_GNU_VTENTRY",   /* name */
00249          FALSE,                 /* partial_inplace */
00250          0,                     /* src_mask */
00251          0,                     /* dst_mask */
00252          FALSE),                /* pcrel_offset */
00253 };
00254 
00255 /* This structure is used to map BFD reloc codes to PJ ELF relocs.  */
00256 
00257 struct elf_reloc_map
00258 {
00259   bfd_reloc_code_real_type bfd_reloc_val;
00260   unsigned char elf_reloc_val;
00261 };
00262 
00263 /* An array mapping BFD reloc codes to PJ ELF relocs.  */
00264 
00265 static const struct elf_reloc_map pj_reloc_map[] =
00266 {
00267     { BFD_RELOC_NONE,              R_PJ_NONE          },
00268     { BFD_RELOC_32,         R_PJ_DATA_DIR32    },
00269     { BFD_RELOC_PJ_CODE_DIR16,     R_PJ_CODE_DIR16    },
00270     { BFD_RELOC_PJ_CODE_DIR32,     R_PJ_CODE_DIR32    },
00271     { BFD_RELOC_PJ_CODE_LO16,      R_PJ_CODE_LO16     },
00272     { BFD_RELOC_PJ_CODE_HI16,      R_PJ_CODE_HI16     },
00273     { BFD_RELOC_PJ_CODE_REL32,  R_PJ_CODE_REL32    },
00274     { BFD_RELOC_PJ_CODE_REL16,  R_PJ_CODE_REL16    },
00275     { BFD_RELOC_VTABLE_INHERIT, R_PJ_GNU_VTINHERIT },
00276     { BFD_RELOC_VTABLE_ENTRY,   R_PJ_GNU_VTENTRY   },
00277 };
00278 
00279 /* Given a BFD reloc code, return the howto structure for the
00280    corresponding PJ ELf reloc.  */
00281 
00282 static reloc_howto_type *
00283 pj_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00284                        bfd_reloc_code_real_type code)
00285 {
00286   unsigned int i;
00287 
00288   for (i = 0; i < sizeof (pj_reloc_map) / sizeof (struct elf_reloc_map); i++)
00289     if (pj_reloc_map[i].bfd_reloc_val == code)
00290       return & pj_elf_howto_table[(int) pj_reloc_map[i].elf_reloc_val];
00291 
00292   return NULL;
00293 }
00294 
00295 static reloc_howto_type *
00296 pj_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
00297                        const char *r_name)
00298 {
00299   unsigned int i;
00300 
00301   for (i = 0;
00302        i < sizeof (pj_elf_howto_table) / sizeof (pj_elf_howto_table[0]);
00303        i++)
00304     if (pj_elf_howto_table[i].name != NULL
00305        && strcasecmp (pj_elf_howto_table[i].name, r_name) == 0)
00306       return &pj_elf_howto_table[i];
00307 
00308   return NULL;
00309 }
00310 
00311 /* Given an ELF reloc, fill in the howto field of a relent.  */
00312 
00313 static void
00314 pj_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
00315                     arelent *cache_ptr,
00316                     Elf_Internal_Rela *dst)
00317 {
00318   unsigned int r;
00319 
00320   r = ELF32_R_TYPE (dst->r_info);
00321 
00322   BFD_ASSERT (r < (unsigned int) R_PJ_max);
00323 
00324   cache_ptr->howto = &pj_elf_howto_table[r];
00325 }
00326 
00327 /* Take this moment to fill in the special picoJava bits in the
00328    e_flags field.  */
00329 
00330 static void
00331 pj_elf_final_write_processing (bfd *abfd,
00332                             bfd_boolean linker ATTRIBUTE_UNUSED)
00333 {
00334   elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_ARCH;
00335   elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_GNUCALLS;
00336 }
00337 
00338 #define TARGET_BIG_SYM             bfd_elf32_pj_vec
00339 #define TARGET_BIG_NAME            "elf32-pj"
00340 #define TARGET_LITTLE_SYM   bfd_elf32_pjl_vec
00341 #define TARGET_LITTLE_NAME  "elf32-pjl"
00342 #define ELF_ARCH            bfd_arch_pj
00343 #define ELF_MACHINE_CODE    EM_PJ
00344 #define ELF_MACHINE_ALT1    EM_PJ_OLD
00345 #define ELF_MAXPAGESIZE            0x1000
00346 #define bfd_elf32_bfd_get_relocated_section_contents \
00347   bfd_generic_get_relocated_section_contents
00348 #define bfd_elf32_bfd_reloc_type_lookup           pj_elf_reloc_type_lookup
00349 #define bfd_elf32_bfd_reloc_name_lookup   pj_elf_reloc_name_lookup
00350 #define elf_backend_final_write_processing      pj_elf_final_write_processing
00351 #define elf_info_to_howto                  pj_elf_info_to_howto
00352 #include "elf32-target.h"