Home | History | Annotate | Line # | Download | only in bfd
elf32-xstormy16.c revision 1.10
      1 /* Xstormy16-specific support for 32-bit ELF.
      2    Copyright (C) 2000-2025 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 	 0,			/* size */
     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 	 4,			/* size */
     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 	 2,			/* size */
    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 	 1,			/* size */
    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 	 4,			/* size */
    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 	 2,			/* size */
    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 	 1,			/* size */
    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 	 2,			/* size */
    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 	 4,			/* size */
    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 	 2,			/* size */
    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 	 2,			/* size */
    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 	 2,			/* size */
    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 	 2,			/* size */
    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 	 4,			/* size */
    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 	 4,			/* size */
    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 bool
    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 bool
    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 (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 	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
    519 	    return false;
    520 	  break;
    521 	}
    522     }
    523 
    524   return true;
    525 }
    526 
    527 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
    528    is within the low 64k, remove any entry for it in the plt.  */
    529 
    530 struct relax_plt_data
    531 {
    532   asection *splt;
    533   bool *again;
    534 };
    535 
    536 static bool
    537 xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
    538 {
    539   struct relax_plt_data *data = (struct relax_plt_data *) xdata;
    540 
    541   if (h->plt.offset != (bfd_vma) -1)
    542     {
    543       bfd_vma address;
    544 
    545       if (h->root.type == bfd_link_hash_undefined
    546 	  || h->root.type == bfd_link_hash_undefweak)
    547 	address = 0;
    548       else
    549 	address = (h->root.u.def.section->output_section->vma
    550 		   + h->root.u.def.section->output_offset
    551 		   + h->root.u.def.value);
    552 
    553       if (address <= 0xffff)
    554 	{
    555 	  h->plt.offset = -1;
    556 	  data->splt->size -= 4;
    557 	  *data->again = true;
    558 	}
    559     }
    560 
    561   return true;
    562 }
    563 
    564 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
    565    previously had a plt entry, give it a new entry offset.  */
    566 
    567 static bool
    568 xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
    569 {
    570   bfd_vma *entry = (bfd_vma *) xdata;
    571 
    572   if (h->plt.offset != (bfd_vma) -1)
    573     {
    574       h->plt.offset = *entry;
    575       *entry += 4;
    576     }
    577 
    578   return true;
    579 }
    580 
    581 static bool
    582 xstormy16_elf_relax_section (bfd *dynobj,
    583 			     asection *splt,
    584 			     struct bfd_link_info *info,
    585 			     bool *again)
    586 {
    587   struct relax_plt_data relax_plt_data;
    588   bfd *ibfd;
    589 
    590   /* Assume nothing changes.  */
    591   *again = false;
    592 
    593   if (bfd_link_relocatable (info)
    594       || !is_elf_hash_table (info->hash))
    595     return true;
    596 
    597   /* We only relax the .plt section at the moment.  */
    598   if (dynobj != elf_hash_table (info)->dynobj
    599       || strcmp (splt->name, ".plt") != 0)
    600     return true;
    601 
    602   /* Quick check for an empty plt.  */
    603   if (splt->size == 0)
    604     return true;
    605 
    606   /* Map across all global symbols; see which ones happen to
    607      fall in the low 64k.  */
    608   relax_plt_data.splt = splt;
    609   relax_plt_data.again = again;
    610   elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
    611 			  &relax_plt_data);
    612 
    613   /* Likewise for local symbols, though that's somewhat less convenient
    614      as we have to walk the list of input bfds and swap in symbol data.  */
    615   for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
    616     {
    617       bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
    618       Elf_Internal_Shdr *symtab_hdr;
    619       Elf_Internal_Sym *isymbuf = NULL;
    620       unsigned int idx;
    621 
    622       if (! local_plt_offsets)
    623 	continue;
    624 
    625       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
    626       if (symtab_hdr->sh_info != 0)
    627 	{
    628 	  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
    629 	  if (isymbuf == NULL)
    630 	    isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
    631 					    symtab_hdr->sh_info, 0,
    632 					    NULL, NULL, NULL);
    633 	  if (isymbuf == NULL)
    634 	    return false;
    635 	}
    636 
    637       for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
    638 	{
    639 	  Elf_Internal_Sym *isym;
    640 	  asection *tsec;
    641 	  bfd_vma address;
    642 
    643 	  if (local_plt_offsets[idx] == (bfd_vma) -1)
    644 	    continue;
    645 
    646 	  isym = &isymbuf[idx];
    647 	  if (isym->st_shndx == SHN_UNDEF)
    648 	    continue;
    649 	  else if (isym->st_shndx == SHN_ABS)
    650 	    tsec = bfd_abs_section_ptr;
    651 	  else if (isym->st_shndx == SHN_COMMON)
    652 	    tsec = bfd_com_section_ptr;
    653 	  else
    654 	    tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
    655 
    656 	  address = (tsec->output_section->vma
    657 		     + tsec->output_offset
    658 		     + isym->st_value);
    659 	  if (address <= 0xffff)
    660 	    {
    661 	      local_plt_offsets[idx] = -1;
    662 	      splt->size -= 4;
    663 	      *again = true;
    664 	    }
    665 	}
    666 
    667       if (isymbuf != NULL
    668 	  && symtab_hdr->contents != (unsigned char *) isymbuf)
    669 	{
    670 	  if (! info->keep_memory)
    671 	    free (isymbuf);
    672 	  else
    673 	    {
    674 	      /* Cache the symbols for elf_link_input_bfd.  */
    675 	      symtab_hdr->contents = (unsigned char *) isymbuf;
    676 	    }
    677 	}
    678     }
    679 
    680   /* If we changed anything, walk the symbols again to reallocate
    681      .plt entry addresses.  */
    682   if (*again && splt->size > 0)
    683     {
    684       bfd_vma entry = 0;
    685 
    686       elf_link_hash_traverse (elf_hash_table (info),
    687 			      xstormy16_relax_plt_realloc, &entry);
    688 
    689       for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
    690 	{
    691 	  bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
    692 	  unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
    693 	  unsigned int idx;
    694 
    695 	  if (! local_plt_offsets)
    696 	    continue;
    697 
    698 	  for (idx = 0; idx < nlocals; ++idx)
    699 	    if (local_plt_offsets[idx] != (bfd_vma) -1)
    700 	      {
    701 		local_plt_offsets[idx] = entry;
    702 		entry += 4;
    703 	      }
    704 	}
    705     }
    706 
    707   return true;
    708 }
    709 
    710 static bool
    711 xstormy16_elf_early_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
    712 				   struct bfd_link_info *info)
    713 {
    714   bfd *dynobj;
    715   asection *splt;
    716 
    717   if (bfd_link_relocatable (info))
    718     return true;
    719 
    720   dynobj = elf_hash_table (info)->dynobj;
    721   if (dynobj == NULL)
    722     return true;
    723 
    724   splt = elf_hash_table (info)->splt;
    725   BFD_ASSERT (splt != NULL);
    726 
    727   splt->contents = bfd_zalloc (dynobj, splt->size);
    728   if (splt->contents == NULL)
    729     return false;
    730   splt->alloced = 1;
    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 int
    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 	  bool 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 (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 bool
    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_early_size_sections \
   1023   xstormy16_elf_early_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