Home | History | Annotate | Line # | Download | only in bfd
elf32-fr30.c revision 1.1.1.1
      1  1.1  christos /* FR30-specific support for 32-bit ELF.
      2  1.1  christos    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
      3  1.1  christos    2010, 2012
      4  1.1  christos    Free Software Foundation, Inc.
      5  1.1  christos 
      6  1.1  christos    This file is part of BFD, the Binary File Descriptor library.
      7  1.1  christos 
      8  1.1  christos    This program is free software; you can redistribute it and/or modify
      9  1.1  christos    it under the terms of the GNU General Public License as published by
     10  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     11  1.1  christos    (at your option) any later version.
     12  1.1  christos 
     13  1.1  christos    This program is distributed in the hope that it will be useful,
     14  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  1.1  christos    GNU General Public License for more details.
     17  1.1  christos 
     18  1.1  christos    You should have received a copy of the GNU General Public License
     19  1.1  christos    along with this program; if not, write to the Free Software
     20  1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21  1.1  christos    MA 02110-1301, USA.  */
     22  1.1  christos 
     23  1.1  christos #include "sysdep.h"
     24  1.1  christos #include "bfd.h"
     25  1.1  christos #include "libbfd.h"
     26  1.1  christos #include "elf-bfd.h"
     27  1.1  christos #include "elf/fr30.h"
     28  1.1  christos 
     29  1.1  christos /* Forward declarations.  */
     30  1.1  christos static bfd_reloc_status_type
     31  1.1  christos fr30_elf_i20_reloc (bfd *, arelent *, asymbol *, void * data,
     32  1.1  christos 		    asection *, bfd *, char **error_message);
     33  1.1  christos static bfd_reloc_status_type
     34  1.1  christos fr30_elf_i32_reloc (bfd *, arelent *, asymbol *, void *,
     35  1.1  christos 		    asection *, bfd *, char **);
     36  1.1  christos 
     37  1.1  christos static reloc_howto_type fr30_elf_howto_table [] =
     38  1.1  christos {
     39  1.1  christos   /* This reloc does nothing.  */
     40  1.1  christos   HOWTO (R_FR30_NONE,		/* type */
     41  1.1  christos 	 0,			/* rightshift */
     42  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
     43  1.1  christos 	 32,			/* bitsize */
     44  1.1  christos 	 FALSE,			/* pc_relative */
     45  1.1  christos 	 0,			/* bitpos */
     46  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
     47  1.1  christos 	 bfd_elf_generic_reloc,	/* special_function */
     48  1.1  christos 	 "R_FR30_NONE",		/* name */
     49  1.1  christos 	 FALSE,			/* partial_inplace */
     50  1.1  christos 	 0,			/* src_mask */
     51  1.1  christos 	 0,			/* dst_mask */
     52  1.1  christos 	 FALSE),		/* pcrel_offset */
     53  1.1  christos 
     54  1.1  christos   /* An 8 bit absolute relocation.  */
     55  1.1  christos   HOWTO (R_FR30_8,		/* type */
     56  1.1  christos 	 0,			/* rightshift */
     57  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
     58  1.1  christos 	 8,			/* bitsize */
     59  1.1  christos 	 FALSE,			/* pc_relative */
     60  1.1  christos 	 4,			/* bitpos */
     61  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
     62  1.1  christos 	 bfd_elf_generic_reloc,	/* special_function */
     63  1.1  christos 	 "R_FR30_8",		/* name */
     64  1.1  christos 	 FALSE,			/* partial_inplace */
     65  1.1  christos 	 0x0000,		/* src_mask */
     66  1.1  christos 	 0x0ff0,		/* dst_mask */
     67  1.1  christos 	 FALSE),		/* pcrel_offset */
     68  1.1  christos 
     69  1.1  christos   /* A 20 bit absolute relocation.  */
     70  1.1  christos   HOWTO (R_FR30_20,		/* type */
     71  1.1  christos 	 0,			/* rightshift */
     72  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
     73  1.1  christos 	 20,			/* bitsize */
     74  1.1  christos 	 FALSE,			/* pc_relative */
     75  1.1  christos 	 0,			/* bitpos */
     76  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
     77  1.1  christos 	 fr30_elf_i20_reloc,	/* special_function */
     78  1.1  christos 	 "R_FR30_20",		/* name */
     79  1.1  christos 	 FALSE,			/* partial_inplace */
     80  1.1  christos 	 0x00000000,		/* src_mask */
     81  1.1  christos 	 0x00f0ffff,		/* dst_mask */
     82  1.1  christos 	 FALSE),		/* pcrel_offset */
     83  1.1  christos 
     84  1.1  christos   /* A 32 bit absolute relocation.  */
     85  1.1  christos   HOWTO (R_FR30_32,		/* type */
     86  1.1  christos 	 0,			/* rightshift */
     87  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
     88  1.1  christos 	 32,			/* bitsize */
     89  1.1  christos 	 FALSE,			/* pc_relative */
     90  1.1  christos 	 0,			/* bitpos */
     91  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
     92  1.1  christos 	 bfd_elf_generic_reloc,	/* special_function */
     93  1.1  christos 	 "R_FR30_32",		/* name */
     94  1.1  christos 	 FALSE,			/* partial_inplace */
     95  1.1  christos 	 0x00000000,		/* src_mask */
     96  1.1  christos 	 0xffffffff,		/* dst_mask */
     97  1.1  christos 	 FALSE),		/* pcrel_offset */
     98  1.1  christos 
     99  1.1  christos   /* A 32 bit into 48 bits absolute relocation.  */
    100  1.1  christos   HOWTO (R_FR30_48,		/* type */
    101  1.1  christos 	 0,			/* rightshift */
    102  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    103  1.1  christos 	 32,			/* bitsize */
    104  1.1  christos 	 FALSE,			/* pc_relative */
    105  1.1  christos 	 0,			/* bitpos */
    106  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    107  1.1  christos 	 fr30_elf_i32_reloc,	/* special_function */
    108  1.1  christos 	 "R_FR30_48",		/* name */
    109  1.1  christos 	 FALSE,			/* partial_inplace */
    110  1.1  christos 	 0x00000000,		/* src_mask */
    111  1.1  christos 	 0xffffffff,		/* dst_mask */
    112  1.1  christos 	 FALSE),		/* pcrel_offset */
    113  1.1  christos 
    114  1.1  christos   /* A 6 bit absolute relocation.  */
    115  1.1  christos   HOWTO (R_FR30_6_IN_4,		/* type */
    116  1.1  christos 	 2,			/* rightshift */
    117  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    118  1.1  christos 	 6,			/* bitsize */
    119  1.1  christos 	 FALSE,			/* pc_relative */
    120  1.1  christos 	 4,			/* bitpos */
    121  1.1  christos 	 complain_overflow_unsigned, /* complain_on_overflow */
    122  1.1  christos 	 bfd_elf_generic_reloc,	/* special_function */
    123  1.1  christos 	 "R_FR30_6_IN_4",	/* name */
    124  1.1  christos 	 FALSE,			/* partial_inplace */
    125  1.1  christos 	 0x0000,		/* src_mask */
    126  1.1  christos 	 0x00f0,		/* dst_mask */
    127  1.1  christos 	 FALSE),		/* pcrel_offset */
    128  1.1  christos 
    129  1.1  christos   /* An 8 bit absolute relocation.  */
    130  1.1  christos   HOWTO (R_FR30_8_IN_8,		/* type */
    131  1.1  christos 	 0,			/* rightshift */
    132  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    133  1.1  christos 	 8,			/* bitsize */
    134  1.1  christos 	 FALSE,			/* pc_relative */
    135  1.1  christos 	 4,			/* bitpos */
    136  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    137  1.1  christos 	 bfd_elf_generic_reloc,/* special_function */
    138  1.1  christos 	 "R_FR30_8_IN_8",	/* name */
    139  1.1  christos 	 FALSE,			/* partial_inplace */
    140  1.1  christos 	 0x0000,		/* src_mask */
    141  1.1  christos 	 0x0ff0,		/* dst_mask */
    142  1.1  christos 	 FALSE),		/* pcrel_offset */
    143  1.1  christos 
    144  1.1  christos   /* A 9 bit absolute relocation.  */
    145  1.1  christos   HOWTO (R_FR30_9_IN_8,		/* type */
    146  1.1  christos 	 1,			/* rightshift */
    147  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    148  1.1  christos 	 9,			/* bitsize */
    149  1.1  christos 	 FALSE,			/* pc_relative */
    150  1.1  christos 	 4,			/* bitpos */
    151  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    152  1.1  christos 	 bfd_elf_generic_reloc,/* special_function */
    153  1.1  christos 	 "R_FR30_9_IN_8",	/* name */
    154  1.1  christos 	 FALSE,			/* partial_inplace */
    155  1.1  christos 	 0x0000,		/* src_mask */
    156  1.1  christos 	 0x0ff0,		/* dst_mask */
    157  1.1  christos 	 FALSE),		/* pcrel_offset */
    158  1.1  christos 
    159  1.1  christos   /* A 10 bit absolute relocation.  */
    160  1.1  christos   HOWTO (R_FR30_10_IN_8,	/* type */
    161  1.1  christos 	 2,			/* rightshift */
    162  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    163  1.1  christos 	 10,			/* bitsize */
    164  1.1  christos 	 FALSE,			/* pc_relative */
    165  1.1  christos 	 4,			/* bitpos */
    166  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    167  1.1  christos 	 bfd_elf_generic_reloc,/* special_function */
    168  1.1  christos 	 "R_FR30_10_IN_8",	/* name */
    169  1.1  christos 	 FALSE,			/* partial_inplace */
    170  1.1  christos 	 0x0000,		/* src_mask */
    171  1.1  christos 	 0x0ff0,		/* dst_mask */
    172  1.1  christos 	 FALSE),		/* pcrel_offset */
    173  1.1  christos 
    174  1.1  christos   /* A PC relative 9 bit relocation, right shifted by 1.  */
    175  1.1  christos   HOWTO (R_FR30_9_PCREL,	/* type */
    176  1.1  christos 	 1,			/* rightshift */
    177  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    178  1.1  christos 	 9,			/* bitsize */
    179  1.1  christos 	 TRUE,			/* pc_relative */
    180  1.1  christos 	 0,			/* bitpos */
    181  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    182  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    183  1.1  christos 	 "R_FR30_9_PCREL",	/* name */
    184  1.1  christos 	 FALSE,			/* partial_inplace */
    185  1.1  christos 	 0x0000,		/* src_mask */
    186  1.1  christos 	 0x00ff,		/* dst_mask */
    187  1.1  christos 	 FALSE),		/* pcrel_offset */
    188  1.1  christos 
    189  1.1  christos   /* A PC relative 12 bit relocation, right shifted by 1.  */
    190  1.1  christos   HOWTO (R_FR30_12_PCREL,	/* type */
    191  1.1  christos 	 1,			/* rightshift */
    192  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    193  1.1  christos 	 12,			/* bitsize */
    194  1.1  christos 	 TRUE,			/* pc_relative */
    195  1.1  christos 	 0,			/* bitpos */
    196  1.1  christos 	 complain_overflow_signed, /* complain_on_overflow */
    197  1.1  christos 	 bfd_elf_generic_reloc, /* special_function */
    198  1.1  christos 	 "R_FR30_12_PCREL",	/* name */
    199  1.1  christos 	 FALSE,			/* partial_inplace */
    200  1.1  christos 	 0x0000,		/* src_mask */
    201  1.1  christos 	 0x07ff,		/* dst_mask */
    202  1.1  christos 	 FALSE),		/* pcrel_offset */
    203  1.1  christos   /* GNU extension to record C++ vtable hierarchy */
    204  1.1  christos   HOWTO (R_FR30_GNU_VTINHERIT, /* type */
    205  1.1  christos          0,                     /* rightshift */
    206  1.1  christos          2,                     /* size (0 = byte, 1 = short, 2 = long) */
    207  1.1  christos          0,                     /* bitsize */
    208  1.1  christos          FALSE,                 /* pc_relative */
    209  1.1  christos          0,                     /* bitpos */
    210  1.1  christos          complain_overflow_dont, /* complain_on_overflow */
    211  1.1  christos          NULL,                  /* special_function */
    212  1.1  christos          "R_FR30_GNU_VTINHERIT", /* name */
    213  1.1  christos          FALSE,                 /* partial_inplace */
    214  1.1  christos          0,                     /* src_mask */
    215  1.1  christos          0,                     /* dst_mask */
    216  1.1  christos          FALSE),                /* pcrel_offset */
    217  1.1  christos 
    218  1.1  christos   /* GNU extension to record C++ vtable member usage */
    219  1.1  christos   HOWTO (R_FR30_GNU_VTENTRY,     /* type */
    220  1.1  christos          0,                     /* rightshift */
    221  1.1  christos          2,                     /* size (0 = byte, 1 = short, 2 = long) */
    222  1.1  christos          0,                     /* bitsize */
    223  1.1  christos          FALSE,                 /* pc_relative */
    224  1.1  christos          0,                     /* bitpos */
    225  1.1  christos          complain_overflow_dont, /* complain_on_overflow */
    226  1.1  christos          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
    227  1.1  christos          "R_FR30_GNU_VTENTRY",   /* name */
    228  1.1  christos          FALSE,                 /* partial_inplace */
    229  1.1  christos          0,                     /* src_mask */
    230  1.1  christos          0,                     /* dst_mask */
    231  1.1  christos          FALSE),                /* pcrel_offset */
    232  1.1  christos };
    233  1.1  christos 
    234  1.1  christos /* Utility to actually perform an R_FR30_20 reloc.  */
    236  1.1  christos 
    237  1.1  christos static bfd_reloc_status_type
    238  1.1  christos fr30_elf_i20_reloc (bfd *abfd,
    239  1.1  christos 		    arelent *reloc_entry,
    240  1.1  christos 		    asymbol *symbol,
    241  1.1  christos 		    void * data,
    242  1.1  christos 		    asection *input_section,
    243  1.1  christos 		    bfd *output_bfd,
    244  1.1  christos 		    char **error_message ATTRIBUTE_UNUSED)
    245  1.1  christos {
    246  1.1  christos   bfd_vma relocation;
    247  1.1  christos   unsigned long x;
    248  1.1  christos 
    249  1.1  christos   /* This part is from bfd_elf_generic_reloc.  */
    250  1.1  christos   if (output_bfd != (bfd *) NULL
    251  1.1  christos       && (symbol->flags & BSF_SECTION_SYM) == 0
    252  1.1  christos       && (! reloc_entry->howto->partial_inplace
    253  1.1  christos 	  || reloc_entry->addend == 0))
    254  1.1  christos     {
    255  1.1  christos       reloc_entry->address += input_section->output_offset;
    256  1.1  christos       return bfd_reloc_ok;
    257  1.1  christos     }
    258  1.1  christos 
    259  1.1  christos   if (output_bfd != NULL)
    260  1.1  christos     /* FIXME: See bfd_perform_relocation.  Is this right?  */
    261  1.1  christos     return bfd_reloc_ok;
    262  1.1  christos 
    263  1.1  christos   relocation =
    264  1.1  christos     symbol->value
    265  1.1  christos     + symbol->section->output_section->vma
    266  1.1  christos     + symbol->section->output_offset
    267  1.1  christos     + reloc_entry->addend;
    268  1.1  christos 
    269  1.1  christos   if (relocation > (((bfd_vma) 1 << 20) - 1))
    270  1.1  christos     return bfd_reloc_overflow;
    271  1.1  christos 
    272  1.1  christos   x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
    273  1.1  christos   x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
    274  1.1  christos   bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
    275  1.1  christos 
    276  1.1  christos   return bfd_reloc_ok;
    277  1.1  christos }
    278  1.1  christos 
    279  1.1  christos /* Utility to actually perform a R_FR30_48 reloc.  */
    281  1.1  christos 
    282  1.1  christos static bfd_reloc_status_type
    283  1.1  christos fr30_elf_i32_reloc (bfd *abfd,
    284  1.1  christos 		    arelent *reloc_entry,
    285  1.1  christos 		    asymbol *symbol,
    286  1.1  christos 		    void * data,
    287  1.1  christos 		    asection *input_section,
    288  1.1  christos 		    bfd *output_bfd,
    289  1.1  christos 		    char **error_message ATTRIBUTE_UNUSED)
    290  1.1  christos {
    291  1.1  christos   bfd_vma relocation;
    292  1.1  christos 
    293  1.1  christos   /* This part is from bfd_elf_generic_reloc.  */
    294  1.1  christos   if (output_bfd != (bfd *) NULL
    295  1.1  christos       && (symbol->flags & BSF_SECTION_SYM) == 0
    296  1.1  christos       && (! reloc_entry->howto->partial_inplace
    297  1.1  christos 	  || reloc_entry->addend == 0))
    298  1.1  christos     {
    299  1.1  christos       reloc_entry->address += input_section->output_offset;
    300  1.1  christos       return bfd_reloc_ok;
    301  1.1  christos     }
    302  1.1  christos 
    303  1.1  christos   if (output_bfd != NULL)
    304  1.1  christos     /* FIXME: See bfd_perform_relocation.  Is this right?  */
    305  1.1  christos     return bfd_reloc_ok;
    306  1.1  christos 
    307  1.1  christos   relocation =
    308  1.1  christos     symbol->value
    309  1.1  christos     + symbol->section->output_section->vma
    310  1.1  christos     + symbol->section->output_offset
    311  1.1  christos     + reloc_entry->addend;
    312  1.1  christos 
    313  1.1  christos   bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
    314  1.1  christos 
    315  1.1  christos   return bfd_reloc_ok;
    316  1.1  christos }
    317  1.1  christos 
    318  1.1  christos /* Map BFD reloc types to FR30 ELF reloc types.  */
    320  1.1  christos 
    321  1.1  christos struct fr30_reloc_map
    322  1.1  christos {
    323  1.1  christos   bfd_reloc_code_real_type bfd_reloc_val;
    324  1.1  christos   unsigned int fr30_reloc_val;
    325  1.1  christos };
    326  1.1  christos 
    327  1.1  christos static const struct fr30_reloc_map fr30_reloc_map [] =
    328  1.1  christos {
    329  1.1  christos   { BFD_RELOC_NONE,           R_FR30_NONE },
    330  1.1  christos   { BFD_RELOC_8,              R_FR30_8 },
    331  1.1  christos   { BFD_RELOC_FR30_20,        R_FR30_20 },
    332  1.1  christos   { BFD_RELOC_32,             R_FR30_32 },
    333  1.1  christos   { BFD_RELOC_FR30_48,        R_FR30_48 },
    334  1.1  christos   { BFD_RELOC_FR30_6_IN_4,    R_FR30_6_IN_4 },
    335  1.1  christos   { BFD_RELOC_FR30_8_IN_8,    R_FR30_8_IN_8 },
    336  1.1  christos   { BFD_RELOC_FR30_9_IN_8,    R_FR30_9_IN_8 },
    337  1.1  christos   { BFD_RELOC_FR30_10_IN_8,   R_FR30_10_IN_8 },
    338  1.1  christos   { BFD_RELOC_FR30_9_PCREL,   R_FR30_9_PCREL },
    339  1.1  christos   { BFD_RELOC_FR30_12_PCREL,  R_FR30_12_PCREL },
    340  1.1  christos   { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
    341  1.1  christos   { BFD_RELOC_VTABLE_ENTRY,   R_FR30_GNU_VTENTRY },
    342  1.1  christos };
    343  1.1  christos 
    344  1.1  christos static reloc_howto_type *
    345  1.1  christos fr30_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    346  1.1  christos 			bfd_reloc_code_real_type code)
    347  1.1  christos {
    348  1.1  christos   unsigned int i;
    349  1.1  christos 
    350  1.1  christos   for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
    351  1.1  christos        --i;)
    352  1.1  christos     if (fr30_reloc_map [i].bfd_reloc_val == code)
    353  1.1  christos       return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
    354  1.1  christos 
    355  1.1  christos   return NULL;
    356  1.1  christos }
    357  1.1  christos 
    358  1.1  christos static reloc_howto_type *
    359  1.1  christos fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
    360  1.1  christos {
    361  1.1  christos   unsigned int i;
    362  1.1  christos 
    363  1.1  christos   for (i = 0;
    364  1.1  christos        i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
    365  1.1  christos        i++)
    366  1.1  christos     if (fr30_elf_howto_table[i].name != NULL
    367  1.1  christos 	&& strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0)
    368  1.1  christos       return &fr30_elf_howto_table[i];
    369  1.1  christos 
    370  1.1  christos   return NULL;
    371  1.1  christos }
    372  1.1  christos 
    373  1.1  christos /* Set the howto pointer for an FR30 ELF reloc.  */
    374  1.1  christos 
    375  1.1  christos static void
    376  1.1  christos fr30_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
    377  1.1  christos 			 arelent *cache_ptr,
    378  1.1  christos 			 Elf_Internal_Rela *dst)
    379  1.1  christos {
    380  1.1  christos   unsigned int r_type;
    381  1.1  christos 
    382  1.1  christos   r_type = ELF32_R_TYPE (dst->r_info);
    383  1.1  christos   BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
    384  1.1  christos   cache_ptr->howto = & fr30_elf_howto_table [r_type];
    385  1.1  christos }
    386  1.1  christos 
    387  1.1  christos /* Perform a single relocation.  By default we use the standard BFD
    389  1.1  christos    routines, but a few relocs, we have to do them ourselves.  */
    390  1.1  christos 
    391  1.1  christos static bfd_reloc_status_type
    392  1.1  christos fr30_final_link_relocate (reloc_howto_type *howto,
    393  1.1  christos 			  bfd *input_bfd,
    394  1.1  christos 			  asection *input_section,
    395  1.1  christos 			  bfd_byte *contents,
    396  1.1  christos 			  Elf_Internal_Rela *rel,
    397  1.1  christos 			  bfd_vma relocation)
    398  1.1  christos {
    399  1.1  christos   bfd_reloc_status_type r = bfd_reloc_ok;
    400  1.1  christos   bfd_vma x;
    401  1.1  christos   bfd_signed_vma srel;
    402  1.1  christos 
    403  1.1  christos   switch (howto->type)
    404  1.1  christos     {
    405  1.1  christos     case R_FR30_20:
    406  1.1  christos       contents   += rel->r_offset;
    407  1.1  christos       relocation += rel->r_addend;
    408  1.1  christos 
    409  1.1  christos       if (relocation > ((1 << 20) - 1))
    410  1.1  christos 	return bfd_reloc_overflow;
    411  1.1  christos 
    412  1.1  christos       x = bfd_get_32 (input_bfd, contents);
    413  1.1  christos       x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
    414  1.1  christos       bfd_put_32 (input_bfd, x, contents);
    415  1.1  christos       break;
    416  1.1  christos 
    417  1.1  christos     case R_FR30_48:
    418  1.1  christos       contents   += rel->r_offset + 2;
    419  1.1  christos       relocation += rel->r_addend;
    420  1.1  christos       bfd_put_32 (input_bfd, relocation, contents);
    421  1.1  christos       break;
    422  1.1  christos 
    423  1.1  christos     case R_FR30_9_PCREL:
    424  1.1  christos       contents   += rel->r_offset + 1;
    425  1.1  christos       srel = (bfd_signed_vma) relocation;
    426  1.1  christos       srel += rel->r_addend;
    427  1.1  christos       srel -= rel->r_offset;
    428  1.1  christos       srel -= 2;  /* Branch instructions add 2 to the PC...  */
    429  1.1  christos       srel -= (input_section->output_section->vma +
    430  1.1  christos 		     input_section->output_offset);
    431  1.1  christos 
    432  1.1  christos       if (srel & 1)
    433  1.1  christos 	return bfd_reloc_outofrange;
    434  1.1  christos       if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
    435  1.1  christos 	return bfd_reloc_overflow;
    436  1.1  christos 
    437  1.1  christos       bfd_put_8 (input_bfd, srel >> 1, contents);
    438  1.1  christos       break;
    439  1.1  christos 
    440  1.1  christos     case R_FR30_12_PCREL:
    441  1.1  christos       contents   += rel->r_offset;
    442  1.1  christos       srel = (bfd_signed_vma) relocation;
    443  1.1  christos       srel += rel->r_addend;
    444  1.1  christos       srel -= rel->r_offset;
    445  1.1  christos       srel -= 2; /* Branch instructions add 2 to the PC...  */
    446  1.1  christos       srel -= (input_section->output_section->vma +
    447  1.1  christos 		     input_section->output_offset);
    448  1.1  christos 
    449  1.1  christos       if (srel & 1)
    450  1.1  christos 	return bfd_reloc_outofrange;
    451  1.1  christos       if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
    452  1.1  christos 	  return bfd_reloc_overflow;
    453  1.1  christos 
    454  1.1  christos       x = bfd_get_16 (input_bfd, contents);
    455  1.1  christos       x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
    456  1.1  christos       bfd_put_16 (input_bfd, x, contents);
    457  1.1  christos       break;
    458  1.1  christos 
    459  1.1  christos     default:
    460  1.1  christos       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    461  1.1  christos 				    contents, rel->r_offset,
    462  1.1  christos 				    relocation, rel->r_addend);
    463  1.1  christos     }
    464  1.1  christos 
    465  1.1  christos   return r;
    466  1.1  christos }
    467  1.1  christos 
    468  1.1  christos /* Relocate an FR30 ELF section.
    470  1.1  christos 
    471  1.1  christos    The RELOCATE_SECTION function is called by the new ELF backend linker
    472  1.1  christos    to handle the relocations for a section.
    473  1.1  christos 
    474  1.1  christos    The relocs are always passed as Rela structures; if the section
    475  1.1  christos    actually uses Rel structures, the r_addend field will always be
    476  1.1  christos    zero.
    477  1.1  christos 
    478  1.1  christos    This function is responsible for adjusting the section contents as
    479  1.1  christos    necessary, and (if using Rela relocs and generating a relocatable
    480  1.1  christos    output file) adjusting the reloc addend as necessary.
    481  1.1  christos 
    482  1.1  christos    This function does not have to worry about setting the reloc
    483  1.1  christos    address or the reloc symbol index.
    484  1.1  christos 
    485  1.1  christos    LOCAL_SYMS is a pointer to the swapped in local symbols.
    486  1.1  christos 
    487  1.1  christos    LOCAL_SECTIONS is an array giving the section in the input file
    488  1.1  christos    corresponding to the st_shndx field of each local symbol.
    489  1.1  christos 
    490  1.1  christos    The global hash table entry for the global symbols can be found
    491  1.1  christos    via elf_sym_hashes (input_bfd).
    492  1.1  christos 
    493  1.1  christos    When generating relocatable output, this function must handle
    494  1.1  christos    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    495  1.1  christos    going to be the section symbol corresponding to the output
    496  1.1  christos    section, which means that the addend must be adjusted
    497  1.1  christos    accordingly.  */
    498  1.1  christos 
    499  1.1  christos static bfd_boolean
    500  1.1  christos fr30_elf_relocate_section (bfd *output_bfd,
    501  1.1  christos 			   struct bfd_link_info *info,
    502  1.1  christos 			   bfd *input_bfd,
    503  1.1  christos 			   asection *input_section,
    504  1.1  christos 			   bfd_byte *contents,
    505  1.1  christos 			   Elf_Internal_Rela *relocs,
    506  1.1  christos 			   Elf_Internal_Sym *local_syms,
    507  1.1  christos 			   asection **local_sections)
    508  1.1  christos {
    509  1.1  christos   Elf_Internal_Shdr *symtab_hdr;
    510  1.1  christos   struct elf_link_hash_entry **sym_hashes;
    511  1.1  christos   Elf_Internal_Rela *rel;
    512  1.1  christos   Elf_Internal_Rela *relend;
    513  1.1  christos 
    514  1.1  christos   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
    515  1.1  christos   sym_hashes = elf_sym_hashes (input_bfd);
    516  1.1  christos   relend     = relocs + input_section->reloc_count;
    517  1.1  christos 
    518  1.1  christos   for (rel = relocs; rel < relend; rel ++)
    519  1.1  christos     {
    520  1.1  christos       reloc_howto_type *howto;
    521  1.1  christos       unsigned long r_symndx;
    522  1.1  christos       Elf_Internal_Sym *sym;
    523  1.1  christos       asection *sec;
    524  1.1  christos       struct elf_link_hash_entry *h;
    525  1.1  christos       bfd_vma relocation;
    526  1.1  christos       bfd_reloc_status_type r;
    527  1.1  christos       const char *name;
    528  1.1  christos       int r_type;
    529  1.1  christos 
    530  1.1  christos       r_type = ELF32_R_TYPE (rel->r_info);
    531  1.1  christos 
    532  1.1  christos       if (   r_type == R_FR30_GNU_VTINHERIT
    533  1.1  christos 	  || r_type == R_FR30_GNU_VTENTRY)
    534  1.1  christos 	continue;
    535  1.1  christos 
    536  1.1  christos       r_symndx = ELF32_R_SYM (rel->r_info);
    537  1.1  christos 
    538  1.1  christos       howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
    539  1.1  christos       h      = NULL;
    540  1.1  christos       sym    = NULL;
    541  1.1  christos       sec    = NULL;
    542  1.1  christos 
    543  1.1  christos       if (r_symndx < symtab_hdr->sh_info)
    544  1.1  christos 	{
    545  1.1  christos 	  sym = local_syms + r_symndx;
    546  1.1  christos 	  sec = local_sections [r_symndx];
    547  1.1  christos 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
    548  1.1  christos 
    549  1.1  christos 	  name = bfd_elf_string_from_elf_section
    550  1.1  christos 	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
    551  1.1  christos 	  name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
    552  1.1  christos 	}
    553  1.1  christos       else
    554  1.1  christos 	{
    555  1.1  christos 	  bfd_boolean unresolved_reloc, warned, ignored;
    556  1.1  christos 
    557  1.1  christos 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    558  1.1  christos 				   r_symndx, symtab_hdr, sym_hashes,
    559  1.1  christos 				   h, sec, relocation,
    560  1.1  christos 				   unresolved_reloc, warned, ignored);
    561  1.1  christos 
    562  1.1  christos 	  name = h->root.root.string;
    563  1.1  christos 	}
    564  1.1  christos 
    565  1.1  christos       if (sec != NULL && discarded_section (sec))
    566  1.1  christos 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    567  1.1  christos 					 rel, 1, relend, howto, 0, contents);
    568  1.1  christos 
    569  1.1  christos       if (info->relocatable)
    570  1.1  christos 	continue;
    571  1.1  christos 
    572  1.1  christos       r = fr30_final_link_relocate (howto, input_bfd, input_section,
    573  1.1  christos 				     contents, rel, relocation);
    574  1.1  christos 
    575  1.1  christos       if (r != bfd_reloc_ok)
    576  1.1  christos 	{
    577  1.1  christos 	  const char * msg = (const char *) NULL;
    578  1.1  christos 
    579  1.1  christos 	  switch (r)
    580  1.1  christos 	    {
    581  1.1  christos 	    case bfd_reloc_overflow:
    582  1.1  christos 	      r = info->callbacks->reloc_overflow
    583  1.1  christos 		(info, (h ? &h->root : NULL), name, howto->name,
    584  1.1  christos 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
    585  1.1  christos 	      break;
    586  1.1  christos 
    587  1.1  christos 	    case bfd_reloc_undefined:
    588  1.1  christos 	      r = info->callbacks->undefined_symbol
    589  1.1  christos 		(info, name, input_bfd, input_section, rel->r_offset,
    590  1.1  christos 		 TRUE);
    591  1.1  christos 	      break;
    592  1.1  christos 
    593  1.1  christos 	    case bfd_reloc_outofrange:
    594  1.1  christos 	      msg = _("internal error: out of range error");
    595  1.1  christos 	      break;
    596  1.1  christos 
    597  1.1  christos 	    case bfd_reloc_notsupported:
    598  1.1  christos 	      msg = _("internal error: unsupported relocation error");
    599  1.1  christos 	      break;
    600  1.1  christos 
    601  1.1  christos 	    case bfd_reloc_dangerous:
    602  1.1  christos 	      msg = _("internal error: dangerous relocation");
    603  1.1  christos 	      break;
    604  1.1  christos 
    605  1.1  christos 	    default:
    606  1.1  christos 	      msg = _("internal error: unknown error");
    607  1.1  christos 	      break;
    608  1.1  christos 	    }
    609  1.1  christos 
    610  1.1  christos 	  if (msg)
    611  1.1  christos 	    r = info->callbacks->warning
    612  1.1  christos 	      (info, msg, name, input_bfd, input_section, rel->r_offset);
    613  1.1  christos 
    614  1.1  christos 	  if (! r)
    615  1.1  christos 	    return FALSE;
    616  1.1  christos 	}
    617  1.1  christos     }
    618  1.1  christos 
    619  1.1  christos   return TRUE;
    620  1.1  christos }
    621  1.1  christos 
    622  1.1  christos /* Return the section that should be marked against GC for a given
    624  1.1  christos    relocation.  */
    625  1.1  christos 
    626  1.1  christos static asection *
    627  1.1  christos fr30_elf_gc_mark_hook (asection *sec,
    628  1.1  christos 		       struct bfd_link_info *info,
    629  1.1  christos 		       Elf_Internal_Rela *rel,
    630  1.1  christos 		       struct elf_link_hash_entry *h,
    631  1.1  christos 		       Elf_Internal_Sym *sym)
    632  1.1  christos {
    633  1.1  christos   if (h != NULL)
    634  1.1  christos     switch (ELF32_R_TYPE (rel->r_info))
    635  1.1  christos       {
    636  1.1  christos       case R_FR30_GNU_VTINHERIT:
    637  1.1  christos       case R_FR30_GNU_VTENTRY:
    638  1.1  christos 	return NULL;
    639  1.1  christos       }
    640  1.1  christos 
    641  1.1  christos   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
    642  1.1  christos }
    643  1.1  christos 
    644  1.1  christos /* Look through the relocs for a section during the first phase.
    645  1.1  christos    Since we don't do .gots or .plts, we just need to consider the
    646  1.1  christos    virtual table relocs for gc.  */
    647  1.1  christos 
    648  1.1  christos static bfd_boolean
    649  1.1  christos fr30_elf_check_relocs (bfd *abfd,
    650  1.1  christos 		       struct bfd_link_info *info,
    651  1.1  christos 		       asection *sec,
    652  1.1  christos 		       const Elf_Internal_Rela *relocs)
    653  1.1  christos {
    654  1.1  christos   Elf_Internal_Shdr *symtab_hdr;
    655  1.1  christos   struct elf_link_hash_entry **sym_hashes;
    656  1.1  christos   const Elf_Internal_Rela *rel;
    657  1.1  christos   const Elf_Internal_Rela *rel_end;
    658  1.1  christos 
    659  1.1  christos   if (info->relocatable)
    660  1.1  christos     return TRUE;
    661  1.1  christos 
    662  1.1  christos   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
    663  1.1  christos   sym_hashes = elf_sym_hashes (abfd);
    664  1.1  christos 
    665  1.1  christos   rel_end = relocs + sec->reloc_count;
    666  1.1  christos   for (rel = relocs; rel < rel_end; rel++)
    667  1.1  christos     {
    668  1.1  christos       struct elf_link_hash_entry *h;
    669  1.1  christos       unsigned long r_symndx;
    670  1.1  christos 
    671  1.1  christos       r_symndx = ELF32_R_SYM (rel->r_info);
    672  1.1  christos       if (r_symndx < symtab_hdr->sh_info)
    673  1.1  christos         h = NULL;
    674  1.1  christos       else
    675  1.1  christos 	{
    676  1.1  christos 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
    677  1.1  christos 	  while (h->root.type == bfd_link_hash_indirect
    678  1.1  christos 		 || h->root.type == bfd_link_hash_warning)
    679  1.1  christos 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    680  1.1  christos 
    681  1.1  christos 	  /* PR15323, ref flags aren't set for references in the same
    682  1.1  christos 	     object.  */
    683  1.1  christos 	  h->root.non_ir_ref = 1;
    684  1.1  christos 	}
    685  1.1  christos 
    686  1.1  christos       switch (ELF32_R_TYPE (rel->r_info))
    687  1.1  christos         {
    688  1.1  christos         /* This relocation describes the C++ object vtable hierarchy.
    689  1.1  christos            Reconstruct it for later use during GC.  */
    690  1.1  christos         case R_FR30_GNU_VTINHERIT:
    691  1.1  christos           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
    692  1.1  christos             return FALSE;
    693  1.1  christos           break;
    694  1.1  christos 
    695  1.1  christos         /* This relocation describes which C++ vtable entries are actually
    696  1.1  christos            used.  Record for later use during GC.  */
    697  1.1  christos         case R_FR30_GNU_VTENTRY:
    698  1.1  christos           BFD_ASSERT (h != NULL);
    699  1.1  christos           if (h != NULL
    700  1.1  christos               && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
    701  1.1  christos             return FALSE;
    702  1.1  christos           break;
    703  1.1  christos         }
    704  1.1  christos     }
    705  1.1  christos 
    706  1.1  christos   return TRUE;
    707  1.1  christos }
    708  1.1  christos 
    709  1.1  christos #define ELF_ARCH		bfd_arch_fr30
    711  1.1  christos #define ELF_MACHINE_CODE	EM_FR30
    712  1.1  christos #define ELF_MACHINE_ALT1	EM_CYGNUS_FR30
    713  1.1  christos #define ELF_MAXPAGESIZE		0x1000
    714  1.1  christos 
    715  1.1  christos #define TARGET_BIG_SYM          bfd_elf32_fr30_vec
    716  1.1  christos #define TARGET_BIG_NAME		"elf32-fr30"
    717  1.1  christos 
    718  1.1  christos #define elf_info_to_howto_rel			NULL
    719  1.1  christos #define elf_info_to_howto			fr30_info_to_howto_rela
    720  1.1  christos #define elf_backend_relocate_section		fr30_elf_relocate_section
    721  1.1  christos #define elf_backend_gc_mark_hook		fr30_elf_gc_mark_hook
    722  1.1  christos #define elf_backend_check_relocs                fr30_elf_check_relocs
    723  1.1  christos 
    724                #define elf_backend_can_gc_sections		1
    725                #define elf_backend_rela_normal			1
    726                
    727                #define bfd_elf32_bfd_reloc_type_lookup		fr30_reloc_type_lookup
    728                #define bfd_elf32_bfd_reloc_name_lookup	fr30_reloc_name_lookup
    729                
    730                #include "elf32-target.h"
    731