Home | History | Annotate | Line # | Download | only in bfd
elf32-xstormy16.c revision 1.1.1.7
      1 /* Xstormy16-specific support for 32-bit ELF.
      2    Copyright (C) 2000-2017 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 void
    380 xstormy16_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED,
    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     cache_ptr->howto
    391       = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
    392   else
    393     abort ();
    394 }
    395 
    396 /* We support 16-bit pointers to code above 64k by generating a thunk
    398    below 64k containing a JMPF instruction to the final address.  We
    399    cannot, unfortunately, minimize the number of thunks unless the
    400    -relax switch is given, as otherwise we have no idea where the
    401    sections will fall in the address space.  */
    402 
    403 static bfd_boolean
    404 xstormy16_elf_check_relocs (bfd *abfd,
    405 			    struct bfd_link_info *info,
    406 			    asection *sec,
    407 			    const Elf_Internal_Rela *relocs)
    408 {
    409   const Elf_Internal_Rela *rel, *relend;
    410   struct elf_link_hash_entry **sym_hashes;
    411   Elf_Internal_Shdr *symtab_hdr;
    412   bfd_vma *local_plt_offsets;
    413   asection *splt;
    414   bfd *dynobj;
    415 
    416   if (bfd_link_relocatable (info))
    417     return TRUE;
    418 
    419   symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
    420   sym_hashes = elf_sym_hashes (abfd);
    421   local_plt_offsets = elf_local_got_offsets (abfd);
    422   dynobj = elf_hash_table(info)->dynobj;
    423 
    424   relend = relocs + sec->reloc_count;
    425   for (rel = relocs; rel < relend; ++rel)
    426     {
    427       unsigned long r_symndx;
    428       struct elf_link_hash_entry *h;
    429       bfd_vma *offset;
    430 
    431       r_symndx = ELF32_R_SYM (rel->r_info);
    432       if (r_symndx < symtab_hdr->sh_info)
    433 	h = NULL;
    434       else
    435 	{
    436 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
    437 	  while (h->root.type == bfd_link_hash_indirect
    438 		 || h->root.type == bfd_link_hash_warning)
    439 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    440 
    441 	  /* PR15323, ref flags aren't set for references in the same
    442 	     object.  */
    443 	  h->root.non_ir_ref = 1;
    444 	}
    445 
    446       switch (ELF32_R_TYPE (rel->r_info))
    447         {
    448 	  /* This relocation describes a 16-bit pointer to a function.
    449 	     We may need to allocate a thunk in low memory; reserve memory
    450 	     for it now.  */
    451 	case R_XSTORMY16_FPTR16:
    452 	  if (rel->r_addend != 0)
    453 	    {
    454 	      (*info->callbacks->warning)
    455 		(info, _("non-zero addend in @fptr reloc"), 0,
    456 		 abfd, 0, 0);
    457 	    }
    458 
    459 	  if (dynobj == NULL)
    460 	    elf_hash_table (info)->dynobj = dynobj = abfd;
    461 	  splt = elf_hash_table (info)->splt;
    462 	  if (splt == NULL)
    463 	    {
    464 	      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
    465 				| SEC_IN_MEMORY | SEC_LINKER_CREATED
    466 				| SEC_READONLY | SEC_CODE);
    467 
    468 	      splt = bfd_make_section_anyway_with_flags (dynobj, ".plt",
    469 							 flags);
    470 	      elf_hash_table (info)->splt = splt;
    471 	      if (splt == NULL
    472 		  || ! bfd_set_section_alignment (dynobj, splt, 1))
    473 		return FALSE;
    474 	    }
    475 
    476 	  if (h != NULL)
    477 	    offset = &h->plt.offset;
    478 	  else
    479 	    {
    480 	      if (local_plt_offsets == NULL)
    481 		{
    482 		  size_t size;
    483 		  unsigned int i;
    484 
    485 		  size = symtab_hdr->sh_info * sizeof (bfd_vma);
    486 		  local_plt_offsets = bfd_alloc (abfd, size);
    487 		  if (local_plt_offsets == NULL)
    488 		    return FALSE;
    489 		  elf_local_got_offsets (abfd) = local_plt_offsets;
    490 
    491 		  for (i = 0; i < symtab_hdr->sh_info; i++)
    492 		    local_plt_offsets[i] = (bfd_vma) -1;
    493 		}
    494 	      offset = &local_plt_offsets[r_symndx];
    495 	    }
    496 
    497 	  if (*offset == (bfd_vma) -1)
    498 	    {
    499 	      *offset = splt->size;
    500 	      splt->size += 4;
    501 	    }
    502 	  break;
    503 
    504 	  /* This relocation describes the C++ object vtable hierarchy.
    505 	     Reconstruct it for later use during GC.  */
    506         case R_XSTORMY16_GNU_VTINHERIT:
    507           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
    508             return FALSE;
    509           break;
    510 
    511 	  /* This relocation describes which C++ vtable entries are actually
    512 	     used.  Record for later use during GC.  */
    513         case R_XSTORMY16_GNU_VTENTRY:
    514           BFD_ASSERT (h != NULL);
    515           if (h != NULL
    516               && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
    517             return FALSE;
    518           break;
    519 	}
    520     }
    521 
    522   return TRUE;
    523 }
    524 
    525 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
    526    is within the low 64k, remove any entry for it in the plt.  */
    527 
    528 struct relax_plt_data
    529 {
    530   asection *splt;
    531   bfd_boolean *again;
    532 };
    533 
    534 static bfd_boolean
    535 xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
    536 {
    537   struct relax_plt_data *data = (struct relax_plt_data *) xdata;
    538 
    539   if (h->plt.offset != (bfd_vma) -1)
    540     {
    541       bfd_vma address;
    542 
    543       if (h->root.type == bfd_link_hash_undefined
    544 	  || h->root.type == bfd_link_hash_undefweak)
    545 	address = 0;
    546       else
    547 	address = (h->root.u.def.section->output_section->vma
    548 		   + h->root.u.def.section->output_offset
    549 		   + h->root.u.def.value);
    550 
    551       if (address <= 0xffff)
    552 	{
    553 	  h->plt.offset = -1;
    554 	  data->splt->size -= 4;
    555 	  *data->again = TRUE;
    556 	}
    557     }
    558 
    559   return TRUE;
    560 }
    561 
    562 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
    563    previously had a plt entry, give it a new entry offset.  */
    564 
    565 static bfd_boolean
    566 xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
    567 {
    568   bfd_vma *entry = (bfd_vma *) xdata;
    569 
    570   if (h->plt.offset != (bfd_vma) -1)
    571     {
    572       h->plt.offset = *entry;
    573       *entry += 4;
    574     }
    575 
    576   return TRUE;
    577 }
    578 
    579 static bfd_boolean
    580 xstormy16_elf_relax_section (bfd *dynobj,
    581 			     asection *splt,
    582 			     struct bfd_link_info *info,
    583 			     bfd_boolean *again)
    584 {
    585   struct relax_plt_data relax_plt_data;
    586   bfd *ibfd;
    587 
    588   /* Assume nothing changes.  */
    589   *again = FALSE;
    590 
    591   if (bfd_link_relocatable (info))
    592     return TRUE;
    593 
    594   /* We only relax the .plt section at the moment.  */
    595   if (dynobj != elf_hash_table (info)->dynobj
    596       || strcmp (splt->name, ".plt") != 0)
    597     return TRUE;
    598 
    599   /* Quick check for an empty plt.  */
    600   if (splt->size == 0)
    601     return TRUE;
    602 
    603   /* Map across all global symbols; see which ones happen to
    604      fall in the low 64k.  */
    605   relax_plt_data.splt = splt;
    606   relax_plt_data.again = again;
    607   elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
    608 			  &relax_plt_data);
    609 
    610   /* Likewise for local symbols, though that's somewhat less convenient
    611      as we have to walk the list of input bfds and swap in symbol data.  */
    612   for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
    613     {
    614       bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
    615       Elf_Internal_Shdr *symtab_hdr;
    616       Elf_Internal_Sym *isymbuf = NULL;
    617       unsigned int idx;
    618 
    619       if (! local_plt_offsets)
    620 	continue;
    621 
    622       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
    623       if (symtab_hdr->sh_info != 0)
    624 	{
    625 	  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
    626 	  if (isymbuf == NULL)
    627 	    isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
    628 					    symtab_hdr->sh_info, 0,
    629 					    NULL, NULL, NULL);
    630 	  if (isymbuf == NULL)
    631 	    return FALSE;
    632 	}
    633 
    634       for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
    635 	{
    636 	  Elf_Internal_Sym *isym;
    637 	  asection *tsec;
    638 	  bfd_vma address;
    639 
    640 	  if (local_plt_offsets[idx] == (bfd_vma) -1)
    641 	    continue;
    642 
    643 	  isym = &isymbuf[idx];
    644 	  if (isym->st_shndx == SHN_UNDEF)
    645 	    continue;
    646 	  else if (isym->st_shndx == SHN_ABS)
    647 	    tsec = bfd_abs_section_ptr;
    648 	  else if (isym->st_shndx == SHN_COMMON)
    649 	    tsec = bfd_com_section_ptr;
    650 	  else
    651 	    tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
    652 
    653 	  address = (tsec->output_section->vma
    654 		     + tsec->output_offset
    655 		     + isym->st_value);
    656 	  if (address <= 0xffff)
    657 	    {
    658 	      local_plt_offsets[idx] = -1;
    659 	      splt->size -= 4;
    660 	      *again = TRUE;
    661 	    }
    662 	}
    663 
    664       if (isymbuf != NULL
    665 	  && symtab_hdr->contents != (unsigned char *) isymbuf)
    666 	{
    667 	  if (! info->keep_memory)
    668 	    free (isymbuf);
    669 	  else
    670 	    {
    671 	      /* Cache the symbols for elf_link_input_bfd.  */
    672 	      symtab_hdr->contents = (unsigned char *) isymbuf;
    673 	    }
    674 	}
    675     }
    676 
    677   /* If we changed anything, walk the symbols again to reallocate
    678      .plt entry addresses.  */
    679   if (*again && splt->size > 0)
    680     {
    681       bfd_vma entry = 0;
    682 
    683       elf_link_hash_traverse (elf_hash_table (info),
    684 			      xstormy16_relax_plt_realloc, &entry);
    685 
    686       for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
    687 	{
    688 	  bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
    689 	  unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
    690 	  unsigned int idx;
    691 
    692 	  if (! local_plt_offsets)
    693 	    continue;
    694 
    695 	  for (idx = 0; idx < nlocals; ++idx)
    696 	    if (local_plt_offsets[idx] != (bfd_vma) -1)
    697 	      {
    698 	        local_plt_offsets[idx] = entry;
    699 		entry += 4;
    700 	      }
    701 	}
    702     }
    703 
    704   return TRUE;
    705 }
    706 
    707 static bfd_boolean
    708 xstormy16_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
    709 				    struct bfd_link_info *info)
    710 {
    711   bfd *dynobj;
    712   asection *splt;
    713 
    714   if (bfd_link_relocatable (info))
    715     return TRUE;
    716 
    717   dynobj = elf_hash_table (info)->dynobj;
    718   if (dynobj == NULL)
    719     return TRUE;
    720 
    721   splt = elf_hash_table (info)->splt;
    722   BFD_ASSERT (splt != NULL);
    723 
    724   splt->contents = bfd_zalloc (dynobj, splt->size);
    725   if (splt->contents == NULL)
    726     return FALSE;
    727 
    728   return TRUE;
    729 }
    730 
    731 /* Relocate an XSTORMY16 ELF section.
    733 
    734    The RELOCATE_SECTION function is called by the new ELF backend linker
    735    to handle the relocations for a section.
    736 
    737    The relocs are always passed as Rela structures; if the section
    738    actually uses Rel structures, the r_addend field will always be
    739    zero.
    740 
    741    This function is responsible for adjusting the section contents as
    742    necessary, and (if using Rela relocs and generating a relocatable
    743    output file) adjusting the reloc addend as necessary.
    744 
    745    This function does not have to worry about setting the reloc
    746    address or the reloc symbol index.
    747 
    748    LOCAL_SYMS is a pointer to the swapped in local symbols.
    749 
    750    LOCAL_SECTIONS is an array giving the section in the input file
    751    corresponding to the st_shndx field of each local symbol.
    752 
    753    The global hash table entry for the global symbols can be found
    754    via elf_sym_hashes (input_bfd).
    755 
    756    When generating relocatable output, this function must handle
    757    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    758    going to be the section symbol corresponding to the output
    759    section, which means that the addend must be adjusted
    760    accordingly.  */
    761 
    762 static bfd_boolean
    763 xstormy16_elf_relocate_section (bfd *                   output_bfd ATTRIBUTE_UNUSED,
    764 				struct bfd_link_info *  info,
    765 				bfd *                   input_bfd,
    766 				asection *              input_section,
    767 				bfd_byte *              contents,
    768 				Elf_Internal_Rela *     relocs,
    769 				Elf_Internal_Sym *      local_syms,
    770 				asection **             local_sections)
    771 {
    772   Elf_Internal_Shdr *           symtab_hdr;
    773   struct elf_link_hash_entry ** sym_hashes;
    774   Elf_Internal_Rela *           rel;
    775   Elf_Internal_Rela *           relend;
    776   asection *splt;
    777 
    778   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
    779   sym_hashes = elf_sym_hashes (input_bfd);
    780   relend     = relocs + input_section->reloc_count;
    781 
    782   splt = elf_hash_table (info)->splt;
    783 
    784   for (rel = relocs; rel < relend; rel ++)
    785     {
    786       reloc_howto_type *           howto;
    787       unsigned long                r_symndx;
    788       Elf_Internal_Sym *           sym;
    789       asection *                   sec;
    790       struct elf_link_hash_entry * h;
    791       bfd_vma                      relocation;
    792       bfd_reloc_status_type        r;
    793       const char *                 name = NULL;
    794       int                          r_type;
    795 
    796       r_type = ELF32_R_TYPE (rel->r_info);
    797 
    798       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
    799 	  || r_type == R_XSTORMY16_GNU_VTENTRY)
    800 	continue;
    801 
    802       r_symndx = ELF32_R_SYM (rel->r_info);
    803       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
    804       h      = NULL;
    805       sym    = NULL;
    806       sec    = NULL;
    807 
    808       if (r_symndx < symtab_hdr->sh_info)
    809 	{
    810 	  sym = local_syms + r_symndx;
    811 	  sec = local_sections [r_symndx];
    812 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
    813 	}
    814       else
    815 	{
    816 	  bfd_boolean unresolved_reloc, warned, ignored;
    817 
    818 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    819 				   r_symndx, symtab_hdr, sym_hashes,
    820 				   h, sec, relocation,
    821 				   unresolved_reloc, warned, ignored);
    822 	}
    823 
    824       if (sec != NULL && discarded_section (sec))
    825 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    826 					 rel, 1, relend, howto, 0, contents);
    827 
    828       if (bfd_link_relocatable (info))
    829 	continue;
    830 
    831       if (h != NULL)
    832 	name = h->root.root.string;
    833       else
    834 	{
    835 	  name = (bfd_elf_string_from_elf_section
    836 		  (input_bfd, symtab_hdr->sh_link, sym->st_name));
    837 	  if (name == NULL || *name == '\0')
    838 	    name = bfd_section_name (input_bfd, sec);
    839 	}
    840 
    841       switch (ELF32_R_TYPE (rel->r_info))
    842 	{
    843 	case R_XSTORMY16_24:
    844 	  {
    845 	    bfd_vma reloc = relocation + rel->r_addend;
    846 	    unsigned int x;
    847 
    848 	    x = bfd_get_32 (input_bfd, contents + rel->r_offset);
    849 	    x &= 0x0000ff00;
    850 	    x |= reloc & 0xff;
    851 	    x |= (reloc << 8) & 0xffff0000;
    852 	    bfd_put_32 (input_bfd, x, contents + rel->r_offset);
    853 
    854 	    if (reloc & ~0xffffff)
    855 	      r = bfd_reloc_overflow;
    856 	    else
    857 	      r = bfd_reloc_ok;
    858 	    break;
    859 	  }
    860 
    861 	case R_XSTORMY16_FPTR16:
    862 	  {
    863 	    bfd_vma *plt_offset;
    864 
    865 	    if (h != NULL)
    866 	      plt_offset = &h->plt.offset;
    867 	    else
    868 	      plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
    869 
    870 	    if (relocation <= 0xffff)
    871 	      {
    872 	        /* If the symbol is in range for a 16-bit address, we should
    873 		   have deallocated the plt entry in relax_section.  */
    874 	        BFD_ASSERT (*plt_offset == (bfd_vma) -1);
    875 	      }
    876 	    else
    877 	      {
    878 		/* If the symbol is out of range for a 16-bit address,
    879 		   we must have allocated a plt entry.  */
    880 		BFD_ASSERT (*plt_offset != (bfd_vma) -1);
    881 
    882 		/* If this is the first time we've processed this symbol,
    883 		   fill in the plt entry with the correct symbol address.  */
    884 		if ((*plt_offset & 1) == 0)
    885 		  {
    886 		    unsigned int x;
    887 
    888 		    x = 0x00000200;  /* jmpf */
    889 		    x |= relocation & 0xff;
    890 		    x |= (relocation << 8) & 0xffff0000;
    891 		    bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
    892 		    *plt_offset |= 1;
    893 		  }
    894 
    895 		relocation = (splt->output_section->vma
    896 			      + splt->output_offset
    897 			      + (*plt_offset & -2));
    898 	      }
    899 	    r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    900 					  contents, rel->r_offset,
    901 					  relocation, 0);
    902 	    break;
    903 	  }
    904 
    905 	default:
    906 	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    907 					contents, rel->r_offset,
    908 					relocation, rel->r_addend);
    909 	  break;
    910 	}
    911 
    912       if (r != bfd_reloc_ok)
    913 	{
    914 	  const char * msg = NULL;
    915 
    916 	  switch (r)
    917 	    {
    918 	    case bfd_reloc_overflow:
    919 	      (*info->callbacks->reloc_overflow)
    920 		(info, (h ? &h->root : NULL), name, howto->name,
    921 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
    922 	      break;
    923 
    924 	    case bfd_reloc_undefined:
    925 	      (*info->callbacks->undefined_symbol)
    926 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
    927 	      break;
    928 
    929 	    case bfd_reloc_outofrange:
    930 	      msg = _("internal error: out of range error");
    931 	      break;
    932 
    933 	    case bfd_reloc_notsupported:
    934 	      msg = _("internal error: unsupported relocation error");
    935 	      break;
    936 
    937 	    case bfd_reloc_dangerous:
    938 	      msg = _("internal error: dangerous relocation");
    939 	      break;
    940 
    941 	    default:
    942 	      msg = _("internal error: unknown error");
    943 	      break;
    944 	    }
    945 
    946 	  if (msg)
    947 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
    948 					 input_section, rel->r_offset);
    949 	}
    950     }
    951 
    952   return TRUE;
    953 }
    954 
    955 /* This must exist if dynobj is ever set.  */
    956 
    957 static bfd_boolean
    958 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
    959 				       struct bfd_link_info *info)
    960 {
    961   bfd *dynobj = elf_hash_table (info)->dynobj;
    962   asection *splt = elf_hash_table (info)->splt;
    963 
    964   /* As an extra sanity check, verify that all plt entries have
    965      been filled in.  */
    966 
    967   if (dynobj != NULL && splt != NULL)
    968     {
    969       bfd_byte *contents = splt->contents;
    970       unsigned int i, size = splt->size;
    971 
    972       for (i = 0; i < size; i += 4)
    973 	{
    974 	  unsigned int x = bfd_get_32 (dynobj, contents + i);
    975 
    976 	  BFD_ASSERT (x != 0);
    977 	}
    978     }
    979 
    980   return TRUE;
    981 }
    982 
    983 /* Return the section that should be marked against GC for a given
    985    relocation.  */
    986 
    987 static asection *
    988 xstormy16_elf_gc_mark_hook (asection *sec,
    989 			    struct bfd_link_info *info,
    990 			    Elf_Internal_Rela *rel,
    991 			    struct elf_link_hash_entry *h,
    992 			    Elf_Internal_Sym *sym)
    993 {
    994   if (h != NULL)
    995     switch (ELF32_R_TYPE (rel->r_info))
    996       {
    997       case R_XSTORMY16_GNU_VTINHERIT:
    998       case R_XSTORMY16_GNU_VTENTRY:
    999 	return NULL;
   1000       }
   1001 
   1002   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
   1003 }
   1004 
   1005 #define ELF_ARCH		bfd_arch_xstormy16
   1007 #define ELF_MACHINE_CODE	EM_XSTORMY16
   1008 #define ELF_MAXPAGESIZE		0x100
   1009 
   1010 #define TARGET_LITTLE_SYM       xstormy16_elf32_vec
   1011 #define TARGET_LITTLE_NAME	"elf32-xstormy16"
   1012 
   1013 #define elf_info_to_howto_rel			NULL
   1014 #define elf_info_to_howto			xstormy16_info_to_howto_rela
   1015 #define elf_backend_relocate_section		xstormy16_elf_relocate_section
   1016 #define elf_backend_gc_mark_hook		xstormy16_elf_gc_mark_hook
   1017 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
   1018 #define elf_backend_always_size_sections \
   1019   xstormy16_elf_always_size_sections
   1020 #define elf_backend_omit_section_dynsym \
   1021   ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
   1022 #define elf_backend_finish_dynamic_sections \
   1023   xstormy16_elf_finish_dynamic_sections
   1024 
   1025 #define elf_backend_can_gc_sections		1
   1026 #define elf_backend_rela_normal			1
   1027 
   1028 #define bfd_elf32_bfd_reloc_type_lookup		xstormy16_reloc_type_lookup
   1029 #define bfd_elf32_bfd_reloc_name_lookup \
   1030   xstormy16_reloc_name_lookup
   1031 #define bfd_elf32_bfd_relax_section		xstormy16_elf_relax_section
   1032 
   1033 #include "elf32-target.h"
   1034