Home | History | Annotate | Download | only in bfd
      1 /* Xstormy16-specific support for 32-bit ELF.
      2    Copyright (C) 2000-2016 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   splt = NULL;
    423   dynobj = elf_hash_table(info)->dynobj;
    424 
    425   relend = relocs + sec->reloc_count;
    426   for (rel = relocs; rel < relend; ++rel)
    427     {
    428       unsigned long r_symndx;
    429       struct elf_link_hash_entry *h;
    430       bfd_vma *offset;
    431 
    432       r_symndx = ELF32_R_SYM (rel->r_info);
    433       if (r_symndx < symtab_hdr->sh_info)
    434 	h = NULL;
    435       else
    436 	{
    437 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
    438 	  while (h->root.type == bfd_link_hash_indirect
    439 		 || h->root.type == bfd_link_hash_warning)
    440 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    441 
    442 	  /* PR15323, ref flags aren't set for references in the same
    443 	     object.  */
    444 	  h->root.non_ir_ref = 1;
    445 	}
    446 
    447       switch (ELF32_R_TYPE (rel->r_info))
    448         {
    449 	  /* This relocation describes a 16-bit pointer to a function.
    450 	     We may need to allocate a thunk in low memory; reserve memory
    451 	     for it now.  */
    452 	case R_XSTORMY16_FPTR16:
    453 	  if (rel->r_addend != 0)
    454 	    {
    455 	      (*info->callbacks->warning)
    456 		(info, _("non-zero addend in @fptr reloc"), 0,
    457 		 abfd, 0, 0);
    458 	    }
    459 
    460 	  if (dynobj == NULL)
    461 	    elf_hash_table (info)->dynobj = dynobj = abfd;
    462 	  if (splt == NULL)
    463 	    {
    464 	      splt = bfd_get_linker_section (dynobj, ".plt");
    465 	      if (splt == NULL)
    466 		{
    467 		  flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
    468 				    | SEC_IN_MEMORY | SEC_LINKER_CREATED
    469 				    | SEC_READONLY | SEC_CODE);
    470 
    471 		  splt = bfd_make_section_anyway_with_flags (dynobj, ".plt",
    472 							     flags);
    473 		  if (splt == NULL
    474 		      || ! bfd_set_section_alignment (dynobj, splt, 1))
    475 		    return FALSE;
    476 		}
    477 	    }
    478 
    479 	  if (h != NULL)
    480 	    offset = &h->plt.offset;
    481 	  else
    482 	    {
    483 	      if (local_plt_offsets == NULL)
    484 		{
    485 		  size_t size;
    486 		  unsigned int i;
    487 
    488 		  size = symtab_hdr->sh_info * sizeof (bfd_vma);
    489 		  local_plt_offsets = bfd_alloc (abfd, size);
    490 		  if (local_plt_offsets == NULL)
    491 		    return FALSE;
    492 		  elf_local_got_offsets (abfd) = local_plt_offsets;
    493 
    494 		  for (i = 0; i < symtab_hdr->sh_info; i++)
    495 		    local_plt_offsets[i] = (bfd_vma) -1;
    496 		}
    497 	      offset = &local_plt_offsets[r_symndx];
    498 	    }
    499 
    500 	  if (*offset == (bfd_vma) -1)
    501 	    {
    502 	      *offset = splt->size;
    503 	      splt->size += 4;
    504 	    }
    505 	  break;
    506 
    507 	  /* This relocation describes the C++ object vtable hierarchy.
    508 	     Reconstruct it for later use during GC.  */
    509         case R_XSTORMY16_GNU_VTINHERIT:
    510           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
    511             return FALSE;
    512           break;
    513 
    514 	  /* This relocation describes which C++ vtable entries are actually
    515 	     used.  Record for later use during GC.  */
    516         case R_XSTORMY16_GNU_VTENTRY:
    517           BFD_ASSERT (h != NULL);
    518           if (h != NULL
    519               && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
    520             return FALSE;
    521           break;
    522 	}
    523     }
    524 
    525   return TRUE;
    526 }
    527 
    528 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
    529    is within the low 64k, remove any entry for it in the plt.  */
    530 
    531 struct relax_plt_data
    532 {
    533   asection *splt;
    534   bfd_boolean *again;
    535 };
    536 
    537 static bfd_boolean
    538 xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
    539 {
    540   struct relax_plt_data *data = (struct relax_plt_data *) xdata;
    541 
    542   if (h->plt.offset != (bfd_vma) -1)
    543     {
    544       bfd_vma address;
    545 
    546       if (h->root.type == bfd_link_hash_undefined
    547 	  || h->root.type == bfd_link_hash_undefweak)
    548 	address = 0;
    549       else
    550 	address = (h->root.u.def.section->output_section->vma
    551 		   + h->root.u.def.section->output_offset
    552 		   + h->root.u.def.value);
    553 
    554       if (address <= 0xffff)
    555 	{
    556 	  h->plt.offset = -1;
    557 	  data->splt->size -= 4;
    558 	  *data->again = TRUE;
    559 	}
    560     }
    561 
    562   return TRUE;
    563 }
    564 
    565 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
    566    previously had a plt entry, give it a new entry offset.  */
    567 
    568 static bfd_boolean
    569 xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
    570 {
    571   bfd_vma *entry = (bfd_vma *) xdata;
    572 
    573   if (h->plt.offset != (bfd_vma) -1)
    574     {
    575       h->plt.offset = *entry;
    576       *entry += 4;
    577     }
    578 
    579   return TRUE;
    580 }
    581 
    582 static bfd_boolean
    583 xstormy16_elf_relax_section (bfd *dynobj,
    584 			     asection *splt,
    585 			     struct bfd_link_info *info,
    586 			     bfd_boolean *again)
    587 {
    588   struct relax_plt_data relax_plt_data;
    589   bfd *ibfd;
    590 
    591   /* Assume nothing changes.  */
    592   *again = FALSE;
    593 
    594   if (bfd_link_relocatable (info))
    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 bfd_boolean
    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 = bfd_get_linker_section (dynobj, ".plt");
    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 bfd_boolean
    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   bfd *dynobj;
    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   dynobj = elf_hash_table (info)->dynobj;
    787   splt = NULL;
    788   if (dynobj != NULL)
    789     splt = bfd_get_linker_section (dynobj, ".plt");
    790 
    791   for (rel = relocs; rel < relend; rel ++)
    792     {
    793       reloc_howto_type *           howto;
    794       unsigned long                r_symndx;
    795       Elf_Internal_Sym *           sym;
    796       asection *                   sec;
    797       struct elf_link_hash_entry * h;
    798       bfd_vma                      relocation;
    799       bfd_reloc_status_type        r;
    800       const char *                 name = NULL;
    801       int                          r_type;
    802 
    803       r_type = ELF32_R_TYPE (rel->r_info);
    804 
    805       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
    806 	  || r_type == R_XSTORMY16_GNU_VTENTRY)
    807 	continue;
    808 
    809       r_symndx = ELF32_R_SYM (rel->r_info);
    810       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
    811       h      = NULL;
    812       sym    = NULL;
    813       sec    = NULL;
    814 
    815       if (r_symndx < symtab_hdr->sh_info)
    816 	{
    817 	  sym = local_syms + r_symndx;
    818 	  sec = local_sections [r_symndx];
    819 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
    820 	}
    821       else
    822 	{
    823 	  bfd_boolean unresolved_reloc, warned, ignored;
    824 
    825 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    826 				   r_symndx, symtab_hdr, sym_hashes,
    827 				   h, sec, relocation,
    828 				   unresolved_reloc, warned, ignored);
    829 	}
    830 
    831       if (sec != NULL && discarded_section (sec))
    832 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
    833 					 rel, 1, relend, howto, 0, contents);
    834 
    835       if (bfd_link_relocatable (info))
    836 	continue;
    837 
    838       if (h != NULL)
    839 	name = h->root.root.string;
    840       else
    841 	{
    842 	  name = (bfd_elf_string_from_elf_section
    843 		  (input_bfd, symtab_hdr->sh_link, sym->st_name));
    844 	  if (name == NULL || *name == '\0')
    845 	    name = bfd_section_name (input_bfd, sec);
    846 	}
    847 
    848       switch (ELF32_R_TYPE (rel->r_info))
    849 	{
    850 	case R_XSTORMY16_24:
    851 	  {
    852 	    bfd_vma reloc = relocation + rel->r_addend;
    853 	    unsigned int x;
    854 
    855 	    x = bfd_get_32 (input_bfd, contents + rel->r_offset);
    856 	    x &= 0x0000ff00;
    857 	    x |= reloc & 0xff;
    858 	    x |= (reloc << 8) & 0xffff0000;
    859 	    bfd_put_32 (input_bfd, x, contents + rel->r_offset);
    860 
    861 	    if (reloc & ~0xffffff)
    862 	      r = bfd_reloc_overflow;
    863 	    else
    864 	      r = bfd_reloc_ok;
    865 	    break;
    866 	  }
    867 
    868 	case R_XSTORMY16_FPTR16:
    869 	  {
    870 	    bfd_vma *plt_offset;
    871 
    872 	    if (h != NULL)
    873 	      plt_offset = &h->plt.offset;
    874 	    else
    875 	      plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
    876 
    877 	    if (relocation <= 0xffff)
    878 	      {
    879 	        /* If the symbol is in range for a 16-bit address, we should
    880 		   have deallocated the plt entry in relax_section.  */
    881 	        BFD_ASSERT (*plt_offset == (bfd_vma) -1);
    882 	      }
    883 	    else
    884 	      {
    885 		/* If the symbol is out of range for a 16-bit address,
    886 		   we must have allocated a plt entry.  */
    887 		BFD_ASSERT (*plt_offset != (bfd_vma) -1);
    888 
    889 		/* If this is the first time we've processed this symbol,
    890 		   fill in the plt entry with the correct symbol address.  */
    891 		if ((*plt_offset & 1) == 0)
    892 		  {
    893 		    unsigned int x;
    894 
    895 		    x = 0x00000200;  /* jmpf */
    896 		    x |= relocation & 0xff;
    897 		    x |= (relocation << 8) & 0xffff0000;
    898 		    bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
    899 		    *plt_offset |= 1;
    900 		  }
    901 
    902 		relocation = (splt->output_section->vma
    903 			      + splt->output_offset
    904 			      + (*plt_offset & -2));
    905 	      }
    906 	    r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    907 					  contents, rel->r_offset,
    908 					  relocation, 0);
    909 	    break;
    910 	  }
    911 
    912 	default:
    913 	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
    914 					contents, rel->r_offset,
    915 					relocation, rel->r_addend);
    916 	  break;
    917 	}
    918 
    919       if (r != bfd_reloc_ok)
    920 	{
    921 	  const char * msg = NULL;
    922 
    923 	  switch (r)
    924 	    {
    925 	    case bfd_reloc_overflow:
    926 	      (*info->callbacks->reloc_overflow)
    927 		(info, (h ? &h->root : NULL), name, howto->name,
    928 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
    929 	      break;
    930 
    931 	    case bfd_reloc_undefined:
    932 	      (*info->callbacks->undefined_symbol)
    933 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
    934 	      break;
    935 
    936 	    case bfd_reloc_outofrange:
    937 	      msg = _("internal error: out of range error");
    938 	      break;
    939 
    940 	    case bfd_reloc_notsupported:
    941 	      msg = _("internal error: unsupported relocation error");
    942 	      break;
    943 
    944 	    case bfd_reloc_dangerous:
    945 	      msg = _("internal error: dangerous relocation");
    946 	      break;
    947 
    948 	    default:
    949 	      msg = _("internal error: unknown error");
    950 	      break;
    951 	    }
    952 
    953 	  if (msg)
    954 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
    955 					 input_section, rel->r_offset);
    956 	}
    957     }
    958 
    959   return TRUE;
    960 }
    961 
    962 /* This must exist if dynobj is ever set.  */
    963 
    964 static bfd_boolean
    965 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
    966 				       struct bfd_link_info *info)
    967 {
    968   bfd *dynobj;
    969   asection *splt;
    970 
    971   /* As an extra sanity check, verify that all plt entries have
    972      been filled in.  */
    973 
    974   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
    975       && (splt = bfd_get_linker_section (dynobj, ".plt")) != NULL)
    976     {
    977       bfd_byte *contents = splt->contents;
    978       unsigned int i, size = splt->size;
    979 
    980       for (i = 0; i < size; i += 4)
    981 	{
    982 	  unsigned int x = bfd_get_32 (dynobj, contents + i);
    983 
    984 	  BFD_ASSERT (x != 0);
    985 	}
    986     }
    987 
    988   return TRUE;
    989 }
    990 
    991 /* Return the section that should be marked against GC for a given
    993    relocation.  */
    994 
    995 static asection *
    996 xstormy16_elf_gc_mark_hook (asection *sec,
    997 			    struct bfd_link_info *info,
    998 			    Elf_Internal_Rela *rel,
    999 			    struct elf_link_hash_entry *h,
   1000 			    Elf_Internal_Sym *sym)
   1001 {
   1002   if (h != NULL)
   1003     switch (ELF32_R_TYPE (rel->r_info))
   1004       {
   1005       case R_XSTORMY16_GNU_VTINHERIT:
   1006       case R_XSTORMY16_GNU_VTENTRY:
   1007 	return NULL;
   1008       }
   1009 
   1010   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
   1011 }
   1012 
   1013 #define ELF_ARCH		bfd_arch_xstormy16
   1015 #define ELF_MACHINE_CODE	EM_XSTORMY16
   1016 #define ELF_MAXPAGESIZE		0x100
   1017 
   1018 #define TARGET_LITTLE_SYM       xstormy16_elf32_vec
   1019 #define TARGET_LITTLE_NAME	"elf32-xstormy16"
   1020 
   1021 #define elf_info_to_howto_rel			NULL
   1022 #define elf_info_to_howto			xstormy16_info_to_howto_rela
   1023 #define elf_backend_relocate_section		xstormy16_elf_relocate_section
   1024 #define elf_backend_gc_mark_hook		xstormy16_elf_gc_mark_hook
   1025 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
   1026 #define elf_backend_always_size_sections \
   1027   xstormy16_elf_always_size_sections
   1028 #define elf_backend_omit_section_dynsym \
   1029   ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
   1030 #define elf_backend_finish_dynamic_sections \
   1031   xstormy16_elf_finish_dynamic_sections
   1032 
   1033 #define elf_backend_can_gc_sections		1
   1034 #define elf_backend_rela_normal			1
   1035 
   1036 #define bfd_elf32_bfd_reloc_type_lookup		xstormy16_reloc_type_lookup
   1037 #define bfd_elf32_bfd_reloc_name_lookup \
   1038   xstormy16_reloc_name_lookup
   1039 #define bfd_elf32_bfd_relax_section		xstormy16_elf_relax_section
   1040 
   1041 #include "elf32-target.h"
   1042