Home | History | Annotate | Line # | Download | only in bfd
      1      1.1  christos /* 32-bit ELF support for TI PRU.
      2  1.1.1.5  christos    Copyright (C) 2014-2024 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.1.2  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.1.2  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.1.2  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.1.2  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.1.2  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.1.2  christos 	 "R_PRU_DIFF32",	/* name */
    259  1.1.1.4  christos 	 false,			/* partial_inplace */
    260      1.1  christos 	 0,			/* src_mask */
    261  1.1.1.2  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.1.2  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.1.2  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.3  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  christos 					 rel, 1, relend, howto, 0, contents);
    754      1.1  christos 
    755      1.1  christos       /* Nothing more to do unless this is a final link.  */
    756      1.1  christos       if (bfd_link_relocatable (info))
    757      1.1  christos 	continue;
    758      1.1  christos 
    759      1.1  christos       if (howto)
    760      1.1  christos 	{
    761      1.1  christos 	  switch (howto->type)
    762      1.1  christos 	    {
    763      1.1  christos 	    case R_PRU_NONE:
    764      1.1  christos 	      /* We don't need to find a value for this symbol.  It's just a
    765      1.1  christos 		 marker.  */
    766      1.1  christos 	      r = bfd_reloc_ok;
    767      1.1  christos 	      break;
    768      1.1  christos 
    769  1.1.1.2  christos 	    case R_PRU_U16:
    770  1.1.1.2  christos 	      if (is_rel_reloc)
    771  1.1.1.2  christos 		{
    772  1.1.1.2  christos 		  unsigned long insn;
    773  1.1.1.2  christos 		  insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
    774  1.1.1.2  christos 		  addend = GET_INSN_FIELD (IMM16, insn);
    775  1.1.1.2  christos 		}
    776  1.1.1.2  christos 	      else
    777  1.1.1.2  christos 		addend = rel->r_addend;
    778  1.1.1.2  christos 	      r = _bfd_final_link_relocate (howto, input_bfd,
    779  1.1.1.2  christos 					    input_section, contents,
    780  1.1.1.2  christos 					    rel->r_offset, relocation,
    781  1.1.1.2  christos 					    addend);
    782  1.1.1.2  christos 	      break;
    783  1.1.1.2  christos 
    784      1.1  christos 	    case R_PRU_U16_PMEMIMM:
    785      1.1  christos 	    case R_PRU_32_PMEM:
    786      1.1  christos 	    case R_PRU_16_PMEM:
    787  1.1.1.2  christos 	      if (is_rel_reloc && howto->type == R_PRU_U16_PMEMIMM)
    788  1.1.1.2  christos 		{
    789  1.1.1.2  christos 		  unsigned long insn;
    790  1.1.1.2  christos 		  insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
    791  1.1.1.2  christos 		  addend = GET_INSN_FIELD (IMM16, insn) << 2;
    792  1.1.1.2  christos 		}
    793  1.1.1.2  christos 	      else if (is_rel_reloc && howto->type == R_PRU_32_PMEM)
    794  1.1.1.2  christos 		{
    795  1.1.1.2  christos 		  addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
    796  1.1.1.2  christos 		  addend <<= 2;
    797  1.1.1.2  christos 		}
    798  1.1.1.2  christos 	      else if (is_rel_reloc && howto->type == R_PRU_16_PMEM)
    799  1.1.1.2  christos 		{
    800  1.1.1.2  christos 		  addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
    801  1.1.1.2  christos 		  addend <<= 2;
    802  1.1.1.2  christos 		}
    803  1.1.1.2  christos 	      else
    804  1.1.1.2  christos 		{
    805  1.1.1.2  christos 		  BFD_ASSERT (!is_rel_reloc);
    806  1.1.1.2  christos 		  addend = rel->r_addend;
    807  1.1.1.2  christos 		}
    808      1.1  christos 	      r = pru_elf32_do_pmem_relocate (input_bfd, howto,
    809      1.1  christos 						input_section,
    810      1.1  christos 						contents, rel->r_offset,
    811  1.1.1.2  christos 						relocation, addend);
    812      1.1  christos 	      break;
    813      1.1  christos 	    case R_PRU_S10_PCREL:
    814  1.1.1.2  christos 	      BFD_ASSERT (! is_rel_reloc);
    815      1.1  christos 	      r = pru_elf32_do_s10_pcrel_relocate (input_bfd, howto,
    816      1.1  christos 						      input_section,
    817      1.1  christos 						      contents,
    818      1.1  christos 						      rel->r_offset,
    819      1.1  christos 						      relocation,
    820      1.1  christos 						      rel->r_addend);
    821      1.1  christos 	      break;
    822      1.1  christos 	    case R_PRU_U8_PCREL:
    823  1.1.1.2  christos 	      BFD_ASSERT (! is_rel_reloc);
    824      1.1  christos 	      r = pru_elf32_do_u8_pcrel_relocate (input_bfd, howto,
    825      1.1  christos 						      input_section,
    826      1.1  christos 						      contents,
    827      1.1  christos 						      rel->r_offset,
    828      1.1  christos 						      relocation,
    829      1.1  christos 						      rel->r_addend);
    830      1.1  christos 	      break;
    831      1.1  christos 	    case R_PRU_LDI32:
    832  1.1.1.2  christos 	      if (is_rel_reloc)
    833  1.1.1.2  christos 		{
    834  1.1.1.2  christos 		  unsigned long in1, in2;
    835  1.1.1.2  christos 		  in1 = bfd_get_32 (input_bfd, contents + rel->r_offset);
    836  1.1.1.2  christos 		  in2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
    837  1.1.1.2  christos 		  addend = (GET_INSN_FIELD (IMM16, in1) << 16)
    838  1.1.1.2  christos 			    | GET_INSN_FIELD (IMM16, in2);
    839  1.1.1.2  christos 		}
    840  1.1.1.2  christos 	      else
    841  1.1.1.2  christos 		{
    842  1.1.1.2  christos 		  addend = rel->r_addend;
    843  1.1.1.2  christos 		}
    844      1.1  christos 	      r = pru_elf32_do_ldi32_relocate (input_bfd, howto,
    845      1.1  christos 					       input_section,
    846      1.1  christos 					       contents,
    847      1.1  christos 					       rel->r_offset,
    848      1.1  christos 					       relocation,
    849  1.1.1.2  christos 					       addend);
    850      1.1  christos 	      break;
    851      1.1  christos 	    case R_PRU_GNU_DIFF8:
    852      1.1  christos 	    case R_PRU_GNU_DIFF16:
    853      1.1  christos 	    case R_PRU_GNU_DIFF32:
    854      1.1  christos 	    case R_PRU_GNU_DIFF16_PMEM:
    855      1.1  christos 	    case R_PRU_GNU_DIFF32_PMEM:
    856  1.1.1.2  christos 	      /* GNU extensions support only rela.  */
    857  1.1.1.2  christos 	      BFD_ASSERT (! is_rel_reloc);
    858      1.1  christos 	      /* Nothing to do here, as contents already contain the
    859      1.1  christos 		 diff value.  */
    860      1.1  christos 	      r = bfd_reloc_ok;
    861      1.1  christos 	      break;
    862      1.1  christos 
    863  1.1.1.2  christos 	    case R_PRU_BFD_RELOC_16:
    864  1.1.1.2  christos 	      if (is_rel_reloc)
    865  1.1.1.2  christos 		addend = bfd_get_16 (input_bfd, contents + rel->r_offset);
    866  1.1.1.2  christos 	      else
    867  1.1.1.2  christos 		addend = rel->r_addend;
    868  1.1.1.2  christos 	      r = _bfd_final_link_relocate (howto, input_bfd,
    869  1.1.1.2  christos 					    input_section, contents,
    870  1.1.1.2  christos 					    rel->r_offset, relocation,
    871  1.1.1.2  christos 					    addend);
    872  1.1.1.2  christos 	      break;
    873  1.1.1.2  christos 
    874  1.1.1.2  christos 	    case R_PRU_BFD_RELOC_32:
    875  1.1.1.2  christos 	      if (is_rel_reloc)
    876  1.1.1.2  christos 		addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
    877  1.1.1.2  christos 	      else
    878  1.1.1.2  christos 		addend = rel->r_addend;
    879  1.1.1.2  christos 	      r = _bfd_final_link_relocate (howto, input_bfd,
    880  1.1.1.2  christos 					    input_section, contents,
    881  1.1.1.2  christos 					    rel->r_offset, relocation,
    882  1.1.1.2  christos 					    addend);
    883  1.1.1.2  christos 	      break;
    884  1.1.1.2  christos 
    885  1.1.1.2  christos 	    case R_PRU_GNU_BFD_RELOC_8:
    886  1.1.1.2  christos 	      BFD_ASSERT (! is_rel_reloc);
    887      1.1  christos 	      r = _bfd_final_link_relocate (howto, input_bfd,
    888      1.1  christos 					    input_section, contents,
    889      1.1  christos 					    rel->r_offset, relocation,
    890      1.1  christos 					    rel->r_addend);
    891      1.1  christos 	      break;
    892  1.1.1.2  christos 
    893  1.1.1.2  christos 	    default:
    894  1.1.1.2  christos 	      BFD_ASSERT (0);
    895  1.1.1.2  christos 	      break;
    896      1.1  christos 	    }
    897      1.1  christos 	}
    898      1.1  christos       else
    899      1.1  christos 	r = bfd_reloc_notsupported;
    900      1.1  christos 
    901      1.1  christos       if (r != bfd_reloc_ok)
    902      1.1  christos 	{
    903      1.1  christos 	  if (h != NULL)
    904      1.1  christos 	    name = h->root.root.string;
    905      1.1  christos 	  else
    906      1.1  christos 	    {
    907      1.1  christos 	      name = bfd_elf_string_from_elf_section (input_bfd,
    908      1.1  christos 						      symtab_hdr->sh_link,
    909      1.1  christos 						      sym->st_name);
    910      1.1  christos 	      if (name == NULL || *name == '\0')
    911  1.1.1.3  christos 		name = bfd_section_name (sec);
    912      1.1  christos 	    }
    913      1.1  christos 
    914      1.1  christos 	  switch (r)
    915      1.1  christos 	    {
    916      1.1  christos 	    case bfd_reloc_overflow:
    917      1.1  christos 	      (*info->callbacks->reloc_overflow) (info, NULL, name,
    918      1.1  christos 						  howto->name, (bfd_vma) 0,
    919      1.1  christos 						  input_bfd, input_section,
    920      1.1  christos 						  rel->r_offset);
    921      1.1  christos 	      break;
    922      1.1  christos 
    923      1.1  christos 	    case bfd_reloc_undefined:
    924      1.1  christos 	      (*info->callbacks->undefined_symbol) (info, name, input_bfd,
    925      1.1  christos 						    input_section,
    926  1.1.1.4  christos 						    rel->r_offset, true);
    927      1.1  christos 	      break;
    928      1.1  christos 
    929      1.1  christos 	    case bfd_reloc_outofrange:
    930      1.1  christos 	      if (msg == NULL)
    931      1.1  christos 		msg = _("relocation out of range");
    932      1.1  christos 	      break;
    933      1.1  christos 
    934      1.1  christos 	    case bfd_reloc_notsupported:
    935      1.1  christos 	      if (msg == NULL)
    936      1.1  christos 		msg = _("unsupported relocation");
    937      1.1  christos 	      break;
    938      1.1  christos 
    939      1.1  christos 	    case bfd_reloc_dangerous:
    940      1.1  christos 	      if (msg == NULL)
    941      1.1  christos 		msg = _("dangerous relocation");
    942      1.1  christos 	      break;
    943      1.1  christos 
    944      1.1  christos 	    default:
    945      1.1  christos 	      if (msg == NULL)
    946      1.1  christos 		msg = _("unknown error");
    947      1.1  christos 	      break;
    948      1.1  christos 	    }
    949      1.1  christos 
    950      1.1  christos 	  if (msg)
    951      1.1  christos 	    {
    952      1.1  christos 	      (*info->callbacks->warning) (info, msg, name, input_bfd,
    953      1.1  christos 					   input_section, rel->r_offset);
    954  1.1.1.4  christos 	      return false;
    955      1.1  christos 	    }
    956      1.1  christos 	}
    957      1.1  christos     }
    958  1.1.1.4  christos   return true;
    959      1.1  christos }
    960      1.1  christos 
    961      1.1  christos 
    962      1.1  christos /* Perform a diff relocation.  Nothing to do, as the difference value is
    964      1.1  christos    already written into the section's contents.  */
    965      1.1  christos 
    966      1.1  christos static bfd_reloc_status_type
    967      1.1  christos bfd_elf_pru_diff_relocate (bfd *abfd ATTRIBUTE_UNUSED,
    968      1.1  christos 			   arelent *reloc_entry ATTRIBUTE_UNUSED,
    969      1.1  christos 			   asymbol *symbol ATTRIBUTE_UNUSED,
    970      1.1  christos 			   void *data ATTRIBUTE_UNUSED,
    971      1.1  christos 			   asection *input_section ATTRIBUTE_UNUSED,
    972      1.1  christos 			   bfd *output_bfd ATTRIBUTE_UNUSED,
    973      1.1  christos 			   char **error_message ATTRIBUTE_UNUSED)
    974      1.1  christos {
    975      1.1  christos   return bfd_reloc_ok;
    976      1.1  christos }
    977      1.1  christos 
    978      1.1  christos 
    979      1.1  christos /* Returns whether the relocation type passed is a diff reloc.  */
    980  1.1.1.4  christos 
    981      1.1  christos static bool
    982      1.1  christos elf32_pru_is_diff_reloc (Elf_Internal_Rela *irel)
    983      1.1  christos {
    984      1.1  christos   return (ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF8
    985      1.1  christos 	  || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16
    986      1.1  christos 	  || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32
    987      1.1  christos 	  || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16_PMEM
    988      1.1  christos 	  || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32_PMEM);
    989      1.1  christos }
    990      1.1  christos 
    991      1.1  christos /* Reduce the diff value written in the section by count if the shrinked
    992      1.1  christos    insn address happens to fall between the two symbols for which this
    993      1.1  christos    diff reloc was emitted.  */
    994      1.1  christos 
    995      1.1  christos static void
    996      1.1  christos elf32_pru_adjust_diff_reloc_value (bfd *abfd,
    997      1.1  christos 				   struct bfd_section *isec,
    998      1.1  christos 				   Elf_Internal_Rela *irel,
    999      1.1  christos 				   bfd_vma symval,
   1000      1.1  christos 				   bfd_vma shrinked_insn_address,
   1001      1.1  christos 				   int count)
   1002      1.1  christos {
   1003      1.1  christos   unsigned char *reloc_contents = NULL;
   1004      1.1  christos   unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
   1005      1.1  christos   if (isec_contents == NULL)
   1006      1.1  christos   {
   1007      1.1  christos     if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
   1008      1.1  christos       return;
   1009      1.1  christos 
   1010      1.1  christos     elf_section_data (isec)->this_hdr.contents = isec_contents;
   1011      1.1  christos   }
   1012      1.1  christos 
   1013      1.1  christos   reloc_contents = isec_contents + irel->r_offset;
   1014      1.1  christos 
   1015      1.1  christos   /* Read value written in object file.  */
   1016      1.1  christos   bfd_signed_vma x = 0;
   1017      1.1  christos   switch (ELF32_R_TYPE (irel->r_info))
   1018      1.1  christos   {
   1019      1.1  christos   case R_PRU_GNU_DIFF8:
   1020      1.1  christos     {
   1021      1.1  christos       x = bfd_get_signed_8 (abfd, reloc_contents);
   1022      1.1  christos       break;
   1023      1.1  christos     }
   1024      1.1  christos   case R_PRU_GNU_DIFF16:
   1025      1.1  christos     {
   1026      1.1  christos       x = bfd_get_signed_16 (abfd, reloc_contents);
   1027      1.1  christos       break;
   1028      1.1  christos     }
   1029      1.1  christos   case R_PRU_GNU_DIFF32:
   1030      1.1  christos     {
   1031      1.1  christos       x = bfd_get_signed_32 (abfd, reloc_contents);
   1032      1.1  christos       break;
   1033      1.1  christos     }
   1034      1.1  christos   case R_PRU_GNU_DIFF16_PMEM:
   1035      1.1  christos     {
   1036      1.1  christos       x = bfd_get_signed_16 (abfd, reloc_contents) * 4;
   1037      1.1  christos       break;
   1038      1.1  christos     }
   1039      1.1  christos   case R_PRU_GNU_DIFF32_PMEM:
   1040      1.1  christos     {
   1041      1.1  christos       x = bfd_get_signed_32 (abfd, reloc_contents) * 4;
   1042      1.1  christos       break;
   1043      1.1  christos     }
   1044      1.1  christos   default:
   1045      1.1  christos     {
   1046      1.1  christos       BFD_FAIL ();
   1047      1.1  christos     }
   1048      1.1  christos   }
   1049      1.1  christos 
   1050      1.1  christos   /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
   1051      1.1  christos      into the object file at the reloc offset.  sym2's logical value is
   1052      1.1  christos      symval (<start_of_section>) + reloc addend.  Compute the start and end
   1053      1.1  christos      addresses and check if the shrinked insn falls between sym1 and sym2.  */
   1054      1.1  christos 
   1055      1.1  christos   bfd_vma end_address = symval + irel->r_addend;
   1056      1.1  christos   bfd_vma start_address = end_address - x;
   1057      1.1  christos 
   1058      1.1  christos   /* Shrink the absolute DIFF value (get the to labels "closer"
   1059      1.1  christos      together), because we have removed data between labels.  */
   1060      1.1  christos   if (x < 0)
   1061      1.1  christos     {
   1062      1.1  christos       x += count;
   1063      1.1  christos       /* In case the signed x is negative, restore order.  */
   1064      1.1  christos       SWAP_VALS (end_address, start_address);
   1065      1.1  christos     }
   1066      1.1  christos   else
   1067      1.1  christos     {
   1068      1.1  christos       x -= count;
   1069      1.1  christos     }
   1070      1.1  christos 
   1071      1.1  christos   /* Reduce the diff value by count bytes and write it back into section
   1072      1.1  christos     contents.  */
   1073      1.1  christos 
   1074      1.1  christos   if (shrinked_insn_address >= start_address
   1075      1.1  christos       && shrinked_insn_address <= end_address)
   1076      1.1  christos   {
   1077      1.1  christos     switch (ELF32_R_TYPE (irel->r_info))
   1078      1.1  christos     {
   1079      1.1  christos     case R_PRU_GNU_DIFF8:
   1080      1.1  christos       {
   1081      1.1  christos 	bfd_put_signed_8 (abfd, x & 0xFF, reloc_contents);
   1082      1.1  christos 	break;
   1083      1.1  christos       }
   1084      1.1  christos     case R_PRU_GNU_DIFF16:
   1085      1.1  christos       {
   1086      1.1  christos 	bfd_put_signed_16 (abfd, x & 0xFFFF, reloc_contents);
   1087      1.1  christos 	break;
   1088      1.1  christos       }
   1089      1.1  christos     case R_PRU_GNU_DIFF32:
   1090      1.1  christos       {
   1091      1.1  christos 	bfd_put_signed_32 (abfd, x & 0xFFFFFFFF, reloc_contents);
   1092      1.1  christos 	break;
   1093      1.1  christos       }
   1094      1.1  christos     case R_PRU_GNU_DIFF16_PMEM:
   1095      1.1  christos       {
   1096      1.1  christos 	bfd_put_signed_16 (abfd, (x / 4) & 0xFFFF, reloc_contents);
   1097      1.1  christos 	break;
   1098      1.1  christos       }
   1099      1.1  christos     case R_PRU_GNU_DIFF32_PMEM:
   1100      1.1  christos       {
   1101      1.1  christos 	bfd_put_signed_32 (abfd, (x / 4) & 0xFFFFFFFF, reloc_contents);
   1102      1.1  christos 	break;
   1103      1.1  christos       }
   1104      1.1  christos     default:
   1105      1.1  christos       {
   1106      1.1  christos 	BFD_FAIL ();
   1107      1.1  christos       }
   1108      1.1  christos     }
   1109      1.1  christos 
   1110      1.1  christos   }
   1111      1.1  christos }
   1112      1.1  christos 
   1113      1.1  christos /* Delete some bytes from a section while changing the size of an instruction.
   1114      1.1  christos    The parameter "addr" denotes the section-relative offset pointing just
   1115      1.1  christos    behind the shrinked instruction. "addr+count" point at the first
   1116      1.1  christos    byte just behind the original unshrinked instruction.
   1117      1.1  christos 
   1118      1.1  christos    Idea copied from the AVR port.  */
   1119  1.1.1.4  christos 
   1120      1.1  christos static bool
   1121      1.1  christos pru_elf_relax_delete_bytes (bfd *abfd,
   1122      1.1  christos 			    asection *sec,
   1123      1.1  christos 			    bfd_vma addr,
   1124      1.1  christos 			    int count)
   1125      1.1  christos {
   1126      1.1  christos   Elf_Internal_Shdr *symtab_hdr;
   1127      1.1  christos   unsigned int sec_shndx;
   1128      1.1  christos   bfd_byte *contents;
   1129      1.1  christos   Elf_Internal_Rela *irel, *irelend;
   1130      1.1  christos   Elf_Internal_Sym *isym;
   1131      1.1  christos   Elf_Internal_Sym *isymbuf = NULL;
   1132      1.1  christos   bfd_vma toaddr;
   1133      1.1  christos   struct elf_link_hash_entry **sym_hashes;
   1134      1.1  christos   struct elf_link_hash_entry **end_hashes;
   1135      1.1  christos   unsigned int symcount;
   1136      1.1  christos 
   1137      1.1  christos   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   1138      1.1  christos   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
   1139      1.1  christos   contents = elf_section_data (sec)->this_hdr.contents;
   1140      1.1  christos 
   1141      1.1  christos   toaddr = sec->size;
   1142      1.1  christos 
   1143      1.1  christos   irel = elf_section_data (sec)->relocs;
   1144      1.1  christos   irelend = irel + sec->reloc_count;
   1145      1.1  christos 
   1146      1.1  christos   /* Actually delete the bytes.  */
   1147      1.1  christos   if (toaddr - addr - count > 0)
   1148      1.1  christos     memmove (contents + addr, contents + addr + count,
   1149      1.1  christos 	     (size_t) (toaddr - addr - count));
   1150      1.1  christos   sec->size -= count;
   1151      1.1  christos 
   1152      1.1  christos   /* Adjust all the reloc addresses.  */
   1153      1.1  christos   for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
   1154      1.1  christos     {
   1155      1.1  christos       bfd_vma old_reloc_address;
   1156      1.1  christos 
   1157      1.1  christos       old_reloc_address = (sec->output_section->vma
   1158      1.1  christos 			   + sec->output_offset + irel->r_offset);
   1159      1.1  christos 
   1160      1.1  christos       /* Get the new reloc address.  */
   1161      1.1  christos       if ((irel->r_offset > addr
   1162      1.1  christos 	   && irel->r_offset < toaddr))
   1163      1.1  christos 	{
   1164      1.1  christos 	  if (debug_relax)
   1165      1.1  christos 	    printf ("Relocation at address 0x%x needs to be moved.\n"
   1166      1.1  christos 		    "Old section offset: 0x%x, New section offset: 0x%x \n",
   1167      1.1  christos 		    (unsigned int) old_reloc_address,
   1168      1.1  christos 		    (unsigned int) irel->r_offset,
   1169      1.1  christos 		    (unsigned int) ((irel->r_offset) - count));
   1170      1.1  christos 
   1171      1.1  christos 	  irel->r_offset -= count;
   1172      1.1  christos 	}
   1173      1.1  christos 
   1174      1.1  christos     }
   1175      1.1  christos 
   1176      1.1  christos    /* The reloc's own addresses are now ok.  However, we need to readjust
   1177      1.1  christos       the reloc's addend, i.e. the reloc's value if two conditions are met:
   1178      1.1  christos       1.) the reloc is relative to a symbol in this section that
   1179      1.1  christos 	  is located in front of the shrinked instruction
   1180      1.1  christos       2.) symbol plus addend end up behind the shrinked instruction.
   1181      1.1  christos 
   1182      1.1  christos       The most common case where this happens are relocs relative to
   1183      1.1  christos       the section-start symbol.
   1184      1.1  christos 
   1185      1.1  christos       This step needs to be done for all of the sections of the bfd.  */
   1186      1.1  christos 
   1187      1.1  christos   {
   1188      1.1  christos     struct bfd_section *isec;
   1189      1.1  christos 
   1190      1.1  christos     for (isec = abfd->sections; isec; isec = isec->next)
   1191      1.1  christos      {
   1192      1.1  christos        bfd_vma symval;
   1193      1.1  christos        bfd_vma shrinked_insn_address;
   1194      1.1  christos 
   1195      1.1  christos        if (isec->reloc_count == 0)
   1196      1.1  christos 	 continue;
   1197      1.1  christos 
   1198  1.1.1.2  christos        shrinked_insn_address = (sec->output_section->vma
   1199      1.1  christos 				+ sec->output_offset + addr);
   1200      1.1  christos 
   1201      1.1  christos        irel = elf_section_data (isec)->relocs;
   1202      1.1  christos        /* PR 12161: Read in the relocs for this section if necessary.  */
   1203  1.1.1.4  christos        if (irel == NULL)
   1204      1.1  christos 	 irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, true);
   1205      1.1  christos 
   1206      1.1  christos        for (irelend = irel + isec->reloc_count;
   1207      1.1  christos 	    irel < irelend;
   1208      1.1  christos 	    irel++)
   1209      1.1  christos 	 {
   1210      1.1  christos 	   /* Read this BFD's local symbols if we haven't done
   1211      1.1  christos 	      so already.  */
   1212      1.1  christos 	   if (isymbuf == NULL && symtab_hdr->sh_info != 0)
   1213      1.1  christos 	     {
   1214      1.1  christos 	       isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
   1215      1.1  christos 	       if (isymbuf == NULL)
   1216      1.1  christos 		 isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
   1217      1.1  christos 						 symtab_hdr->sh_info, 0,
   1218      1.1  christos 						 NULL, NULL, NULL);
   1219  1.1.1.4  christos 	       if (isymbuf == NULL)
   1220      1.1  christos 		 return false;
   1221      1.1  christos 	     }
   1222      1.1  christos 
   1223      1.1  christos 	   /* Get the value of the symbol referred to by the reloc.  */
   1224      1.1  christos 	   if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
   1225      1.1  christos 	     {
   1226      1.1  christos 	       /* A local symbol.  */
   1227      1.1  christos 	       asection *sym_sec;
   1228      1.1  christos 
   1229      1.1  christos 	       isym = isymbuf + ELF32_R_SYM (irel->r_info);
   1230      1.1  christos 	       sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
   1231      1.1  christos 	       symval = isym->st_value;
   1232      1.1  christos 	       /* If the reloc is absolute, it will not have
   1233      1.1  christos 		  a symbol or section associated with it.  */
   1234      1.1  christos 	       if (sym_sec == sec)
   1235      1.1  christos 		 {
   1236      1.1  christos 		   symval += sym_sec->output_section->vma
   1237      1.1  christos 		     + sym_sec->output_offset;
   1238      1.1  christos 
   1239      1.1  christos 		   if (debug_relax)
   1240      1.1  christos 		     printf ("Checking if the relocation's "
   1241      1.1  christos 			     "addend needs corrections.\n"
   1242      1.1  christos 			     "Address of anchor symbol: 0x%x \n"
   1243      1.1  christos 			     "Address of relocation target: 0x%x \n"
   1244      1.1  christos 			     "Address of relaxed insn: 0x%x \n",
   1245      1.1  christos 			     (unsigned int) symval,
   1246      1.1  christos 			     (unsigned int) (symval + irel->r_addend),
   1247      1.1  christos 			     (unsigned int) shrinked_insn_address);
   1248      1.1  christos 
   1249      1.1  christos 		   /* Shrink the special DIFF relocations.  */
   1250      1.1  christos 		   if (elf32_pru_is_diff_reloc (irel))
   1251      1.1  christos 		     {
   1252      1.1  christos 		       elf32_pru_adjust_diff_reloc_value (abfd, isec, irel,
   1253      1.1  christos 							  symval,
   1254      1.1  christos 							  shrinked_insn_address,
   1255      1.1  christos 							  count);
   1256      1.1  christos 		     }
   1257      1.1  christos 
   1258      1.1  christos 		   /* Fix the addend, if it is affected.  */
   1259      1.1  christos 		   if (symval <= shrinked_insn_address
   1260      1.1  christos 		       && (symval + irel->r_addend) > shrinked_insn_address)
   1261      1.1  christos 		     {
   1262      1.1  christos 
   1263      1.1  christos 		       irel->r_addend -= count;
   1264      1.1  christos 
   1265      1.1  christos 		       if (debug_relax)
   1266      1.1  christos 			 printf ("Relocation's addend needed to be fixed \n");
   1267      1.1  christos 		     }
   1268      1.1  christos 		 }
   1269      1.1  christos 	       /* else...Reference symbol is absolute.
   1270      1.1  christos 		  No adjustment needed.  */
   1271      1.1  christos 	     }
   1272      1.1  christos 	   /* else...Reference symbol is extern.  No need for adjusting
   1273      1.1  christos 	      the addend.  */
   1274      1.1  christos 	 }
   1275      1.1  christos      }
   1276      1.1  christos   }
   1277      1.1  christos 
   1278      1.1  christos   /* Adjust the local symbols defined in this section.  */
   1279      1.1  christos   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
   1280      1.1  christos   /* Fix PR 9841, there may be no local symbols.  */
   1281      1.1  christos   if (isym != NULL)
   1282      1.1  christos     {
   1283      1.1  christos       Elf_Internal_Sym *isymend;
   1284      1.1  christos 
   1285      1.1  christos       isymend = isym + symtab_hdr->sh_info;
   1286      1.1  christos       for (; isym < isymend; isym++)
   1287      1.1  christos 	{
   1288      1.1  christos 	  if (isym->st_shndx == sec_shndx)
   1289      1.1  christos 	    {
   1290      1.1  christos 	      if (isym->st_value > addr
   1291      1.1  christos 		  && isym->st_value <= toaddr)
   1292      1.1  christos 		isym->st_value -= count;
   1293      1.1  christos 
   1294      1.1  christos 	      if (isym->st_value <= addr
   1295      1.1  christos 		  && isym->st_value + isym->st_size > addr)
   1296      1.1  christos 		{
   1297      1.1  christos 		  /* If this assert fires then we have a symbol that ends
   1298      1.1  christos 		     part way through an instruction.  Does that make
   1299      1.1  christos 		     sense?  */
   1300      1.1  christos 		  BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
   1301      1.1  christos 		  isym->st_size -= count;
   1302      1.1  christos 		}
   1303      1.1  christos 	    }
   1304      1.1  christos 	}
   1305      1.1  christos     }
   1306      1.1  christos 
   1307      1.1  christos   /* Now adjust the global symbols defined in this section.  */
   1308      1.1  christos   symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
   1309      1.1  christos 	      - symtab_hdr->sh_info);
   1310      1.1  christos   sym_hashes = elf_sym_hashes (abfd);
   1311      1.1  christos   end_hashes = sym_hashes + symcount;
   1312      1.1  christos   for (; sym_hashes < end_hashes; sym_hashes++)
   1313      1.1  christos     {
   1314      1.1  christos       struct elf_link_hash_entry *sym_hash = *sym_hashes;
   1315      1.1  christos       if ((sym_hash->root.type == bfd_link_hash_defined
   1316      1.1  christos 	   || sym_hash->root.type == bfd_link_hash_defweak)
   1317      1.1  christos 	  && sym_hash->root.u.def.section == sec)
   1318      1.1  christos 	{
   1319      1.1  christos 	  if (sym_hash->root.u.def.value > addr
   1320      1.1  christos 	      && sym_hash->root.u.def.value <= toaddr)
   1321      1.1  christos 	    sym_hash->root.u.def.value -= count;
   1322      1.1  christos 
   1323      1.1  christos 	  if (sym_hash->root.u.def.value <= addr
   1324      1.1  christos 	      && (sym_hash->root.u.def.value + sym_hash->size > addr))
   1325      1.1  christos 	    {
   1326      1.1  christos 	      /* If this assert fires then we have a symbol that ends
   1327      1.1  christos 		 part way through an instruction.  Does that make
   1328      1.1  christos 		 sense?  */
   1329      1.1  christos 	      BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size
   1330      1.1  christos 			  >= addr + count);
   1331      1.1  christos 	      sym_hash->size -= count;
   1332      1.1  christos 	    }
   1333      1.1  christos 	}
   1334      1.1  christos     }
   1335  1.1.1.4  christos 
   1336      1.1  christos   return true;
   1337      1.1  christos }
   1338  1.1.1.4  christos 
   1339  1.1.1.4  christos static bool
   1340  1.1.1.4  christos pru_elf32_relax_section (bfd *abfd, asection *sec,
   1341  1.1.1.4  christos 			 struct bfd_link_info *link_info,
   1342      1.1  christos 			 bool *again)
   1343      1.1  christos {
   1344      1.1  christos   Elf_Internal_Shdr * symtab_hdr;
   1345      1.1  christos   Elf_Internal_Rela * internal_relocs;
   1346      1.1  christos   Elf_Internal_Rela * irel;
   1347      1.1  christos   Elf_Internal_Rela * irelend;
   1348      1.1  christos   bfd_byte *	      contents = NULL;
   1349      1.1  christos   Elf_Internal_Sym *  isymbuf = NULL;
   1350      1.1  christos 
   1351  1.1.1.4  christos   /* Assume nothing changes.  */
   1352      1.1  christos   *again = false;
   1353      1.1  christos 
   1354      1.1  christos   /* We don't have to do anything for a relocatable link, if
   1355      1.1  christos      this section does not have relocs, or if this is not a
   1356      1.1  christos      code section.  */
   1357  1.1.1.5  christos   if (bfd_link_relocatable (link_info)
   1358  1.1.1.5  christos       || sec->reloc_count == 0
   1359  1.1.1.5  christos       || (sec->flags & SEC_RELOC) == 0
   1360  1.1.1.5  christos       || (sec->flags & SEC_HAS_CONTENTS) == 0
   1361  1.1.1.4  christos       || (sec->flags & SEC_CODE) == 0)
   1362      1.1  christos     return true;
   1363      1.1  christos 
   1364      1.1  christos   symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
   1365      1.1  christos 
   1366      1.1  christos   /* Get a copy of the native relocations.  */
   1367      1.1  christos   internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
   1368      1.1  christos 					       link_info->keep_memory);
   1369      1.1  christos   if (internal_relocs == NULL)
   1370      1.1  christos     goto error_return;
   1371      1.1  christos 
   1372      1.1  christos   /* Walk through them looking for relaxing opportunities.  */
   1373      1.1  christos   irelend = internal_relocs + sec->reloc_count;
   1374      1.1  christos 
   1375      1.1  christos   for (irel = internal_relocs; irel < irelend; irel++)
   1376      1.1  christos     {
   1377      1.1  christos       bfd_vma symval;
   1378      1.1  christos 
   1379      1.1  christos       /* Get the section contents if we haven't done so already.  */
   1380      1.1  christos       if (contents == NULL)
   1381      1.1  christos 	{
   1382      1.1  christos 	  /* Get cached copy if it exists.  */
   1383      1.1  christos 	  if (elf_section_data (sec)->this_hdr.contents != NULL)
   1384      1.1  christos 	    contents = elf_section_data (sec)->this_hdr.contents;
   1385      1.1  christos 	  else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
   1386      1.1  christos 	    goto error_return;
   1387      1.1  christos 	}
   1388      1.1  christos 
   1389      1.1  christos       /* Read this BFD's local symbols if we haven't done so already.  */
   1390      1.1  christos       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
   1391      1.1  christos 	{
   1392      1.1  christos 	  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
   1393      1.1  christos 	  if (isymbuf == NULL)
   1394      1.1  christos 	    isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
   1395      1.1  christos 					    symtab_hdr->sh_info, 0,
   1396      1.1  christos 					    NULL, NULL, NULL);
   1397      1.1  christos 	  if (isymbuf == NULL)
   1398      1.1  christos 	    goto error_return;
   1399      1.1  christos 	}
   1400      1.1  christos 
   1401      1.1  christos       /* Get the value of the symbol referred to by the reloc.  */
   1402      1.1  christos       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
   1403      1.1  christos 	{
   1404      1.1  christos 	  /* A local symbol.  */
   1405      1.1  christos 	  Elf_Internal_Sym *isym;
   1406      1.1  christos 	  asection *sym_sec;
   1407      1.1  christos 
   1408      1.1  christos 	  isym = isymbuf + ELF32_R_SYM (irel->r_info);
   1409      1.1  christos 	  if (isym->st_shndx == SHN_UNDEF)
   1410      1.1  christos 	    sym_sec = bfd_und_section_ptr;
   1411      1.1  christos 	  else if (isym->st_shndx == SHN_ABS)
   1412      1.1  christos 	    sym_sec = bfd_abs_section_ptr;
   1413      1.1  christos 	  else if (isym->st_shndx == SHN_COMMON)
   1414      1.1  christos 	    sym_sec = bfd_com_section_ptr;
   1415      1.1  christos 	  else
   1416      1.1  christos 	    sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
   1417      1.1  christos 	  symval = (isym->st_value
   1418      1.1  christos 		    + sym_sec->output_section->vma + sym_sec->output_offset);
   1419      1.1  christos 	}
   1420      1.1  christos       else
   1421      1.1  christos 	{
   1422      1.1  christos 	  unsigned long indx;
   1423      1.1  christos 	  struct elf_link_hash_entry *h;
   1424      1.1  christos 
   1425      1.1  christos 	  /* An external symbol.  */
   1426      1.1  christos 	  indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
   1427      1.1  christos 	  h = elf_sym_hashes (abfd)[indx];
   1428      1.1  christos 	  BFD_ASSERT (h != NULL);
   1429      1.1  christos 
   1430      1.1  christos 	  if (h->root.type != bfd_link_hash_defined
   1431      1.1  christos 	      && h->root.type != bfd_link_hash_defweak)
   1432      1.1  christos 	    /* This appears to be a reference to an undefined
   1433      1.1  christos 	       symbol.  Just ignore it--it will be caught by the
   1434      1.1  christos 	       regular reloc processing.  */
   1435      1.1  christos 	    continue;
   1436      1.1  christos 
   1437      1.1  christos 	  symval = (h->root.u.def.value
   1438      1.1  christos 		    + h->root.u.def.section->output_section->vma
   1439      1.1  christos 		    + h->root.u.def.section->output_offset);
   1440      1.1  christos 	}
   1441      1.1  christos 
   1442      1.1  christos       /* For simplicity of coding, we are going to modify the section
   1443      1.1  christos 	 contents, the section relocs, and the BFD symbol table.  We
   1444      1.1  christos 	 must tell the rest of the code not to free up this
   1445      1.1  christos 	 information.  It would be possible to instead create a table
   1446      1.1  christos 	 of changes which have to be made, as is done in coff-mips.c;
   1447      1.1  christos 	 that would be more work, but would require less memory when
   1448      1.1  christos 	 the linker is run.  */
   1449      1.1  christos 
   1450      1.1  christos       /* Check if we can remove an LDI instruction from the LDI32
   1451      1.1  christos 	 pseudo instruction if the upper 16 operand bits are zero.  */
   1452      1.1  christos       if (ELF32_R_TYPE (irel->r_info) == (int) R_PRU_LDI32)
   1453      1.1  christos 	{
   1454      1.1  christos 	  bfd_vma value = symval + irel->r_addend;
   1455      1.1  christos 
   1456      1.1  christos 	  if (debug_relax)
   1457      1.1  christos 	    printf ("R_PRU_LDI32 with value=0x%lx\n", (long) value);
   1458      1.1  christos 
   1459      1.1  christos 	  if ((long) value >> 16 == 0)
   1460  1.1.1.2  christos 	    {
   1461  1.1.1.2  christos 	      unsigned long insn;
   1462      1.1  christos 
   1463      1.1  christos 	      /* Note that we've changed the relocs, section contents.  */
   1464      1.1  christos 	      elf_section_data (sec)->relocs = internal_relocs;
   1465      1.1  christos 	      elf_section_data (sec)->this_hdr.contents = contents;
   1466      1.1  christos 	      symtab_hdr->contents = (unsigned char *) isymbuf;
   1467  1.1.1.2  christos 
   1468  1.1.1.2  christos 	      /* Make the second instruction load the 16-bit constant
   1469  1.1.1.2  christos 		 into the full 32-bit register.  */
   1470  1.1.1.2  christos 	      insn = bfd_get_32 (abfd, contents + irel->r_offset + 4);
   1471  1.1.1.2  christos 
   1472  1.1.1.2  christos 	      /* Old GAS and LD versions have a bug, where the two
   1473  1.1.1.2  christos 		 LDI instructions are swapped.  Detect such object
   1474  1.1.1.2  christos 		 files and bail.  */
   1475  1.1.1.2  christos 	      if (GET_INSN_FIELD (RDSEL, insn) != RSEL_15_0)
   1476  1.1.1.2  christos 		{
   1477  1.1.1.2  christos 		  /* xgettext:c-format */
   1478  1.1.1.2  christos 		  _bfd_error_handler (_("error: %pB: old incompatible object file detected"),
   1479  1.1.1.2  christos 				      abfd);
   1480  1.1.1.2  christos 		  goto error_return;
   1481  1.1.1.2  christos 		}
   1482  1.1.1.2  christos 
   1483  1.1.1.2  christos 	      SET_INSN_FIELD (RDSEL, insn, RSEL_31_0);
   1484  1.1.1.2  christos 	      bfd_put_32 (abfd, insn, contents + irel->r_offset + 4);
   1485  1.1.1.2  christos 
   1486  1.1.1.2  christos 	      /* Delete the first LDI instruction.  Note that there should
   1487  1.1.1.2  christos 		 be no relocations or symbols pointing to the second LDI
   1488  1.1.1.2  christos 		 instruction.  */
   1489      1.1  christos 	      if (!pru_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 4))
   1490      1.1  christos 		goto error_return;
   1491  1.1.1.2  christos 
   1492  1.1.1.2  christos 	      /* We're done with deletion of the first instruction.
   1493      1.1  christos 		 Set a regular LDI relocation for the second instruction
   1494      1.1  christos 		 we left to load the 16-bit value into the 32-bit
   1495      1.1  christos 		 register.  */
   1496      1.1  christos 	      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
   1497      1.1  christos 					   R_PRU_U16);
   1498      1.1  christos 
   1499      1.1  christos 	      /* That will change things, so, we should relax again.
   1500  1.1.1.4  christos 		 Note that this is not required, and it may be slow.  */
   1501      1.1  christos 	      *again = true;
   1502      1.1  christos 	    }
   1503      1.1  christos 	}
   1504      1.1  christos     }
   1505      1.1  christos 
   1506      1.1  christos   if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
   1507      1.1  christos     {
   1508      1.1  christos       if (!link_info->keep_memory)
   1509      1.1  christos 	free (isymbuf);
   1510      1.1  christos       else
   1511      1.1  christos 	{
   1512      1.1  christos 	  /* Cache the symbols for elf_link_input_bfd.  */
   1513      1.1  christos 	  symtab_hdr->contents = (unsigned char *) isymbuf;
   1514      1.1  christos 	}
   1515      1.1  christos     }
   1516      1.1  christos 
   1517      1.1  christos   if (contents != NULL
   1518      1.1  christos       && elf_section_data (sec)->this_hdr.contents != contents)
   1519      1.1  christos     {
   1520      1.1  christos       if (!link_info->keep_memory)
   1521      1.1  christos 	free (contents);
   1522      1.1  christos       else
   1523      1.1  christos 	{
   1524      1.1  christos 	  /* Cache the section contents for elf_link_input_bfd.  */
   1525      1.1  christos 	  elf_section_data (sec)->this_hdr.contents = contents;
   1526      1.1  christos 	}
   1527      1.1  christos     }
   1528  1.1.1.3  christos 
   1529      1.1  christos   if (elf_section_data (sec)->relocs != internal_relocs)
   1530      1.1  christos     free (internal_relocs);
   1531  1.1.1.4  christos 
   1532      1.1  christos   return true;
   1533  1.1.1.3  christos 
   1534  1.1.1.3  christos  error_return:
   1535      1.1  christos   if (symtab_hdr->contents != (unsigned char *) isymbuf)
   1536  1.1.1.3  christos     free (isymbuf);
   1537      1.1  christos   if (elf_section_data (sec)->this_hdr.contents != contents)
   1538  1.1.1.3  christos     free (contents);
   1539      1.1  christos   if (elf_section_data (sec)->relocs != internal_relocs)
   1540      1.1  christos     free (internal_relocs);
   1541  1.1.1.4  christos 
   1542      1.1  christos   return false;
   1543      1.1  christos }
   1544      1.1  christos 
   1545      1.1  christos /* Free the derived linker hash table.  */
   1546      1.1  christos static void
   1547      1.1  christos pru_elf32_link_hash_table_free (bfd *obfd)
   1548      1.1  christos {
   1549      1.1  christos   _bfd_elf_link_hash_table_free (obfd);
   1550      1.1  christos }
   1551      1.1  christos 
   1552      1.1  christos /* Implement bfd_elf32_bfd_link_hash_table_create.  */
   1553      1.1  christos static struct bfd_link_hash_table *
   1554      1.1  christos pru_elf32_link_hash_table_create (bfd *abfd)
   1555      1.1  christos {
   1556  1.1.1.3  christos   struct elf_link_hash_table *ret;
   1557      1.1  christos   size_t amt = sizeof (struct elf_link_hash_table);
   1558      1.1  christos 
   1559      1.1  christos   ret = bfd_zmalloc (amt);
   1560      1.1  christos   if (ret == NULL)
   1561      1.1  christos     return NULL;
   1562  1.1.1.6  christos 
   1563  1.1.1.6  christos   if (!_bfd_elf_link_hash_table_init (ret, abfd, link_hash_newfunc,
   1564      1.1  christos 				      sizeof (struct elf_link_hash_entry)))
   1565      1.1  christos     {
   1566      1.1  christos       free (ret);
   1567      1.1  christos       return NULL;
   1568      1.1  christos     }
   1569      1.1  christos 
   1570      1.1  christos   ret->root.hash_table_free = pru_elf32_link_hash_table_free;
   1571      1.1  christos 
   1572      1.1  christos   return &ret->root;
   1573      1.1  christos }
   1574      1.1  christos 
   1575      1.1  christos #define ELF_ARCH			bfd_arch_pru
   1576      1.1  christos #define ELF_TARGET_ID			PRU_ELF_DATA
   1577      1.1  christos #define ELF_MACHINE_CODE		EM_TI_PRU
   1578      1.1  christos 
   1579      1.1  christos #define ELF_MAXPAGESIZE			1
   1580      1.1  christos 
   1581      1.1  christos #define bfd_elf32_bfd_link_hash_table_create \
   1582      1.1  christos 					  pru_elf32_link_hash_table_create
   1583      1.1  christos 
   1584      1.1  christos /* Relocation table lookup macros.  */
   1585      1.1  christos 
   1586      1.1  christos #define bfd_elf32_bfd_reloc_type_lookup	  pru_elf32_bfd_reloc_type_lookup
   1587      1.1  christos #define bfd_elf32_bfd_reloc_name_lookup	  pru_elf32_bfd_reloc_name_lookup
   1588      1.1  christos 
   1589  1.1.1.2  christos #define elf_info_to_howto		pru_elf32_info_to_howto
   1590      1.1  christos #define elf_info_to_howto_rel		NULL
   1591      1.1  christos 
   1592      1.1  christos /* elf backend functions.  */
   1593  1.1.1.2  christos 
   1594  1.1.1.2  christos /* TI folks like to use a mix of REL and RELA relocations.  See also
   1595  1.1.1.2  christos    the MSP430 and TI C6X backends.  */
   1596  1.1.1.2  christos #define elf_backend_may_use_rel_p  1
   1597  1.1.1.2  christos #define elf_backend_may_use_rela_p 1
   1598  1.1.1.2  christos #define elf_backend_default_use_rela_p 1
   1599      1.1  christos 
   1600      1.1  christos #define elf_backend_rela_normal		1
   1601      1.1  christos 
   1602      1.1  christos #define elf_backend_relocate_section	pru_elf32_relocate_section
   1603  1.1.1.4  christos #define bfd_elf32_bfd_relax_section	pru_elf32_relax_section
   1604  1.1.1.4  christos #define elf_backend_can_gc_sections	1
   1605  1.1.1.4  christos 
   1606      1.1  christos #define elf_backend_default_execstack	0
   1607      1.1  christos 
   1608      1.1  christos #define TARGET_LITTLE_SYM		pru_elf32_vec
   1609      1.1  christos #define TARGET_LITTLE_NAME		"elf32-pru"
   1610      1.1  christos 
   1611                    #include "elf32-target.h"
   1612