Home | History | Annotate | Line # | Download | only in bfd
elf32-xstormy16.c revision 1.1.1.10
      1 /* Xstormy16-specific support for 32-bit ELF.
      2    Copyright (C) 2000-2022 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_always_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 
    731   return true;
    732 }
    733 
    734 /* Relocate an XSTORMY16 ELF section.
    736 
    737    The RELOCATE_SECTION function is called by the new ELF backend linker
    738    to handle the relocations for a section.
    739 
    740    The relocs are always passed as Rela structures; if the section
    741    actually uses Rel structures, the r_addend field will always be
    742    zero.
    743 
    744    This function is responsible for adjusting the section contents as
    745    necessary, and (if using Rela relocs and generating a relocatable
    746    output file) adjusting the reloc addend as necessary.
    747 
    748    This function does not have to worry about setting the reloc
    749    address or the reloc symbol index.
    750 
    751    LOCAL_SYMS is a pointer to the swapped in local symbols.
    752 
    753    LOCAL_SECTIONS is an array giving the section in the input file
    754    corresponding to the st_shndx field of each local symbol.
    755 
    756    The global hash table entry for the global symbols can be found
    757    via elf_sym_hashes (input_bfd).
    758 
    759    When generating relocatable output, this function must handle
    760    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    761    going to be the section symbol corresponding to the output
    762    section, which means that the addend must be adjusted
    763    accordingly.  */
    764 
    765 static int
    766 xstormy16_elf_relocate_section (bfd *			output_bfd ATTRIBUTE_UNUSED,
    767 				struct bfd_link_info *	info,
    768 				bfd *			input_bfd,
    769 				asection *		input_section,
    770 				bfd_byte *		contents,
    771 				Elf_Internal_Rela *	relocs,
    772 				Elf_Internal_Sym *	local_syms,
    773 				asection **		local_sections)
    774 {
    775   Elf_Internal_Shdr *		symtab_hdr;
    776   struct elf_link_hash_entry ** sym_hashes;
    777   Elf_Internal_Rela *		rel;
    778   Elf_Internal_Rela *		relend;
    779   asection *splt;
    780 
    781   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
    782   sym_hashes = elf_sym_hashes (input_bfd);
    783   relend     = relocs + input_section->reloc_count;
    784 
    785   splt = elf_hash_table (info)->splt;
    786 
    787   for (rel = relocs; rel < relend; rel ++)
    788     {
    789       reloc_howto_type *	   howto;
    790       unsigned long		   r_symndx;
    791       Elf_Internal_Sym *	   sym;
    792       asection *		   sec;
    793       struct elf_link_hash_entry * h;
    794       bfd_vma			   relocation;
    795       bfd_reloc_status_type	   r;
    796       const char *		   name = NULL;
    797       int			   r_type;
    798 
    799       r_type = ELF32_R_TYPE (rel->r_info);
    800 
    801       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
    802 	  || r_type == R_XSTORMY16_GNU_VTENTRY)
    803 	continue;
    804 
    805       r_symndx = ELF32_R_SYM (rel->r_info);
    806       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
    807       h      = NULL;
    808       sym    = NULL;
    809       sec    = NULL;
    810 
    811       if (r_symndx < symtab_hdr->sh_info)
    812 	{
    813 	  sym = local_syms + r_symndx;
    814 	  sec = local_sections [r_symndx];
    815 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
    816 	}
    817       else
    818 	{
    819 	  bool unresolved_reloc, warned, ignored;
    820 
    821 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    822 				   r_symndx, symtab_hdr, sym_hashes,
    823 				   h, sec, relocation,
    824 				   unresolved_reloc, warned, ignored);
    825 	}
    826 
    827       if (sec != NULL && discarded_section (sec))
    828 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    829 					 rel, 1, relend, howto, 0, contents);
    830 
    831       if (bfd_link_relocatable (info))
    832 	continue;
    833 
    834       if (h != NULL)
    835 	name = h->root.root.string;
    836       else
    837 	{
    838 	  name = (bfd_elf_string_from_elf_section
    839 		  (input_bfd, symtab_hdr->sh_link, sym->st_name));
    840 	  if (name == NULL || *name == '\0')
    841 	    name = bfd_section_name (sec);
    842 	}
    843 
    844       switch (ELF32_R_TYPE (rel->r_info))
    845 	{
    846 	case R_XSTORMY16_24:
    847 	  {
    848 	    bfd_vma reloc = relocation + rel->r_addend;
    849 	    unsigned int x;
    850 
    851 	    x = bfd_get_32 (input_bfd, contents + rel->r_offset);
    852 	    x &= 0x0000ff00;
    853 	    x |= reloc & 0xff;
    854 	    x |= (reloc << 8) & 0xffff0000;
    855 	    bfd_put_32 (input_bfd, x, contents + rel->r_offset);
    856 
    857 	    if (reloc & ~0xffffff)
    858 	      r = bfd_reloc_overflow;
    859 	    else
    860 	      r = bfd_reloc_ok;
    861 	    break;
    862 	  }
    863 
    864 	case R_XSTORMY16_FPTR16:
    865 	  {
    866 	    bfd_vma *plt_offset;
    867 
    868 	    if (h != NULL)
    869 	      plt_offset = &h->plt.offset;
    870 	    else
    871 	      plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
    872 
    873 	    if (relocation <= 0xffff)
    874 	      {
    875 		/* If the symbol is in range for a 16-bit address, we should
    876 		   have deallocated the plt entry in relax_section.  */
    877 		BFD_ASSERT (*plt_offset == (bfd_vma) -1);
    878 	      }
    879 	    else
    880 	      {
    881 		/* If the symbol is out of range for a 16-bit address,
    882 		   we must have allocated a plt entry.  */
    883 		BFD_ASSERT (*plt_offset != (bfd_vma) -1);
    884 
    885 		/* If this is the first time we've processed this symbol,
    886 		   fill in the plt entry with the correct symbol address.  */
    887 		if ((*plt_offset & 1) == 0)
    888 		  {
    889 		    unsigned int x;
    890 
    891 		    x = 0x00000200;  /* jmpf */
    892 		    x |= relocation & 0xff;
    893 		    x |= (relocation << 8) & 0xffff0000;
    894 		    bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
    895 		    *plt_offset |= 1;
    896 		  }
    897 
    898 		relocation = (splt->output_section->vma
    899 			      + splt->output_offset
    900 			      + (*plt_offset & -2));
    901 	      }
    902 	    r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    903 					  contents, rel->r_offset,
    904 					  relocation, 0);
    905 	    break;
    906 	  }
    907 
    908 	default:
    909 	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    910 					contents, rel->r_offset,
    911 					relocation, rel->r_addend);
    912 	  break;
    913 	}
    914 
    915       if (r != bfd_reloc_ok)
    916 	{
    917 	  const char * msg = NULL;
    918 
    919 	  switch (r)
    920 	    {
    921 	    case bfd_reloc_overflow:
    922 	      (*info->callbacks->reloc_overflow)
    923 		(info, (h ? &h->root : NULL), name, howto->name,
    924 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
    925 	      break;
    926 
    927 	    case bfd_reloc_undefined:
    928 	      (*info->callbacks->undefined_symbol)
    929 		(info, name, input_bfd, input_section, rel->r_offset, true);
    930 	      break;
    931 
    932 	    case bfd_reloc_outofrange:
    933 	      msg = _("internal error: out of range error");
    934 	      break;
    935 
    936 	    case bfd_reloc_notsupported:
    937 	      msg = _("internal error: unsupported relocation error");
    938 	      break;
    939 
    940 	    case bfd_reloc_dangerous:
    941 	      msg = _("internal error: dangerous relocation");
    942 	      break;
    943 
    944 	    default:
    945 	      msg = _("internal error: unknown error");
    946 	      break;
    947 	    }
    948 
    949 	  if (msg)
    950 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
    951 					 input_section, rel->r_offset);
    952 	}
    953     }
    954 
    955   return true;
    956 }
    957 
    958 /* This must exist if dynobj is ever set.  */
    959 
    960 static bool
    961 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
    962 				       struct bfd_link_info *info)
    963 {
    964   bfd *dynobj = elf_hash_table (info)->dynobj;
    965   asection *splt = elf_hash_table (info)->splt;
    966 
    967   /* As an extra sanity check, verify that all plt entries have
    968      been filled in.  */
    969 
    970   if (dynobj != NULL && splt != NULL)
    971     {
    972       bfd_byte *contents = splt->contents;
    973       unsigned int i, size = splt->size;
    974 
    975       for (i = 0; i < size; i += 4)
    976 	{
    977 	  unsigned int x = bfd_get_32 (dynobj, contents + i);
    978 
    979 	  BFD_ASSERT (x != 0);
    980 	}
    981     }
    982 
    983   return true;
    984 }
    985 
    986 /* Return the section that should be marked against GC for a given
    988    relocation.  */
    989 
    990 static asection *
    991 xstormy16_elf_gc_mark_hook (asection *sec,
    992 			    struct bfd_link_info *info,
    993 			    Elf_Internal_Rela *rel,
    994 			    struct elf_link_hash_entry *h,
    995 			    Elf_Internal_Sym *sym)
    996 {
    997   if (h != NULL)
    998     switch (ELF32_R_TYPE (rel->r_info))
    999       {
   1000       case R_XSTORMY16_GNU_VTINHERIT:
   1001       case R_XSTORMY16_GNU_VTENTRY:
   1002 	return NULL;
   1003       }
   1004 
   1005   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
   1006 }
   1007 
   1008 #define ELF_ARCH		bfd_arch_xstormy16
   1010 #define ELF_MACHINE_CODE	EM_XSTORMY16
   1011 #define ELF_MAXPAGESIZE		0x100
   1012 
   1013 #define TARGET_LITTLE_SYM       xstormy16_elf32_vec
   1014 #define TARGET_LITTLE_NAME	"elf32-xstormy16"
   1015 
   1016 #define elf_info_to_howto_rel			NULL
   1017 #define elf_info_to_howto			xstormy16_info_to_howto_rela
   1018 #define elf_backend_relocate_section		xstormy16_elf_relocate_section
   1019 #define elf_backend_gc_mark_hook		xstormy16_elf_gc_mark_hook
   1020 #define elf_backend_check_relocs		xstormy16_elf_check_relocs
   1021 #define elf_backend_always_size_sections \
   1022   xstormy16_elf_always_size_sections
   1023 #define elf_backend_omit_section_dynsym \
   1024   _bfd_elf_omit_section_dynsym_all
   1025 #define elf_backend_finish_dynamic_sections \
   1026   xstormy16_elf_finish_dynamic_sections
   1027 
   1028 #define elf_backend_can_gc_sections		1
   1029 #define elf_backend_rela_normal			1
   1030 
   1031 #define bfd_elf32_bfd_reloc_type_lookup		xstormy16_reloc_type_lookup
   1032 #define bfd_elf32_bfd_reloc_name_lookup \
   1033   xstormy16_reloc_name_lookup
   1034 #define bfd_elf32_bfd_relax_section		xstormy16_elf_relax_section
   1035 
   1036 #include "elf32-target.h"
   1037