(root)/
binutils-2.41/
bfd/
elf32-d10v.c
       1  /* D10V-specific support for 32-bit ELF
       2     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       3     Contributed by Martin Hunt (hunt@cygnus.com).
       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/d10v.h"
      27  
      28  /* Use REL instead of RELA to save space.  */
      29  #define USE_REL	1
      30  
      31  static reloc_howto_type elf_d10v_howto_table[] =
      32  {
      33    /* This reloc does nothing.  */
      34    HOWTO (R_D10V_NONE,		/* Type.  */
      35  	 0,			/* Rightshift.  */
      36  	 0,			/* Size.  */
      37  	 0,			/* Bitsize.  */
      38  	 false,			/* PC_relative.  */
      39  	 0,			/* Bitpos.  */
      40  	 complain_overflow_dont,/* Complain_on_overflow.  */
      41  	 bfd_elf_generic_reloc, /* Special_function.  */
      42  	 "R_D10V_NONE",		/* Name.  */
      43  	 false,			/* Partial_inplace.  */
      44  	 0,			/* Src_mask.  */
      45  	 0,			/* Dst_mask.  */
      46  	 false),		/* PCrel_offset.  */
      47  
      48    /* An PC Relative 10-bit relocation, shifted by 2, right container.  */
      49    HOWTO (R_D10V_10_PCREL_R,	/* Type.  */
      50  	 2,			/* Rightshift.  */
      51  	 4,			/* Size.  */
      52  	 8,			/* Bitsize.  */
      53  	 true,			/* PC_relative.  */
      54  	 0,			/* Bitpos.  */
      55  	 complain_overflow_signed, /* Complain_on_overflow.  */
      56  	 bfd_elf_generic_reloc, /* Special_function.  */
      57  	 "R_D10V_10_PCREL_R",	/* Name.  */
      58  	 false,			/* Partial_inplace.  */
      59  	 0xff,			/* Src_mask.  */
      60  	 0xff,			/* Dst_mask.  */
      61  	 true),			/* PCrel_offset.  */
      62  
      63    /* An PC Relative 10-bit relocation, shifted by 2, left container.  */
      64    HOWTO (R_D10V_10_PCREL_L,	/* Type.  */
      65  	 2,			/* Rightshift.  */
      66  	 4,			/* Size.  */
      67  	 8,			/* Bitsize.  */
      68  	 true,			/* PC_relative.  */
      69  	 15,			/* Bitpos.  */
      70  	 complain_overflow_signed, /* Complain_on_overflow.  */
      71  	 bfd_elf_generic_reloc, /* Special_function.  */
      72  	 "R_D10V_10_PCREL_L",	/* Name.  */
      73  	 false,			/* Partial_inplace.  */
      74  	 0x07f8000,		/* Src_mask.  */
      75  	 0x07f8000,		/* Dst_mask.  */
      76  	 true),			/* PCrel_offset.  */
      77  
      78    /* A 16 bit absolute relocation.  */
      79    HOWTO (R_D10V_16,		/* Type.  */
      80  	 0,			/* Rightshift.  */
      81  	 2,			/* Size.  */
      82  	 16,			/* Bitsize.  */
      83  	 false,			/* PC_relative.  */
      84  	 0,			/* Bitpos.  */
      85  	 complain_overflow_dont,/* Complain_on_overflow.  */
      86  	 bfd_elf_generic_reloc, /* Special_function.  */
      87  	 "R_D10V_16",		/* Name.  */
      88  	 false,			/* Partial_inplace.  */
      89  	 0xffff,		/* Src_mask.  */
      90  	 0xffff,		/* Dst_mask.  */
      91  	 false),		/* PCrel_offset.  */
      92  
      93    /* An 18 bit absolute relocation, right shifted 2.  */
      94    HOWTO (R_D10V_18,		/* Type.  */
      95  	 2,			/* Rightshift.  */
      96  	 2,			/* Size.  */
      97  	 16,			/* Bitsize.  */
      98  	 false,			/* PC_relative.  */
      99  	 0,			/* Bitpos.  */
     100  	 complain_overflow_dont, /* Complain_on_overflow.  */
     101  	 bfd_elf_generic_reloc, /* Special_function.  */
     102  	 "R_D10V_18",		/* Name.  */
     103  	 false,			/* Partial_inplace.  */
     104  	 0xffff,		/* Src_mask.  */
     105  	 0xffff,		/* Dst_mask.  */
     106  	 false),		/* PCrel_offset.  */
     107  
     108    /* A relative 18 bit relocation, right shifted by 2.  */
     109    HOWTO (R_D10V_18_PCREL,	/* Type.  */
     110  	 2,			/* Rightshift.  */
     111  	 4,			/* Size.  */
     112  	 16,			/* Bitsize.  */
     113  	 true,			/* PC_relative.  */
     114  	 0,			/* Bitpos.  */
     115  	 complain_overflow_signed, /* Complain_on_overflow.  */
     116  	 bfd_elf_generic_reloc, /* Special_function.  */
     117  	 "R_D10V_18_PCREL",	/* Name.  */
     118  	 false,			/* Partial_inplace.  */
     119  	 0xffff,		/* Src_mask.  */
     120  	 0xffff,		/* Dst_mask.  */
     121  	 true),			/* PCrel_offset.  */
     122  
     123    /* A 32 bit absolute relocation.  */
     124    HOWTO (R_D10V_32,		/* Type.  */
     125  	 0,			/* Rightshift.  */
     126  	 4,			/* Size.  */
     127  	 32,			/* Bitsize.  */
     128  	 false,			/* PC_relative.  */
     129  	 0,			/* Bitpos.  */
     130  	 complain_overflow_dont,/* Complain_on_overflow.  */
     131  	 bfd_elf_generic_reloc, /* Special_function.  */
     132  	 "R_D10V_32",		/* Name.  */
     133  	 false,			/* Partial_inplace.  */
     134  	 0xffffffff,		/* Src_mask.  */
     135  	 0xffffffff,		/* Dst_mask.  */
     136  	 false),		/* PCrel_offset.  */
     137  
     138    /* GNU extension to record C++ vtable hierarchy.  */
     139    HOWTO (R_D10V_GNU_VTINHERIT,	/* Type.  */
     140  	 0,			/* Rightshift.  */
     141  	 4,			/* Size.  */
     142  	 0,			/* Bitsize.  */
     143  	 false,			/* PC_relative.  */
     144  	 0,			/* Bitpos.  */
     145  	 complain_overflow_dont,/* Complain_on_overflow.  */
     146  	 NULL,			/* Special_function.  */
     147  	 "R_D10V_GNU_VTINHERIT",/* Name.  */
     148  	 false,			/* Partial_inplace.  */
     149  	 0,			/* Src_mask.  */
     150  	 0,			/* Dst_mask.  */
     151  	 false),		/* PCrel_offset.  */
     152  
     153    /* GNU extension to record C++ vtable member usage.  */
     154    HOWTO (R_D10V_GNU_VTENTRY,	/* Type.  */
     155  	 0,			/* Rightshift.  */
     156  	 4,			/* Size.  */
     157  	 0,			/* Bitsize.  */
     158  	 false,			/* PC_relative.  */
     159  	 0,			/* Bitpos.  */
     160  	 complain_overflow_dont,/* Complain_on_overflow.  */
     161  	 _bfd_elf_rel_vtable_reloc_fn,  /* Special_function.  */
     162  	 "R_D10V_GNU_VTENTRY",	/* Name.  */
     163  	 false,			/* Partial_inplace.  */
     164  	 0,			/* Src_mask.  */
     165  	 0,			/* Dst_mask.  */
     166  	 false),		/* PCrel_offset.  */
     167  };
     168  
     169  /* Map BFD reloc types to D10V ELF reloc types.  */
     170  
     171  struct d10v_reloc_map
     172  {
     173    bfd_reloc_code_real_type bfd_reloc_val;
     174    unsigned char elf_reloc_val;
     175  };
     176  
     177  static const struct d10v_reloc_map d10v_reloc_map[] =
     178  {
     179    { BFD_RELOC_NONE, R_D10V_NONE, },
     180    { BFD_RELOC_D10V_10_PCREL_R, R_D10V_10_PCREL_R },
     181    { BFD_RELOC_D10V_10_PCREL_L, R_D10V_10_PCREL_L },
     182    { BFD_RELOC_16, R_D10V_16 },
     183    { BFD_RELOC_D10V_18, R_D10V_18 },
     184    { BFD_RELOC_D10V_18_PCREL, R_D10V_18_PCREL },
     185    { BFD_RELOC_32, R_D10V_32 },
     186    { BFD_RELOC_VTABLE_INHERIT, R_D10V_GNU_VTINHERIT },
     187    { BFD_RELOC_VTABLE_ENTRY, R_D10V_GNU_VTENTRY },
     188  };
     189  
     190  static reloc_howto_type *
     191  bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     192  				 bfd_reloc_code_real_type code)
     193  {
     194    unsigned int i;
     195  
     196    for (i = 0;
     197         i < sizeof (d10v_reloc_map) / sizeof (struct d10v_reloc_map);
     198         i++)
     199      if (d10v_reloc_map[i].bfd_reloc_val == code)
     200        return &elf_d10v_howto_table[d10v_reloc_map[i].elf_reloc_val];
     201  
     202    return NULL;
     203  }
     204  
     205  static reloc_howto_type *
     206  bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     207  				 const char *r_name)
     208  {
     209    unsigned int i;
     210  
     211    for (i = 0;
     212         i < sizeof (elf_d10v_howto_table) / sizeof (elf_d10v_howto_table[0]);
     213         i++)
     214      if (elf_d10v_howto_table[i].name != NULL
     215  	&& strcasecmp (elf_d10v_howto_table[i].name, r_name) == 0)
     216        return &elf_d10v_howto_table[i];
     217  
     218    return NULL;
     219  }
     220  
     221  /* Set the howto pointer for an D10V ELF reloc.  */
     222  
     223  static bool
     224  d10v_info_to_howto_rel (bfd *abfd,
     225  			arelent *cache_ptr,
     226  			Elf_Internal_Rela *dst)
     227  {
     228    unsigned int r_type;
     229  
     230    r_type = ELF32_R_TYPE (dst->r_info);
     231    if (r_type >= (unsigned int) R_D10V_max)
     232      {
     233        /* xgettext:c-format */
     234        _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
     235  			  abfd, r_type);
     236        bfd_set_error (bfd_error_bad_value);
     237        return false;
     238      }
     239    cache_ptr->howto = &elf_d10v_howto_table[r_type];
     240    return true;
     241  }
     242  
     243  static asection *
     244  elf32_d10v_gc_mark_hook (asection *sec,
     245  			 struct bfd_link_info *info,
     246  			 Elf_Internal_Rela *rel,
     247  			 struct elf_link_hash_entry *h,
     248  			 Elf_Internal_Sym *sym)
     249  {
     250    if (h != NULL)
     251      switch (ELF32_R_TYPE (rel->r_info))
     252        {
     253        case R_D10V_GNU_VTINHERIT:
     254        case R_D10V_GNU_VTENTRY:
     255  	return NULL;
     256        }
     257  
     258    return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
     259  }
     260  
     261  /* Look through the relocs for a section during the first phase.
     262     Since we don't do .gots or .plts, we just need to consider the
     263     virtual table relocs for gc.  */
     264  
     265  static bool
     266  elf32_d10v_check_relocs (bfd *abfd,
     267  			 struct bfd_link_info *info,
     268  			 asection *sec,
     269  			 const Elf_Internal_Rela *relocs)
     270  {
     271    Elf_Internal_Shdr *symtab_hdr;
     272    struct elf_link_hash_entry **sym_hashes;
     273    const Elf_Internal_Rela *rel;
     274    const Elf_Internal_Rela *rel_end;
     275  
     276    if (bfd_link_relocatable (info))
     277      return true;
     278  
     279    symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
     280    sym_hashes = elf_sym_hashes (abfd);
     281  
     282    rel_end = relocs + sec->reloc_count;
     283    for (rel = relocs; rel < rel_end; rel++)
     284      {
     285        struct elf_link_hash_entry *h;
     286        unsigned long r_symndx;
     287  
     288        r_symndx = ELF32_R_SYM (rel->r_info);
     289        if (r_symndx < symtab_hdr->sh_info)
     290  	h = NULL;
     291        else
     292  	{
     293  	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
     294  	  while (h->root.type == bfd_link_hash_indirect
     295  		 || h->root.type == bfd_link_hash_warning)
     296  	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
     297  	}
     298  
     299        switch (ELF32_R_TYPE (rel->r_info))
     300  	{
     301  	/* This relocation describes the C++ object vtable hierarchy.
     302  	   Reconstruct it for later use during GC.  */
     303  	case R_D10V_GNU_VTINHERIT:
     304  	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
     305  	    return false;
     306  	  break;
     307  
     308  	/* This relocation describes which C++ vtable entries are actually
     309  	   used.  Record for later use during GC.  */
     310  	case R_D10V_GNU_VTENTRY:
     311  	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
     312  	    return false;
     313  	  break;
     314  	}
     315      }
     316  
     317    return true;
     318  }
     319  
     320  static bfd_vma
     321  extract_rel_addend (bfd *abfd,
     322  		    bfd_byte *where,
     323  		    reloc_howto_type *howto)
     324  {
     325    bfd_vma insn, val;
     326  
     327    switch (bfd_get_reloc_size (howto))
     328      {
     329      case 1:
     330        insn = bfd_get_8 (abfd, where);
     331        break;
     332      case 2:
     333        insn = bfd_get_16 (abfd, where);
     334        break;
     335      case 4:
     336        insn = bfd_get_32 (abfd, where);
     337        break;
     338      default:
     339        abort ();
     340      }
     341  
     342    val = (insn & howto->dst_mask) >> howto->bitpos << howto->rightshift;
     343    /* We should really be testing for signed addends here, but we don't
     344       have that info directly in the howto.  */
     345    if (howto->pc_relative)
     346      {
     347        bfd_vma sign;
     348        sign = howto->dst_mask & (~howto->dst_mask >> 1 | ~(-(bfd_vma) 1 >> 1));
     349        sign = sign >> howto->bitpos << howto->rightshift;
     350        val = (val ^ sign) - sign;
     351      }
     352    return val;
     353  }
     354  
     355  static void
     356  insert_rel_addend (bfd *abfd,
     357  		   bfd_byte *where,
     358  		   reloc_howto_type *howto,
     359  		   bfd_vma addend)
     360  {
     361    bfd_vma insn;
     362  
     363    addend = (addend >> howto->rightshift << howto->bitpos) & howto->dst_mask;
     364    insn = ~howto->dst_mask;
     365    switch (bfd_get_reloc_size (howto))
     366      {
     367      case 1:
     368        insn &= bfd_get_8 (abfd, where);
     369        insn |= addend;
     370        bfd_put_8 (abfd, insn, where);
     371        break;
     372      case 2:
     373        insn &= bfd_get_16 (abfd, where);
     374        insn |= addend;
     375        bfd_put_16 (abfd, insn, where);
     376        break;
     377      case 4:
     378        insn &= bfd_get_32 (abfd, where);
     379        insn |= addend;
     380        bfd_put_32 (abfd, insn, where);
     381        break;
     382      default:
     383        abort ();
     384      }
     385  }
     386  
     387  /* Relocate a D10V ELF section.  */
     388  
     389  static int
     390  elf32_d10v_relocate_section (bfd *output_bfd,
     391  			     struct bfd_link_info *info,
     392  			     bfd *input_bfd,
     393  			     asection *input_section,
     394  			     bfd_byte *contents,
     395  			     Elf_Internal_Rela *relocs,
     396  			     Elf_Internal_Sym *local_syms,
     397  			     asection **local_sections)
     398  {
     399    Elf_Internal_Shdr *symtab_hdr;
     400    struct elf_link_hash_entry **sym_hashes;
     401    Elf_Internal_Rela *rel, *relend;
     402    const char *name;
     403  
     404    symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
     405    sym_hashes = elf_sym_hashes (input_bfd);
     406  
     407    rel = relocs;
     408    relend = relocs + input_section->reloc_count;
     409    for (; rel < relend; rel++)
     410      {
     411        int r_type;
     412        reloc_howto_type *howto;
     413        unsigned long r_symndx;
     414        Elf_Internal_Sym *sym;
     415        asection *sec;
     416        struct elf_link_hash_entry *h;
     417        bfd_vma relocation;
     418        bfd_reloc_status_type r;
     419  
     420        r_symndx = ELF32_R_SYM (rel->r_info);
     421        r_type = ELF32_R_TYPE (rel->r_info);
     422  
     423        if (r_type == R_D10V_GNU_VTENTRY
     424  	  || r_type == R_D10V_GNU_VTINHERIT)
     425  	continue;
     426  
     427        howto = elf_d10v_howto_table + r_type;
     428        h = NULL;
     429        sym = NULL;
     430        sec = NULL;
     431        if (r_symndx < symtab_hdr->sh_info)
     432  	{
     433  	  sym = local_syms + r_symndx;
     434  	  sec = local_sections[r_symndx];
     435  	  relocation = (sec->output_section->vma
     436  			+ sec->output_offset
     437  			+ sym->st_value);
     438  	  if (ELF_ST_TYPE (sym->st_info) == STT_SECTION
     439  	      && ((sec->flags & SEC_MERGE) != 0
     440  		  || (bfd_link_relocatable (info)
     441  		      && sec->output_offset != 0)))
     442  	    {
     443  	      bfd_vma addend;
     444  	      bfd_byte *where = contents + rel->r_offset;
     445  
     446  	      addend = extract_rel_addend (input_bfd, where, howto);
     447  
     448  	      if (bfd_link_relocatable (info))
     449  		addend += sec->output_offset;
     450  	      else
     451  		{
     452  		  asection *msec = sec;
     453  		  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec,
     454  						   addend);
     455  		  addend -= relocation;
     456  		  addend += msec->output_section->vma + msec->output_offset;
     457  		}
     458  	      insert_rel_addend (input_bfd, where, howto, addend);
     459  	    }
     460  	}
     461        else
     462  	{
     463  	  bool unresolved_reloc, warned, ignored;
     464  
     465  	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
     466  				   r_symndx, symtab_hdr, sym_hashes,
     467  				   h, sec, relocation,
     468  				   unresolved_reloc, warned, ignored);
     469  	}
     470  
     471        if (sec != NULL && discarded_section (sec))
     472  	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
     473  					 rel, 1, relend, howto, 0, contents);
     474  
     475        if (bfd_link_relocatable (info))
     476  	continue;
     477  
     478        if (h != NULL)
     479  	name = h->root.root.string;
     480        else
     481  	{
     482  	  name = (bfd_elf_string_from_elf_section
     483  		  (input_bfd, symtab_hdr->sh_link, sym->st_name));
     484  	  if (name == NULL || *name == '\0')
     485  	    name = bfd_section_name (sec);
     486  	}
     487  
     488        r = _bfd_final_link_relocate (howto, input_bfd, input_section,
     489  				    contents, rel->r_offset,
     490  				    relocation, (bfd_vma) 0);
     491  
     492        if (r != bfd_reloc_ok)
     493  	{
     494  	  const char * msg = (const char *) 0;
     495  
     496  	  switch (r)
     497  	    {
     498  	    case bfd_reloc_overflow:
     499  	      (*info->callbacks->reloc_overflow)
     500  		(info, (h ? &h->root : NULL), name, howto->name,
     501  		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
     502  	      break;
     503  
     504  	    case bfd_reloc_undefined:
     505  	      (*info->callbacks->undefined_symbol)
     506  		(info, name, input_bfd, input_section, rel->r_offset, true);
     507  	      break;
     508  
     509  	    case bfd_reloc_outofrange:
     510  	      msg = _("internal error: out of range error");
     511  	      goto common_error;
     512  
     513  	    case bfd_reloc_notsupported:
     514  	      msg = _("internal error: unsupported relocation error");
     515  	      goto common_error;
     516  
     517  	    case bfd_reloc_dangerous:
     518  	      msg = _("internal error: dangerous error");
     519  	      goto common_error;
     520  
     521  	    default:
     522  	      msg = _("internal error: unknown error");
     523  	      /* fall through */
     524  
     525  	    common_error:
     526  	      (*info->callbacks->warning) (info, msg, name, input_bfd,
     527  					   input_section, rel->r_offset);
     528  	      break;
     529  	    }
     530  	}
     531      }
     532  
     533    return true;
     534  }
     535  #define ELF_ARCH		bfd_arch_d10v
     536  #define ELF_MACHINE_CODE	EM_D10V
     537  #define ELF_MACHINE_ALT1	EM_CYGNUS_D10V
     538  #define ELF_MAXPAGESIZE		0x1000
     539  
     540  #define TARGET_BIG_SYM		d10v_elf32_vec
     541  #define TARGET_BIG_NAME		"elf32-d10v"
     542  
     543  #define elf_info_to_howto		     NULL
     544  #define elf_info_to_howto_rel		     d10v_info_to_howto_rel
     545  #define elf_backend_object_p		     0
     546  #define elf_backend_gc_mark_hook	     elf32_d10v_gc_mark_hook
     547  #define elf_backend_check_relocs	     elf32_d10v_check_relocs
     548  #define elf_backend_relocate_section	     elf32_d10v_relocate_section
     549  #define elf_backend_can_gc_sections	     1
     550  
     551  #include "elf32-target.h"