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