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