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).
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
27 #define align_power(addr, align) \
28 (((addr) + ((bfd_vma) 1 << (align)) - 1) & (-((bfd_vma) 1 << (align))))
49 struct got_entry
*next
;
53 bool created_dyn_relocation
;
54 enum tls_got_entries existing_entries
;
57 /* Return the local got list, if not defined, create an empty one. */
59 static struct got_entry
**
60 arc_get_local_got_ents (bfd
* abfd
)
62 if (elf_local_got_ents (abfd
) == NULL
)
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
)
69 _bfd_error_handler (_("%pB: cannot allocate memory for local "
70 "GOT entries"), abfd
);
71 bfd_set_error (bfd_error_bad_value
);
76 return elf_local_got_ents (abfd
);
79 static struct got_entry
*
80 got_entry_for_type (struct got_entry
**list
,
83 struct got_entry
**p
= list
;
87 if ((*p
)->type
== type
)
95 new_got_entry_to_list (struct got_entry
**list
,
98 enum tls_got_entries existing_entries
)
100 /* Find list end. Avoid having multiple entries of the same
102 struct got_entry
**p
= list
;
103 struct got_entry
*entry
;
107 if ((*p
)->type
== type
)
112 entry
= (struct got_entry
*) xmalloc (sizeof (struct got_entry
));
115 entry
->offset
= offset
;
117 entry
->processed
= false;
118 entry
->created_dyn_relocation
= false;
119 entry
->existing_entries
= existing_entries
;
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
);
125 /* Add the entry to the end of the list. */
129 static enum tls_type_e
130 tls_type_for_reloc (reloc_howto_type
*howto
)
132 enum tls_type_e ret
= GOT_UNKNOWN
;
134 if (is_reloc_for_GOT (howto
))
139 case R_ARC_TLS_GD_GOT
:
142 case R_ARC_TLS_IE_GOT
:
145 case R_ARC_TLS_LE_32
:
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
)
161 struct elf_arc_link_hash_entry
*h1
=
162 ((struct elf_arc_link_hash_entry
*) h
);
165 return &h1
->got_ents
;
169 return arc_get_local_got_ents (abfd
) + r_symndx
;
174 static enum tls_type_e
175 arc_got_entry_type_for_reloc (reloc_howto_type
*howto
)
177 enum tls_type_e type
= GOT_UNKNOWN
;
179 if (is_reloc_for_GOT (howto
))
182 if (is_reloc_for_TLS (howto
))
186 case R_ARC_TLS_GD_GOT
:
189 case R_ARC_TLS_IE_GOT
:
199 #define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \
200 htab->s##SECNAME->size; \
202 if (COND_FOR_RELOC) \
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)); \
211 if (H->dynindx == -1 && !H->forced_local) \
212 if (! bfd_elf_link_record_dynamic_symbol (info, H)) \
214 htab->s##SECNAME->size += 4; \
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
)
223 struct elf_link_hash_table
*htab
= elf_hash_table (info
);
225 if (got_entry_for_type (list
, type
) != NULL
)
233 = ADD_SYMBOL_REF_SEC_AND_RELOC (got
, bfd_link_pic (info
)
235 new_got_entry_to_list (list
, type
, offset
, TLS_GOT_NONE
);
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
);
253 = ADD_SYMBOL_REF_SEC_AND_RELOC (got
, true, h
);
254 new_got_entry_to_list (list
, type
, offset
, TLS_GOT_OFF
);
265 struct arc_static_sym_data
{
267 const char *symbol_name
;
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
)
277 static const char local_name
[] = "(local)";
278 struct arc_static_sym_data ret
= { 0, NULL
};
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
;
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
;
292 ret
.symbol_name
= h
->root
.root
.string
;
296 Elf_Internal_Sym
*sym
= local_syms
+ r_symndx
;
297 asection
*sec
= local_sections
[r_symndx
];
299 ret
.sym_value
= sym
->st_value
300 + sec
->output_section
->vma
301 + sec
->output_offset
;
303 ret
.symbol_name
= local_name
;
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
,
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
)
319 struct elf_link_hash_table
*htab
= elf_hash_table (info
);
320 struct got_entry
*entry
= NULL
;
322 if (list_p
== NULL
|| type
== GOT_UNKNOWN
|| type
== GOT_TLS_LE
)
325 entry
= got_entry_for_type (list_p
, type
);
329 || h
->forced_local
== true
330 || (! elf_hash_table (info
)->dynamic_sections_created
331 || (bfd_link_pic (info
)
332 && SYMBOL_REFERENCES_LOCAL (info
, h
))))
334 const char ATTRIBUTE_UNUSED
*symbol_name
;
335 asection
*tls_sec
= elf_hash_table (info
)->tls_sec
;
337 if (entry
&& !entry
->processed
)
343 BFD_ASSERT (tls_sec
&& tls_sec
->output_section
);
344 bfd_vma sec_vma
= tls_sec
->output_section
->vma
;
346 if (h
== NULL
|| h
->forced_local
347 || !elf_hash_table (info
)->dynamic_sections_created
)
349 struct arc_static_sym_data tmp
=
350 get_static_sym_data (r_symndx
, local_syms
, local_sections
,
353 bfd_put_32 (output_bfd
,
354 tmp
.sym_value
- sec_vma
355 + (elf_hash_table (info
)->dynamic_sections_created
358 tls_sec
->alignment_power
))),
359 htab
->sgot
->contents
+ entry
->offset
360 + (entry
->existing_entries
== TLS_GOT_MOD_AND_OFF
363 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
364 "@ %lx, for symbol %s\n",
365 (entry
->type
== GOT_TLS_GD
? "GOT_TLS_GD" :
367 (long) (sym_value
- sec_vma
),
368 (long) (htab
->sgot
->output_section
->vma
369 + htab
->sgot
->output_offset
371 + (entry
->existing_entries
== TLS_GOT_MOD_AND_OFF
380 BFD_ASSERT (tls_sec
&& tls_sec
->output_section
);
381 bfd_vma ATTRIBUTE_UNUSED sec_vma
382 = tls_sec
->output_section
->vma
;
384 struct arc_static_sym_data tmp
=
385 get_static_sym_data (r_symndx
, local_syms
, local_sections
,
388 bfd_put_32 (output_bfd
,
389 tmp
.sym_value
- sec_vma
390 + (elf_hash_table (info
)->dynamic_sections_created
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
398 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
399 "@ %p, for symbol %s\n",
400 (entry
->type
== GOT_TLS_GD
? "GOT_TLS_GD" :
402 (long) (sym_value
- sec_vma
),
403 (long) (htab
->sgot
->output_section
->vma
404 + htab
->sgot
->output_offset
406 + (entry
->existing_entries
== TLS_GOT_MOD_AND_OFF
415 = reloc_data
->sym_section
->output_section
->vma
416 + reloc_data
->sym_section
->output_offset
;
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 "
423 (long) (htab
->sgot
->output_section
->vma
424 + htab
->sgot
->output_offset
427 (long) entry
->offset
);
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
440 (long) entry
->offset
);
448 entry
->processed
= true;
452 return entry
->offset
;
456 create_got_dynrelocs_for_single_entry (struct got_entry
*list
,
458 struct bfd_link_info
* info
,
459 struct elf_link_hash_entry
*h
)
464 bfd_vma got_offset
= list
->offset
;
466 if (list
->type
== GOT_NORMAL
467 && !list
->created_dyn_relocation
)
469 if (bfd_link_pic (info
)
471 && (info
->symbolic
|| h
->dynindx
== -1)
474 ADD_RELA (output_bfd
, got
, got_offset
, 0, R_ARC_RELATIVE
, 0);
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)
481 ADD_RELA (output_bfd
, got
, got_offset
, h
->dynindx
, R_ARC_GLOB_DAT
, 0);
483 list
->created_dyn_relocation
= true;
485 else if (list
->existing_entries
!= TLS_GOT_NONE
486 && !list
->created_dyn_relocation
)
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
;
496 BFD_ASSERT (list
->type
!= GOT_TLS_GD
497 || list
->existing_entries
== TLS_GOT_MOD_AND_OFF
);
499 bfd_vma dynindx
= (h
== NULL
|| h
->dynindx
== -1) ? 0 : h
->dynindx
;
501 if (e
== TLS_GOT_MOD_AND_OFF
|| e
== TLS_GOT_MOD
)
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",
509 (long) (htab
->sgot
->output_section
->vma
510 + htab
->sgot
->output_offset
+ got_offset
),
514 if (e
== TLS_GOT_MOD_AND_OFF
|| e
== TLS_GOT_OFF
)
517 if (list
->type
== GOT_TLS_IE
)
519 addend
= bfd_get_32 (output_bfd
,
520 htab
->sgot
->contents
+ got_offset
);
523 ADD_RELA (output_bfd
, got
,
524 got_offset
+ (e
== TLS_GOT_MOD_AND_OFF
? 4 : 0),
526 (list
->type
== GOT_TLS_IE
? R_ARC_TLS_TPOFF
530 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
531 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
534 (long) (htab
->sgot
->output_section
->vma
535 + htab
->sgot
->output_offset
+ got_offset
),
536 (long) dynindx
, (long) addend
);
538 list
->created_dyn_relocation
= true;
543 create_got_dynrelocs_for_got_info (struct got_entry
**list_p
,
545 struct bfd_link_info
* info
,
546 struct elf_link_hash_entry
*h
)
551 struct got_entry
*list
= *list_p
;
552 /* Traverse the list of got entries for this symbol. */
555 create_got_dynrelocs_for_single_entry (list
, output_bfd
, info
, h
);
560 #undef ADD_SYMBOL_REF_SEC_AND_RELOC
562 #endif /* ARC_GOT_H */