(root)/
binutils-2.41/
bfd/
arc-got.h
       1  /* ARC-specific support for 32-bit ELF
       2     Copyright (C) 1994-2023 Free Software Foundation, Inc.
       3     Contributed by Cupertino Miranda (cmiranda@synopsys.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  #ifndef ARC_GOT_H
      23  #define ARC_GOT_H
      24  
      25  #define TCB_SIZE (8)
      26  
      27  #define	align_power(addr, align)	\
      28    (((addr) + ((bfd_vma) 1 << (align)) - 1) & (-((bfd_vma) 1 << (align))))
      29  
      30  enum tls_type_e
      31  {
      32    GOT_UNKNOWN = 0,
      33    GOT_NORMAL,
      34    GOT_TLS_GD,
      35    GOT_TLS_IE,
      36    GOT_TLS_LE
      37  };
      38  
      39  enum tls_got_entries
      40  {
      41    TLS_GOT_NONE = 0,
      42    TLS_GOT_MOD,
      43    TLS_GOT_OFF,
      44    TLS_GOT_MOD_AND_OFF
      45  };
      46  
      47  struct got_entry
      48  {
      49    struct got_entry *next;
      50    enum tls_type_e type;
      51    bfd_vma offset;
      52    bool processed;
      53    bool created_dyn_relocation;
      54    enum tls_got_entries existing_entries;
      55  };
      56  
      57  /* Return the local got list, if not defined, create an empty one.  */
      58  
      59  static struct got_entry **
      60  arc_get_local_got_ents (bfd * abfd)
      61  {
      62    if (elf_local_got_ents (abfd) == NULL)
      63      {
      64        bfd_size_type amt = (elf_tdata (abfd)->symtab_hdr.sh_info
      65  			   * sizeof (*elf_local_got_ents (abfd)));
      66        elf_local_got_ents (abfd) = bfd_zmalloc (amt);
      67        if (elf_local_got_ents (abfd) == NULL)
      68  	{
      69  	  _bfd_error_handler (_("%pB: cannot allocate memory for local "
      70  				"GOT entries"), abfd);
      71  	  bfd_set_error (bfd_error_bad_value);
      72  	  return NULL;
      73  	}
      74      }
      75  
      76    return elf_local_got_ents (abfd);
      77  }
      78  
      79  static struct got_entry *
      80  got_entry_for_type (struct got_entry **list,
      81  		    enum tls_type_e type)
      82  {
      83    struct got_entry **p = list;
      84  
      85    while (*p != NULL)
      86      {
      87        if ((*p)->type == type)
      88  	return *p;
      89        p = &((*p)->next);
      90      }
      91    return NULL;
      92  }
      93  
      94  static void
      95  new_got_entry_to_list (struct got_entry **list,
      96  		       enum tls_type_e type,
      97  		       bfd_vma offset,
      98  		       enum tls_got_entries existing_entries)
      99  {
     100    /* Find list end.  Avoid having multiple entries of the same
     101       type.  */
     102    struct got_entry **p = list;
     103    struct got_entry *entry;
     104  
     105    while (*p != NULL)
     106      {
     107        if ((*p)->type == type)
     108  	return;
     109        p = &((*p)->next);
     110      }
     111  
     112    entry = (struct got_entry *) xmalloc (sizeof (struct got_entry));
     113  
     114    entry->type = type;
     115    entry->offset = offset;
     116    entry->next = NULL;
     117    entry->processed = false;
     118    entry->created_dyn_relocation = false;
     119    entry->existing_entries = existing_entries;
     120  
     121    ARC_DEBUG ("New GOT got entry added to list: "
     122  	     "type: %d, offset: %ld, existing_entries: %d\n",
     123  	     type, (long) offset, existing_entries);
     124  
     125    /* Add the entry to the end of the list.  */
     126    *p = entry;
     127  }
     128  
     129  static enum tls_type_e
     130  tls_type_for_reloc (reloc_howto_type *howto)
     131  {
     132    enum tls_type_e ret = GOT_UNKNOWN;
     133  
     134    if (is_reloc_for_GOT (howto))
     135      return GOT_NORMAL;
     136  
     137    switch (howto->type)
     138      {
     139      case R_ARC_TLS_GD_GOT:
     140        ret = GOT_TLS_GD;
     141        break;
     142      case R_ARC_TLS_IE_GOT:
     143        ret = GOT_TLS_IE;
     144        break;
     145      case R_ARC_TLS_LE_32:
     146        ret = GOT_TLS_LE;
     147        break;
     148      default:
     149        ret = GOT_UNKNOWN;
     150        break;
     151      }
     152  
     153    return ret;
     154  };
     155  
     156  static struct got_entry **
     157  get_got_entry_list_for_symbol (bfd *abfd,
     158  			       unsigned long r_symndx,
     159  			       struct elf_link_hash_entry *h)
     160  {
     161    struct elf_arc_link_hash_entry *h1 =
     162      ((struct elf_arc_link_hash_entry *) h);
     163    if (h1 != NULL)
     164      {
     165        return &h1->got_ents;
     166      }
     167    else
     168      {
     169        return arc_get_local_got_ents (abfd) + r_symndx;
     170      }
     171  }
     172  
     173  
     174  static enum tls_type_e
     175  arc_got_entry_type_for_reloc (reloc_howto_type *howto)
     176  {
     177    enum tls_type_e type = GOT_UNKNOWN;
     178  
     179    if (is_reloc_for_GOT (howto))
     180      return  GOT_NORMAL;
     181  
     182    if (is_reloc_for_TLS (howto))
     183      {
     184        switch (howto->type)
     185  	{
     186  	  case R_ARC_TLS_GD_GOT:
     187  	    type = GOT_TLS_GD;
     188  	    break;
     189  	  case R_ARC_TLS_IE_GOT:
     190  	    type = GOT_TLS_IE;
     191  	    break;
     192  	  default:
     193  	    break;
     194  	}
     195      }
     196    return type;
     197  }
     198  
     199  #define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H)	\
     200    htab->s##SECNAME->size;						\
     201    {									\
     202      if (COND_FOR_RELOC)							\
     203        {									\
     204  	htab->srel##SECNAME->size += sizeof (Elf32_External_Rela);	\
     205  	  ARC_DEBUG ("arc_info: Added reloc space in "			\
     206  		     #SECNAME " section at " __FILE__			\
     207  		     ":%d for symbol %s\n",				\
     208  		     __LINE__, name_for_global_symbol (H));		\
     209        }									\
     210      if (H)								\
     211        if (H->dynindx == -1 && !H->forced_local)				\
     212  	if (! bfd_elf_link_record_dynamic_symbol (info, H))		\
     213  	  return false;							\
     214       htab->s##SECNAME->size += 4;					\
     215     }									\
     216  
     217  static bool
     218  arc_fill_got_info_for_reloc (enum tls_type_e type,
     219  			     struct got_entry **list,
     220  			     struct bfd_link_info *  info,
     221  			     struct elf_link_hash_entry *h)
     222  {
     223    struct elf_link_hash_table *htab = elf_hash_table (info);
     224  
     225    if (got_entry_for_type (list, type) != NULL)
     226      return true;
     227  
     228    switch (type)
     229      {
     230        case GOT_NORMAL:
     231  	{
     232  	  bfd_vma offset
     233  	    = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info)
     234  						 || h != NULL, h);
     235  	  new_got_entry_to_list (list, type, offset, TLS_GOT_NONE);
     236  	}
     237  	break;
     238  
     239  
     240        case GOT_TLS_GD:
     241  	{
     242  	  bfd_vma offset
     243  	    = ADD_SYMBOL_REF_SEC_AND_RELOC (got, true, h);
     244  	  bfd_vma ATTRIBUTE_UNUSED notneeded
     245  	    = ADD_SYMBOL_REF_SEC_AND_RELOC (got, true, h);
     246  	  new_got_entry_to_list (list, type, offset, TLS_GOT_MOD_AND_OFF);
     247  	}
     248  	break;
     249        case GOT_TLS_IE:
     250        case GOT_TLS_LE:
     251  	{
     252  	  bfd_vma offset
     253  	    = ADD_SYMBOL_REF_SEC_AND_RELOC (got, true, h);
     254  	  new_got_entry_to_list (list, type, offset, TLS_GOT_OFF);
     255  	}
     256  	break;
     257  
     258        default:
     259  	return false;
     260  	break;
     261      }
     262    return true;
     263  }
     264  
     265  struct arc_static_sym_data {
     266    bfd_vma sym_value;
     267    const char *symbol_name;
     268  };
     269  
     270  static struct arc_static_sym_data
     271  get_static_sym_data (unsigned long  r_symndx,
     272  		     Elf_Internal_Sym  *local_syms,
     273  		     asection **local_sections,
     274  		     struct elf_link_hash_entry *h,
     275  		     struct arc_relocation_data *reloc_data)
     276  {
     277    static const char local_name[] = "(local)";
     278    struct arc_static_sym_data ret = { 0, NULL };
     279  
     280    if (h != NULL)
     281      {
     282        BFD_ASSERT (h->root.type != bfd_link_hash_undefweak
     283  		  && h->root.type != bfd_link_hash_undefined);
     284        /* TODO: This should not be here.  */
     285        reloc_data->sym_value = h->root.u.def.value;
     286        reloc_data->sym_section = h->root.u.def.section;
     287  
     288        ret.sym_value = h->root.u.def.value
     289  	+ h->root.u.def.section->output_section->vma
     290  	+ h->root.u.def.section->output_offset;
     291  
     292        ret.symbol_name = h->root.root.string;
     293      }
     294    else
     295    {
     296      Elf_Internal_Sym *sym = local_syms + r_symndx;
     297      asection *sec = local_sections[r_symndx];
     298  
     299      ret.sym_value = sym->st_value
     300        + sec->output_section->vma
     301        + sec->output_offset;
     302  
     303      ret.symbol_name = local_name;
     304    }
     305    return ret;
     306  }
     307  
     308  static bfd_vma
     309  relocate_fix_got_relocs_for_got_info (struct got_entry **	   list_p,
     310  				      enum tls_type_e		   type,
     311  				      struct bfd_link_info *	   info,
     312  				      bfd *			   output_bfd,
     313  				      unsigned long		   r_symndx,
     314  				      Elf_Internal_Sym *	   local_syms,
     315  				      asection **		   local_sections,
     316  				      struct elf_link_hash_entry * h,
     317  				      struct arc_relocation_data * reloc_data)
     318  {
     319    struct elf_link_hash_table *htab = elf_hash_table (info);
     320    struct got_entry *entry = NULL;
     321  
     322    if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE)
     323      return 0;
     324  
     325    entry = got_entry_for_type (list_p, type);
     326    BFD_ASSERT (entry);
     327  
     328    if (h == NULL
     329        || h->forced_local == true
     330        || (! elf_hash_table (info)->dynamic_sections_created
     331  	  || (bfd_link_pic (info)
     332  	      && SYMBOL_REFERENCES_LOCAL (info, h))))
     333      {
     334        const char ATTRIBUTE_UNUSED *symbol_name;
     335        asection *tls_sec = elf_hash_table (info)->tls_sec;
     336  
     337        if (entry && !entry->processed)
     338  	{
     339  	  switch (entry->type)
     340  	    {
     341  	    case GOT_TLS_GD:
     342  	      {
     343  		BFD_ASSERT (tls_sec && tls_sec->output_section);
     344  		bfd_vma sec_vma = tls_sec->output_section->vma;
     345  
     346  		if (h == NULL || h->forced_local
     347  		   || !elf_hash_table (info)->dynamic_sections_created)
     348  		  {
     349  		    struct arc_static_sym_data tmp =
     350  		      get_static_sym_data (r_symndx, local_syms, local_sections,
     351  					   h, reloc_data);
     352  
     353  		    bfd_put_32 (output_bfd,
     354  			    tmp.sym_value - sec_vma
     355  			    + (elf_hash_table (info)->dynamic_sections_created
     356  			       ? 0
     357  			       : (align_power (0,
     358  					       tls_sec->alignment_power))),
     359  			    htab->sgot->contents + entry->offset
     360  			    + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
     361  			       ? 4 : 0));
     362  
     363  		    ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
     364  			  "@ %lx, for symbol %s\n",
     365  			  (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
     366  			   "GOT_TLS_IE"),
     367  			  (long) (sym_value - sec_vma),
     368  			  (long) (htab->sgot->output_section->vma
     369  			     + htab->sgot->output_offset
     370  			     + entry->offset
     371  			     + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
     372  				? 4 : 0)),
     373  			  tmp.symbol_name);
     374  		  }
     375  	      }
     376  	      break;
     377  
     378  	    case GOT_TLS_IE:
     379  	      {
     380  		BFD_ASSERT (tls_sec && tls_sec->output_section);
     381  		bfd_vma ATTRIBUTE_UNUSED sec_vma
     382  		  = tls_sec->output_section->vma;
     383  
     384  		struct arc_static_sym_data tmp =
     385  		  get_static_sym_data (r_symndx, local_syms, local_sections,
     386  				       h, reloc_data);
     387  
     388  		bfd_put_32 (output_bfd,
     389  			    tmp.sym_value - sec_vma
     390  			    + (elf_hash_table (info)->dynamic_sections_created
     391  			       ? 0
     392  			       : (align_power (TCB_SIZE,
     393  					       tls_sec->alignment_power))),
     394  			    htab->sgot->contents + entry->offset
     395  			    + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
     396  			       ? 4 : 0));
     397  
     398  		ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
     399  			   "@ %p, for symbol %s\n",
     400  			   (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
     401  			    "GOT_TLS_IE"),
     402  			   (long) (sym_value - sec_vma),
     403  			   (long) (htab->sgot->output_section->vma
     404  			      + htab->sgot->output_offset
     405  			      + entry->offset
     406  			      + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
     407  				 ? 4 : 0)),
     408  			   tmp.symbol_name);
     409  	      }
     410  	      break;
     411  
     412  	    case GOT_NORMAL:
     413  	      {
     414  		bfd_vma sec_vma
     415  		  = reloc_data->sym_section->output_section->vma
     416  		  + reloc_data->sym_section->output_offset;
     417  
     418  		if (h != NULL
     419  		    && h->root.type == bfd_link_hash_undefweak)
     420  		  ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
     421  			     "@ %#08lx for sym %s in got offset %#lx "
     422  			     "(is undefweak)\n",
     423  			     (long) (htab->sgot->output_section->vma
     424  				     + htab->sgot->output_offset
     425  				     + entry->offset),
     426  			     symbol_name,
     427  			     (long) entry->offset);
     428  		else
     429  		  {
     430  		    bfd_put_32 (output_bfd,
     431  				reloc_data->sym_value + sec_vma,
     432  				htab->sgot->contents + entry->offset);
     433  		    ARC_DEBUG ("arc_info: PATCHED: %#08lx "
     434  			       "@ %#08lx for sym %s in got offset %#lx\n",
     435  			       (long) (reloc_data->sym_value + sec_vma),
     436  			       (long) (htab->sgot->output_section->vma
     437  				       + htab->sgot->output_offset
     438  				       + entry->offset),
     439  			       symbol_name,
     440  			       (long) entry->offset);
     441  		  }
     442  	      }
     443  	      break;
     444  	    default:
     445  	      BFD_ASSERT (0);
     446  	      break;
     447  	    }
     448  	  entry->processed = true;
     449  	}
     450      }
     451  
     452    return entry->offset;
     453  }
     454  
     455  static void
     456  create_got_dynrelocs_for_single_entry (struct got_entry *list,
     457  				       bfd *output_bfd,
     458  				       struct bfd_link_info *  info,
     459  				       struct elf_link_hash_entry *h)
     460  {
     461    if (list == NULL)
     462      return;
     463  
     464    bfd_vma got_offset = list->offset;
     465  
     466    if (list->type == GOT_NORMAL
     467        && !list->created_dyn_relocation)
     468      {
     469        if (bfd_link_pic (info)
     470  	  && h != NULL
     471  	      && (info->symbolic || h->dynindx == -1)
     472  	      && h->def_regular)
     473  	{
     474  	  ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
     475  	}
     476        /* Do not fully understand the side effects of this condition.
     477  	 The relocation space might still being reserved.  Perhaps
     478  	 I should clear its value.  */
     479        else if (h != NULL && h->dynindx != -1)
     480  	{
     481  	  ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0);
     482  	}
     483        list->created_dyn_relocation = true;
     484      }
     485    else if (list->existing_entries != TLS_GOT_NONE
     486  	   && !list->created_dyn_relocation)
     487      {
     488         /* TODO TLS: This is not called for local symbols.
     489  	  In order to correctly implement TLS, this should also
     490  	  be called for all local symbols with tls got entries.
     491  	  Should be moved to relocate_section in order to make it
     492  	  work for local symbols.  */
     493        struct elf_link_hash_table *htab = elf_hash_table (info);
     494        enum tls_got_entries e = list->existing_entries;
     495  
     496        BFD_ASSERT (list->type != GOT_TLS_GD
     497  		  || list->existing_entries == TLS_GOT_MOD_AND_OFF);
     498  
     499        bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx;
     500  
     501        if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
     502  	{
     503  	      ADD_RELA (output_bfd, got, got_offset, dynindx,
     504  			R_ARC_TLS_DTPMOD, 0);
     505  	      ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
     506  GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n",
     507  			 list->type,
     508  			 (long) got_offset,
     509  			 (long) (htab->sgot->output_section->vma
     510  				 + htab->sgot->output_offset + got_offset),
     511  			 (long) dynindx);
     512  	}
     513  
     514        if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
     515  	{
     516  	  bfd_vma addend = 0;
     517  	  if (list->type == GOT_TLS_IE)
     518  	  {
     519  	    addend = bfd_get_32 (output_bfd,
     520  				 htab->sgot->contents + got_offset);
     521  	  }
     522  
     523  	  ADD_RELA (output_bfd, got,
     524  		    got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
     525  		    dynindx,
     526  		    (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF
     527  					      : R_ARC_TLS_DTPOFF),
     528  		    addend);
     529  
     530  	  ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
     531  GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
     532  		     list->type,
     533  		     (long) got_offset,
     534  		     (long) (htab->sgot->output_section->vma
     535  			     + htab->sgot->output_offset + got_offset),
     536  		     (long) dynindx, (long) addend);
     537  	}
     538        list->created_dyn_relocation = true;
     539      }
     540  }
     541  
     542  static void
     543  create_got_dynrelocs_for_got_info (struct got_entry **list_p,
     544  				   bfd *output_bfd,
     545  				   struct bfd_link_info *  info,
     546  				   struct elf_link_hash_entry *h)
     547  {
     548    if (list_p == NULL)
     549      return;
     550  
     551    struct got_entry *list = *list_p;
     552    /* Traverse the list of got entries for this symbol.  */
     553    while (list)
     554      {
     555        create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
     556        list = list->next;
     557      }
     558  }
     559  
     560  #undef ADD_SYMBOL_REF_SEC_AND_RELOC
     561  
     562  #endif /* ARC_GOT_H */