1 /* ARC-specific support for 32-bit ELF
2 Copyright (C) 1994-2017 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. */
46 struct got_entry *next;
49 bfd_boolean processed;
50 bfd_boolean created_dyn_relocation;
51 enum tls_got_entries existing_entries;
54 static struct got_entry **
55 arc_get_local_got_ents (bfd * abfd)
57 static struct got_entry **local_got_ents = NULL;
59 if (local_got_ents == NULL)
62 Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
64 size = symtab_hdr->sh_info * sizeof (bfd_vma);
65 local_got_ents = (struct got_entry **)
66 bfd_alloc (abfd, sizeof (struct got_entry *) * size);
67 if (local_got_ents == NULL)
70 memset (local_got_ents, 0, sizeof (struct got_entry *) * size);
71 elf_local_got_ents (abfd) = local_got_ents;
74 return local_got_ents;
77 static struct got_entry *
78 got_entry_for_type (struct got_entry **list,
81 struct got_entry **p = list;
85 if ((*p)->type == type)
93 new_got_entry_to_list (struct got_entry **list,
96 enum tls_got_entries existing_entries)
98 /* Find list end. Avoid having multiple entries of the same
100 struct got_entry **p = list;
101 struct got_entry *entry;
105 if ((*p)->type == type)
110 entry = (struct got_entry *) xmalloc (sizeof (struct got_entry));
113 entry->offset = offset;
115 entry->processed = FALSE;
116 entry->created_dyn_relocation = FALSE;
117 entry->existing_entries = existing_entries;
119 ARC_DEBUG ("New GOT got entry added to list: "
120 "type: %d, offset: %ld, existing_entries: %d\n",
121 type, (long) offset, existing_entries);
123 /* Add the entry to the end of the list. */
127 static enum tls_type_e
128 tls_type_for_reloc (reloc_howto_type *howto)
130 enum tls_type_e ret = GOT_UNKNOWN;
132 if (is_reloc_for_GOT (howto))
137 case R_ARC_TLS_GD_GOT:
140 case R_ARC_TLS_IE_GOT:
143 case R_ARC_TLS_LE_32:
154 static struct got_entry **
155 get_got_entry_list_for_symbol (bfd *abfd,
156 unsigned long r_symndx,
157 struct elf_link_hash_entry *h)
161 return &h->got.glist;
165 struct got_entry **local_got_ents
166 = arc_get_local_got_ents (abfd);
167 return &local_got_ents[r_symndx];
172 static enum tls_type_e
173 arc_got_entry_type_for_reloc (reloc_howto_type *howto)
175 enum tls_type_e type = GOT_UNKNOWN;
177 if (is_reloc_for_GOT (howto))
180 if (is_reloc_for_TLS (howto))
184 case R_ARC_TLS_GD_GOT:
187 case R_ARC_TLS_IE_GOT:
197 #define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \
198 htab->s##SECNAME->size; \
200 if (COND_FOR_RELOC) \
202 htab->srel##SECNAME->size += sizeof (Elf32_External_Rela); \
203 ARC_DEBUG ("arc_info: Added reloc space in " \
204 #SECNAME " section at " __FILE__ \
205 ":%d for symbol %s\n", \
206 __LINE__, name_for_global_symbol (H)); \
209 if (h->dynindx == -1 && !h->forced_local) \
210 if (! bfd_elf_link_record_dynamic_symbol (info, H)) \
212 htab->s##SECNAME->size += 4; \
216 arc_fill_got_info_for_reloc (enum tls_type_e type,
217 struct got_entry **list,
218 struct bfd_link_info * info,
219 struct elf_link_hash_entry *h)
221 struct elf_link_hash_table *htab = elf_hash_table (info);
223 if (got_entry_for_type (list, type) != NULL)
231 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info)
233 new_got_entry_to_list (list, type, offset, TLS_GOT_NONE);
241 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
242 bfd_vma ATTRIBUTE_UNUSED notneeded
243 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
244 new_got_entry_to_list (list, type, offset, TLS_GOT_MOD_AND_OFF);
251 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
252 new_got_entry_to_list (list, type, offset, TLS_GOT_OFF);
265 relocate_fix_got_relocs_for_got_info (struct got_entry ** list_p,
266 enum tls_type_e type,
267 struct bfd_link_info * info,
269 unsigned long r_symndx,
270 Elf_Internal_Sym * local_syms,
271 asection ** local_sections,
272 struct elf_link_hash_entry * h,
273 struct arc_relocation_data * reloc_data)
275 struct elf_link_hash_table *htab = elf_hash_table (info);
276 struct got_entry *entry = NULL;
278 if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE)
281 entry = got_entry_for_type (list_p, type);
285 || (! elf_hash_table (info)->dynamic_sections_created
286 || (bfd_link_pic (info)
287 && SYMBOL_REFERENCES_LOCAL (info, h))))
289 const char ATTRIBUTE_UNUSED *symbol_name;
290 static const char local_name[] = "(local)";
291 asection *tls_sec = NULL;
292 bfd_vma sym_value = 0;
296 // TODO: This should not be here.
297 reloc_data->sym_value = h->root.u.def.value;
298 reloc_data->sym_section = h->root.u.def.section;
300 sym_value = h->root.u.def.value
301 + h->root.u.def.section->output_section->vma
302 + h->root.u.def.section->output_offset;
304 tls_sec = elf_hash_table (info)->tls_sec;
306 symbol_name = h->root.root.string;
310 Elf_Internal_Sym *sym = local_syms + r_symndx;
311 asection *sec = local_sections[r_symndx];
313 sym_value = sym->st_value
314 + sec->output_section->vma
315 + sec->output_offset;
317 tls_sec = elf_hash_table (info)->tls_sec;
319 symbol_name = local_name;
323 if (entry && !entry->processed)
329 BFD_ASSERT (tls_sec && tls_sec->output_section);
330 bfd_vma sec_vma = tls_sec->output_section->vma;
332 bfd_put_32 (output_bfd,
334 htab->sgot->contents + entry->offset
335 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
338 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
339 "@ %lx, for symbol %s\n",
340 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
342 (long) (sym_value - sec_vma),
343 (long) (htab->sgot->output_section->vma
344 + htab->sgot->output_offset->vma
346 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
354 BFD_ASSERT (tls_sec && tls_sec->output_section);
355 bfd_vma ATTRIBUTE_UNUSED sec_vma
356 = tls_sec->output_section->vma;
358 bfd_put_32 (output_bfd,
360 + (elf_hash_table (info)->dynamic_sections_created ? 0 : TCB_SIZE),
361 htab->sgot->contents + entry->offset
362 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
365 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
366 "@ %p, for symbol %s\n",
367 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
369 (long) (sym_value - sec_vma),
370 (long) (htab->sgot->output_section->vma
371 + htab->sgot->output_offset->vma
373 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
382 = reloc_data->sym_section->output_section->vma
383 + reloc_data->sym_section->output_offset;
386 && h->root.type == bfd_link_hash_undefweak)
387 ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
388 "@ %#08lx for sym %s in got offset %#lx "
390 (long) (htab->sgot->output_section->vma
391 + htab->sgot->output_offset
394 (long) entry->offset);
397 bfd_put_32 (output_bfd,
398 reloc_data->sym_value + sec_vma,
399 htab->sgot->contents + entry->offset);
400 ARC_DEBUG ("arc_info: PATCHED: %#08lx "
401 "@ %#08lx for sym %s in got offset %#lx\n",
402 (long) (reloc_data->sym_value + sec_vma),
403 (long) (htab->sgot->output_section->vma
404 + htab->sgot->output_offset + entry->offset),
406 (long) entry->offset);
414 entry->processed = TRUE;
418 return entry->offset;
422 create_got_dynrelocs_for_single_entry (struct got_entry *list,
424 struct bfd_link_info * info,
425 struct elf_link_hash_entry *h)
430 bfd_vma got_offset = list->offset;
432 if (list->type == GOT_NORMAL
433 && !list->created_dyn_relocation)
435 if (bfd_link_pic (info)
437 && (info->symbolic || h->dynindx == -1)
440 ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
442 /* Do not fully understand the side effects of this condition.
443 The relocation space might still being reserved. Perhaps
444 I should clear its value. */
445 else if (h != NULL && h->dynindx != -1)
447 ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0);
449 list->created_dyn_relocation = TRUE;
451 else if (list->existing_entries != TLS_GOT_NONE
452 && !list->created_dyn_relocation)
454 /* TODO TLS: This is not called for local symbols.
455 In order to correctly implement TLS, this should also
456 be called for all local symbols with tls got entries.
457 Should be moved to relocate_section in order to make it
458 work for local symbols. */
459 struct elf_link_hash_table *htab = elf_hash_table (info);
460 enum tls_got_entries e = list->existing_entries;
462 BFD_ASSERT (list->type != GOT_TLS_GD
463 || list->existing_entries == TLS_GOT_MOD_AND_OFF);
465 bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx;
467 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
469 ADD_RELA (output_bfd, got, got_offset, dynindx,
470 R_ARC_TLS_DTPMOD, 0);
471 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
472 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n",
475 (long) (htab->sgot->output_section->vma
476 + htab->sgot->output_offset + got_offset),
480 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
483 if (list->type == GOT_TLS_IE)
485 addend = bfd_get_32 (output_bfd,
486 htab->sgot->contents + got_offset);
489 ADD_RELA (output_bfd, got,
490 got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
492 (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF
496 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
497 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
500 (long) (htab->sgot->output_section->vma
501 + htab->sgot->output_offset + got_offset),
502 (long) dynindx, (long) addend);
504 list->created_dyn_relocation = TRUE;
509 create_got_dynrelocs_for_got_info (struct got_entry **list_p,
511 struct bfd_link_info * info,
512 struct elf_link_hash_entry *h)
517 struct got_entry *list = *list_p;
518 /* Traverse the list of got entries for this symbol. */
521 create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
526 #undef ADD_SYMBOL_REF_SEC_AND_RELOC
528 #endif /* ARC_GOT_H */