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