]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/arc-got.h
Fix Common symbol override test fails
[thirdparty/binutils-gdb.git] / bfd / arc-got.h
CommitLineData
08759e0f 1/* ARC-specific support for 32-bit ELF
2571583a 2 Copyright (C) 1994-2017 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
08759e0f
CM
27enum tls_type_e
28{
29 GOT_UNKNOWN = 0,
30 GOT_NORMAL,
31 GOT_TLS_GD,
32 GOT_TLS_IE,
33 GOT_TLS_LE
34};
35
36enum tls_got_entries
37{
38 TLS_GOT_NONE = 0,
39 TLS_GOT_MOD,
40 TLS_GOT_OFF,
41 TLS_GOT_MOD_AND_OFF
42};
43
44struct got_entry
45{
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;
52};
53
54static struct got_entry **
55arc_get_local_got_ents (bfd * abfd)
56{
57 static struct got_entry **local_got_ents = NULL;
58
59 if (local_got_ents == NULL)
60 {
61 size_t size;
62 Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
63
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;
69
70 memset (local_got_ents, 0, sizeof (struct got_entry *) * size);
71 elf_local_got_ents (abfd) = local_got_ents;
72 }
73
74 return local_got_ents;
75}
76
77static struct got_entry *
78got_entry_for_type (struct got_entry **list,
79 enum tls_type_e type)
80{
81 struct got_entry **p = list;
f7e8b360 82
08759e0f
CM
83 while (*p != NULL)
84 {
85 if ((*p)->type == type)
86 return *p;
87 p = &((*p)->next);
88 }
89 return NULL;
90}
91
92static void
93new_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)
97{
98 /* Find list end. Avoid having multiple entries of the same
99 type. */
100 struct got_entry **p = list;
f7e8b360
NC
101 struct got_entry *entry;
102
08759e0f
CM
103 while (*p != NULL)
104 {
105 if ((*p)->type == type)
106 return;
107 p = &((*p)->next);
108 }
109
f7e8b360 110 entry = (struct got_entry *) xmalloc (sizeof (struct got_entry));
08759e0f
CM
111
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;
118
119 ARC_DEBUG ("New GOT got entry added to list: "
f7e8b360
NC
120 "type: %d, offset: %ld, existing_entries: %d\n",
121 type, (long) offset, existing_entries);
08759e0f
CM
122
123 /* Add the entry to the end of the list. */
124 *p = entry;
125}
126
127static enum tls_type_e
128tls_type_for_reloc (reloc_howto_type *howto)
129{
130 enum tls_type_e ret = GOT_UNKNOWN;
f7e8b360 131
08759e0f 132 if (is_reloc_for_GOT (howto))
f7e8b360
NC
133 return GOT_NORMAL;
134
135 switch (howto->type)
08759e0f 136 {
f7e8b360
NC
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;
08759e0f 149 }
f7e8b360 150
08759e0f
CM
151 return ret;
152};
153
154static struct got_entry **
155get_got_entry_list_for_symbol (bfd *abfd,
156 unsigned long r_symndx,
157 struct elf_link_hash_entry *h)
158{
159 if (h != NULL)
160 {
161 return &h->got.glist;
162 }
163 else
164 {
165 struct got_entry **local_got_ents
166 = arc_get_local_got_ents (abfd);
167 return &local_got_ents[r_symndx];
168 }
169}
170
171
172static enum tls_type_e
173arc_got_entry_type_for_reloc (reloc_howto_type *howto)
174{
175 enum tls_type_e type = GOT_UNKNOWN;
176
177 if (is_reloc_for_GOT (howto))
f7e8b360
NC
178 return GOT_NORMAL;
179
180 if (is_reloc_for_TLS (howto))
08759e0f
CM
181 {
182 switch (howto->type)
183 {
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;
192 }
193 }
194 return type;
195}
196
197#define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \
198 htab->s##SECNAME->size; \
199 { \
200 if (COND_FOR_RELOC) \
201 { \
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)); \
207 } \
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; \
213 } \
214
215static bfd_boolean
216arc_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)
220{
221 struct elf_link_hash_table *htab = elf_hash_table (info);
222
223 if (got_entry_for_type (list, type) != NULL)
224 return TRUE;
225
226 switch (type)
227 {
228 case GOT_NORMAL:
229 {
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);
234 }
235 break;
236
237
238 case GOT_TLS_GD:
239 {
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);
245 }
246 break;
247 case GOT_TLS_IE:
248 case GOT_TLS_LE:
249 {
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);
253 }
254 break;
255
256 default:
257 return FALSE;
258 break;
259 }
260 return TRUE;
261}
262
263
264static bfd_vma
f7e8b360
NC
265relocate_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)
08759e0f 274{
f7e8b360
NC
275 struct elf_link_hash_table *htab = elf_hash_table (info);
276 struct got_entry *entry = NULL;
08759e0f
CM
277
278 if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE)
279 return 0;
280
08759e0f
CM
281 entry = got_entry_for_type (list_p, type);
282 BFD_ASSERT (entry);
283
284 if (h == NULL
285 || (! elf_hash_table (info)->dynamic_sections_created
286 || (bfd_link_pic (info)
f7e8b360 287 && SYMBOL_REFERENCES_LOCAL (info, h))))
08759e0f
CM
288 {
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;
293
294 if (h != NULL)
295 {
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;
299
300 sym_value = h->root.u.def.value
f7e8b360
NC
301 + h->root.u.def.section->output_section->vma
302 + h->root.u.def.section->output_offset;
08759e0f
CM
303
304 tls_sec = elf_hash_table (info)->tls_sec;
305
306 symbol_name = h->root.root.string;
307 }
308 else
309 {
310 Elf_Internal_Sym *sym = local_syms + r_symndx;
311 asection *sec = local_sections[r_symndx];
312
313 sym_value = sym->st_value
f7e8b360
NC
314 + sec->output_section->vma
315 + sec->output_offset;
08759e0f
CM
316
317 tls_sec = elf_hash_table (info)->tls_sec;
318
319 symbol_name = local_name;
320 }
321
322
535b785f 323 if (entry && !entry->processed)
08759e0f
CM
324 {
325 switch (entry->type)
326 {
f7e8b360
NC
327 case GOT_TLS_GD:
328 {
329 BFD_ASSERT (tls_sec && tls_sec->output_section);
330 bfd_vma sec_vma = tls_sec->output_section->vma;
331
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));
337
338 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
4dd72ffd 339 "@ %lx, for symbol %s\n",
f7e8b360
NC
340 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
341 "GOT_TLS_IE"),
342 (long) (sym_value - sec_vma),
4dd72ffd
CM
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)),
f7e8b360
NC
348 symbol_name);
349 }
350 break;
351
352 case GOT_TLS_IE:
353 {
354 BFD_ASSERT (tls_sec && tls_sec->output_section);
355 bfd_vma ATTRIBUTE_UNUSED sec_vma
356 = tls_sec->output_section->vma;
357
4dd72ffd 358 bfd_put_32 (output_bfd,
a0abe743
CM
359 sym_value - sec_vma
360 + (elf_hash_table (info)->dynamic_sections_created ? 0 : TCB_SIZE),
4dd72ffd
CM
361 htab->sgot->contents + entry->offset
362 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
363 ? 4 : 0));
364
f7e8b360
NC
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),
4dd72ffd
CM
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)),
f7e8b360
NC
375 symbol_name);
376 }
377 break;
378
379 case GOT_NORMAL:
380 {
381 bfd_vma sec_vma
382 = reloc_data->sym_section->output_section->vma
383 + reloc_data->sym_section->output_offset;
384
c02d11a5
CM
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
f7e8b360
NC
396 {
397 bfd_put_32 (output_bfd,
398 reloc_data->sym_value + sec_vma,
399 htab->sgot->contents + entry->offset);
f7e8b360
NC
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);
407 }
f7e8b360
NC
408 }
409 break;
410 default:
411 BFD_ASSERT (0);
412 break;
08759e0f
CM
413 }
414 entry->processed = TRUE;
415 }
416 }
417
418 return entry->offset;
419}
420
421static void
422create_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)
426{
427 if (list == NULL)
428 return;
429
430 bfd_vma got_offset = list->offset;
431
432 if (list->type == GOT_NORMAL
535b785f 433 && !list->created_dyn_relocation)
08759e0f
CM
434 {
435 if (bfd_link_pic (info)
436 && h != NULL
437 && (info->symbolic || h->dynindx == -1)
438 && h->def_regular)
439 {
440 ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
441 }
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)
446 {
447 ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0);
448 }
449 list->created_dyn_relocation = TRUE;
450 }
451 else if (list->existing_entries != TLS_GOT_NONE
535b785f 452 && !list->created_dyn_relocation)
08759e0f
CM
453 {
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;
461
462 BFD_ASSERT (list->type != GOT_TLS_GD
463 || list->existing_entries == TLS_GOT_MOD_AND_OFF);
464
465 bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx;
466
467 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
468 {
469 ADD_RELA (output_bfd, got, got_offset, dynindx,
470 R_ARC_TLS_DTPMOD, 0);
471 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
f7e8b360 472GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n",
08759e0f 473 list->type,
f7e8b360
NC
474 (long) got_offset,
475 (long) (htab->sgot->output_section->vma
476 + htab->sgot->output_offset + got_offset),
477 (long) dynindx);
08759e0f 478 }
f7e8b360 479
08759e0f
CM
480 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
481 {
482 bfd_vma addend = 0;
483 if (list->type == GOT_TLS_IE)
a0abe743 484 {
08759e0f
CM
485 addend = bfd_get_32 (output_bfd,
486 htab->sgot->contents + got_offset);
a0abe743 487 }
08759e0f
CM
488
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);
495
496 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
f7e8b360 497GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
08759e0f 498 list->type,
f7e8b360
NC
499 (long) got_offset,
500 (long) (htab->sgot->output_section->vma
501 + htab->sgot->output_offset + got_offset),
502 (long) dynindx, (long) addend);
08759e0f
CM
503 }
504 list->created_dyn_relocation = TRUE;
505 }
506}
507
508static void
509create_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)
513{
514 if (list_p == NULL)
515 return;
516
517 struct got_entry *list = *list_p;
518 /* Traverse the list of got entries for this symbol. */
519 while (list)
520 {
521 create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
522 list = list->next;
523 }
524}
525
526#undef ADD_SYMBOL_REF_SEC_AND_RELOC
527
528#endif /* ARC_GOT_H */