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