]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/arc-got.h
Revert "arc: Add new ARCv3 ISA to BFD."
[thirdparty/binutils-gdb.git] / bfd / arc-got.h
CommitLineData
08759e0f 1/* ARC-specific support for 32-bit ELF
d87bef3a 2 Copyright (C) 1994-2023 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 25#define TCB_SIZE (8)
d9d85c08
CZ
26
27#define align_power(addr, align) \
0411fca5
CM
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;
0a1b45a2
AM
52 bool processed;
53 bool created_dyn_relocation;
08759e0f
CM
54 enum tls_got_entries existing_entries;
55};
56
0f206410
CZ
57/* Return the local got list, if not defined, create an empty one. */
58
08759e0f
CM
59static struct got_entry **
60arc_get_local_got_ents (bfd * abfd)
61{
0f206410 62 if (elf_local_got_ents (abfd) == NULL)
08759e0f 63 {
0f206410
CZ
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)
68 {
69 _bfd_error_handler (_("%pB: cannot allocate memory for local "
70 "GOT entries"), abfd);
71 bfd_set_error (bfd_error_bad_value);
72 return NULL;
73 }
08759e0f
CM
74 }
75
0f206410 76 return elf_local_got_ents (abfd);
08759e0f
CM
77}
78
79static struct got_entry *
80got_entry_for_type (struct got_entry **list,
81 enum tls_type_e type)
82{
83 struct got_entry **p = list;
f7e8b360 84
08759e0f
CM
85 while (*p != NULL)
86 {
87 if ((*p)->type == type)
88 return *p;
89 p = &((*p)->next);
90 }
91 return NULL;
92}
93
94static void
95new_got_entry_to_list (struct got_entry **list,
96 enum tls_type_e type,
97 bfd_vma offset,
98 enum tls_got_entries existing_entries)
99{
100 /* Find list end. Avoid having multiple entries of the same
101 type. */
102 struct got_entry **p = list;
f7e8b360
NC
103 struct got_entry *entry;
104
08759e0f
CM
105 while (*p != NULL)
106 {
107 if ((*p)->type == type)
108 return;
109 p = &((*p)->next);
110 }
111
f7e8b360 112 entry = (struct got_entry *) xmalloc (sizeof (struct got_entry));
08759e0f
CM
113
114 entry->type = type;
115 entry->offset = offset;
116 entry->next = NULL;
0a1b45a2
AM
117 entry->processed = false;
118 entry->created_dyn_relocation = false;
08759e0f
CM
119 entry->existing_entries = existing_entries;
120
121 ARC_DEBUG ("New GOT got entry added to list: "
f7e8b360
NC
122 "type: %d, offset: %ld, existing_entries: %d\n",
123 type, (long) offset, existing_entries);
08759e0f
CM
124
125 /* Add the entry to the end of the list. */
126 *p = entry;
127}
128
129static enum tls_type_e
130tls_type_for_reloc (reloc_howto_type *howto)
131{
132 enum tls_type_e ret = GOT_UNKNOWN;
f7e8b360 133
08759e0f 134 if (is_reloc_for_GOT (howto))
f7e8b360
NC
135 return GOT_NORMAL;
136
137 switch (howto->type)
08759e0f 138 {
f7e8b360
NC
139 case R_ARC_TLS_GD_GOT:
140 ret = GOT_TLS_GD;
141 break;
142 case R_ARC_TLS_IE_GOT:
143 ret = GOT_TLS_IE;
144 break;
145 case R_ARC_TLS_LE_32:
146 ret = GOT_TLS_LE;
147 break;
148 default:
149 ret = GOT_UNKNOWN;
150 break;
08759e0f 151 }
f7e8b360 152
08759e0f
CM
153 return ret;
154};
155
156static struct got_entry **
157get_got_entry_list_for_symbol (bfd *abfd,
158 unsigned long r_symndx,
159 struct elf_link_hash_entry *h)
160{
854b8506
CM
161 struct elf_arc_link_hash_entry *h1 =
162 ((struct elf_arc_link_hash_entry *) h);
163 if (h1 != NULL)
08759e0f 164 {
854b8506 165 return &h1->got_ents;
08759e0f
CM
166 }
167 else
168 {
0f206410 169 return arc_get_local_got_ents (abfd) + r_symndx;
08759e0f
CM
170 }
171}
172
173
174static enum tls_type_e
175arc_got_entry_type_for_reloc (reloc_howto_type *howto)
176{
177 enum tls_type_e type = GOT_UNKNOWN;
178
179 if (is_reloc_for_GOT (howto))
f7e8b360
NC
180 return GOT_NORMAL;
181
182 if (is_reloc_for_TLS (howto))
08759e0f
CM
183 {
184 switch (howto->type)
185 {
186 case R_ARC_TLS_GD_GOT:
187 type = GOT_TLS_GD;
188 break;
189 case R_ARC_TLS_IE_GOT:
190 type = GOT_TLS_IE;
191 break;
192 default:
193 break;
194 }
195 }
196 return type;
197}
198
199#define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \
200 htab->s##SECNAME->size; \
201 { \
202 if (COND_FOR_RELOC) \
203 { \
d9d85c08 204 htab->srel##SECNAME->size += sizeof (Elf32_External_Rela); \
08759e0f
CM
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)); \
209 } \
210 if (H) \
d07b621f 211 if (H->dynindx == -1 && !H->forced_local) \
08759e0f 212 if (! bfd_elf_link_record_dynamic_symbol (info, H)) \
0a1b45a2 213 return false; \
d9d85c08 214 htab->s##SECNAME->size += 4; \
08759e0f
CM
215 } \
216
0a1b45a2 217static bool
08759e0f
CM
218arc_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)
222{
223 struct elf_link_hash_table *htab = elf_hash_table (info);
224
225 if (got_entry_for_type (list, type) != NULL)
0a1b45a2 226 return true;
08759e0f
CM
227
228 switch (type)
229 {
230 case GOT_NORMAL:
231 {
07d6d2b8 232 bfd_vma offset
d9d85c08
CZ
233 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info)
234 || h != NULL, h);
07d6d2b8 235 new_got_entry_to_list (list, type, offset, TLS_GOT_NONE);
08759e0f
CM
236 }
237 break;
238
d9d85c08 239
08759e0f
CM
240 case GOT_TLS_GD:
241 {
242 bfd_vma offset
0a1b45a2 243 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, true, h);
08759e0f 244 bfd_vma ATTRIBUTE_UNUSED notneeded
0a1b45a2 245 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, true, h);
08759e0f
CM
246 new_got_entry_to_list (list, type, offset, TLS_GOT_MOD_AND_OFF);
247 }
248 break;
249 case GOT_TLS_IE:
250 case GOT_TLS_LE:
251 {
252 bfd_vma offset
0a1b45a2 253 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, true, h);
08759e0f
CM
254 new_got_entry_to_list (list, type, offset, TLS_GOT_OFF);
255 }
256 break;
257
258 default:
0a1b45a2 259 return false;
08759e0f
CM
260 break;
261 }
0a1b45a2 262 return true;
08759e0f
CM
263}
264
d9d85c08
CZ
265struct arc_static_sym_data {
266 bfd_vma sym_value;
267 const char *symbol_name;
268};
269
270static struct arc_static_sym_data
271get_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)
276{
277 static const char local_name[] = "(local)";
278 struct arc_static_sym_data ret = { 0, NULL };
279
280 if (h != NULL)
281 {
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;
287
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;
291
292 ret.symbol_name = h->root.root.string;
293 }
294 else
295 {
296 Elf_Internal_Sym *sym = local_syms + r_symndx;
297 asection *sec = local_sections[r_symndx];
298
299 ret.sym_value = sym->st_value
300 + sec->output_section->vma
301 + sec->output_offset;
302
303 ret.symbol_name = local_name;
304 }
305 return ret;
306}
307
08759e0f 308static bfd_vma
d9d85c08
CZ
309relocate_fix_got_relocs_for_got_info (struct got_entry ** list_p,
310 enum tls_type_e type,
311 struct bfd_link_info * info,
312 bfd * output_bfd,
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)
08759e0f 318{
f7e8b360
NC
319 struct elf_link_hash_table *htab = elf_hash_table (info);
320 struct got_entry *entry = NULL;
08759e0f
CM
321
322 if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE)
323 return 0;
324
08759e0f
CM
325 entry = got_entry_for_type (list_p, type);
326 BFD_ASSERT (entry);
327
328 if (h == NULL
0a1b45a2 329 || h->forced_local == true
08759e0f
CM
330 || (! elf_hash_table (info)->dynamic_sections_created
331 || (bfd_link_pic (info)
f7e8b360 332 && SYMBOL_REFERENCES_LOCAL (info, h))))
08759e0f
CM
333 {
334 const char ATTRIBUTE_UNUSED *symbol_name;
d9d85c08 335 asection *tls_sec = elf_hash_table (info)->tls_sec;
08759e0f 336
535b785f 337 if (entry && !entry->processed)
08759e0f
CM
338 {
339 switch (entry->type)
340 {
f7e8b360
NC
341 case GOT_TLS_GD:
342 {
343 BFD_ASSERT (tls_sec && tls_sec->output_section);
d9d85c08 344 bfd_vma sec_vma = tls_sec->output_section->vma;
f7e8b360 345
d9d85c08
CZ
346 if (h == NULL || h->forced_local
347 || !elf_hash_table (info)->dynamic_sections_created)
d07b621f 348 {
d9d85c08
CZ
349 struct arc_static_sym_data tmp =
350 get_static_sym_data (r_symndx, local_syms, local_sections,
351 h, reloc_data);
352
353 bfd_put_32 (output_bfd,
354 tmp.sym_value - sec_vma
355 + (elf_hash_table (info)->dynamic_sections_created
356 ? 0
357 : (align_power (0,
358 tls_sec->alignment_power))),
359 htab->sgot->contents + entry->offset
360 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
361 ? 4 : 0));
362
363 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
364 "@ %lx, for symbol %s\n",
365 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
366 "GOT_TLS_IE"),
367 (long) (sym_value - sec_vma),
368 (long) (htab->sgot->output_section->vma
369 + htab->sgot->output_offset
370 + entry->offset
371 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
372 ? 4 : 0)),
373 tmp.symbol_name);
d07b621f 374 }
f7e8b360
NC
375 }
376 break;
377
d9d85c08
CZ
378 case GOT_TLS_IE:
379 {
380 BFD_ASSERT (tls_sec && tls_sec->output_section);
381 bfd_vma ATTRIBUTE_UNUSED sec_vma
382 = tls_sec->output_section->vma;
383
384 struct arc_static_sym_data tmp =
385 get_static_sym_data (r_symndx, local_syms, local_sections,
386 h, reloc_data);
387
388 bfd_put_32 (output_bfd,
389 tmp.sym_value - sec_vma
390 + (elf_hash_table (info)->dynamic_sections_created
391 ? 0
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
396 ? 4 : 0));
397
398 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
399 "@ %p, for symbol %s\n",
400 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
401 "GOT_TLS_IE"),
402 (long) (sym_value - sec_vma),
403 (long) (htab->sgot->output_section->vma
404 + htab->sgot->output_offset
405 + entry->offset
406 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
407 ? 4 : 0)),
408 tmp.symbol_name);
409 }
410 break;
411
f7e8b360
NC
412 case GOT_NORMAL:
413 {
d9d85c08
CZ
414 bfd_vma sec_vma
415 = reloc_data->sym_section->output_section->vma
416 + reloc_data->sym_section->output_offset;
417
c02d11a5 418 if (h != NULL
d9d85c08 419 && h->root.type == bfd_link_hash_undefweak)
c02d11a5
CM
420 ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
421 "@ %#08lx for sym %s in got offset %#lx "
422 "(is undefweak)\n",
423 (long) (htab->sgot->output_section->vma
424 + htab->sgot->output_offset
425 + entry->offset),
426 symbol_name,
427 (long) entry->offset);
428 else
f7e8b360 429 {
d9d85c08
CZ
430 bfd_put_32 (output_bfd,
431 reloc_data->sym_value + sec_vma,
432 htab->sgot->contents + entry->offset);
f7e8b360
NC
433 ARC_DEBUG ("arc_info: PATCHED: %#08lx "
434 "@ %#08lx for sym %s in got offset %#lx\n",
d9d85c08 435 (long) (reloc_data->sym_value + sec_vma),
f7e8b360 436 (long) (htab->sgot->output_section->vma
09a7e912
CZ
437 + htab->sgot->output_offset
438 + entry->offset),
f7e8b360
NC
439 symbol_name,
440 (long) entry->offset);
441 }
f7e8b360
NC
442 }
443 break;
444 default:
445 BFD_ASSERT (0);
446 break;
08759e0f 447 }
0a1b45a2 448 entry->processed = true;
08759e0f
CM
449 }
450 }
451
452 return entry->offset;
453}
454
455static void
456create_got_dynrelocs_for_single_entry (struct got_entry *list,
457 bfd *output_bfd,
d9d85c08 458 struct bfd_link_info * info,
08759e0f
CM
459 struct elf_link_hash_entry *h)
460{
461 if (list == NULL)
462 return;
463
464 bfd_vma got_offset = list->offset;
465
466 if (list->type == GOT_NORMAL
535b785f 467 && !list->created_dyn_relocation)
08759e0f
CM
468 {
469 if (bfd_link_pic (info)
470 && h != NULL
471 && (info->symbolic || h->dynindx == -1)
472 && h->def_regular)
473 {
474 ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
475 }
476 /* Do not fully understand the side effects of this condition.
d9d85c08
CZ
477 The relocation space might still being reserved. Perhaps
478 I should clear its value. */
08759e0f
CM
479 else if (h != NULL && h->dynindx != -1)
480 {
481 ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0);
482 }
0a1b45a2 483 list->created_dyn_relocation = true;
08759e0f
CM
484 }
485 else if (list->existing_entries != TLS_GOT_NONE
535b785f 486 && !list->created_dyn_relocation)
08759e0f
CM
487 {
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;
495
496 BFD_ASSERT (list->type != GOT_TLS_GD
07d6d2b8 497 || list->existing_entries == TLS_GOT_MOD_AND_OFF);
08759e0f
CM
498
499 bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx;
500
501 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
502 {
503 ADD_RELA (output_bfd, got, got_offset, dynindx,
07d6d2b8 504 R_ARC_TLS_DTPMOD, 0);
08759e0f 505 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
f7e8b360 506GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n",
08759e0f 507 list->type,
f7e8b360
NC
508 (long) got_offset,
509 (long) (htab->sgot->output_section->vma
510 + htab->sgot->output_offset + got_offset),
511 (long) dynindx);
08759e0f 512 }
f7e8b360 513
08759e0f
CM
514 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
515 {
516 bfd_vma addend = 0;
517 if (list->type == GOT_TLS_IE)
a0abe743 518 {
d9d85c08
CZ
519 addend = bfd_get_32 (output_bfd,
520 htab->sgot->contents + got_offset);
a0abe743 521 }
08759e0f 522
d9d85c08
CZ
523 ADD_RELA (output_bfd, got,
524 got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
08759e0f
CM
525 dynindx,
526 (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF
527 : R_ARC_TLS_DTPOFF),
528 addend);
529
530 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
f7e8b360 531GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
08759e0f 532 list->type,
f7e8b360
NC
533 (long) got_offset,
534 (long) (htab->sgot->output_section->vma
535 + htab->sgot->output_offset + got_offset),
536 (long) dynindx, (long) addend);
08759e0f 537 }
0a1b45a2 538 list->created_dyn_relocation = true;
08759e0f
CM
539 }
540}
541
542static void
543create_got_dynrelocs_for_got_info (struct got_entry **list_p,
544 bfd *output_bfd,
d9d85c08 545 struct bfd_link_info * info,
07d6d2b8 546 struct elf_link_hash_entry *h)
08759e0f
CM
547{
548 if (list_p == NULL)
549 return;
550
d9d85c08 551 struct got_entry *list = *list_p;
08759e0f
CM
552 /* Traverse the list of got entries for this symbol. */
553 while (list)
554 {
555 create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
556 list = list->next;
557 }
558}
559
560#undef ADD_SYMBOL_REF_SEC_AND_RELOC
561
562#endif /* ARC_GOT_H */