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