Home | History | Annotate | Download | only in bfd
      1 /* picoJava specific support for 32-bit ELF
      2    Copyright (C) 1999-2014 Free Software Foundation, Inc.
      3    Contributed by Steve Chamberlan of Transmeta (sac (at) pobox.com).
      4 
      5    This file is part of BFD, the Binary File Descriptor library.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program; if not, write to the Free Software
     19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     20    MA 02110-1301, USA.  */
     21 
     22 #include "sysdep.h"
     23 #include "bfd.h"
     24 #include "bfdlink.h"
     25 #include "libbfd.h"
     26 #include "elf-bfd.h"
     27 #include "elf/pj.h"
     28 
     29 /* This function is used for normal relocs.  This is like the COFF
     30    function, and is almost certainly incorrect for other ELF targets.  */
     31 
     32 static bfd_reloc_status_type
     33 pj_elf_reloc (bfd *abfd,
     34 	      arelent *reloc_entry,
     35 	      asymbol *symbol_in,
     36 	      void * data,
     37 	      asection *input_section,
     38 	      bfd *output_bfd,
     39 	      char **error_message ATTRIBUTE_UNUSED)
     40 {
     41   unsigned long insn;
     42   bfd_vma sym_value;
     43   enum elf_pj_reloc_type r_type;
     44   bfd_vma addr = reloc_entry->address;
     45   bfd_byte *hit_data = addr + (bfd_byte *) data;
     46 
     47   r_type = (enum elf_pj_reloc_type) reloc_entry->howto->type;
     48 
     49   if (output_bfd != NULL)
     50     {
     51       /* Partial linking--do nothing.  */
     52       reloc_entry->address += input_section->output_offset;
     53       return bfd_reloc_ok;
     54     }
     55 
     56   if (symbol_in != NULL
     57       && bfd_is_und_section (symbol_in->section))
     58     return bfd_reloc_undefined;
     59 
     60   if (bfd_is_com_section (symbol_in->section))
     61     sym_value = 0;
     62   else
     63     sym_value = (symbol_in->value +
     64 		 symbol_in->section->output_section->vma +
     65 		 symbol_in->section->output_offset);
     66 
     67   switch (r_type)
     68     {
     69     case R_PJ_DATA_DIR32:
     70       insn = bfd_get_32 (abfd, hit_data);
     71       insn += sym_value + reloc_entry->addend;
     72       bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
     73       break;
     74 
     75       /* Relocations in code are always bigendian, no matter what the
     76 	 data endianness is.  */
     77 
     78     case R_PJ_CODE_DIR32:
     79       insn = bfd_getb32 (hit_data);
     80       insn += sym_value + reloc_entry->addend;
     81       bfd_putb32 ((bfd_vma) insn, hit_data);
     82       break;
     83 
     84     case R_PJ_CODE_REL16:
     85       insn = bfd_getb16 (hit_data);
     86       insn += sym_value + reloc_entry->addend
     87         -  (input_section->output_section->vma
     88             + input_section->output_offset);
     89       bfd_putb16 ((bfd_vma) insn, hit_data);
     90       break;
     91     case R_PJ_CODE_LO16:
     92       insn = bfd_getb16 (hit_data);
     93       insn += sym_value + reloc_entry->addend;
     94       bfd_putb16 ((bfd_vma) insn, hit_data);
     95       break;
     96 
     97     case R_PJ_CODE_HI16:
     98       insn = bfd_getb16 (hit_data);
     99       insn += (sym_value + reloc_entry->addend) >> 16;
    100       bfd_putb16 ((bfd_vma) insn, hit_data);
    101       break;
    102 
    103     default:
    104       abort ();
    105       break;
    106     }
    107 
    108   return bfd_reloc_ok;
    109 }
    110 
    111 static reloc_howto_type pj_elf_howto_table[] =
    112 {
    113   /* No relocation.  */
    114   HOWTO (R_PJ_NONE,		/* type */
    115 	 0,			/* rightshift */
    116 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
    117 	 0,			/* bitsize */
    118 	 FALSE,			/* pc_relative */
    119 	 0,			/* bitpos */
    120 	 complain_overflow_dont, /* complain_on_overflow */
    121 	 pj_elf_reloc,		/* special_function */
    122 	 "R_PJ_NONE",		/* name */
    123 	 FALSE,			/* partial_inplace */
    124 	 0,			/* src_mask */
    125 	 0,			/* dst_mask */
    126 	 FALSE),		/* pcrel_offset */
    127 
    128   /* 32 bit absolute relocation.  Setting partial_inplace to TRUE and
    129      src_mask to a non-zero value is similar to the COFF toolchain.  */
    130   HOWTO (R_PJ_DATA_DIR32,	/* type */
    131 	 0,			/* rightshift */
    132 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    133 	 32,			/* bitsize */
    134 	 FALSE,			/* pc_relative */
    135 	 0,			/* bitpos */
    136 	 complain_overflow_bitfield, /* complain_on_overflow */
    137 	 pj_elf_reloc,		/* special_function */
    138 	 "R_PJ_DIR32",		/* name */
    139 	 TRUE,			/* partial_inplace */
    140 	 0xffffffff,		/* src_mask */
    141 	 0xffffffff,		/* dst_mask */
    142 	 FALSE),		/* pcrel_offset */
    143 
    144   /* 32 bit PC relative relocation.  */
    145   HOWTO (R_PJ_CODE_REL32,	/* type */
    146 	 0,			/* rightshift */
    147 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    148 	 32,			/* bitsize */
    149 	 TRUE,			/* pc_relative */
    150 	 0,			/* bitpos */
    151 	 complain_overflow_signed, /* complain_on_overflow */
    152 	 pj_elf_reloc,		/* special_function */
    153 	 "R_PJ_REL32",		/* name */
    154 	 FALSE,			/* partial_inplace */
    155 	 0,			/* src_mask */
    156 	 0xffffffff,		/* dst_mask */
    157 	 TRUE),			/* pcrel_offset */
    158 
    159 /* 16 bit PC relative relocation.  */
    160   HOWTO (R_PJ_CODE_REL16,	/* type */
    161 	 0,			/* rightshift */
    162 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    163 	 16,			/* bitsize */
    164 	 TRUE,			/* pc_relative */
    165 	 0,			/* bitpos */
    166 	 complain_overflow_signed, /* complain_on_overf6w */
    167 	 pj_elf_reloc,		/* special_function */
    168 	 "R_PJ_REL16",		/* name */
    169 	 FALSE,			/* partial_inplace */
    170 	 0xffff,		/* src_mask */
    171 	 0xffff,		/* dst_mask */
    172 	 TRUE),			/* pcrel_offset */
    173   EMPTY_HOWTO (4),
    174   EMPTY_HOWTO (5),
    175   HOWTO (R_PJ_CODE_DIR32,	/* type */
    176 	 0,			/* rightshift */
    177 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    178 	 32,			/* bitsize */
    179 	 FALSE,			/* pc_relative */
    180 	 0,			/* bitpos */
    181 	 complain_overflow_bitfield, /* complain_on_overflow */
    182 	 pj_elf_reloc,		/* special_function */
    183 	 "R_PJ_CODE_DIR32",	/* name */
    184 	 TRUE,			/* partial_inplace */
    185 	 0xffffffff,		/* src_mask */
    186 	 0xffffffff,		/* dst_mask */
    187 	 FALSE),		/* pcrel_offset */
    188 
    189   EMPTY_HOWTO (7),
    190   EMPTY_HOWTO (8),
    191   EMPTY_HOWTO (9),
    192   EMPTY_HOWTO (10),
    193   EMPTY_HOWTO (11),
    194   EMPTY_HOWTO (12),
    195 
    196   HOWTO (R_PJ_CODE_LO16,	/* type */
    197 	 0,			/* rightshift */
    198 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    199 	 16,			/* bitsize */
    200 	 FALSE,			/* pc_relative */
    201 	 0,			/* bitpos */
    202 	 complain_overflow_unsigned, /* complain_on_overflow */
    203 	 pj_elf_reloc,		/* special_function */
    204 	 "R_PJ_LO16",		/* name */
    205 	 FALSE,			/* partial_inplace */
    206 	 0xffff,		/* src_mask */
    207 	 0xffff,		/* dst_mask */
    208 	 TRUE),			/* pcrel_offset */
    209 
    210     HOWTO (R_PJ_CODE_HI16,	/* type */
    211 	 16,			/* rightshift */
    212 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    213 	 16,			/* bitsize */
    214 	 FALSE,			/* pc_relative */
    215 	 0,			/* bitpos */
    216 	 complain_overflow_unsigned, /* complain_on_overflow */
    217 	 pj_elf_reloc,		/* special_function */
    218 	 "R_PJ_HI16",		/* name */
    219 	 FALSE,			/* partial_inplace */
    220 	 0xffff,		/* src_mask */
    221 	 0xffff,		/* dst_mask */
    222 	 TRUE),			/* pcrel_offset */
    223 
    224   /* GNU extension to record C++ vtable hierarchy.  */
    225   HOWTO (R_PJ_GNU_VTINHERIT,    /* type */
    226          0,                     /* rightshift */
    227          2,                     /* size (0 = byte, 1 = short, 2 = long) */
    228          0,                     /* bitsize */
    229          FALSE,                 /* pc_relative */
    230          0,                     /* bitpos */
    231          complain_overflow_dont, /* complain_on_overflow */
    232          NULL,                  /* special_function */
    233          "R_PJ_GNU_VTINHERIT",  /* name */
    234          FALSE,                 /* partial_inplace */
    235          0,                     /* src_mask */
    236          0,                     /* dst_mask */
    237          FALSE),                /* pcrel_offset */
    238 
    239   /* GNU extension to record C++ vtable member usage.  */
    240   HOWTO (R_PJ_GNU_VTENTRY,     /* type */
    241          0,                     /* rightshift */
    242          2,                     /* size (0 = byte, 1 = short, 2 = long) */
    243          0,                     /* bitsize */
    244          FALSE,                 /* pc_relative */
    245          0,                     /* bitpos */
    246          complain_overflow_dont, /* complain_on_overflow */
    247          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
    248          "R_PJ_GNU_VTENTRY",   /* name */
    249          FALSE,                 /* partial_inplace */
    250          0,                     /* src_mask */
    251          0,                     /* dst_mask */
    252          FALSE),                /* pcrel_offset */
    253 };
    254 
    255 /* This structure is used to map BFD reloc codes to PJ ELF relocs.  */
    256 
    257 struct elf_reloc_map
    258 {
    259   bfd_reloc_code_real_type bfd_reloc_val;
    260   unsigned char elf_reloc_val;
    261 };
    262 
    263 /* An array mapping BFD reloc codes to PJ ELF relocs.  */
    264 
    265 static const struct elf_reloc_map pj_reloc_map[] =
    266 {
    267     { BFD_RELOC_NONE, 		R_PJ_NONE          },
    268     { BFD_RELOC_32, 		R_PJ_DATA_DIR32    },
    269     { BFD_RELOC_PJ_CODE_DIR16, 	R_PJ_CODE_DIR16    },
    270     { BFD_RELOC_PJ_CODE_DIR32, 	R_PJ_CODE_DIR32    },
    271     { BFD_RELOC_PJ_CODE_LO16, 	R_PJ_CODE_LO16     },
    272     { BFD_RELOC_PJ_CODE_HI16, 	R_PJ_CODE_HI16     },
    273     { BFD_RELOC_PJ_CODE_REL32,  R_PJ_CODE_REL32    },
    274     { BFD_RELOC_PJ_CODE_REL16,  R_PJ_CODE_REL16    },
    275     { BFD_RELOC_VTABLE_INHERIT, R_PJ_GNU_VTINHERIT },
    276     { BFD_RELOC_VTABLE_ENTRY,   R_PJ_GNU_VTENTRY   },
    277 };
    278 
    279 /* Given a BFD reloc code, return the howto structure for the
    280    corresponding PJ ELf reloc.  */
    281 
    282 static reloc_howto_type *
    283 pj_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    284 			  bfd_reloc_code_real_type code)
    285 {
    286   unsigned int i;
    287 
    288   for (i = 0; i < sizeof (pj_reloc_map) / sizeof (struct elf_reloc_map); i++)
    289     if (pj_reloc_map[i].bfd_reloc_val == code)
    290       return & pj_elf_howto_table[(int) pj_reloc_map[i].elf_reloc_val];
    291 
    292   return NULL;
    293 }
    294 
    295 static reloc_howto_type *
    296 pj_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    297 			  const char *r_name)
    298 {
    299   unsigned int i;
    300 
    301   for (i = 0;
    302        i < sizeof (pj_elf_howto_table) / sizeof (pj_elf_howto_table[0]);
    303        i++)
    304     if (pj_elf_howto_table[i].name != NULL
    305 	&& strcasecmp (pj_elf_howto_table[i].name, r_name) == 0)
    306       return &pj_elf_howto_table[i];
    307 
    308   return NULL;
    309 }
    310 
    311 /* Given an ELF reloc, fill in the howto field of a relent.  */
    312 
    313 static void
    314 pj_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
    315 		      arelent *cache_ptr,
    316 		      Elf_Internal_Rela *dst)
    317 {
    318   unsigned int r;
    319 
    320   r = ELF32_R_TYPE (dst->r_info);
    321 
    322   BFD_ASSERT (r < (unsigned int) R_PJ_max);
    323 
    324   cache_ptr->howto = &pj_elf_howto_table[r];
    325 }
    326 
    327 /* Take this moment to fill in the special picoJava bits in the
    328    e_flags field.  */
    329 
    330 static void
    331 pj_elf_final_write_processing (bfd *abfd,
    332 			       bfd_boolean linker ATTRIBUTE_UNUSED)
    333 {
    334   elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_ARCH;
    335   elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_GNUCALLS;
    336 }
    337 
    338 #define TARGET_BIG_SYM		pj_elf32_vec
    339 #define TARGET_BIG_NAME		"elf32-pj"
    340 #define TARGET_LITTLE_SYM	pj_elf32_le_vec
    341 #define TARGET_LITTLE_NAME	"elf32-pjl"
    342 #define ELF_ARCH		bfd_arch_pj
    343 #define ELF_MACHINE_CODE	EM_PJ
    344 #define ELF_MACHINE_ALT1	EM_PJ_OLD
    345 #define ELF_MAXPAGESIZE		0x1000
    346 #define bfd_elf32_bfd_get_relocated_section_contents \
    347   bfd_generic_get_relocated_section_contents
    348 #define bfd_elf32_bfd_reloc_type_lookup	        pj_elf_reloc_type_lookup
    349 #define bfd_elf32_bfd_reloc_name_lookup   pj_elf_reloc_name_lookup
    350 #define elf_backend_final_write_processing      pj_elf_final_write_processing
    351 #define elf_info_to_howto		        pj_elf_info_to_howto
    352 #include "elf32-target.h"
    353