Allow for compilers that do not produce aligned .rdat sections in PE format files.
[deliverable/binutils-gdb.git] / bfd / arc-got.h
CommitLineData
08759e0f 1/* ARC-specific support for 32-bit ELF
219d1afa 2 Copyright (C) 1994-2018 Free Software Foundation, Inc.
08759e0f
CM
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
a0abe743
CM
25#define TCB_SIZE (8)
26
0411fca5
CM
27#define align_power(addr, align) \
28 (((addr) + ((bfd_vma) 1 << (align)) - 1) & (-((bfd_vma) 1 << (align))))
29
08759e0f
CM
30enum 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
39enum 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
47struct 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
57static struct got_entry **
58arc_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
80static struct got_entry *
81got_entry_for_type (struct got_entry **list,
82 enum tls_type_e type)
83{
84 struct got_entry **p = list;
f7e8b360 85
08759e0f
CM
86 while (*p != NULL)
87 {
88 if ((*p)->type == type)
89 return *p;
90 p = &((*p)->next);
91 }
92 return NULL;
93}
94
95static void
96new_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;
f7e8b360
NC
104 struct got_entry *entry;
105
08759e0f
CM
106 while (*p != NULL)
107 {
108 if ((*p)->type == type)
109 return;
110 p = &((*p)->next);
111 }
112
f7e8b360 113 entry = (struct got_entry *) xmalloc (sizeof (struct got_entry));
08759e0f
CM
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: "
f7e8b360
NC
123 "type: %d, offset: %ld, existing_entries: %d\n",
124 type, (long) offset, existing_entries);
08759e0f
CM
125
126 /* Add the entry to the end of the list. */
127 *p = entry;
128}
129
130static enum tls_type_e
131tls_type_for_reloc (reloc_howto_type *howto)
132{
133 enum tls_type_e ret = GOT_UNKNOWN;
f7e8b360 134
08759e0f 135 if (is_reloc_for_GOT (howto))
f7e8b360
NC
136 return GOT_NORMAL;
137
138 switch (howto->type)
08759e0f 139 {
f7e8b360
NC
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;
08759e0f 152 }
f7e8b360 153
08759e0f
CM
154 return ret;
155};
156
157static struct got_entry **
158get_got_entry_list_for_symbol (bfd *abfd,
159 unsigned long r_symndx,
160 struct elf_link_hash_entry *h)
161{
854b8506
CM
162 struct elf_arc_link_hash_entry *h1 =
163 ((struct elf_arc_link_hash_entry *) h);
164 if (h1 != NULL)
08759e0f 165 {
854b8506 166 return &h1->got_ents;
08759e0f
CM
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
177static enum tls_type_e
178arc_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))
f7e8b360
NC
183 return GOT_NORMAL;
184
185 if (is_reloc_for_TLS (howto))
08759e0f
CM
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
220static bfd_boolean
221arc_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 {
07d6d2b8 235 bfd_vma offset
08759e0f
CM
236 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info)
237 || h != NULL, h);
07d6d2b8 238 new_got_entry_to_list (list, type, offset, TLS_GOT_NONE);
08759e0f
CM
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
269static bfd_vma
07d6d2b8
AM
270relocate_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,
f7e8b360 278 struct arc_relocation_data * reloc_data)
08759e0f 279{
f7e8b360
NC
280 struct elf_link_hash_table *htab = elf_hash_table (info);
281 struct got_entry *entry = NULL;
08759e0f
CM
282
283 if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE)
284 return 0;
285
08759e0f
CM
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)
f7e8b360 292 && SYMBOL_REFERENCES_LOCAL (info, h))))
08759e0f
CM
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
f7e8b360
NC
306 + h->root.u.def.section->output_section->vma
307 + h->root.u.def.section->output_offset;
08759e0f
CM
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
f7e8b360
NC
319 + sec->output_section->vma
320 + sec->output_offset;
08759e0f
CM
321
322 tls_sec = elf_hash_table (info)->tls_sec;
323
324 symbol_name = local_name;
325 }
326
327
535b785f 328 if (entry && !entry->processed)
08759e0f
CM
329 {
330 switch (entry->type)
331 {
f7e8b360
NC
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,
714e9a95
CM
338 sym_value - sec_vma
339 + (elf_hash_table (info)->dynamic_sections_created
340 ? 0
341 : (align_power (TCB_SIZE,
342 tls_sec->alignment_power))),
f7e8b360
NC
343 htab->sgot->contents + entry->offset
344 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
345 ? 4 : 0));
346
347 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
4dd72ffd 348 "@ %lx, for symbol %s\n",
f7e8b360
NC
349 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
350 "GOT_TLS_IE"),
351 (long) (sym_value - sec_vma),
4dd72ffd 352 (long) (htab->sgot->output_section->vma
714e9a95 353 + htab->sgot->output_offset
4dd72ffd
CM
354 + entry->offset
355 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
356 ? 4 : 0)),
f7e8b360
NC
357 symbol_name);
358 }
359 break;
360
361 case GOT_TLS_IE:
362 {
363 BFD_ASSERT (tls_sec && tls_sec->output_section);
364 bfd_vma ATTRIBUTE_UNUSED sec_vma
365 = tls_sec->output_section->vma;
366
4dd72ffd 367 bfd_put_32 (output_bfd,
a0abe743 368 sym_value - sec_vma
0411fca5
CM
369 + (elf_hash_table (info)->dynamic_sections_created
370 ? 0
371 : (align_power (TCB_SIZE,
372 tls_sec->alignment_power))),
4dd72ffd
CM
373 htab->sgot->contents + entry->offset
374 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
375 ? 4 : 0));
376
f7e8b360
NC
377 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
378 "@ %p, for symbol %s\n",
379 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
380 "GOT_TLS_IE"),
381 (long) (sym_value - sec_vma),
4dd72ffd 382 (long) (htab->sgot->output_section->vma
714e9a95 383 + htab->sgot->output_offset
4dd72ffd
CM
384 + entry->offset
385 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
386 ? 4 : 0)),
f7e8b360
NC
387 symbol_name);
388 }
389 break;
390
391 case GOT_NORMAL:
392 {
393 bfd_vma sec_vma
394 = reloc_data->sym_section->output_section->vma
395 + reloc_data->sym_section->output_offset;
396
c02d11a5
CM
397 if (h != NULL
398 && h->root.type == bfd_link_hash_undefweak)
399 ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
400 "@ %#08lx for sym %s in got offset %#lx "
401 "(is undefweak)\n",
402 (long) (htab->sgot->output_section->vma
403 + htab->sgot->output_offset
404 + entry->offset),
405 symbol_name,
406 (long) entry->offset);
407 else
f7e8b360
NC
408 {
409 bfd_put_32 (output_bfd,
410 reloc_data->sym_value + sec_vma,
411 htab->sgot->contents + entry->offset);
f7e8b360
NC
412 ARC_DEBUG ("arc_info: PATCHED: %#08lx "
413 "@ %#08lx for sym %s in got offset %#lx\n",
414 (long) (reloc_data->sym_value + sec_vma),
415 (long) (htab->sgot->output_section->vma
416 + htab->sgot->output_offset + entry->offset),
417 symbol_name,
418 (long) entry->offset);
419 }
f7e8b360
NC
420 }
421 break;
422 default:
423 BFD_ASSERT (0);
424 break;
08759e0f
CM
425 }
426 entry->processed = TRUE;
427 }
428 }
429
430 return entry->offset;
431}
432
433static void
434create_got_dynrelocs_for_single_entry (struct got_entry *list,
435 bfd *output_bfd,
436 struct bfd_link_info * info,
437 struct elf_link_hash_entry *h)
438{
439 if (list == NULL)
440 return;
441
442 bfd_vma got_offset = list->offset;
443
444 if (list->type == GOT_NORMAL
535b785f 445 && !list->created_dyn_relocation)
08759e0f
CM
446 {
447 if (bfd_link_pic (info)
448 && h != NULL
449 && (info->symbolic || h->dynindx == -1)
450 && h->def_regular)
451 {
452 ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
453 }
454 /* Do not fully understand the side effects of this condition.
455 The relocation space might still being reserved. Perhaps
456 I should clear its value. */
457 else if (h != NULL && h->dynindx != -1)
458 {
459 ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0);
460 }
461 list->created_dyn_relocation = TRUE;
462 }
463 else if (list->existing_entries != TLS_GOT_NONE
535b785f 464 && !list->created_dyn_relocation)
08759e0f
CM
465 {
466 /* TODO TLS: This is not called for local symbols.
467 In order to correctly implement TLS, this should also
468 be called for all local symbols with tls got entries.
469 Should be moved to relocate_section in order to make it
470 work for local symbols. */
471 struct elf_link_hash_table *htab = elf_hash_table (info);
472 enum tls_got_entries e = list->existing_entries;
473
474 BFD_ASSERT (list->type != GOT_TLS_GD
07d6d2b8 475 || list->existing_entries == TLS_GOT_MOD_AND_OFF);
08759e0f
CM
476
477 bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx;
478
479 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
480 {
481 ADD_RELA (output_bfd, got, got_offset, dynindx,
07d6d2b8 482 R_ARC_TLS_DTPMOD, 0);
08759e0f 483 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
f7e8b360 484GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n",
08759e0f 485 list->type,
f7e8b360
NC
486 (long) got_offset,
487 (long) (htab->sgot->output_section->vma
488 + htab->sgot->output_offset + got_offset),
489 (long) dynindx);
08759e0f 490 }
f7e8b360 491
08759e0f
CM
492 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
493 {
494 bfd_vma addend = 0;
495 if (list->type == GOT_TLS_IE)
a0abe743 496 {
08759e0f
CM
497 addend = bfd_get_32 (output_bfd,
498 htab->sgot->contents + got_offset);
a0abe743 499 }
08759e0f
CM
500
501 ADD_RELA (output_bfd, got,
502 got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
503 dynindx,
504 (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF
505 : R_ARC_TLS_DTPOFF),
506 addend);
507
508 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
f7e8b360 509GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
08759e0f 510 list->type,
f7e8b360
NC
511 (long) got_offset,
512 (long) (htab->sgot->output_section->vma
513 + htab->sgot->output_offset + got_offset),
514 (long) dynindx, (long) addend);
08759e0f
CM
515 }
516 list->created_dyn_relocation = TRUE;
517 }
518}
519
520static void
521create_got_dynrelocs_for_got_info (struct got_entry **list_p,
522 bfd *output_bfd,
523 struct bfd_link_info * info,
07d6d2b8 524 struct elf_link_hash_entry *h)
08759e0f
CM
525{
526 if (list_p == NULL)
527 return;
528
529 struct got_entry *list = *list_p;
530 /* Traverse the list of got entries for this symbol. */
531 while (list)
532 {
533 create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
534 list = list->next;
535 }
536}
537
538#undef ADD_SYMBOL_REF_SEC_AND_RELOC
539
540#endif /* ARC_GOT_H */
This page took 0.152951 seconds and 4 git commands to generate.