Update my e-mail address.
[binutils-gdb.git] / bfd / arc-got.h
blobf1f6c0ea81431f3778dbc35f333616997f1cacef
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. */
22 #ifndef ARC_GOT_H
23 #define ARC_GOT_H
25 #define TCB_SIZE (8)
27 enum tls_type_e
29 GOT_UNKNOWN = 0,
30 GOT_NORMAL,
31 GOT_TLS_GD,
32 GOT_TLS_IE,
33 GOT_TLS_LE
36 enum tls_got_entries
38 TLS_GOT_NONE = 0,
39 TLS_GOT_MOD,
40 TLS_GOT_OFF,
41 TLS_GOT_MOD_AND_OFF
44 struct got_entry
46 struct got_entry *next;
47 enum tls_type_e type;
48 bfd_vma offset;
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)
61 size_t size;
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)
68 return FALSE;
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,
79 enum tls_type_e type)
81 struct got_entry **p = list;
83 while (*p != NULL)
85 if ((*p)->type == type)
86 return *p;
87 p = &((*p)->next);
89 return NULL;
92 static void
93 new_got_entry_to_list (struct got_entry **list,
94 enum tls_type_e type,
95 bfd_vma offset,
96 enum tls_got_entries existing_entries)
98 /* Find list end. Avoid having multiple entries of the same
99 type. */
100 struct got_entry **p = list;
101 struct got_entry *entry;
103 while (*p != NULL)
105 if ((*p)->type == type)
106 return;
107 p = &((*p)->next);
110 entry = (struct got_entry *) xmalloc (sizeof (struct got_entry));
112 entry->type = type;
113 entry->offset = offset;
114 entry->next = NULL;
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. */
124 *p = entry;
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))
133 return GOT_NORMAL;
135 switch (howto->type)
137 case R_ARC_TLS_GD_GOT:
138 ret = GOT_TLS_GD;
139 break;
140 case R_ARC_TLS_IE_GOT:
141 ret = GOT_TLS_IE;
142 break;
143 case R_ARC_TLS_LE_32:
144 ret = GOT_TLS_LE;
145 break;
146 default:
147 ret = GOT_UNKNOWN;
148 break;
151 return ret;
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)
159 if (h != NULL)
161 return &h->got.glist;
163 else
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))
178 return GOT_NORMAL;
180 if (is_reloc_for_TLS (howto))
182 switch (howto->type)
184 case R_ARC_TLS_GD_GOT:
185 type = GOT_TLS_GD;
186 break;
187 case R_ARC_TLS_IE_GOT:
188 type = GOT_TLS_IE;
189 break;
190 default:
191 break;
194 return type;
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)); \
208 if (H) \
209 if (h->dynindx == -1 && !h->forced_local) \
210 if (! bfd_elf_link_record_dynamic_symbol (info, H)) \
211 return FALSE; \
212 htab->s##SECNAME->size += 4; \
215 static bfd_boolean
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)
224 return TRUE;
226 switch (type)
228 case GOT_NORMAL:
230 bfd_vma offset
231 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info)
232 || h != NULL, h);
233 new_got_entry_to_list (list, type, offset, TLS_GOT_NONE);
235 break;
238 case GOT_TLS_GD:
240 bfd_vma offset
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);
246 break;
247 case GOT_TLS_IE:
248 case GOT_TLS_LE:
250 bfd_vma offset
251 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
252 new_got_entry_to_list (list, type, offset, TLS_GOT_OFF);
254 break;
256 default:
257 return FALSE;
258 break;
260 return TRUE;
264 static bfd_vma
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,
268 bfd * output_bfd,
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)
279 return 0;
281 entry = got_entry_for_type (list_p, type);
282 BFD_ASSERT (entry);
284 if (h == NULL
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;
294 if (h != NULL)
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;
308 else
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)
325 switch (entry->type)
327 case GOT_TLS_GD:
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,
333 sym_value - sec_vma,
334 htab->sgot->contents + entry->offset
335 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
336 ? 4 : 0));
338 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
339 "@ %lx, for symbol %s\n",
340 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
341 "GOT_TLS_IE"),
342 (long) (sym_value - sec_vma),
343 (long) (htab->sgot->output_section->vma
344 + htab->sgot->output_offset->vma
345 + entry->offset
346 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
347 ? 4 : 0)),
348 symbol_name);
350 break;
352 case GOT_TLS_IE:
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,
359 sym_value - sec_vma
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
363 ? 4 : 0));
365 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
366 "@ %p, for symbol %s\n",
367 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
368 "GOT_TLS_IE"),
369 (long) (sym_value - sec_vma),
370 (long) (htab->sgot->output_section->vma
371 + htab->sgot->output_offset->vma
372 + entry->offset
373 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
374 ? 4 : 0)),
375 symbol_name);
377 break;
379 case GOT_NORMAL:
381 bfd_vma sec_vma
382 = reloc_data->sym_section->output_section->vma
383 + reloc_data->sym_section->output_offset;
385 if (h != NULL
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 "
389 "(is undefweak)\n",
390 (long) (htab->sgot->output_section->vma
391 + htab->sgot->output_offset
392 + entry->offset),
393 symbol_name,
394 (long) entry->offset);
395 else
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),
405 symbol_name,
406 (long) entry->offset);
409 break;
410 default:
411 BFD_ASSERT (0);
412 break;
414 entry->processed = TRUE;
418 return entry->offset;
421 static void
422 create_got_dynrelocs_for_single_entry (struct got_entry *list,
423 bfd *output_bfd,
424 struct bfd_link_info * info,
425 struct elf_link_hash_entry *h)
427 if (list == NULL)
428 return;
430 bfd_vma got_offset = list->offset;
432 if (list->type == GOT_NORMAL
433 && !list->created_dyn_relocation)
435 if (bfd_link_pic (info)
436 && h != NULL
437 && (info->symbolic || h->dynindx == -1)
438 && h->def_regular)
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",
473 list->type,
474 (long) got_offset,
475 (long) (htab->sgot->output_section->vma
476 + htab->sgot->output_offset + got_offset),
477 (long) dynindx);
480 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
482 bfd_vma addend = 0;
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),
491 dynindx,
492 (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF
493 : R_ARC_TLS_DTPOFF),
494 addend);
496 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
497 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
498 list->type,
499 (long) got_offset,
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;
508 static void
509 create_got_dynrelocs_for_got_info (struct got_entry **list_p,
510 bfd *output_bfd,
511 struct bfd_link_info * info,
512 struct elf_link_hash_entry *h)
514 if (list_p == NULL)
515 return;
517 struct got_entry *list = *list_p;
518 /* Traverse the list of got entries for this symbol. */
519 while (list)
521 create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
522 list = list->next;
526 #undef ADD_SYMBOL_REF_SEC_AND_RELOC
528 #endif /* ARC_GOT_H */