xref: /netbsd-src/external/gpl3/binutils.old/dist/bfd/arc-got.h (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1 /* ARC-specific support for 32-bit ELF
2    Copyright (C) 1994-2022 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 **
arc_get_local_got_ents(bfd * abfd)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 *
got_entry_for_type(struct got_entry ** list,enum tls_type_e type)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
new_got_entry_to_list(struct got_entry ** list,enum tls_type_e type,bfd_vma offset,enum tls_got_entries existing_entries)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
tls_type_for_reloc(reloc_howto_type * howto)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 **
get_got_entry_list_for_symbol(bfd * abfd,unsigned long r_symndx,struct elf_link_hash_entry * h)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
arc_got_entry_type_for_reloc(reloc_howto_type * howto)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
arc_fill_got_info_for_reloc(enum tls_type_e type,struct got_entry ** list,struct bfd_link_info * info,struct elf_link_hash_entry * h)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
get_static_sym_data(unsigned long r_symndx,Elf_Internal_Sym * local_syms,asection ** local_sections,struct elf_link_hash_entry * h,struct arc_relocation_data * reloc_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
relocate_fix_got_relocs_for_got_info(struct got_entry ** list_p,enum tls_type_e type,struct bfd_link_info * info,bfd * output_bfd,unsigned long r_symndx,Elf_Internal_Sym * local_syms,asection ** local_sections,struct elf_link_hash_entry * h,struct arc_relocation_data * reloc_data)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
create_got_dynrelocs_for_single_entry(struct got_entry * list,bfd * output_bfd,struct bfd_link_info * info,struct elf_link_hash_entry * h)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
create_got_dynrelocs_for_got_info(struct got_entry ** list_p,bfd * output_bfd,struct bfd_link_info * info,struct elf_link_hash_entry * h)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 */
563