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