Home | History | Annotate | Line # | Download | only in bfd
elf32-pru.c revision 1.1
      1  1.1  christos /* 32-bit ELF support for TI PRU.
      2  1.1  christos    Copyright (C) 2014-2017 Free Software Foundation, Inc.
      3  1.1  christos    Contributed by Dimitar Dimitrov <dimitar (at) dinux.eu>
      4  1.1  christos    Based on elf32-nios2.c
      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 /* This file handles TI PRU ELF targets.  */
     24  1.1  christos 
     25  1.1  christos #include "sysdep.h"
     26  1.1  christos #include "bfd.h"
     27  1.1  christos #include "libbfd.h"
     28  1.1  christos #include "bfdlink.h"
     29  1.1  christos #include "genlink.h"
     30  1.1  christos #include "elf-bfd.h"
     31  1.1  christos #include "elf/pru.h"
     32  1.1  christos #include "opcode/pru.h"
     33  1.1  christos 
     34  1.1  christos #define SWAP_VALS(A,B)		      \
     35  1.1  christos   do {				      \
     36  1.1  christos       (A) ^= (B);		      \
     37  1.1  christos       (B) ^= (A);		      \
     38  1.1  christos       (A) ^= (B);		      \
     39  1.1  christos   } while (0)
     40  1.1  christos 
     41  1.1  christos /* Enable debugging printout at stdout with this variable.  */
     42  1.1  christos static bfd_boolean debug_relax = FALSE;
     43  1.1  christos 
     44  1.1  christos /* Forward declarations.  */
     45  1.1  christos static bfd_reloc_status_type pru_elf32_pmem_relocate
     46  1.1  christos   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
     47  1.1  christos static bfd_reloc_status_type pru_elf32_s10_pcrel_relocate
     48  1.1  christos   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
     49  1.1  christos static bfd_reloc_status_type pru_elf32_u8_pcrel_relocate
     50  1.1  christos   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
     51  1.1  christos static bfd_reloc_status_type pru_elf32_ldi32_relocate
     52  1.1  christos   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
     53  1.1  christos static bfd_reloc_status_type bfd_elf_pru_diff_relocate
     54  1.1  christos   (bfd *, arelent *, asymbol *, void *,	asection *, bfd *, char **);
     55  1.1  christos 
     56  1.1  christos /* Target vector.  */
     57  1.1  christos extern const bfd_target pru_elf32_vec;
     58  1.1  christos 
     59  1.1  christos /* The relocation table used for SHT_REL sections.  */
     60  1.1  christos static reloc_howto_type elf_pru_howto_table_rel[] = {
     61  1.1  christos   /* No relocation.  */
     62  1.1  christos   HOWTO (R_PRU_NONE,		/* type */
     63  1.1  christos 	 0,			/* rightshift */
     64  1.1  christos 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
     65  1.1  christos 	 3,			/* bitsize */
     66  1.1  christos 	 FALSE,			/* pc_relative */
     67  1.1  christos 	 0,			/* bitpos */
     68  1.1  christos 	 complain_overflow_dont,/* complain_on_overflow */
     69  1.1  christos 	 bfd_elf_generic_reloc,	/* special_function */
     70  1.1  christos 	 "R_PRU_NONE",		/* name */
     71  1.1  christos 	 FALSE,			/* partial_inplace */
     72  1.1  christos 	 0,			/* src_mask */
     73  1.1  christos 	 0,			/* dst_mask */
     74  1.1  christos 	 FALSE),		/* pcrel_offset */
     75  1.1  christos 
     76  1.1  christos   HOWTO (R_PRU_16_PMEM,
     77  1.1  christos 	 2,
     78  1.1  christos 	 1,			/* short */
     79  1.1  christos 	 32,
     80  1.1  christos 	 FALSE,
     81  1.1  christos 	 0,
     82  1.1  christos 	 complain_overflow_dont,
     83  1.1  christos 	 bfd_elf_generic_reloc,
     84  1.1  christos 	 "R_PRU_16_PMEM",
     85  1.1  christos 	 FALSE,
     86  1.1  christos 	 0,			/* src_mask */
     87  1.1  christos 	 0xffff,
     88  1.1  christos 	 FALSE),
     89  1.1  christos 
     90  1.1  christos   HOWTO (R_PRU_U16_PMEMIMM,
     91  1.1  christos 	 2,
     92  1.1  christos 	 2,
     93  1.1  christos 	 32,
     94  1.1  christos 	 FALSE,
     95  1.1  christos 	 8,
     96  1.1  christos 	 complain_overflow_unsigned,
     97  1.1  christos 	 pru_elf32_pmem_relocate,
     98  1.1  christos 	 "R_PRU_U16_PMEMIMM",
     99  1.1  christos 	 FALSE,
    100  1.1  christos 	 0,			/* src_mask */
    101  1.1  christos 	 0x00ffff00,
    102  1.1  christos 	 FALSE),
    103  1.1  christos 
    104  1.1  christos   HOWTO (R_PRU_BFD_RELOC_16,
    105  1.1  christos 	 0,
    106  1.1  christos 	 1,			/* short */
    107  1.1  christos 	 16,
    108  1.1  christos 	 FALSE,
    109  1.1  christos 	 0,
    110  1.1  christos 	 complain_overflow_bitfield,
    111  1.1  christos 	 bfd_elf_generic_reloc,
    112  1.1  christos 	 "R_PRU_BFD_RELOC16",
    113  1.1  christos 	 FALSE,
    114  1.1  christos 	 0,			/* src_mask */
    115  1.1  christos 	 0x0000ffff,
    116  1.1  christos 	 FALSE),
    117  1.1  christos 
    118  1.1  christos   /* 16-bit unsigned immediate relocation.  */
    119  1.1  christos   HOWTO (R_PRU_U16,		/* type */
    120  1.1  christos 	 0,			/* rightshift */
    121  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    122  1.1  christos 	 16,			/* bitsize */
    123  1.1  christos 	 FALSE,			/* pc_relative */
    124  1.1  christos 	 8,			/* bitpos */
    125  1.1  christos 	 complain_overflow_unsigned,	/* complain on overflow */
    126  1.1  christos 	 bfd_elf_generic_reloc,	/* special function */
    127  1.1  christos 	 "R_PRU_U16",		/* name */
    128  1.1  christos 	 FALSE,			/* partial_inplace */
    129  1.1  christos 	 0,			/* src_mask */
    130  1.1  christos 	 0x00ffff00,		/* dest_mask */
    131  1.1  christos 	 FALSE),		/* pcrel_offset */
    132  1.1  christos 
    133  1.1  christos   HOWTO (R_PRU_32_PMEM,
    134  1.1  christos 	 2,
    135  1.1  christos 	 2,			/* long */
    136  1.1  christos 	 32,
    137  1.1  christos 	 FALSE,
    138  1.1  christos 	 0,
    139  1.1  christos 	 complain_overflow_dont,
    140  1.1  christos 	 pru_elf32_pmem_relocate,
    141  1.1  christos 	 "R_PRU_32_PMEM",
    142  1.1  christos 	 FALSE,
    143  1.1  christos 	 0,			/* src_mask */
    144  1.1  christos 	 0xffffffff,
    145  1.1  christos 	 FALSE),
    146  1.1  christos 
    147  1.1  christos   HOWTO (R_PRU_BFD_RELOC_32,
    148  1.1  christos 	 0,
    149  1.1  christos 	 2,			/* long */
    150  1.1  christos 	 32,
    151  1.1  christos 	 FALSE,
    152  1.1  christos 	 0,
    153  1.1  christos 	 complain_overflow_dont,
    154  1.1  christos 	 bfd_elf_generic_reloc,
    155  1.1  christos 	 "R_PRU_BFD_RELOC32",
    156  1.1  christos 	 FALSE,
    157  1.1  christos 	 0,			/* src_mask */
    158  1.1  christos 	 0xffffffff,
    159  1.1  christos 	 FALSE),
    160  1.1  christos 
    161  1.1  christos   HOWTO (R_PRU_S10_PCREL,
    162  1.1  christos 	 2,
    163  1.1  christos 	 2,
    164  1.1  christos 	 10,
    165  1.1  christos 	 TRUE,
    166  1.1  christos 	 0,
    167  1.1  christos 	 complain_overflow_bitfield,
    168  1.1  christos 	 pru_elf32_s10_pcrel_relocate,
    169  1.1  christos 	 "R_PRU_S10_PCREL",
    170  1.1  christos 	 FALSE,
    171  1.1  christos 	 0,			/* src_mask */
    172  1.1  christos 	 0x060000ff,
    173  1.1  christos 	 TRUE),
    174  1.1  christos 
    175  1.1  christos   HOWTO (R_PRU_U8_PCREL,
    176  1.1  christos 	 2,
    177  1.1  christos 	 2,
    178  1.1  christos 	 8,
    179  1.1  christos 	 TRUE,
    180  1.1  christos 	 0,
    181  1.1  christos 	 complain_overflow_unsigned,
    182  1.1  christos 	 pru_elf32_u8_pcrel_relocate,
    183  1.1  christos 	 "R_PRU_U8_PCREL",
    184  1.1  christos 	 FALSE,
    185  1.1  christos 	 0,			/* src_mask */
    186  1.1  christos 	 0x000000ff,
    187  1.1  christos 	 TRUE),
    188  1.1  christos 
    189  1.1  christos   HOWTO (R_PRU_LDI32,
    190  1.1  christos 	 0,			/* rightshift */
    191  1.1  christos 	 4,			/* size (4 = 8bytes) */
    192  1.1  christos 	 32,			/* bitsize */
    193  1.1  christos 	 FALSE,			/* pc_relative */
    194  1.1  christos 	 0,			/* bitpos */
    195  1.1  christos 	 complain_overflow_unsigned, /* complain on overflow */
    196  1.1  christos 	 pru_elf32_ldi32_relocate, /* special function */
    197  1.1  christos 	 "R_PRU_LDI32",		/* name */
    198  1.1  christos 	 FALSE,			/* partial_inplace */
    199  1.1  christos 	 0,			/* src_mask */
    200  1.1  christos 	 0xffffffff,		/* dest_mask */
    201  1.1  christos 	 FALSE),		/* pcrel_offset */
    202  1.1  christos 
    203  1.1  christos   /* GNU-specific relocations.  */
    204  1.1  christos   HOWTO (R_PRU_GNU_BFD_RELOC_8,
    205  1.1  christos 	 0,
    206  1.1  christos 	 0,			/* byte */
    207  1.1  christos 	 8,
    208  1.1  christos 	 FALSE,
    209  1.1  christos 	 0,
    210  1.1  christos 	 complain_overflow_bitfield,
    211  1.1  christos 	 bfd_elf_generic_reloc,
    212  1.1  christos 	 "R_PRU_BFD_RELOC8",
    213  1.1  christos 	 FALSE,
    214  1.1  christos 	 0,			/* src_mask */
    215  1.1  christos 	 0x000000ff,
    216  1.1  christos 	 FALSE),
    217  1.1  christos 
    218  1.1  christos   HOWTO (R_PRU_GNU_DIFF8,	/* type */
    219  1.1  christos 	 0,			/* rightshift */
    220  1.1  christos 	 0, 			/* size (0 = byte, 1 = short, 2 = long) */
    221  1.1  christos 	 8, 			/* bitsize */
    222  1.1  christos 	 FALSE,			/* pc_relative */
    223  1.1  christos 	 0,			/* bitpos */
    224  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    225  1.1  christos 	 bfd_elf_pru_diff_relocate, /* special_function */
    226  1.1  christos 	 "R_PRU_DIFF8",     	/* name */
    227  1.1  christos 	 FALSE,			/* partial_inplace */
    228  1.1  christos 	 0,			/* src_mask */
    229  1.1  christos 	 0xff,			/* dst_mask */
    230  1.1  christos 	 FALSE),		/* pcrel_offset */
    231  1.1  christos 
    232  1.1  christos   HOWTO (R_PRU_GNU_DIFF16,  	/* type */
    233  1.1  christos 	 0,			/* rightshift */
    234  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    235  1.1  christos 	 16,			/* bitsize */
    236  1.1  christos 	 FALSE,			/* pc_relative */
    237  1.1  christos 	 0,			/* bitpos */
    238  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    239  1.1  christos 	 bfd_elf_pru_diff_relocate,/* special_function */
    240  1.1  christos 	 "R_PRU_DIFF16",     	/* name */
    241  1.1  christos 	 FALSE,			/* partial_inplace */
    242  1.1  christos 	 0,			/* src_mask */
    243  1.1  christos 	 0xffff,		/* dst_mask */
    244  1.1  christos 	 FALSE),		/* pcrel_offset */
    245  1.1  christos 
    246  1.1  christos   HOWTO (R_PRU_GNU_DIFF32,  	/* type */
    247  1.1  christos 	 0,			/* rightshift */
    248  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    249  1.1  christos 	 32,			/* bitsize */
    250  1.1  christos 	 FALSE,			/* pc_relative */
    251  1.1  christos 	 0,			/* bitpos */
    252  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    253  1.1  christos 	 bfd_elf_pru_diff_relocate,/* special_function */
    254  1.1  christos 	 "R_PRU_DIFF32",     	/* name */
    255  1.1  christos 	 FALSE,			/* partial_inplace */
    256  1.1  christos 	 0,			/* src_mask */
    257  1.1  christos 	 0xffffffff,    	/* dst_mask */
    258  1.1  christos 	 FALSE),		/* pcrel_offset */
    259  1.1  christos 
    260  1.1  christos   HOWTO (R_PRU_GNU_DIFF16_PMEM,	/* type */
    261  1.1  christos 	 0,			/* rightshift */
    262  1.1  christos 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    263  1.1  christos 	 16,			/* bitsize */
    264  1.1  christos 	 FALSE,			/* pc_relative */
    265  1.1  christos 	 0,			/* bitpos */
    266  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    267  1.1  christos 	 bfd_elf_pru_diff_relocate,/* special_function */
    268  1.1  christos 	 "R_PRU_DIFF16_PMEM",   /* name */
    269  1.1  christos 	 FALSE,			/* partial_inplace */
    270  1.1  christos 	 0,			/* src_mask */
    271  1.1  christos 	 0xffff,		/* dst_mask */
    272  1.1  christos 	 FALSE),		/* pcrel_offset */
    273  1.1  christos 
    274  1.1  christos   HOWTO (R_PRU_GNU_DIFF32_PMEM, /* type */
    275  1.1  christos 	 0,			/* rightshift */
    276  1.1  christos 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    277  1.1  christos 	 32,			/* bitsize */
    278  1.1  christos 	 FALSE,			/* pc_relative */
    279  1.1  christos 	 0,			/* bitpos */
    280  1.1  christos 	 complain_overflow_bitfield, /* complain_on_overflow */
    281  1.1  christos 	 bfd_elf_pru_diff_relocate,/* special_function */
    282  1.1  christos 	 "R_PRU_DIFF32_PMEM",   /* name */
    283  1.1  christos 	 FALSE,			/* partial_inplace */
    284  1.1  christos 	 0,			/* src_mask */
    285  1.1  christos 	 0xffffffff,		/* dst_mask */
    286  1.1  christos 	 FALSE),		/* pcrel_offset */
    287  1.1  christos 
    288  1.1  christos /* Add other relocations here.  */
    289  1.1  christos };
    290  1.1  christos 
    291  1.1  christos static unsigned char elf_code_to_howto_index[R_PRU_ILLEGAL + 1];
    292  1.1  christos 
    293  1.1  christos /* Return the howto for relocation RTYPE.  */
    294  1.1  christos static reloc_howto_type *
    295  1.1  christos lookup_howto (unsigned int rtype)
    296  1.1  christos {
    297  1.1  christos   static int initialized = 0;
    298  1.1  christos   int i;
    299  1.1  christos   int howto_tbl_size = (int) (sizeof (elf_pru_howto_table_rel)
    300  1.1  christos 			      / sizeof (elf_pru_howto_table_rel[0]));
    301  1.1  christos 
    302  1.1  christos   if (!initialized)
    303  1.1  christos     {
    304  1.1  christos       initialized = 1;
    305  1.1  christos       memset (elf_code_to_howto_index, 0xff,
    306  1.1  christos 	      sizeof (elf_code_to_howto_index));
    307  1.1  christos       for (i = 0; i < howto_tbl_size; i++)
    308  1.1  christos 	elf_code_to_howto_index[elf_pru_howto_table_rel[i].type] = i;
    309  1.1  christos     }
    310  1.1  christos 
    311  1.1  christos   BFD_ASSERT (rtype <= R_PRU_ILLEGAL);
    312  1.1  christos   i = elf_code_to_howto_index[rtype];
    313  1.1  christos   if (i >= howto_tbl_size)
    314  1.1  christos     return 0;
    315  1.1  christos   return elf_pru_howto_table_rel + i;
    316  1.1  christos }
    317  1.1  christos 
    318  1.1  christos /* Map for converting BFD reloc types to PRU reloc types.  */
    319  1.1  christos struct elf_reloc_map
    320  1.1  christos {
    321  1.1  christos   bfd_reloc_code_real_type bfd_val;
    322  1.1  christos   enum elf_pru_reloc_type elf_val;
    323  1.1  christos };
    324  1.1  christos 
    325  1.1  christos static const struct elf_reloc_map pru_reloc_map[] = {
    326  1.1  christos   {BFD_RELOC_NONE, R_PRU_NONE},
    327  1.1  christos   {BFD_RELOC_PRU_16_PMEM, R_PRU_16_PMEM},
    328  1.1  christos   {BFD_RELOC_PRU_U16_PMEMIMM, R_PRU_U16_PMEMIMM},
    329  1.1  christos   {BFD_RELOC_16, R_PRU_BFD_RELOC_16},
    330  1.1  christos   {BFD_RELOC_PRU_U16, R_PRU_U16},
    331  1.1  christos   {BFD_RELOC_PRU_32_PMEM, R_PRU_32_PMEM},
    332  1.1  christos   {BFD_RELOC_32, R_PRU_BFD_RELOC_32},
    333  1.1  christos   {BFD_RELOC_PRU_S10_PCREL, R_PRU_S10_PCREL},
    334  1.1  christos   {BFD_RELOC_PRU_U8_PCREL, R_PRU_U8_PCREL},
    335  1.1  christos   {BFD_RELOC_PRU_LDI32, R_PRU_LDI32},
    336  1.1  christos 
    337  1.1  christos   {BFD_RELOC_8, R_PRU_GNU_BFD_RELOC_8},
    338  1.1  christos   {BFD_RELOC_PRU_GNU_DIFF8, R_PRU_GNU_DIFF8},
    339  1.1  christos   {BFD_RELOC_PRU_GNU_DIFF16, R_PRU_GNU_DIFF16},
    340  1.1  christos   {BFD_RELOC_PRU_GNU_DIFF32, R_PRU_GNU_DIFF32},
    341  1.1  christos   {BFD_RELOC_PRU_GNU_DIFF16_PMEM, R_PRU_GNU_DIFF16_PMEM},
    342  1.1  christos   {BFD_RELOC_PRU_GNU_DIFF32_PMEM, R_PRU_GNU_DIFF32_PMEM},
    343  1.1  christos };
    344  1.1  christos 
    345  1.1  christos 
    346  1.1  christos /* Assorted hash table functions.  */
    347  1.1  christos 
    348  1.1  christos /* Create an entry in a PRU ELF linker hash table.  */
    349  1.1  christos static struct bfd_hash_entry *
    350  1.1  christos link_hash_newfunc (struct bfd_hash_entry *entry,
    351  1.1  christos 		   struct bfd_hash_table *table, const char *string)
    352  1.1  christos {
    353  1.1  christos   /* Allocate the structure if it has not already been allocated by a
    354  1.1  christos      subclass.  */
    355  1.1  christos   if (entry == NULL)
    356  1.1  christos     {
    357  1.1  christos       entry = bfd_hash_allocate (table,
    358  1.1  christos 				 sizeof (struct elf_link_hash_entry));
    359  1.1  christos       if (entry == NULL)
    360  1.1  christos 	return entry;
    361  1.1  christos     }
    362  1.1  christos 
    363  1.1  christos   /* Call the allocation method of the superclass.  */
    364  1.1  christos   entry = _bfd_elf_link_hash_newfunc (entry, table, string);
    365  1.1  christos 
    366  1.1  christos   return entry;
    367  1.1  christos }
    368  1.1  christos 
    369  1.1  christos /* Implement bfd_elf32_bfd_reloc_type_lookup:
    370  1.1  christos    Given a BFD reloc type, return a howto structure.  */
    371  1.1  christos static reloc_howto_type *
    372  1.1  christos pru_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    373  1.1  christos 				   bfd_reloc_code_real_type code)
    374  1.1  christos {
    375  1.1  christos   int i;
    376  1.1  christos   for (i = 0;
    377  1.1  christos        i < (int) (sizeof (pru_reloc_map) / sizeof (struct elf_reloc_map));
    378  1.1  christos        ++i)
    379  1.1  christos     if (pru_reloc_map[i].bfd_val == code)
    380  1.1  christos       return lookup_howto ((unsigned int) pru_reloc_map[i].elf_val);
    381  1.1  christos   return NULL;
    382  1.1  christos }
    383  1.1  christos 
    384  1.1  christos /* Implement bfd_elf32_bfd_reloc_name_lookup:
    385  1.1  christos    Given a reloc name, return a howto structure.  */
    386  1.1  christos static reloc_howto_type *
    387  1.1  christos pru_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    388  1.1  christos 				   const char *r_name)
    389  1.1  christos {
    390  1.1  christos   unsigned int i;
    391  1.1  christos   for (i = 0;
    392  1.1  christos        i < (sizeof (elf_pru_howto_table_rel)
    393  1.1  christos 	    / sizeof (elf_pru_howto_table_rel[0]));
    394  1.1  christos        i++)
    395  1.1  christos     if (elf_pru_howto_table_rel[i].name
    396  1.1  christos 	&& strcasecmp (elf_pru_howto_table_rel[i].name, r_name) == 0)
    397  1.1  christos       return &elf_pru_howto_table_rel[i];
    398  1.1  christos 
    399  1.1  christos   return NULL;
    400  1.1  christos }
    401  1.1  christos 
    402  1.1  christos /* Implement elf_info_to_howto:
    403  1.1  christos    Given a ELF32 relocation, fill in a arelent structure.  */
    404  1.1  christos static void
    405  1.1  christos pru_elf32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
    406  1.1  christos 			 Elf_Internal_Rela *dst)
    407  1.1  christos {
    408  1.1  christos   unsigned int r_type;
    409  1.1  christos 
    410  1.1  christos   r_type = ELF32_R_TYPE (dst->r_info);
    411  1.1  christos   BFD_ASSERT (r_type < R_PRU_ILLEGAL);
    412  1.1  christos   cache_ptr->howto = lookup_howto (r_type);
    413  1.1  christos }
    414  1.1  christos 
    415  1.1  christos /* Do the relocations that require special handling.  */
    416  1.1  christos /* Produce a word address for program memory.  Linker scripts will put .text
    417  1.1  christos    at a high offset in order to differentiate it from .data.  So here we also
    418  1.1  christos    mask the high bits of PMEM address.
    419  1.1  christos 
    420  1.1  christos    But why 1MB when internal Program Memory much smaller? We want to catch
    421  1.1  christos    unintended overflows.
    422  1.1  christos 
    423  1.1  christos    Why not use (1<<31) as an offset and a mask? Sitara DDRAM usually resides
    424  1.1  christos    there, and users might want to put some shared carveout memory region in
    425  1.1  christos    their linker scripts.  So 0x80000000 might be a valid .data address.
    426  1.1  christos 
    427  1.1  christos    Note that we still keep and pass down the original howto.  This way we
    428  1.1  christos    can reuse this function for several different relocations.  */
    429  1.1  christos static bfd_reloc_status_type
    430  1.1  christos pru_elf32_do_pmem_relocate (bfd *abfd, reloc_howto_type *howto,
    431  1.1  christos 			    asection *input_section,
    432  1.1  christos 			    bfd_byte *data, bfd_vma offset,
    433  1.1  christos 			    bfd_vma symbol_value, bfd_vma addend)
    434  1.1  christos {
    435  1.1  christos   symbol_value = symbol_value + addend;
    436  1.1  christos   addend = 0;
    437  1.1  christos   symbol_value &= 0x3fffff;
    438  1.1  christos   return _bfd_final_link_relocate (howto, abfd, input_section,
    439  1.1  christos 				   data, offset, symbol_value, addend);
    440  1.1  christos }
    441  1.1  christos 
    442  1.1  christos /* Direct copy of _bfd_final_link_relocate, but with special
    443  1.1  christos    "fill-in".  This copy-paste mumbo jumbo is only needed because BFD
    444  1.1  christos    cannot deal correctly with non-contiguous bit fields.  */
    445  1.1  christos static bfd_reloc_status_type
    446  1.1  christos pru_elf32_do_s10_pcrel_relocate (bfd *input_bfd, reloc_howto_type *howto,
    447  1.1  christos 				 asection *input_section,
    448  1.1  christos 				 bfd_byte *contents, bfd_vma address,
    449  1.1  christos 				 bfd_vma relocation, bfd_vma addend)
    450  1.1  christos {
    451  1.1  christos   bfd_byte *location;
    452  1.1  christos   bfd_vma x = 0;
    453  1.1  christos   bfd_vma qboff;
    454  1.1  christos   bfd_reloc_status_type flag = bfd_reloc_ok;
    455  1.1  christos 
    456  1.1  christos   /* Sanity check the address.  */
    457  1.1  christos   if (address > bfd_get_section_limit (input_bfd, input_section))
    458  1.1  christos     return bfd_reloc_outofrange;
    459  1.1  christos 
    460  1.1  christos   BFD_ASSERT (howto->pc_relative);
    461  1.1  christos   BFD_ASSERT (howto->pcrel_offset);
    462  1.1  christos 
    463  1.1  christos   relocation = relocation + addend - (input_section->output_section->vma
    464  1.1  christos 		+ input_section->output_offset) - address;
    465  1.1  christos 
    466  1.1  christos   location = contents + address;
    467  1.1  christos 
    468  1.1  christos   /* Get the value we are going to relocate.  */
    469  1.1  christos   BFD_ASSERT (bfd_get_reloc_size (howto) == 4);
    470  1.1  christos   x = bfd_get_32 (input_bfd, location);
    471  1.1  christos 
    472  1.1  christos   qboff = GET_BROFF_SIGNED (x) << howto->rightshift;
    473  1.1  christos   relocation += qboff;
    474  1.1  christos 
    475  1.1  christos   BFD_ASSERT (howto->complain_on_overflow == complain_overflow_bitfield);
    476  1.1  christos 
    477  1.1  christos   if (relocation > 2047 && relocation < (bfd_vma)-2048l)
    478  1.1  christos     flag = bfd_reloc_overflow;
    479  1.1  christos 
    480  1.1  christos   /* Check that target address is word-aligned.  */
    481  1.1  christos   if (relocation & ((1 << howto->rightshift) - 1))
    482  1.1  christos     flag = bfd_reloc_outofrange;
    483  1.1  christos 
    484  1.1  christos   relocation >>= (bfd_vma) howto->rightshift;
    485  1.1  christos 
    486  1.1  christos   /* Fill-in the RELOCATION to the right bits of X.  */
    487  1.1  christos   SET_BROFF_URAW (x, relocation);
    488  1.1  christos 
    489  1.1  christos   bfd_put_32 (input_bfd, x, location);
    490  1.1  christos 
    491  1.1  christos   return flag;
    492  1.1  christos }
    493  1.1  christos 
    494  1.1  christos static bfd_reloc_status_type
    495  1.1  christos pru_elf32_do_u8_pcrel_relocate (bfd *abfd, reloc_howto_type *howto,
    496  1.1  christos 				asection *input_section,
    497  1.1  christos 				bfd_byte *data, bfd_vma offset,
    498  1.1  christos 				bfd_vma symbol_value, bfd_vma addend)
    499  1.1  christos {
    500  1.1  christos   bfd_vma relocation;
    501  1.1  christos 
    502  1.1  christos   BFD_ASSERT (howto->pc_relative);
    503  1.1  christos   BFD_ASSERT (howto->pcrel_offset);
    504  1.1  christos 
    505  1.1  christos   relocation = symbol_value + addend - (input_section->output_section->vma
    506  1.1  christos 		+ input_section->output_offset) - offset;
    507  1.1  christos   relocation >>= howto->rightshift;
    508  1.1  christos 
    509  1.1  christos   /* 0 and 1 are invalid target labels for LOOP.  We cannot
    510  1.1  christos      encode this info in HOWTO, so catch such cases here.  */
    511  1.1  christos   if (relocation < 2)
    512  1.1  christos       return bfd_reloc_outofrange;
    513  1.1  christos 
    514  1.1  christos   return _bfd_final_link_relocate (howto, abfd, input_section,
    515  1.1  christos 				   data, offset, symbol_value, addend);
    516  1.1  christos }
    517  1.1  christos 
    518  1.1  christos /* Idea and code taken from elf32-d30v.  */
    519  1.1  christos static bfd_reloc_status_type
    520  1.1  christos pru_elf32_do_ldi32_relocate (bfd *abfd, reloc_howto_type *howto,
    521  1.1  christos 			     asection *input_section,
    522  1.1  christos 			     bfd_byte *data, bfd_vma offset,
    523  1.1  christos 			     bfd_vma symbol_value, bfd_vma addend)
    524  1.1  christos {
    525  1.1  christos   bfd_signed_vma relocation;
    526  1.1  christos   bfd_size_type octets = offset * bfd_octets_per_byte (abfd);
    527  1.1  christos   bfd_byte *location;
    528  1.1  christos   unsigned long in1, in2, num;
    529  1.1  christos 
    530  1.1  christos   /* A hacked-up version of _bfd_final_link_relocate() follows.  */
    531  1.1  christos 
    532  1.1  christos   /* Sanity check the address.  */
    533  1.1  christos   if (octets + bfd_get_reloc_size (howto)
    534  1.1  christos       > bfd_get_section_limit_octets (abfd, input_section))
    535  1.1  christos     return bfd_reloc_outofrange;
    536  1.1  christos 
    537  1.1  christos   /* This function assumes that we are dealing with a basic relocation
    538  1.1  christos      against a symbol.  We want to compute the value of the symbol to
    539  1.1  christos      relocate to.  This is just VALUE, the value of the symbol, plus
    540  1.1  christos      ADDEND, any addend associated with the reloc.  */
    541  1.1  christos   relocation = symbol_value + addend;
    542  1.1  christos 
    543  1.1  christos   BFD_ASSERT (!howto->pc_relative);
    544  1.1  christos 
    545  1.1  christos   /* A hacked-up version of _bfd_relocate_contents() follows.  */
    546  1.1  christos   location = data + offset * bfd_octets_per_byte (abfd);
    547  1.1  christos 
    548  1.1  christos   BFD_ASSERT (!howto->pc_relative);
    549  1.1  christos 
    550  1.1  christos   in1 = bfd_get_32 (abfd, location);
    551  1.1  christos   in2 = bfd_get_32 (abfd, location + 4);
    552  1.1  christos 
    553  1.1  christos   /* Extract the addend - should be zero per my understanding.  */
    554  1.1  christos   num = GET_INSN_FIELD (IMM16, in1) | (GET_INSN_FIELD (IMM16, in2) << 16);
    555  1.1  christos   BFD_ASSERT (!num);
    556  1.1  christos 
    557  1.1  christos   relocation += num;
    558  1.1  christos 
    559  1.1  christos   SET_INSN_FIELD (IMM16, in1, relocation & 0xffff);
    560  1.1  christos   SET_INSN_FIELD (IMM16, in2, relocation >> 16);
    561  1.1  christos 
    562  1.1  christos   bfd_put_32 (abfd, in1, location);
    563  1.1  christos   bfd_put_32 (abfd, in2, location + 4);
    564  1.1  christos 
    565  1.1  christos   return bfd_reloc_ok;
    566  1.1  christos }
    567  1.1  christos 
    568  1.1  christos /* HOWTO handlers for relocations that require special handling.  */
    569  1.1  christos 
    570  1.1  christos static bfd_reloc_status_type
    571  1.1  christos pru_elf32_pmem_relocate (bfd *abfd, arelent *reloc_entry,
    572  1.1  christos 			 asymbol *symbol, void *data,
    573  1.1  christos 			 asection *input_section, bfd *output_bfd,
    574  1.1  christos 			 char **error_message)
    575  1.1  christos {
    576  1.1  christos   /* If this is a relocatable link (output_bfd test tells us), just
    577  1.1  christos      call the generic function.  Any adjustment will be done at final
    578  1.1  christos      link time.  */
    579  1.1  christos   if (output_bfd != NULL)
    580  1.1  christos     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
    581  1.1  christos 				  input_section, output_bfd, error_message);
    582  1.1  christos 
    583  1.1  christos   return pru_elf32_do_pmem_relocate (abfd, reloc_entry->howto,
    584  1.1  christos 				     input_section,
    585  1.1  christos 				     data, reloc_entry->address,
    586  1.1  christos 				     (symbol->value
    587  1.1  christos 				      + symbol->section->output_section->vma
    588  1.1  christos 				      + symbol->section->output_offset),
    589  1.1  christos 				     reloc_entry->addend);
    590  1.1  christos }
    591  1.1  christos 
    592  1.1  christos static bfd_reloc_status_type
    593  1.1  christos pru_elf32_s10_pcrel_relocate (bfd *abfd, arelent *reloc_entry,
    594  1.1  christos 				 asymbol *symbol, void *data,
    595  1.1  christos 				 asection *input_section, bfd *output_bfd,
    596  1.1  christos 				 char **error_message)
    597  1.1  christos {
    598  1.1  christos   /* If this is a relocatable link (output_bfd test tells us), just
    599  1.1  christos      call the generic function.  Any adjustment will be done at final
    600  1.1  christos      link time.  */
    601  1.1  christos   if (output_bfd != NULL)
    602  1.1  christos     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
    603  1.1  christos 				  input_section, output_bfd, error_message);
    604  1.1  christos 
    605  1.1  christos   return pru_elf32_do_s10_pcrel_relocate (abfd, reloc_entry->howto,
    606  1.1  christos 					  input_section, data,
    607  1.1  christos 					  reloc_entry->address,
    608  1.1  christos 					  (symbol->value
    609  1.1  christos 					   + symbol->section->output_section->vma
    610  1.1  christos 					   + symbol->section->output_offset),
    611  1.1  christos 					  reloc_entry->addend);
    612  1.1  christos }
    613  1.1  christos 
    614  1.1  christos static bfd_reloc_status_type
    615  1.1  christos pru_elf32_u8_pcrel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
    616  1.1  christos 			     void *data, asection *input_section,
    617  1.1  christos 			     bfd *output_bfd,
    618  1.1  christos 			     char **error_message)
    619  1.1  christos {
    620  1.1  christos   /* If this is a relocatable link (output_bfd test tells us), just
    621  1.1  christos      call the generic function.  Any adjustment will be done at final
    622  1.1  christos      link time.  */
    623  1.1  christos   if (output_bfd != NULL)
    624  1.1  christos     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
    625  1.1  christos 				  input_section, output_bfd, error_message);
    626  1.1  christos 
    627  1.1  christos   return pru_elf32_do_u8_pcrel_relocate (abfd, reloc_entry->howto,
    628  1.1  christos 					 input_section,
    629  1.1  christos 					 data, reloc_entry->address,
    630  1.1  christos 					 (symbol->value
    631  1.1  christos 					  + symbol->section->output_section->vma
    632  1.1  christos 					  + symbol->section->output_offset),
    633  1.1  christos 					 reloc_entry->addend);
    634  1.1  christos }
    635  1.1  christos 
    636  1.1  christos static bfd_reloc_status_type
    637  1.1  christos pru_elf32_ldi32_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
    638  1.1  christos 			  void *data, asection *input_section,
    639  1.1  christos 			  bfd *output_bfd,
    640  1.1  christos 			  char **error_message)
    641  1.1  christos {
    642  1.1  christos   /* If this is a relocatable link (output_bfd test tells us), just
    643  1.1  christos      call the generic function.  Any adjustment will be done at final
    644  1.1  christos      link time.  */
    645  1.1  christos   if (output_bfd != NULL)
    646  1.1  christos     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
    647  1.1  christos 				  input_section, output_bfd, error_message);
    648  1.1  christos 
    649  1.1  christos   return pru_elf32_do_ldi32_relocate (abfd, reloc_entry->howto,
    650  1.1  christos 				      input_section,
    651  1.1  christos 				      data, reloc_entry->address,
    652  1.1  christos 				      (symbol->value
    653  1.1  christos 				       + symbol->section->output_section->vma
    654  1.1  christos 				       + symbol->section->output_offset),
    655  1.1  christos 				      reloc_entry->addend);
    656  1.1  christos }
    657  1.1  christos 
    658  1.1  christos 
    659  1.1  christos /* Implement elf_backend_relocate_section.  */
    660  1.1  christos static bfd_boolean
    661  1.1  christos pru_elf32_relocate_section (bfd *output_bfd,
    662  1.1  christos 			    struct bfd_link_info *info,
    663  1.1  christos 			    bfd *input_bfd,
    664  1.1  christos 			    asection *input_section,
    665  1.1  christos 			    bfd_byte *contents,
    666  1.1  christos 			    Elf_Internal_Rela *relocs,
    667  1.1  christos 			    Elf_Internal_Sym *local_syms,
    668  1.1  christos 			    asection **local_sections)
    669  1.1  christos {
    670  1.1  christos   Elf_Internal_Shdr *symtab_hdr;
    671  1.1  christos   struct elf_link_hash_entry **sym_hashes;
    672  1.1  christos   Elf_Internal_Rela *rel;
    673  1.1  christos   Elf_Internal_Rela *relend;
    674  1.1  christos 
    675  1.1  christos   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
    676  1.1  christos   sym_hashes = elf_sym_hashes (input_bfd);
    677  1.1  christos   relend = relocs + input_section->reloc_count;
    678  1.1  christos 
    679  1.1  christos   for (rel = relocs; rel < relend; rel++)
    680  1.1  christos     {
    681  1.1  christos       reloc_howto_type *howto;
    682  1.1  christos       unsigned long r_symndx;
    683  1.1  christos       Elf_Internal_Sym *sym;
    684  1.1  christos       asection *sec;
    685  1.1  christos       struct elf_link_hash_entry *h;
    686  1.1  christos       bfd_vma relocation;
    687  1.1  christos       bfd_reloc_status_type r = bfd_reloc_ok;
    688  1.1  christos       const char *name = NULL;
    689  1.1  christos       const char* msg = (const char*) NULL;
    690  1.1  christos       bfd_boolean unresolved_reloc;
    691  1.1  christos 
    692  1.1  christos       r_symndx = ELF32_R_SYM (rel->r_info);
    693  1.1  christos 
    694  1.1  christos       howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info));
    695  1.1  christos       h = NULL;
    696  1.1  christos       sym = NULL;
    697  1.1  christos       sec = NULL;
    698  1.1  christos 
    699  1.1  christos       if (r_symndx < symtab_hdr->sh_info)
    700  1.1  christos 	{
    701  1.1  christos 	  sym = local_syms + r_symndx;
    702  1.1  christos 	  sec = local_sections[r_symndx];
    703  1.1  christos 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
    704  1.1  christos 	}
    705  1.1  christos       else
    706  1.1  christos 	{
    707  1.1  christos 	  bfd_boolean warned, ignored;
    708  1.1  christos 
    709  1.1  christos 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    710  1.1  christos 				   r_symndx, symtab_hdr, sym_hashes,
    711  1.1  christos 				   h, sec, relocation,
    712  1.1  christos 				   unresolved_reloc, warned, ignored);
    713  1.1  christos 	}
    714  1.1  christos 
    715  1.1  christos       if (sec && discarded_section (sec))
    716  1.1  christos 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    717  1.1  christos 					 rel, 1, relend, howto, 0, contents);
    718  1.1  christos 
    719  1.1  christos       /* Nothing more to do unless this is a final link.  */
    720  1.1  christos       if (bfd_link_relocatable (info))
    721  1.1  christos 	continue;
    722  1.1  christos 
    723  1.1  christos       if (howto)
    724  1.1  christos 	{
    725  1.1  christos 	  switch (howto->type)
    726  1.1  christos 	    {
    727  1.1  christos 	    case R_PRU_NONE:
    728  1.1  christos 	      /* We don't need to find a value for this symbol.  It's just a
    729  1.1  christos 		 marker.  */
    730  1.1  christos 	      r = bfd_reloc_ok;
    731  1.1  christos 	      break;
    732  1.1  christos 
    733  1.1  christos 	    case R_PRU_U16_PMEMIMM:
    734  1.1  christos 	    case R_PRU_32_PMEM:
    735  1.1  christos 	    case R_PRU_16_PMEM:
    736  1.1  christos 	      r = pru_elf32_do_pmem_relocate (input_bfd, howto,
    737  1.1  christos 						input_section,
    738  1.1  christos 						contents, rel->r_offset,
    739  1.1  christos 						relocation, rel->r_addend);
    740  1.1  christos 	      break;
    741  1.1  christos 	    case R_PRU_S10_PCREL:
    742  1.1  christos 	      r = pru_elf32_do_s10_pcrel_relocate (input_bfd, howto,
    743  1.1  christos 						      input_section,
    744  1.1  christos 						      contents,
    745  1.1  christos 						      rel->r_offset,
    746  1.1  christos 						      relocation,
    747  1.1  christos 						      rel->r_addend);
    748  1.1  christos 	      break;
    749  1.1  christos 	    case R_PRU_U8_PCREL:
    750  1.1  christos 	      r = pru_elf32_do_u8_pcrel_relocate (input_bfd, howto,
    751  1.1  christos 						      input_section,
    752  1.1  christos 						      contents,
    753  1.1  christos 						      rel->r_offset,
    754  1.1  christos 						      relocation,
    755  1.1  christos 						      rel->r_addend);
    756  1.1  christos 	      break;
    757  1.1  christos 	    case R_PRU_LDI32:
    758  1.1  christos 	      r = pru_elf32_do_ldi32_relocate (input_bfd, howto,
    759  1.1  christos 					       input_section,
    760  1.1  christos 					       contents,
    761  1.1  christos 					       rel->r_offset,
    762  1.1  christos 					       relocation,
    763  1.1  christos 					       rel->r_addend);
    764  1.1  christos 	      break;
    765  1.1  christos 	    case R_PRU_GNU_DIFF8:
    766  1.1  christos 	    case R_PRU_GNU_DIFF16:
    767  1.1  christos 	    case R_PRU_GNU_DIFF32:
    768  1.1  christos 	    case R_PRU_GNU_DIFF16_PMEM:
    769  1.1  christos 	    case R_PRU_GNU_DIFF32_PMEM:
    770  1.1  christos 	      /* Nothing to do here, as contents already contain the
    771  1.1  christos 		 diff value.  */
    772  1.1  christos 	      r = bfd_reloc_ok;
    773  1.1  christos 	      break;
    774  1.1  christos 
    775  1.1  christos 	    default:
    776  1.1  christos 	      r = _bfd_final_link_relocate (howto, input_bfd,
    777  1.1  christos 					    input_section, contents,
    778  1.1  christos 					    rel->r_offset, relocation,
    779  1.1  christos 					    rel->r_addend);
    780  1.1  christos 	      break;
    781  1.1  christos 	    }
    782  1.1  christos 	}
    783  1.1  christos       else
    784  1.1  christos 	r = bfd_reloc_notsupported;
    785  1.1  christos 
    786  1.1  christos       if (r != bfd_reloc_ok)
    787  1.1  christos 	{
    788  1.1  christos 	  if (h != NULL)
    789  1.1  christos 	    name = h->root.root.string;
    790  1.1  christos 	  else
    791  1.1  christos 	    {
    792  1.1  christos 	      name = bfd_elf_string_from_elf_section (input_bfd,
    793  1.1  christos 						      symtab_hdr->sh_link,
    794  1.1  christos 						      sym->st_name);
    795  1.1  christos 	      if (name == NULL || *name == '\0')
    796  1.1  christos 		name = bfd_section_name (input_bfd, sec);
    797  1.1  christos 	    }
    798  1.1  christos 
    799  1.1  christos 	  switch (r)
    800  1.1  christos 	    {
    801  1.1  christos 	    case bfd_reloc_overflow:
    802  1.1  christos 	      (*info->callbacks->reloc_overflow) (info, NULL, name,
    803  1.1  christos 						  howto->name, (bfd_vma) 0,
    804  1.1  christos 						  input_bfd, input_section,
    805  1.1  christos 						  rel->r_offset);
    806  1.1  christos 	      break;
    807  1.1  christos 
    808  1.1  christos 	    case bfd_reloc_undefined:
    809  1.1  christos 	      (*info->callbacks->undefined_symbol) (info, name, input_bfd,
    810  1.1  christos 						    input_section,
    811  1.1  christos 						    rel->r_offset, TRUE);
    812  1.1  christos 	      break;
    813  1.1  christos 
    814  1.1  christos 	    case bfd_reloc_outofrange:
    815  1.1  christos 	      if (msg == NULL)
    816  1.1  christos 		msg = _("relocation out of range");
    817  1.1  christos 	      break;
    818  1.1  christos 
    819  1.1  christos 	    case bfd_reloc_notsupported:
    820  1.1  christos 	      if (msg == NULL)
    821  1.1  christos 		msg = _("unsupported relocation");
    822  1.1  christos 	      break;
    823  1.1  christos 
    824  1.1  christos 	    case bfd_reloc_dangerous:
    825  1.1  christos 	      if (msg == NULL)
    826  1.1  christos 		msg = _("dangerous relocation");
    827  1.1  christos 	      break;
    828  1.1  christos 
    829  1.1  christos 	    default:
    830  1.1  christos 	      if (msg == NULL)
    831  1.1  christos 		msg = _("unknown error");
    832  1.1  christos 	      break;
    833  1.1  christos 	    }
    834  1.1  christos 
    835  1.1  christos 	  if (msg)
    836  1.1  christos 	    {
    837  1.1  christos 	      (*info->callbacks->warning) (info, msg, name, input_bfd,
    838  1.1  christos 					   input_section, rel->r_offset);
    839  1.1  christos 	      return FALSE;
    840  1.1  christos 	    }
    841  1.1  christos 	}
    842  1.1  christos     }
    843  1.1  christos   return TRUE;
    844  1.1  christos }
    845  1.1  christos 
    846  1.1  christos 
    847  1.1  christos /* Perform a diff relocation.  Nothing to do, as the difference value is
    849  1.1  christos    already written into the section's contents.  */
    850  1.1  christos 
    851  1.1  christos static bfd_reloc_status_type
    852  1.1  christos bfd_elf_pru_diff_relocate (bfd *abfd ATTRIBUTE_UNUSED,
    853  1.1  christos 			   arelent *reloc_entry ATTRIBUTE_UNUSED,
    854  1.1  christos 			   asymbol *symbol ATTRIBUTE_UNUSED,
    855  1.1  christos 			   void *data ATTRIBUTE_UNUSED,
    856  1.1  christos 			   asection *input_section ATTRIBUTE_UNUSED,
    857  1.1  christos 			   bfd *output_bfd ATTRIBUTE_UNUSED,
    858  1.1  christos 			   char **error_message ATTRIBUTE_UNUSED)
    859  1.1  christos {
    860  1.1  christos   return bfd_reloc_ok;
    861  1.1  christos }
    862  1.1  christos 
    863  1.1  christos 
    864  1.1  christos /* Returns whether the relocation type passed is a diff reloc.  */
    865  1.1  christos 
    866  1.1  christos static bfd_boolean
    867  1.1  christos elf32_pru_is_diff_reloc (Elf_Internal_Rela *irel)
    868  1.1  christos {
    869  1.1  christos   return (ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF8
    870  1.1  christos 	  || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16
    871  1.1  christos 	  || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32
    872  1.1  christos 	  || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16_PMEM
    873  1.1  christos 	  || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32_PMEM);
    874  1.1  christos }
    875  1.1  christos 
    876  1.1  christos /* Reduce the diff value written in the section by count if the shrinked
    877  1.1  christos    insn address happens to fall between the two symbols for which this
    878  1.1  christos    diff reloc was emitted.  */
    879  1.1  christos 
    880  1.1  christos static void
    881  1.1  christos elf32_pru_adjust_diff_reloc_value (bfd *abfd,
    882  1.1  christos 				   struct bfd_section *isec,
    883  1.1  christos 				   Elf_Internal_Rela *irel,
    884  1.1  christos 				   bfd_vma symval,
    885  1.1  christos 				   bfd_vma shrinked_insn_address,
    886  1.1  christos 				   int count)
    887  1.1  christos {
    888  1.1  christos   unsigned char *reloc_contents = NULL;
    889  1.1  christos   unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
    890  1.1  christos   if (isec_contents == NULL)
    891  1.1  christos   {
    892  1.1  christos     if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
    893  1.1  christos       return;
    894  1.1  christos 
    895  1.1  christos     elf_section_data (isec)->this_hdr.contents = isec_contents;
    896  1.1  christos   }
    897  1.1  christos 
    898  1.1  christos   reloc_contents = isec_contents + irel->r_offset;
    899  1.1  christos 
    900  1.1  christos   /* Read value written in object file.  */
    901  1.1  christos   bfd_signed_vma x = 0;
    902  1.1  christos   switch (ELF32_R_TYPE (irel->r_info))
    903  1.1  christos   {
    904  1.1  christos   case R_PRU_GNU_DIFF8:
    905  1.1  christos     {
    906  1.1  christos       x = bfd_get_signed_8 (abfd, reloc_contents);
    907  1.1  christos       break;
    908  1.1  christos     }
    909  1.1  christos   case R_PRU_GNU_DIFF16:
    910  1.1  christos     {
    911  1.1  christos       x = bfd_get_signed_16 (abfd, reloc_contents);
    912  1.1  christos       break;
    913  1.1  christos     }
    914  1.1  christos   case R_PRU_GNU_DIFF32:
    915  1.1  christos     {
    916  1.1  christos       x = bfd_get_signed_32 (abfd, reloc_contents);
    917  1.1  christos       break;
    918  1.1  christos     }
    919  1.1  christos   case R_PRU_GNU_DIFF16_PMEM:
    920  1.1  christos     {
    921  1.1  christos       x = bfd_get_signed_16 (abfd, reloc_contents) * 4;
    922  1.1  christos       break;
    923  1.1  christos     }
    924  1.1  christos   case R_PRU_GNU_DIFF32_PMEM:
    925  1.1  christos     {
    926  1.1  christos       x = bfd_get_signed_32 (abfd, reloc_contents) * 4;
    927  1.1  christos       break;
    928  1.1  christos     }
    929  1.1  christos   default:
    930  1.1  christos     {
    931  1.1  christos       BFD_FAIL ();
    932  1.1  christos     }
    933  1.1  christos   }
    934  1.1  christos 
    935  1.1  christos   /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
    936  1.1  christos      into the object file at the reloc offset.  sym2's logical value is
    937  1.1  christos      symval (<start_of_section>) + reloc addend.  Compute the start and end
    938  1.1  christos      addresses and check if the shrinked insn falls between sym1 and sym2.  */
    939  1.1  christos 
    940  1.1  christos   bfd_vma end_address = symval + irel->r_addend;
    941  1.1  christos   bfd_vma start_address = end_address - x;
    942  1.1  christos 
    943  1.1  christos   /* Shrink the absolute DIFF value (get the to labels "closer"
    944  1.1  christos      together), because we have removed data between labels.  */
    945  1.1  christos   if (x < 0)
    946  1.1  christos     {
    947  1.1  christos       x += count;
    948  1.1  christos       /* In case the signed x is negative, restore order.  */
    949  1.1  christos       SWAP_VALS (end_address, start_address);
    950  1.1  christos     }
    951  1.1  christos   else
    952  1.1  christos     {
    953  1.1  christos       x -= count;
    954  1.1  christos     }
    955  1.1  christos 
    956  1.1  christos   /* Reduce the diff value by count bytes and write it back into section
    957  1.1  christos     contents.  */
    958  1.1  christos 
    959  1.1  christos   if (shrinked_insn_address >= start_address
    960  1.1  christos       && shrinked_insn_address <= end_address)
    961  1.1  christos   {
    962  1.1  christos     switch (ELF32_R_TYPE (irel->r_info))
    963  1.1  christos     {
    964  1.1  christos     case R_PRU_GNU_DIFF8:
    965  1.1  christos       {
    966  1.1  christos 	bfd_put_signed_8 (abfd, x & 0xFF, reloc_contents);
    967  1.1  christos 	break;
    968  1.1  christos       }
    969  1.1  christos     case R_PRU_GNU_DIFF16:
    970  1.1  christos       {
    971  1.1  christos 	bfd_put_signed_16 (abfd, x & 0xFFFF, reloc_contents);
    972  1.1  christos 	break;
    973  1.1  christos       }
    974  1.1  christos     case R_PRU_GNU_DIFF32:
    975  1.1  christos       {
    976  1.1  christos 	bfd_put_signed_32 (abfd, x & 0xFFFFFFFF, reloc_contents);
    977  1.1  christos 	break;
    978  1.1  christos       }
    979  1.1  christos     case R_PRU_GNU_DIFF16_PMEM:
    980  1.1  christos       {
    981  1.1  christos 	bfd_put_signed_16 (abfd, (x / 4) & 0xFFFF, reloc_contents);
    982  1.1  christos 	break;
    983  1.1  christos       }
    984  1.1  christos     case R_PRU_GNU_DIFF32_PMEM:
    985  1.1  christos       {
    986  1.1  christos 	bfd_put_signed_32 (abfd, (x / 4) & 0xFFFFFFFF, reloc_contents);
    987  1.1  christos 	break;
    988  1.1  christos       }
    989  1.1  christos     default:
    990  1.1  christos       {
    991  1.1  christos 	BFD_FAIL ();
    992  1.1  christos       }
    993  1.1  christos     }
    994  1.1  christos 
    995  1.1  christos   }
    996  1.1  christos }
    997  1.1  christos 
    998  1.1  christos /* Delete some bytes from a section while changing the size of an instruction.
    999  1.1  christos    The parameter "addr" denotes the section-relative offset pointing just
   1000  1.1  christos    behind the shrinked instruction. "addr+count" point at the first
   1001  1.1  christos    byte just behind the original unshrinked instruction.
   1002  1.1  christos 
   1003  1.1  christos    Idea copied from the AVR port.  */
   1004  1.1  christos 
   1005  1.1  christos static bfd_boolean
   1006  1.1  christos pru_elf_relax_delete_bytes (bfd *abfd,
   1007  1.1  christos 			    asection *sec,
   1008  1.1  christos 			    bfd_vma addr,
   1009  1.1  christos 			    int count)
   1010  1.1  christos {
   1011  1.1  christos   Elf_Internal_Shdr *symtab_hdr;
   1012  1.1  christos   unsigned int sec_shndx;
   1013  1.1  christos   bfd_byte *contents;
   1014  1.1  christos   Elf_Internal_Rela *irel, *irelend;
   1015  1.1  christos   Elf_Internal_Sym *isym;
   1016  1.1  christos   Elf_Internal_Sym *isymbuf = NULL;
   1017  1.1  christos   bfd_vma toaddr;
   1018  1.1  christos   struct elf_link_hash_entry **sym_hashes;
   1019  1.1  christos   struct elf_link_hash_entry **end_hashes;
   1020  1.1  christos   unsigned int symcount;
   1021  1.1  christos 
   1022  1.1  christos   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   1023  1.1  christos   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
   1024  1.1  christos   contents = elf_section_data (sec)->this_hdr.contents;
   1025  1.1  christos 
   1026  1.1  christos   toaddr = sec->size;
   1027  1.1  christos 
   1028  1.1  christos   irel = elf_section_data (sec)->relocs;
   1029  1.1  christos   irelend = irel + sec->reloc_count;
   1030  1.1  christos 
   1031  1.1  christos   /* Actually delete the bytes.  */
   1032  1.1  christos   if (toaddr - addr - count > 0)
   1033  1.1  christos     memmove (contents + addr, contents + addr + count,
   1034  1.1  christos 	     (size_t) (toaddr - addr - count));
   1035  1.1  christos   sec->size -= count;
   1036  1.1  christos 
   1037  1.1  christos   /* Adjust all the reloc addresses.  */
   1038  1.1  christos   for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
   1039  1.1  christos     {
   1040  1.1  christos       bfd_vma old_reloc_address;
   1041  1.1  christos 
   1042  1.1  christos       old_reloc_address = (sec->output_section->vma
   1043  1.1  christos 			   + sec->output_offset + irel->r_offset);
   1044  1.1  christos 
   1045  1.1  christos       /* Get the new reloc address.  */
   1046  1.1  christos       if ((irel->r_offset > addr
   1047  1.1  christos 	   && irel->r_offset < toaddr))
   1048  1.1  christos 	{
   1049  1.1  christos 	  if (debug_relax)
   1050  1.1  christos 	    printf ("Relocation at address 0x%x needs to be moved.\n"
   1051  1.1  christos 		    "Old section offset: 0x%x, New section offset: 0x%x \n",
   1052  1.1  christos 		    (unsigned int) old_reloc_address,
   1053  1.1  christos 		    (unsigned int) irel->r_offset,
   1054  1.1  christos 		    (unsigned int) ((irel->r_offset) - count));
   1055  1.1  christos 
   1056  1.1  christos 	  irel->r_offset -= count;
   1057  1.1  christos 	}
   1058  1.1  christos 
   1059  1.1  christos     }
   1060  1.1  christos 
   1061  1.1  christos    /* The reloc's own addresses are now ok.  However, we need to readjust
   1062  1.1  christos       the reloc's addend, i.e. the reloc's value if two conditions are met:
   1063  1.1  christos       1.) the reloc is relative to a symbol in this section that
   1064  1.1  christos 	  is located in front of the shrinked instruction
   1065  1.1  christos       2.) symbol plus addend end up behind the shrinked instruction.
   1066  1.1  christos 
   1067  1.1  christos       The most common case where this happens are relocs relative to
   1068  1.1  christos       the section-start symbol.
   1069  1.1  christos 
   1070  1.1  christos       This step needs to be done for all of the sections of the bfd.  */
   1071  1.1  christos 
   1072  1.1  christos   {
   1073  1.1  christos     struct bfd_section *isec;
   1074  1.1  christos 
   1075  1.1  christos     for (isec = abfd->sections; isec; isec = isec->next)
   1076  1.1  christos      {
   1077  1.1  christos        bfd_vma symval;
   1078  1.1  christos        bfd_vma shrinked_insn_address;
   1079  1.1  christos 
   1080  1.1  christos        if (isec->reloc_count == 0)
   1081  1.1  christos 	 continue;
   1082  1.1  christos 
   1083  1.1  christos        shrinked_insn_address = (sec->output_section->vma
   1084  1.1  christos 				+ sec->output_offset + addr - count);
   1085  1.1  christos 
   1086  1.1  christos        irel = elf_section_data (isec)->relocs;
   1087  1.1  christos        /* PR 12161: Read in the relocs for this section if necessary.  */
   1088  1.1  christos        if (irel == NULL)
   1089  1.1  christos 	 irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
   1090  1.1  christos 
   1091  1.1  christos        for (irelend = irel + isec->reloc_count;
   1092  1.1  christos 	    irel < irelend;
   1093  1.1  christos 	    irel++)
   1094  1.1  christos 	 {
   1095  1.1  christos 	   /* Read this BFD's local symbols if we haven't done
   1096  1.1  christos 	      so already.  */
   1097  1.1  christos 	   if (isymbuf == NULL && symtab_hdr->sh_info != 0)
   1098  1.1  christos 	     {
   1099  1.1  christos 	       isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
   1100  1.1  christos 	       if (isymbuf == NULL)
   1101  1.1  christos 		 isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
   1102  1.1  christos 						 symtab_hdr->sh_info, 0,
   1103  1.1  christos 						 NULL, NULL, NULL);
   1104  1.1  christos 	       if (isymbuf == NULL)
   1105  1.1  christos 		 return FALSE;
   1106  1.1  christos 	     }
   1107  1.1  christos 
   1108  1.1  christos 	   /* Get the value of the symbol referred to by the reloc.  */
   1109  1.1  christos 	   if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
   1110  1.1  christos 	     {
   1111  1.1  christos 	       /* A local symbol.  */
   1112  1.1  christos 	       asection *sym_sec;
   1113  1.1  christos 
   1114  1.1  christos 	       isym = isymbuf + ELF32_R_SYM (irel->r_info);
   1115  1.1  christos 	       sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
   1116  1.1  christos 	       symval = isym->st_value;
   1117  1.1  christos 	       /* If the reloc is absolute, it will not have
   1118  1.1  christos 		  a symbol or section associated with it.  */
   1119  1.1  christos 	       if (sym_sec == sec)
   1120  1.1  christos 		 {
   1121  1.1  christos 		   symval += sym_sec->output_section->vma
   1122  1.1  christos 		     + sym_sec->output_offset;
   1123  1.1  christos 
   1124  1.1  christos 		   if (debug_relax)
   1125  1.1  christos 		     printf ("Checking if the relocation's "
   1126  1.1  christos 			     "addend needs corrections.\n"
   1127  1.1  christos 			     "Address of anchor symbol: 0x%x \n"
   1128  1.1  christos 			     "Address of relocation target: 0x%x \n"
   1129  1.1  christos 			     "Address of relaxed insn: 0x%x \n",
   1130  1.1  christos 			     (unsigned int) symval,
   1131  1.1  christos 			     (unsigned int) (symval + irel->r_addend),
   1132  1.1  christos 			     (unsigned int) shrinked_insn_address);
   1133  1.1  christos 
   1134  1.1  christos 		   /* Shrink the special DIFF relocations.  */
   1135  1.1  christos 		   if (elf32_pru_is_diff_reloc (irel))
   1136  1.1  christos 		     {
   1137  1.1  christos 		       elf32_pru_adjust_diff_reloc_value (abfd, isec, irel,
   1138  1.1  christos 							  symval,
   1139  1.1  christos 							  shrinked_insn_address,
   1140  1.1  christos 							  count);
   1141  1.1  christos 		     }
   1142  1.1  christos 
   1143  1.1  christos 		   /* Fix the addend, if it is affected.  */
   1144  1.1  christos 		   if (symval <= shrinked_insn_address
   1145  1.1  christos 		       && (symval + irel->r_addend) > shrinked_insn_address)
   1146  1.1  christos 		     {
   1147  1.1  christos 
   1148  1.1  christos 		       irel->r_addend -= count;
   1149  1.1  christos 
   1150  1.1  christos 		       if (debug_relax)
   1151  1.1  christos 			 printf ("Relocation's addend needed to be fixed \n");
   1152  1.1  christos 		     }
   1153  1.1  christos 		 }
   1154  1.1  christos 	       /* else...Reference symbol is absolute.
   1155  1.1  christos 		  No adjustment needed.  */
   1156  1.1  christos 	     }
   1157  1.1  christos 	   /* else...Reference symbol is extern.  No need for adjusting
   1158  1.1  christos 	      the addend.  */
   1159  1.1  christos 	 }
   1160  1.1  christos      }
   1161  1.1  christos   }
   1162  1.1  christos 
   1163  1.1  christos   /* Adjust the local symbols defined in this section.  */
   1164  1.1  christos   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
   1165  1.1  christos   /* Fix PR 9841, there may be no local symbols.  */
   1166  1.1  christos   if (isym != NULL)
   1167  1.1  christos     {
   1168  1.1  christos       Elf_Internal_Sym *isymend;
   1169  1.1  christos 
   1170  1.1  christos       isymend = isym + symtab_hdr->sh_info;
   1171  1.1  christos       for (; isym < isymend; isym++)
   1172  1.1  christos 	{
   1173  1.1  christos 	  if (isym->st_shndx == sec_shndx)
   1174  1.1  christos 	    {
   1175  1.1  christos 	      if (isym->st_value > addr
   1176  1.1  christos 		  && isym->st_value <= toaddr)
   1177  1.1  christos 		isym->st_value -= count;
   1178  1.1  christos 
   1179  1.1  christos 	      if (isym->st_value <= addr
   1180  1.1  christos 		  && isym->st_value + isym->st_size > addr)
   1181  1.1  christos 		{
   1182  1.1  christos 		  /* If this assert fires then we have a symbol that ends
   1183  1.1  christos 		     part way through an instruction.  Does that make
   1184  1.1  christos 		     sense?  */
   1185  1.1  christos 		  BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
   1186  1.1  christos 		  isym->st_size -= count;
   1187  1.1  christos 		}
   1188  1.1  christos 	    }
   1189  1.1  christos 	}
   1190  1.1  christos     }
   1191  1.1  christos 
   1192  1.1  christos   /* Now adjust the global symbols defined in this section.  */
   1193  1.1  christos   symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
   1194  1.1  christos 	      - symtab_hdr->sh_info);
   1195  1.1  christos   sym_hashes = elf_sym_hashes (abfd);
   1196  1.1  christos   end_hashes = sym_hashes + symcount;
   1197  1.1  christos   for (; sym_hashes < end_hashes; sym_hashes++)
   1198  1.1  christos     {
   1199  1.1  christos       struct elf_link_hash_entry *sym_hash = *sym_hashes;
   1200  1.1  christos       if ((sym_hash->root.type == bfd_link_hash_defined
   1201  1.1  christos 	   || sym_hash->root.type == bfd_link_hash_defweak)
   1202  1.1  christos 	  && sym_hash->root.u.def.section == sec)
   1203  1.1  christos 	{
   1204  1.1  christos 	  if (sym_hash->root.u.def.value > addr
   1205  1.1  christos 	      && sym_hash->root.u.def.value <= toaddr)
   1206  1.1  christos 	    sym_hash->root.u.def.value -= count;
   1207  1.1  christos 
   1208  1.1  christos 	  if (sym_hash->root.u.def.value <= addr
   1209  1.1  christos 	      && (sym_hash->root.u.def.value + sym_hash->size > addr))
   1210  1.1  christos 	    {
   1211  1.1  christos 	      /* If this assert fires then we have a symbol that ends
   1212  1.1  christos 		 part way through an instruction.  Does that make
   1213  1.1  christos 		 sense?  */
   1214  1.1  christos 	      BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size
   1215  1.1  christos 			  >= addr + count);
   1216  1.1  christos 	      sym_hash->size -= count;
   1217  1.1  christos 	    }
   1218  1.1  christos 	}
   1219  1.1  christos     }
   1220  1.1  christos 
   1221  1.1  christos   return TRUE;
   1222  1.1  christos }
   1223  1.1  christos 
   1224  1.1  christos static bfd_boolean
   1225  1.1  christos pru_elf32_relax_section (bfd * abfd, asection * sec,
   1226  1.1  christos 			  struct bfd_link_info * link_info,
   1227  1.1  christos 			  bfd_boolean * again)
   1228  1.1  christos {
   1229  1.1  christos   Elf_Internal_Shdr * symtab_hdr;
   1230  1.1  christos   Elf_Internal_Rela * internal_relocs;
   1231  1.1  christos   Elf_Internal_Rela * irel;
   1232  1.1  christos   Elf_Internal_Rela * irelend;
   1233  1.1  christos   bfd_byte *	      contents = NULL;
   1234  1.1  christos   Elf_Internal_Sym *  isymbuf = NULL;
   1235  1.1  christos 
   1236  1.1  christos   /* Assume nothing changes.  */
   1237  1.1  christos   *again = FALSE;
   1238  1.1  christos 
   1239  1.1  christos   /* We don't have to do anything for a relocatable link, if
   1240  1.1  christos      this section does not have relocs, or if this is not a
   1241  1.1  christos      code section.  */
   1242  1.1  christos   if (bfd_link_relocatable (link_info)
   1243  1.1  christos     || (sec->flags & SEC_RELOC) == 0
   1244  1.1  christos     || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0)
   1245  1.1  christos     return TRUE;
   1246  1.1  christos 
   1247  1.1  christos   symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
   1248  1.1  christos 
   1249  1.1  christos   /* Get a copy of the native relocations.  */
   1250  1.1  christos   internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
   1251  1.1  christos 					       link_info->keep_memory);
   1252  1.1  christos   if (internal_relocs == NULL)
   1253  1.1  christos     goto error_return;
   1254  1.1  christos 
   1255  1.1  christos   /* Walk through them looking for relaxing opportunities.  */
   1256  1.1  christos   irelend = internal_relocs + sec->reloc_count;
   1257  1.1  christos 
   1258  1.1  christos   for (irel = internal_relocs; irel < irelend; irel++)
   1259  1.1  christos     {
   1260  1.1  christos       bfd_vma symval;
   1261  1.1  christos 
   1262  1.1  christos       /* Get the section contents if we haven't done so already.  */
   1263  1.1  christos       if (contents == NULL)
   1264  1.1  christos 	{
   1265  1.1  christos 	  /* Get cached copy if it exists.  */
   1266  1.1  christos 	  if (elf_section_data (sec)->this_hdr.contents != NULL)
   1267  1.1  christos 	    contents = elf_section_data (sec)->this_hdr.contents;
   1268  1.1  christos 	  else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
   1269  1.1  christos 	    goto error_return;
   1270  1.1  christos 	}
   1271  1.1  christos 
   1272  1.1  christos       /* Read this BFD's local symbols if we haven't done so already.  */
   1273  1.1  christos       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
   1274  1.1  christos 	{
   1275  1.1  christos 	  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
   1276  1.1  christos 	  if (isymbuf == NULL)
   1277  1.1  christos 	    isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
   1278  1.1  christos 					    symtab_hdr->sh_info, 0,
   1279  1.1  christos 					    NULL, NULL, NULL);
   1280  1.1  christos 	  if (isymbuf == NULL)
   1281  1.1  christos 	    goto error_return;
   1282  1.1  christos 	}
   1283  1.1  christos 
   1284  1.1  christos       /* Get the value of the symbol referred to by the reloc.  */
   1285  1.1  christos       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
   1286  1.1  christos 	{
   1287  1.1  christos 	  /* A local symbol.  */
   1288  1.1  christos 	  Elf_Internal_Sym *isym;
   1289  1.1  christos 	  asection *sym_sec;
   1290  1.1  christos 
   1291  1.1  christos 	  isym = isymbuf + ELF32_R_SYM (irel->r_info);
   1292  1.1  christos 	  if (isym->st_shndx == SHN_UNDEF)
   1293  1.1  christos 	    sym_sec = bfd_und_section_ptr;
   1294  1.1  christos 	  else if (isym->st_shndx == SHN_ABS)
   1295  1.1  christos 	    sym_sec = bfd_abs_section_ptr;
   1296  1.1  christos 	  else if (isym->st_shndx == SHN_COMMON)
   1297  1.1  christos 	    sym_sec = bfd_com_section_ptr;
   1298  1.1  christos 	  else
   1299  1.1  christos 	    sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
   1300  1.1  christos 	  symval = (isym->st_value
   1301  1.1  christos 		    + sym_sec->output_section->vma + sym_sec->output_offset);
   1302  1.1  christos 	}
   1303  1.1  christos       else
   1304  1.1  christos 	{
   1305  1.1  christos 	  unsigned long indx;
   1306  1.1  christos 	  struct elf_link_hash_entry *h;
   1307  1.1  christos 
   1308  1.1  christos 	  /* An external symbol.  */
   1309  1.1  christos 	  indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
   1310  1.1  christos 	  h = elf_sym_hashes (abfd)[indx];
   1311  1.1  christos 	  BFD_ASSERT (h != NULL);
   1312  1.1  christos 
   1313  1.1  christos 	  if (h->root.type != bfd_link_hash_defined
   1314  1.1  christos 	      && h->root.type != bfd_link_hash_defweak)
   1315  1.1  christos 	    /* This appears to be a reference to an undefined
   1316  1.1  christos 	       symbol.  Just ignore it--it will be caught by the
   1317  1.1  christos 	       regular reloc processing.  */
   1318  1.1  christos 	    continue;
   1319  1.1  christos 
   1320  1.1  christos 	  symval = (h->root.u.def.value
   1321  1.1  christos 		    + h->root.u.def.section->output_section->vma
   1322  1.1  christos 		    + h->root.u.def.section->output_offset);
   1323  1.1  christos 	}
   1324  1.1  christos 
   1325  1.1  christos       /* For simplicity of coding, we are going to modify the section
   1326  1.1  christos 	 contents, the section relocs, and the BFD symbol table.  We
   1327  1.1  christos 	 must tell the rest of the code not to free up this
   1328  1.1  christos 	 information.  It would be possible to instead create a table
   1329  1.1  christos 	 of changes which have to be made, as is done in coff-mips.c;
   1330  1.1  christos 	 that would be more work, but would require less memory when
   1331  1.1  christos 	 the linker is run.  */
   1332  1.1  christos 
   1333  1.1  christos       /* Check if we can remove an LDI instruction from the LDI32
   1334  1.1  christos 	 pseudo instruction if the upper 16 operand bits are zero.  */
   1335  1.1  christos       if (ELF32_R_TYPE (irel->r_info) == (int) R_PRU_LDI32)
   1336  1.1  christos 	{
   1337  1.1  christos 	  bfd_vma value = symval + irel->r_addend;
   1338  1.1  christos 
   1339  1.1  christos 	  if (debug_relax)
   1340  1.1  christos 	    printf ("R_PRU_LDI32 with value=0x%lx\n", (long) value);
   1341  1.1  christos 
   1342  1.1  christos 	  if ((long) value >> 16 == 0)
   1343  1.1  christos 	    {
   1344  1.1  christos 	      /* Note that we've changed the relocs, section contents.  */
   1345  1.1  christos 	      elf_section_data (sec)->relocs = internal_relocs;
   1346  1.1  christos 	      elf_section_data (sec)->this_hdr.contents = contents;
   1347  1.1  christos 	      symtab_hdr->contents = (unsigned char *) isymbuf;
   1348  1.1  christos 
   1349  1.1  christos 	      /* Delete bytes.  */
   1350  1.1  christos 	      if (!pru_elf_relax_delete_bytes (abfd, sec, irel->r_offset + 4, 4))
   1351  1.1  christos 		goto error_return;
   1352  1.1  christos 
   1353  1.1  christos 	      /* We're done with deletion of the second instruction.
   1354  1.1  christos 		 Set a regular LDI relocation for the first instruction
   1355  1.1  christos 		 we left to load the 16-bit value into the 32-bit
   1356  1.1  christos 		 register.  */
   1357  1.1  christos 	      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
   1358  1.1  christos 					   R_PRU_U16);
   1359  1.1  christos 
   1360  1.1  christos 	      /* That will change things, so, we should relax again.
   1361  1.1  christos 		 Note that this is not required, and it may be slow.  */
   1362  1.1  christos 	      *again = TRUE;
   1363  1.1  christos 	    }
   1364  1.1  christos 	}
   1365  1.1  christos     }
   1366  1.1  christos 
   1367  1.1  christos   if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
   1368  1.1  christos     {
   1369  1.1  christos       if (!link_info->keep_memory)
   1370  1.1  christos 	free (isymbuf);
   1371  1.1  christos       else
   1372  1.1  christos 	{
   1373  1.1  christos 	  /* Cache the symbols for elf_link_input_bfd.  */
   1374  1.1  christos 	  symtab_hdr->contents = (unsigned char *) isymbuf;
   1375  1.1  christos 	}
   1376  1.1  christos     }
   1377  1.1  christos 
   1378  1.1  christos   if (contents != NULL
   1379  1.1  christos       && elf_section_data (sec)->this_hdr.contents != contents)
   1380  1.1  christos     {
   1381  1.1  christos       if (!link_info->keep_memory)
   1382  1.1  christos 	free (contents);
   1383  1.1  christos       else
   1384  1.1  christos 	{
   1385  1.1  christos 	  /* Cache the section contents for elf_link_input_bfd.  */
   1386  1.1  christos 	  elf_section_data (sec)->this_hdr.contents = contents;
   1387  1.1  christos 	}
   1388  1.1  christos     }
   1389  1.1  christos 
   1390  1.1  christos   if (internal_relocs != NULL
   1391  1.1  christos       && elf_section_data (sec)->relocs != internal_relocs)
   1392  1.1  christos     free (internal_relocs);
   1393  1.1  christos 
   1394  1.1  christos   return TRUE;
   1395  1.1  christos 
   1396  1.1  christos error_return:
   1397  1.1  christos   if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
   1398  1.1  christos     free (isymbuf);
   1399  1.1  christos   if (contents != NULL
   1400  1.1  christos       && elf_section_data (sec)->this_hdr.contents != contents)
   1401  1.1  christos     free (contents);
   1402  1.1  christos   if (internal_relocs != NULL
   1403  1.1  christos       && elf_section_data (sec)->relocs != internal_relocs)
   1404  1.1  christos     free (internal_relocs);
   1405  1.1  christos 
   1406  1.1  christos   return FALSE;
   1407  1.1  christos }
   1408  1.1  christos 
   1409  1.1  christos /* Free the derived linker hash table.  */
   1410  1.1  christos static void
   1411  1.1  christos pru_elf32_link_hash_table_free (bfd *obfd)
   1412  1.1  christos {
   1413  1.1  christos   _bfd_elf_link_hash_table_free (obfd);
   1414  1.1  christos }
   1415  1.1  christos 
   1416  1.1  christos /* Implement bfd_elf32_bfd_link_hash_table_create.  */
   1417  1.1  christos static struct bfd_link_hash_table *
   1418  1.1  christos pru_elf32_link_hash_table_create (bfd *abfd)
   1419  1.1  christos {
   1420  1.1  christos   struct elf_link_hash_table *ret;
   1421  1.1  christos   bfd_size_type amt = sizeof (struct elf_link_hash_table);
   1422  1.1  christos 
   1423  1.1  christos   ret = bfd_zmalloc (amt);
   1424  1.1  christos   if (ret == NULL)
   1425  1.1  christos     return NULL;
   1426  1.1  christos 
   1427  1.1  christos   if (!_bfd_elf_link_hash_table_init (ret, abfd,
   1428  1.1  christos 				      link_hash_newfunc,
   1429  1.1  christos 				      sizeof (struct
   1430  1.1  christos 					      elf_link_hash_entry),
   1431  1.1  christos 				      PRU_ELF_DATA))
   1432  1.1  christos     {
   1433  1.1  christos       free (ret);
   1434  1.1  christos       return NULL;
   1435  1.1  christos     }
   1436  1.1  christos 
   1437  1.1  christos   ret->root.hash_table_free = pru_elf32_link_hash_table_free;
   1438  1.1  christos 
   1439  1.1  christos   return &ret->root;
   1440  1.1  christos }
   1441  1.1  christos 
   1442  1.1  christos #define ELF_ARCH			bfd_arch_pru
   1443  1.1  christos #define ELF_TARGET_ID			PRU_ELF_DATA
   1444  1.1  christos #define ELF_MACHINE_CODE		EM_TI_PRU
   1445  1.1  christos 
   1446  1.1  christos #define ELF_MAXPAGESIZE			1
   1447  1.1  christos 
   1448  1.1  christos #define bfd_elf32_bfd_link_hash_table_create \
   1449  1.1  christos 					  pru_elf32_link_hash_table_create
   1450  1.1  christos 
   1451  1.1  christos /* Relocation table lookup macros.  */
   1452  1.1  christos 
   1453  1.1  christos #define bfd_elf32_bfd_reloc_type_lookup	  pru_elf32_bfd_reloc_type_lookup
   1454  1.1  christos #define bfd_elf32_bfd_reloc_name_lookup	  pru_elf32_bfd_reloc_name_lookup
   1455  1.1  christos 
   1456  1.1  christos /* elf_info_to_howto (using RELA relocations).  */
   1457  1.1  christos 
   1458  1.1  christos #define elf_info_to_howto		pru_elf32_info_to_howto
   1459  1.1  christos 
   1460  1.1  christos /* elf backend functions.  */
   1461  1.1  christos 
   1462  1.1  christos #define elf_backend_rela_normal		1
   1463  1.1  christos 
   1464  1.1  christos #define elf_backend_relocate_section	pru_elf32_relocate_section
   1465  1.1  christos #define bfd_elf32_bfd_relax_section	pru_elf32_relax_section
   1466  1.1  christos 
   1467  1.1  christos #define TARGET_LITTLE_SYM		pru_elf32_vec
   1468  1.1  christos #define TARGET_LITTLE_NAME		"elf32-pru"
   1469  1.1  christos 
   1470                #include "elf32-target.h"
   1471