Home | History | Annotate | Line # | Download | only in bfd
elf32-xstormy16.c revision 1.5.2.1
      1 /* Xstormy16-specific support for 32-bit ELF.
      2    Copyright (C) 2000-2018 Free Software Foundation, Inc.
      3 
      4    This file is part of BFD, the Binary File Descriptor library.
      5 
      6    This program is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3 of the License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program; if not, write to the Free Software
     18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     19    MA 02110-1301, USA.  */
     20 
     21 #include "sysdep.h"
     22 #include "bfd.h"
     23 #include "libbfd.h"
     24 #include "elf-bfd.h"
     25 #include "elf/xstormy16.h"
     26 #include "libiberty.h"
     27 
     28 /* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement.  */
     29 
     30 static bfd_reloc_status_type
     31 xstormy16_elf_24_reloc (bfd *abfd,
     32 			arelent *reloc_entry,
     33 			asymbol *symbol,
     34 			void * data,
     35 			asection *input_section,
     36 			bfd *output_bfd,
     37 			char **error_message ATTRIBUTE_UNUSED)
     38 {
     39   bfd_vma relocation, x;
     40 
     41   if (output_bfd != NULL)
     42     {
     43       reloc_entry->address += input_section->output_offset;
     44       return bfd_reloc_ok;
     45     }
     46 
     47   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
     48     return bfd_reloc_outofrange;
     49 
     50   if (bfd_is_com_section (symbol->section))
     51     relocation = 0;
     52   else
     53     relocation = symbol->value;
     54 
     55   relocation += symbol->section->output_section->vma;
     56   relocation += symbol->section->output_offset;
     57   relocation += reloc_entry->addend;
     58 
     59   x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
     60   x &= 0x0000ff00;
     61   x |= relocation & 0xff;
     62   x |= (relocation << 8) & 0xffff0000;
     63   bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
     64 
     65   if (relocation & ~ (bfd_vma) 0xffffff)
     66     return bfd_reloc_overflow;
     67 
     68   return bfd_reloc_ok;
     69 }
     70 
     71 static reloc_howto_type xstormy16_elf_howto_table [] =
     72 {
     73   /* This reloc does nothing.  */
     74   HOWTO (R_XSTORMY16_NONE,	/* type */
     75 	 0,			/* rightshift */
     76 	 3,			/* size (0 = byte, 1 = short, 2 = long) */
     77 	 0,			/* bitsize */
     78 	 FALSE,			/* pc_relative */
     79 	 0,			/* bitpos */
     80 	 complain_overflow_dont, /* complain_on_overflow */
     81 	 bfd_elf_generic_reloc,	/* special_function */
     82 	 "R_XSTORMY16_NONE",	/* name */
     83 	 FALSE,			/* partial_inplace */
     84 	 0,			/* src_mask */
     85 	 0,			/* dst_mask */
     86 	 FALSE),		/* pcrel_offset */
     87 
     88   /* A 32 bit absolute relocation.  */
     89   HOWTO (R_XSTORMY16_32,	/* type */
     90 	 0,			/* rightshift */
     91 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
     92 	 32,			/* bitsize */
     93 	 FALSE,			/* pc_relative */
     94 	 0,			/* bitpos */
     95 	 complain_overflow_dont, /* complain_on_overflow */
     96 	 bfd_elf_generic_reloc,	/* special_function */
     97 	 "R_XSTORMY16_32",	/* name */
     98 	 FALSE,			/* partial_inplace */
     99 	 0,			/* src_mask */
    100 	 0xffffffff,		/* dst_mask */
    101 	 FALSE),		/* pcrel_offset */
    102 
    103   /* A 16 bit absolute relocation.  */
    104   HOWTO (R_XSTORMY16_16,	/* type */
    105 	 0,			/* rightshift */
    106 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    107 	 16,			/* bitsize */
    108 	 FALSE,			/* pc_relative */
    109 	 0,			/* bitpos */
    110 	 complain_overflow_bitfield, /* complain_on_overflow */
    111 	 bfd_elf_generic_reloc,	/* special_function */
    112 	 "R_XSTORMY16_16",	/* name */
    113 	 FALSE,			/* partial_inplace */
    114 	 0,			/* src_mask */
    115 	 0xffff,		/* dst_mask */
    116 	 FALSE),		/* pcrel_offset */
    117 
    118   /* An 8 bit absolute relocation.  */
    119   HOWTO (R_XSTORMY16_8,		/* type */
    120 	 0,			/* rightshift */
    121 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
    122 	 8,			/* bitsize */
    123 	 FALSE,			/* pc_relative */
    124 	 0,			/* bitpos */
    125 	 complain_overflow_unsigned, /* complain_on_overflow */
    126 	 bfd_elf_generic_reloc,	/* special_function */
    127 	 "R_XSTORMY16_8",	/* name */
    128 	 FALSE,			/* partial_inplace */
    129 	 0,			/* src_mask */
    130 	 0xff,			/* dst_mask */
    131 	 FALSE),		/* pcrel_offset */
    132 
    133   /* A 32 bit pc-relative relocation.  */
    134   HOWTO (R_XSTORMY16_PC32,	/* type */
    135 	 0,			/* rightshift */
    136 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    137 	 32,			/* bitsize */
    138 	 TRUE,			/* pc_relative */
    139 	 0,			/* bitpos */
    140 	 complain_overflow_dont, /* complain_on_overflow */
    141 	 bfd_elf_generic_reloc,	/* special_function */
    142 	 "R_XSTORMY16_PC32",	/* name */
    143 	 FALSE,			/* partial_inplace */
    144 	 0,			/* src_mask */
    145 	 0xffffffff,		/* dst_mask */
    146 	 TRUE),			/* pcrel_offset */
    147 
    148   /* A 16 bit pc-relative relocation.  */
    149   HOWTO (R_XSTORMY16_PC16,	/* type */
    150 	 0,			/* rightshift */
    151 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    152 	 16,			/* bitsize */
    153 	 TRUE,			/* pc_relative */
    154 	 0,			/* bitpos */
    155 	 complain_overflow_signed, /* complain_on_overflow */
    156 	 bfd_elf_generic_reloc,	/* special_function */
    157 	 "R_XSTORMY16_PC16",	/* name */
    158 	 FALSE,			/* partial_inplace */
    159 	 0,			/* src_mask */
    160 	 0xffffffff,		/* dst_mask */
    161 	 TRUE),			/* pcrel_offset */
    162 
    163   /* An 8 bit pc-relative relocation.  */
    164   HOWTO (R_XSTORMY16_PC8,	/* type */
    165 	 0,			/* rightshift */
    166 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
    167 	 8,			/* bitsize */
    168 	 TRUE,			/* pc_relative */
    169 	 0,			/* bitpos */
    170 	 complain_overflow_signed, /* complain_on_overflow */
    171 	 bfd_elf_generic_reloc,	/* special_function */
    172 	 "R_XSTORMY16_PC8",	/* name */
    173 	 FALSE,			/* partial_inplace */
    174 	 0,			/* src_mask */
    175 	 0xffffffff,		/* dst_mask */
    176 	 TRUE),			/* pcrel_offset */
    177 
    178   /* A 12-bit pc-relative relocation suitable for the branch instructions.  */
    179   HOWTO (R_XSTORMY16_REL_12,	/* type */
    180 	 1,			/* rightshift */
    181 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    182 	 11,			/* bitsize */
    183 	 TRUE,			/* pc_relative */
    184 	 1,			/* bitpos */
    185 	 complain_overflow_signed, /* complain_on_overflow */
    186 	 bfd_elf_generic_reloc,	/* special_function */
    187 	 "R_XSTORMY16_REL_12",	/* name */
    188 	 FALSE,			/* partial_inplace */
    189 	 0,			/* src_mask */
    190 	 0x0ffe,		/* dst_mask */
    191 	 TRUE),			/* pcrel_offset */
    192 
    193   /* A 24-bit absolute relocation suitable for the jump instructions.  */
    194   HOWTO (R_XSTORMY16_24,	/* type */
    195 	 0,			/* rightshift */
    196 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    197 	 24,			/* bitsize */
    198 	 FALSE,			/* pc_relative */
    199 	 0,			/* bitpos */
    200 	 complain_overflow_unsigned, /* complain_on_overflow */
    201 	 xstormy16_elf_24_reloc,	/* special_function */
    202 	 "R_XSTORMY16_24",	/* name */
    203 	 TRUE,			/* partial_inplace */
    204 	 0,			/* src_mask */
    205 	 0xffff00ff,		/* dst_mask */
    206 	 TRUE),			/* pcrel_offset */
    207 
    208   /* A 16 bit absolute relocation to a function pointer.  */
    209   HOWTO (R_XSTORMY16_FPTR16,	/* type */
    210 	 0,			/* rightshift */
    211 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    212 	 16,			/* bitsize */
    213 	 FALSE,			/* pc_relative */
    214 	 0,			/* bitpos */
    215 	 complain_overflow_bitfield, /* complain_on_overflow */
    216 	 bfd_elf_generic_reloc,	/* special_function */
    217 	 "R_XSTORMY16_FPTR16",	/* name */
    218 	 FALSE,			/* partial_inplace */
    219 	 0,			/* src_mask */
    220 	 0xffffffff,		/* dst_mask */
    221 	 FALSE),		/* pcrel_offset */
    222 
    223   /* Low order 16 bit value of a high memory address.  */
    224   HOWTO (R_XSTORMY16_LO16,	/* type */
    225 	 0,			/* rightshift */
    226 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    227 	 16,			/* bitsize */
    228 	 FALSE,			/* pc_relative */
    229 	 0,			/* bitpos */
    230 	 complain_overflow_dont, /* complain_on_overflow */
    231 	 bfd_elf_generic_reloc,	/* special_function */
    232 	 "R_XSTORMY16_LO16",	/* name */
    233 	 FALSE,			/* partial_inplace */
    234 	 0,			/* src_mask */
    235 	 0xffff,		/* dst_mask */
    236 	 FALSE),		/* pcrel_offset */
    237 
    238   /* High order 16 bit value of a high memory address.  */
    239   HOWTO (R_XSTORMY16_HI16,	/* type */
    240 	 16,			/* rightshift */
    241 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    242 	 16,			/* bitsize */
    243 	 FALSE,			/* pc_relative */
    244 	 0,			/* bitpos */
    245 	 complain_overflow_dont, /* complain_on_overflow */
    246 	 bfd_elf_generic_reloc,	/* special_function */
    247 	 "R_XSTORMY16_HI16",	/* name */
    248 	 FALSE,			/* partial_inplace */
    249 	 0,			/* src_mask */
    250 	 0xffff,		/* dst_mask */
    251 	 FALSE),		/* pcrel_offset */
    252 
    253   /* A 12 bit absolute relocation.  */
    254   HOWTO (R_XSTORMY16_12,	/* type */
    255 	 0,			/* rightshift */
    256 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
    257 	 12,			/* bitsize */
    258 	 FALSE,			/* pc_relative */
    259 	 0,			/* bitpos */
    260 	 complain_overflow_signed, /* complain_on_overflow */
    261 	 bfd_elf_generic_reloc,	/* special_function */
    262 	 "R_XSTORMY16_12",	/* name */
    263 	 FALSE,			/* partial_inplace */
    264 	 0x0000,		/* src_mask */
    265 	 0x0fff,		/* dst_mask */
    266 	 FALSE),		/* pcrel_offset */
    267 };
    268 
    269 static reloc_howto_type xstormy16_elf_howto_table2 [] =
    270 {
    271   /* GNU extension to record C++ vtable hierarchy */
    272   HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */
    273 	 0,			/* rightshift */
    274 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    275 	 0,			/* bitsize */
    276 	 FALSE,			/* pc_relative */
    277 	 0,			/* bitpos */
    278 	 complain_overflow_dont, /* complain_on_overflow */
    279 	 NULL,			/* special_function */
    280 	 "R_XSTORMY16_GNU_VTINHERIT", /* name */
    281 	 FALSE,			/* partial_inplace */
    282 	 0,			/* src_mask */
    283 	 0,			/* dst_mask */
    284 	 FALSE),		/* pcrel_offset */
    285 
    286   /* GNU extension to record C++ vtable member usage */
    287   HOWTO (R_XSTORMY16_GNU_VTENTRY,     /* type */
    288 	 0,			/* rightshift */
    289 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
    290 	 0,			/* bitsize */
    291 	 FALSE,			/* pc_relative */
    292 	 0,			/* bitpos */
    293 	 complain_overflow_dont, /* complain_on_overflow */
    294 	 _bfd_elf_rel_vtable_reloc_fn,	/* special_function */
    295 	 "R_XSTORMY16_GNU_VTENTRY",   /* name */
    296 	 FALSE,			/* partial_inplace */
    297 	 0,			/* src_mask */
    298 	 0,			/* dst_mask */
    299 	 FALSE),		/* pcrel_offset */
    300 
    301 };
    302 
    303 /* Map BFD reloc types to XSTORMY16 ELF reloc types.  */
    305 
    306 typedef struct xstormy16_reloc_map
    307 {
    308   bfd_reloc_code_real_type  bfd_reloc_val;
    309   unsigned int		    xstormy16_reloc_val;
    310   reloc_howto_type *	    table;
    311 } reloc_map;
    312 
    313 static const reloc_map xstormy16_reloc_map [] =
    314 {
    315   { BFD_RELOC_NONE,		    R_XSTORMY16_NONE,	       xstormy16_elf_howto_table },
    316   { BFD_RELOC_32,		    R_XSTORMY16_32,	       xstormy16_elf_howto_table },
    317   { BFD_RELOC_16,		    R_XSTORMY16_16,	       xstormy16_elf_howto_table },
    318   { BFD_RELOC_8,		    R_XSTORMY16_8,	       xstormy16_elf_howto_table },
    319   { BFD_RELOC_32_PCREL,		    R_XSTORMY16_PC32,	       xstormy16_elf_howto_table },
    320   { BFD_RELOC_16_PCREL,		    R_XSTORMY16_PC16,	       xstormy16_elf_howto_table },
    321   { BFD_RELOC_8_PCREL,		    R_XSTORMY16_PC8,	       xstormy16_elf_howto_table },
    322   { BFD_RELOC_XSTORMY16_REL_12,	    R_XSTORMY16_REL_12,	       xstormy16_elf_howto_table },
    323   { BFD_RELOC_XSTORMY16_24,	    R_XSTORMY16_24,	       xstormy16_elf_howto_table },
    324   { BFD_RELOC_XSTORMY16_FPTR16,	    R_XSTORMY16_FPTR16,	       xstormy16_elf_howto_table },
    325   { BFD_RELOC_LO16,		    R_XSTORMY16_LO16,	       xstormy16_elf_howto_table },
    326   { BFD_RELOC_HI16,		    R_XSTORMY16_HI16,	       xstormy16_elf_howto_table },
    327   { BFD_RELOC_XSTORMY16_12,	    R_XSTORMY16_12,	       xstormy16_elf_howto_table },
    328   { BFD_RELOC_VTABLE_INHERIT,	    R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 },
    329   { BFD_RELOC_VTABLE_ENTRY,	    R_XSTORMY16_GNU_VTENTRY,   xstormy16_elf_howto_table2 },
    330 };
    331 
    332 static reloc_howto_type *
    333 xstormy16_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
    334 			     bfd_reloc_code_real_type code)
    335 {
    336   unsigned int i;
    337 
    338   for (i = ARRAY_SIZE (xstormy16_reloc_map); i--;)
    339     {
    340       const reloc_map * entry;
    341 
    342       entry = xstormy16_reloc_map + i;
    343 
    344       if (entry->bfd_reloc_val == code)
    345 	return entry->table + (entry->xstormy16_reloc_val
    346 			       - entry->table[0].type);
    347     }
    348 
    349   return NULL;
    350 }
    351 
    352 static reloc_howto_type *
    353 xstormy16_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
    354 			     const char *r_name)
    355 {
    356   unsigned int i;
    357 
    358   for (i = 0;
    359        i < (sizeof (xstormy16_elf_howto_table)
    360 	    / sizeof (xstormy16_elf_howto_table[0]));
    361        i++)
    362     if (xstormy16_elf_howto_table[i].name != NULL
    363 	&& strcasecmp (xstormy16_elf_howto_table[i].name, r_name) == 0)
    364       return &xstormy16_elf_howto_table[i];
    365 
    366   for (i = 0;
    367        i < (sizeof (xstormy16_elf_howto_table2)
    368 	    / sizeof (xstormy16_elf_howto_table2[0]));
    369        i++)
    370     if (xstormy16_elf_howto_table2[i].name != NULL
    371 	&& strcasecmp (xstormy16_elf_howto_table2[i].name, r_name) == 0)
    372       return &xstormy16_elf_howto_table2[i];
    373 
    374   return NULL;
    375 }
    376 
    377 /* Set the howto pointer for an XSTORMY16 ELF reloc.  */
    378 
    379 static bfd_boolean
    380 xstormy16_info_to_howto_rela (bfd * abfd,
    381 			      arelent * cache_ptr,
    382 			      Elf_Internal_Rela * dst)
    383 {
    384   unsigned int r_type = ELF32_R_TYPE (dst->r_info);
    385 
    386   if (r_type <= (unsigned int) R_XSTORMY16_12)
    387     cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
    388   else if (r_type - R_XSTORMY16_GNU_VTINHERIT
    389 	   <= ((unsigned int) R_XSTORMY16_GNU_VTENTRY
    390 	       - (unsigned int) R_XSTORMY16_GNU_VTINHERIT))
    391     cache_ptr->howto
    392       = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
    393   else
    394     {
    395       /* xgettext:c-format */
    396       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
    397 			  abfd, r_type);
    398       bfd_set_error (bfd_error_bad_value);
    399       return FALSE;
    400     }
    401   return TRUE;
    402 }
    403 
    404 /* We support 16-bit pointers to code above 64k by generating a thunk
    406    below 64k containing a JMPF instruction to the final address.  We
    407    cannot, unfortunately, minimize the number of thunks unless the
    408    -relax switch is given, as otherwise we have no idea where the
    409    sections will fall in the address space.  */
    410 
    411 static bfd_boolean
    412 xstormy16_elf_check_relocs (bfd *abfd,
    413 			    struct bfd_link_info *info,
    414 			    asection *sec,
    415 			    const Elf_Internal_Rela *relocs)
    416 {
    417   const Elf_Internal_Rela *rel, *relend;
    418   struct elf_link_hash_entry **sym_hashes;
    419   Elf_Internal_Shdr *symtab_hdr;
    420   bfd_vma *local_plt_offsets;
    421   asection *splt;
    422   bfd *dynobj;
    423 
    424   if (bfd_link_relocatable (info))
    425     return TRUE;
    426 
    427   symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
    428   sym_hashes = elf_sym_hashes (abfd);
    429   local_plt_offsets = elf_local_got_offsets (abfd);
    430   dynobj = elf_hash_table(info)->dynobj;
    431 
    432   relend = relocs + sec->reloc_count;
    433   for (rel = relocs; rel < relend; ++rel)
    434     {
    435       unsigned long r_symndx;
    436       struct elf_link_hash_entry *h;
    437       bfd_vma *offset;
    438 
    439       r_symndx = ELF32_R_SYM (rel->r_info);
    440       if (r_symndx < symtab_hdr->sh_info)
    441 	h = NULL;
    442       else
    443 	{
    444 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
    445 	  while (h->root.type == bfd_link_hash_indirect
    446 		 || h->root.type == bfd_link_hash_warning)
    447 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    448 	}
    449 
    450       switch (ELF32_R_TYPE (rel->r_info))
    451 	{
    452 	  /* This relocation describes a 16-bit pointer to a function.
    453 	     We may need to allocate a thunk in low memory; reserve memory
    454 	     for it now.  */
    455 	case R_XSTORMY16_FPTR16:
    456 	  if (rel->r_addend != 0)
    457 	    {
    458 	      (*info->callbacks->warning)
    459 		(info, _("non-zero addend in @fptr reloc"), 0,
    460 		 abfd, 0, 0);
    461 	    }
    462 
    463 	  if (dynobj == NULL)
    464 	    elf_hash_table (info)->dynobj = dynobj = abfd;
    465 	  splt = elf_hash_table (info)->splt;
    466 	  if (splt == NULL)
    467 	    {
    468 	      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
    469 				| SEC_IN_MEMORY | SEC_LINKER_CREATED
    470 				| SEC_READONLY | SEC_CODE);
    471 
    472 	      splt = bfd_make_section_anyway_with_flags (dynobj, ".plt",
    473 							 flags);
    474 	      elf_hash_table (info)->splt = splt;
    475 	      if (splt == NULL
    476 		  || ! bfd_set_section_alignment (dynobj, splt, 1))
    477 		return FALSE;
    478 	    }
    479 
    480 	  if (h != NULL)
    481 	    offset = &h->plt.offset;
    482 	  else
    483 	    {
    484 	      if (local_plt_offsets == NULL)
    485 		{
    486 		  size_t size;
    487 		  unsigned int i;
    488 
    489 		  size = symtab_hdr->sh_info * sizeof (bfd_vma);
    490 		  local_plt_offsets = bfd_alloc (abfd, size);
    491 		  if (local_plt_offsets == NULL)
    492 		    return FALSE;
    493 		  elf_local_got_offsets (abfd) = local_plt_offsets;
    494 
    495 		  for (i = 0; i < symtab_hdr->sh_info; i++)
    496 		    local_plt_offsets[i] = (bfd_vma) -1;
    497 		}
    498 	      offset = &local_plt_offsets[r_symndx];
    499 	    }
    500 
    501 	  if (*offset == (bfd_vma) -1)
    502 	    {
    503 	      *offset = splt->size;
    504 	      splt->size += 4;
    505 	    }
    506 	  break;
    507 
    508 	  /* This relocation describes the C++ object vtable hierarchy.
    509 	     Reconstruct it for later use during GC.  */
    510 	case R_XSTORMY16_GNU_VTINHERIT:
    511 	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
    512 	    return FALSE;
    513 	  break;
    514 
    515 	  /* This relocation describes which C++ vtable entries are actually
    516 	     used.  Record for later use during GC.  */
    517 	case R_XSTORMY16_GNU_VTENTRY:
    518 	  BFD_ASSERT (h != NULL);
    519 	  if (h != NULL
    520 	      && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
    521 	    return FALSE;
    522 	  break;
    523 	}
    524     }
    525 
    526   return TRUE;
    527 }
    528 
    529 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
    530    is within the low 64k, remove any entry for it in the plt.  */
    531 
    532 struct relax_plt_data
    533 {
    534   asection *splt;
    535   bfd_boolean *again;
    536 };
    537 
    538 static bfd_boolean
    539 xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
    540 {
    541   struct relax_plt_data *data = (struct relax_plt_data *) xdata;
    542 
    543   if (h->plt.offset != (bfd_vma) -1)
    544     {
    545       bfd_vma address;
    546 
    547       if (h->root.type == bfd_link_hash_undefined
    548 	  || h->root.type == bfd_link_hash_undefweak)
    549 	address = 0;
    550       else
    551 	address = (h->root.u.def.section->output_section->vma
    552 		   + h->root.u.def.section->output_offset
    553 		   + h->root.u.def.value);
    554 
    555       if (address <= 0xffff)
    556 	{
    557 	  h->plt.offset = -1;
    558 	  data->splt->size -= 4;
    559 	  *data->again = TRUE;
    560 	}
    561     }
    562 
    563   return TRUE;
    564 }
    565 
    566 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
    567    previously had a plt entry, give it a new entry offset.  */
    568 
    569 static bfd_boolean
    570 xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
    571 {
    572   bfd_vma *entry = (bfd_vma *) xdata;
    573 
    574   if (h->plt.offset != (bfd_vma) -1)
    575     {
    576       h->plt.offset = *entry;
    577       *entry += 4;
    578     }
    579 
    580   return TRUE;
    581 }
    582 
    583 static bfd_boolean
    584 xstormy16_elf_relax_section (bfd *dynobj,
    585 			     asection *splt,
    586 			     struct bfd_link_info *info,
    587 			     bfd_boolean *again)
    588 {
    589   struct relax_plt_data relax_plt_data;
    590   bfd *ibfd;
    591 
    592   /* Assume nothing changes.  */
    593   *again = FALSE;
    594 
    595   if (bfd_link_relocatable (info))
    596     return TRUE;
    597 
    598   /* We only relax the .plt section at the moment.  */
    599   if (dynobj != elf_hash_table (info)->dynobj
    600       || strcmp (splt->name, ".plt") != 0)
    601     return TRUE;
    602 
    603   /* Quick check for an empty plt.  */
    604   if (splt->size == 0)
    605     return TRUE;
    606 
    607   /* Map across all global symbols; see which ones happen to
    608      fall in the low 64k.  */
    609   relax_plt_data.splt = splt;
    610   relax_plt_data.again = again;
    611   elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
    612 			  &relax_plt_data);
    613 
    614   /* Likewise for local symbols, though that's somewhat less convenient
    615      as we have to walk the list of input bfds and swap in symbol data.  */
    616   for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
    617     {
    618       bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
    619       Elf_Internal_Shdr *symtab_hdr;
    620       Elf_Internal_Sym *isymbuf = NULL;
    621       unsigned int idx;
    622 
    623       if (! local_plt_offsets)
    624 	continue;
    625 
    626       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
    627       if (symtab_hdr->sh_info != 0)
    628 	{
    629 	  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
    630 	  if (isymbuf == NULL)
    631 	    isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
    632 					    symtab_hdr->sh_info, 0,
    633 					    NULL, NULL, NULL);
    634 	  if (isymbuf == NULL)
    635 	    return FALSE;
    636 	}
    637 
    638       for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
    639 	{
    640 	  Elf_Internal_Sym *isym;
    641 	  asection *tsec;
    642 	  bfd_vma address;
    643 
    644 	  if (local_plt_offsets[idx] == (bfd_vma) -1)
    645 	    continue;
    646 
    647 	  isym = &isymbuf[idx];
    648 	  if (isym->st_shndx == SHN_UNDEF)
    649 	    continue;
    650 	  else if (isym->st_shndx == SHN_ABS)
    651 	    tsec = bfd_abs_section_ptr;
    652 	  else if (isym->st_shndx == SHN_COMMON)
    653 	    tsec = bfd_com_section_ptr;
    654 	  else
    655 	    tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
    656 
    657 	  address = (tsec->output_section->vma
    658 		     + tsec->output_offset
    659 		     + isym->st_value);
    660 	  if (address <= 0xffff)
    661 	    {
    662 	      local_plt_offsets[idx] = -1;
    663 	      splt->size -= 4;
    664 	      *again = TRUE;
    665 	    }
    666 	}
    667 
    668       if (isymbuf != NULL
    669 	  && symtab_hdr->contents != (unsigned char *) isymbuf)
    670 	{
    671 	  if (! info->keep_memory)
    672 	    free (isymbuf);
    673 	  else
    674 	    {
    675 	      /* Cache the symbols for elf_link_input_bfd.  */
    676 	      symtab_hdr->contents = (unsigned char *) isymbuf;
    677 	    }
    678 	}
    679     }
    680 
    681   /* If we changed anything, walk the symbols again to reallocate
    682      .plt entry addresses.  */
    683   if (*again && splt->size > 0)
    684     {
    685       bfd_vma entry = 0;
    686 
    687       elf_link_hash_traverse (elf_hash_table (info),
    688 			      xstormy16_relax_plt_realloc, &entry);
    689 
    690       for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
    691 	{
    692 	  bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
    693 	  unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
    694 	  unsigned int idx;
    695 
    696 	  if (! local_plt_offsets)
    697 	    continue;
    698 
    699 	  for (idx = 0; idx < nlocals; ++idx)
    700 	    if (local_plt_offsets[idx] != (bfd_vma) -1)
    701 	      {
    702 		local_plt_offsets[idx] = entry;
    703 		entry += 4;
    704 	      }
    705 	}
    706     }
    707 
    708   return TRUE;
    709 }
    710 
    711 static bfd_boolean
    712 xstormy16_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
    713 				    struct bfd_link_info *info)
    714 {
    715   bfd *dynobj;
    716   asection *splt;
    717 
    718   if (bfd_link_relocatable (info))
    719     return TRUE;
    720 
    721   dynobj = elf_hash_table (info)->dynobj;
    722   if (dynobj == NULL)
    723     return TRUE;
    724 
    725   splt = elf_hash_table (info)->splt;
    726   BFD_ASSERT (splt != NULL);
    727 
    728   splt->contents = bfd_zalloc (dynobj, splt->size);
    729   if (splt->contents == NULL)
    730     return FALSE;
    731 
    732   return TRUE;
    733 }
    734 
    735 /* Relocate an XSTORMY16 ELF section.
    737 
    738    The RELOCATE_SECTION function is called by the new ELF backend linker
    739    to handle the relocations for a section.
    740 
    741    The relocs are always passed as Rela structures; if the section
    742    actually uses Rel structures, the r_addend field will always be
    743    zero.
    744 
    745    This function is responsible for adjusting the section contents as
    746    necessary, and (if using Rela relocs and generating a relocatable
    747    output file) adjusting the reloc addend as necessary.
    748 
    749    This function does not have to worry about setting the reloc
    750    address or the reloc symbol index.
    751 
    752    LOCAL_SYMS is a pointer to the swapped in local symbols.
    753 
    754    LOCAL_SECTIONS is an array giving the section in the input file
    755    corresponding to the st_shndx field of each local symbol.
    756 
    757    The global hash table entry for the global symbols can be found
    758    via elf_sym_hashes (input_bfd).
    759 
    760    When generating relocatable output, this function must handle
    761    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    762    going to be the section symbol corresponding to the output
    763    section, which means that the addend must be adjusted
    764    accordingly.  */
    765 
    766 static bfd_boolean
    767 xstormy16_elf_relocate_section (bfd *			output_bfd ATTRIBUTE_UNUSED,
    768 				struct bfd_link_info *	info,
    769 				bfd *			input_bfd,
    770 				asection *		input_section,
    771 				bfd_byte *		contents,
    772 				Elf_Internal_Rela *	relocs,
    773 				Elf_Internal_Sym *	local_syms,
    774 				asection **		local_sections)
    775 {
    776   Elf_Internal_Shdr *		symtab_hdr;
    777   struct elf_link_hash_entry ** sym_hashes;
    778   Elf_Internal_Rela *		rel;
    779   Elf_Internal_Rela *		relend;
    780   asection *splt;
    781 
    782   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
    783   sym_hashes = elf_sym_hashes (input_bfd);
    784   relend     = relocs + input_section->reloc_count;
    785 
    786   splt = elf_hash_table (info)->splt;
    787 
    788   for (rel = relocs; rel < relend; rel ++)
    789     {
    790       reloc_howto_type *	   howto;
    791       unsigned long		   r_symndx;
    792       Elf_Internal_Sym *	   sym;
    793       asection *		   sec;
    794       struct elf_link_hash_entry * h;
    795       bfd_vma			   relocation;
    796       bfd_reloc_status_type	   r;
    797       const char *		   name = NULL;
    798       int			   r_type;
    799 
    800       r_type = ELF32_R_TYPE (rel->r_info);
    801 
    802       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
    803 	  || r_type == R_XSTORMY16_GNU_VTENTRY)
    804 	continue;
    805 
    806       r_symndx = ELF32_R_SYM (rel->r_info);
    807       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
    808       h      = NULL;
    809       sym    = NULL;
    810       sec    = NULL;
    811 
    812       if (r_symndx < symtab_hdr->sh_info)
    813 	{
    814 	  sym = local_syms + r_symndx;
    815 	  sec = local_sections [r_symndx];
    816 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
    817 	}
    818       else
    819 	{
    820 	  bfd_boolean unresolved_reloc, warned, ignored;
    821 
    822 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    823 				   r_symndx, symtab_hdr, sym_hashes,
    824 				   h, sec, relocation,
    825 				   unresolved_reloc, warned, ignored);
    826 	}
    827 
    828       if (sec != NULL && discarded_section (sec))
    829 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    830 					 rel, 1, relend, howto, 0, contents);
    831 
    832       if (bfd_link_relocatable (info))
    833 	continue;
    834 
    835       if (h != NULL)
    836 	name = h->root.root.string;
    837       else
    838 	{
    839 	  name = (bfd_elf_string_from_elf_section
    840 		  (input_bfd, symtab_hdr->sh_link, sym->st_name));
    841 	  if (name == NULL || *name == '\0')
    842 	    name = bfd_section_name (input_bfd, sec);
    843 	}
    844 
    845       switch (ELF32_R_TYPE (rel->r_info))
    846 	{
    847 	case R_XSTORMY16_24:
    848 	  {
    849 	    bfd_vma reloc = relocation + rel->r_addend;
    850 	    unsigned int x;
    851 
    852 	    x = bfd_get_32 (input_bfd, contents + rel->r_offset);
    853 	    x &= 0x0000ff00;
    854 	    x |= reloc & 0xff;
    855 	    x |= (reloc << 8) & 0xffff0000;
    856 	    bfd_put_32 (input_bfd, x, contents + rel->r_offset);
    857 
    858 	    if (reloc & ~0xffffff)
    859 	      r = bfd_reloc_overflow;
    860 	    else
    861 	      r = bfd_reloc_ok;
    862 	    break;
    863 	  }
    864 
    865 	case R_XSTORMY16_FPTR16:
    866 	  {
    867 	    bfd_vma *plt_offset;
    868 
    869 	    if (h != NULL)
    870 	      plt_offset = &h->plt.offset;
    871 	    else
    872 	      plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
    873 
    874 	    if (relocation <= 0xffff)
    875 	      {
    876 		/* If the symbol is in range for a 16-bit address, we should
    877 		   have deallocated the plt entry in relax_section.  */
    878 		BFD_ASSERT (*plt_offset == (bfd_vma) -1);
    879 	      }
    880 	    else
    881 	      {
    882 		/* If the symbol is out of range for a 16-bit address,
    883 		   we must have allocated a plt entry.  */
    884 		BFD_ASSERT (*plt_offset != (bfd_vma) -1);
    885 
    886 		/* If this is the first time we've processed this symbol,
    887 		   fill in the plt entry with the correct symbol address.  */
    888 		if ((*plt_offset & 1) == 0)
    889 		  {
    890 		    unsigned int x;
    891 
    892 		    x = 0x00000200;  /* jmpf */
    893 		    x |= relocation & 0xff;
    894 		    x |= (relocation << 8) & 0xffff0000;
    895 		    bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
    896 		    *plt_offset |= 1;
    897 		  }
    898 
    899 		relocation = (splt->output_section->vma
    900 			      + splt->output_offset
    901 			      + (*plt_offset & -2));
    902 	      }
    903 	    r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    904 					  contents, rel->r_offset,
    905 					  relocation, 0);
    906 	    break;
    907 	  }
    908 
    909 	default:
    910 	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    911 					contents, rel->r_offset,
    912 					relocation, rel->r_addend);
    913 	  break;
    914 	}
    915 
    916       if (r != bfd_reloc_ok)
    917 	{
    918 	  const char * msg = NULL;
    919 
    920 	  switch (r)
    921 	    {
    922 	    case bfd_reloc_overflow:
    923 	      (*info->callbacks->reloc_overflow)
    924 		(info, (h ? &h->root : NULL), name, howto->name,
    925 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
    926 	      break;
    927 
    928 	    case bfd_reloc_undefined:
    929 	      (*info->callbacks->undefined_symbol)
    930 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
    931 	      break;
    932 
    933 	    case bfd_reloc_outofrange:
    934 	      msg = _("internal error: out of range error");
    935 	      break;
    936 
    937 	    case bfd_reloc_notsupported:
    938 	      msg = _("internal error: unsupported relocation error");
    939 	      break;
    940 
    941 	    case bfd_reloc_dangerous:
    942 	      msg = _("internal error: dangerous relocation");
    943 	      break;
    944 
    945 	    default:
    946 	      msg = _("internal error: unknown error");
    947 	      break;
    948 	    }
    949 
    950 	  if (msg)
    951 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
    952 					 input_section, rel->r_offset);
    953 	}
    954     }
    955 
    956   return TRUE;
    957 }
    958 
    959 /* This must exist if dynobj is ever set.  */
    960 
    961 static bfd_boolean
    962 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
    963 				       struct bfd_link_info *info)
    964 {
    965   bfd *dynobj = elf_hash_table (info)->dynobj;
    966   asection *splt = elf_hash_table (info)->splt;
    967 
    968   /* As an extra sanity check, verify that all plt entries have
    969      been filled in.  */
    970 
    971   if (dynobj != NULL && splt != NULL)
    972     {
    973       bfd_byte *contents = splt->contents;
    974       unsigned int i, size = splt->size;
    975 
    976       for (i = 0; i < size; i += 4)
    977 	{
    978 	  unsigned int x = bfd_get_32 (dynobj, contents + i);
    979 
    980 	  BFD_ASSERT (x != 0);
    981 	}
    982     }
    983 
    984   return TRUE;
    985 }
    986 
    987 /* Return the section that should be marked against GC for a given
    989    relocation.  */
    990 
    991 static asection *
    992 xstormy16_elf_gc_mark_hook (asection *sec,
    993 			    struct bfd_link_info *info,
    994 			    Elf_Internal_Rela *rel,
    995 			    struct elf_link_hash_entry *h,
    996 			    Elf_Internal_Sym *sym)
    997 {
    998   if (h != NULL)
    999     switch (ELF32_R_TYPE (rel->r_info))
   1000       {
   1001       case R_XSTORMY16_GNU_VTINHERIT:
   1002       case R_XSTORMY16_GNU_VTENTRY:
   1003 	return NULL;
   1004       }
   1005 
   1006   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
   1007 }
   1008 
   1009 #define ELF_ARCH		bfd_arch_xstormy16
   1011 #define ELF_MACHINE_CODE	EM_XSTORMY16
   1012 #define ELF_MAXPAGESIZE		0x100
   1013 
   1014 #define TARGET_LITTLE_SYM       xstormy16_elf32_vec
   1015 #define TARGET_LITTLE_NAME	"elf32-xstormy16"
   1016 
   1017 #define elf_info_to_howto_rel			NULL
   1018 #define elf_info_to_howto			xstormy16_info_to_howto_rela
   1019 #define elf_backend_relocate_section		xstormy16_elf_relocate_section
   1020 #define elf_backend_gc_mark_hook		xstormy16_elf_gc_mark_hook
   1021 #define elf_backend_check_relocs		xstormy16_elf_check_relocs
   1022 #define elf_backend_always_size_sections \
   1023   xstormy16_elf_always_size_sections
   1024 #define elf_backend_omit_section_dynsym \
   1025   _bfd_elf_omit_section_dynsym_all
   1026 #define elf_backend_finish_dynamic_sections \
   1027   xstormy16_elf_finish_dynamic_sections
   1028 
   1029 #define elf_backend_can_gc_sections		1
   1030 #define elf_backend_rela_normal			1
   1031 
   1032 #define bfd_elf32_bfd_reloc_type_lookup		xstormy16_reloc_type_lookup
   1033 #define bfd_elf32_bfd_reloc_name_lookup \
   1034   xstormy16_reloc_name_lookup
   1035 #define bfd_elf32_bfd_relax_section		xstormy16_elf_relax_section
   1036 
   1037 #include "elf32-target.h"
   1038