[ARC] Refactored location where GOT information is collected.
[deliverable/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 enum 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
36 enum 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
44 struct 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
54 static struct got_entry **
55 arc_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
77 static struct got_entry *
78 got_entry_for_type (struct got_entry **list,
79 enum tls_type_e type)
80 {
81 struct got_entry **p = list;
82
83 while (*p != NULL)
84 {
85 if ((*p)->type == type)
86 return *p;
87 p = &((*p)->next);
88 }
89 return NULL;
90 }
91
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)
97 {
98 /* Find list end. Avoid having multiple entries of the same
99 type. */
100 struct got_entry **p = list;
101 struct got_entry *entry;
102
103 while (*p != NULL)
104 {
105 if ((*p)->type == type)
106 return;
107 p = &((*p)->next);
108 }
109
110 entry = (struct got_entry *) xmalloc (sizeof (struct got_entry));
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: "
120 "type: %d, offset: %ld, existing_entries: %d\n",
121 type, (long) offset, existing_entries);
122
123 /* Add the entry to the end of the list. */
124 *p = entry;
125 }
126
127 static enum tls_type_e
128 tls_type_for_reloc (reloc_howto_type *howto)
129 {
130 enum tls_type_e ret = GOT_UNKNOWN;
131
132 if (is_reloc_for_GOT (howto))
133 return GOT_NORMAL;
134
135 switch (howto->type)
136 {
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;
149 }
150
151 return ret;
152 };
153
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)
158 {
159 struct elf_arc_link_hash_entry *h1 =
160 ((struct elf_arc_link_hash_entry *) h);
161 if (h1 != NULL)
162 {
163 return &h1->got_ents;
164 }
165 else
166 {
167 struct got_entry **local_got_ents
168 = arc_get_local_got_ents (abfd);
169 return &local_got_ents[r_symndx];
170 }
171 }
172
173
174 static enum tls_type_e
175 arc_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))
180 return GOT_NORMAL;
181
182 if (is_reloc_for_TLS (howto))
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 { \
204 htab->srel##SECNAME->size += sizeof (Elf32_External_Rela); \
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) \
211 if (h->dynindx == -1 && !h->forced_local) \
212 if (! bfd_elf_link_record_dynamic_symbol (info, H)) \
213 return FALSE; \
214 htab->s##SECNAME->size += 4; \
215 } \
216
217 static bfd_boolean
218 arc_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)
226 return TRUE;
227
228 switch (type)
229 {
230 case GOT_NORMAL:
231 {
232 bfd_vma offset
233 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info)
234 || h != NULL, h);
235 new_got_entry_to_list (list, type, offset, TLS_GOT_NONE);
236 }
237 break;
238
239
240 case GOT_TLS_GD:
241 {
242 bfd_vma offset
243 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
244 bfd_vma ATTRIBUTE_UNUSED notneeded
245 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
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
253 = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
254 new_got_entry_to_list (list, type, offset, TLS_GOT_OFF);
255 }
256 break;
257
258 default:
259 return FALSE;
260 break;
261 }
262 return TRUE;
263 }
264
265
266 static bfd_vma
267 relocate_fix_got_relocs_for_got_info (struct got_entry ** list_p,
268 enum tls_type_e type,
269 struct bfd_link_info * info,
270 bfd * output_bfd,
271 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 struct elf_link_hash_table *htab = elf_hash_table (info);
278 struct got_entry *entry = NULL;
279
280 if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE)
281 return 0;
282
283 entry = got_entry_for_type (list_p, type);
284 BFD_ASSERT (entry);
285
286 if (h == NULL
287 || (! elf_hash_table (info)->dynamic_sections_created
288 || (bfd_link_pic (info)
289 && SYMBOL_REFERENCES_LOCAL (info, h))))
290 {
291 const char ATTRIBUTE_UNUSED *symbol_name;
292 static const char local_name[] = "(local)";
293 asection *tls_sec = NULL;
294 bfd_vma sym_value = 0;
295
296 if (h != NULL)
297 {
298 // TODO: This should not be here.
299 reloc_data->sym_value = h->root.u.def.value;
300 reloc_data->sym_section = h->root.u.def.section;
301
302 sym_value = h->root.u.def.value
303 + h->root.u.def.section->output_section->vma
304 + h->root.u.def.section->output_offset;
305
306 tls_sec = elf_hash_table (info)->tls_sec;
307
308 symbol_name = h->root.root.string;
309 }
310 else
311 {
312 Elf_Internal_Sym *sym = local_syms + r_symndx;
313 asection *sec = local_sections[r_symndx];
314
315 sym_value = sym->st_value
316 + sec->output_section->vma
317 + sec->output_offset;
318
319 tls_sec = elf_hash_table (info)->tls_sec;
320
321 symbol_name = local_name;
322 }
323
324
325 if (entry && !entry->processed)
326 {
327 switch (entry->type)
328 {
329 case GOT_TLS_GD:
330 {
331 BFD_ASSERT (tls_sec && tls_sec->output_section);
332 bfd_vma sec_vma = tls_sec->output_section->vma;
333
334 bfd_put_32 (output_bfd,
335 sym_value - sec_vma,
336 htab->sgot->contents + entry->offset
337 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
338 ? 4 : 0));
339
340 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
341 "@ %lx, for symbol %s\n",
342 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
343 "GOT_TLS_IE"),
344 (long) (sym_value - sec_vma),
345 (long) (htab->sgot->output_section->vma
346 + htab->sgot->output_offset->vma
347 + entry->offset
348 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
349 ? 4 : 0)),
350 symbol_name);
351 }
352 break;
353
354 case GOT_TLS_IE:
355 {
356 BFD_ASSERT (tls_sec && tls_sec->output_section);
357 bfd_vma ATTRIBUTE_UNUSED sec_vma
358 = tls_sec->output_section->vma;
359
360 bfd_put_32 (output_bfd,
361 sym_value - sec_vma
362 + (elf_hash_table (info)->dynamic_sections_created ? 0 : TCB_SIZE),
363 htab->sgot->contents + entry->offset
364 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
365 ? 4 : 0));
366
367 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
368 "@ %p, for symbol %s\n",
369 (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
370 "GOT_TLS_IE"),
371 (long) (sym_value - sec_vma),
372 (long) (htab->sgot->output_section->vma
373 + htab->sgot->output_offset->vma
374 + entry->offset
375 + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
376 ? 4 : 0)),
377 symbol_name);
378 }
379 break;
380
381 case GOT_NORMAL:
382 {
383 bfd_vma sec_vma
384 = reloc_data->sym_section->output_section->vma
385 + reloc_data->sym_section->output_offset;
386
387 if (h != NULL
388 && h->root.type == bfd_link_hash_undefweak)
389 ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
390 "@ %#08lx for sym %s in got offset %#lx "
391 "(is undefweak)\n",
392 (long) (htab->sgot->output_section->vma
393 + htab->sgot->output_offset
394 + entry->offset),
395 symbol_name,
396 (long) entry->offset);
397 else
398 {
399 bfd_put_32 (output_bfd,
400 reloc_data->sym_value + sec_vma,
401 htab->sgot->contents + entry->offset);
402 ARC_DEBUG ("arc_info: PATCHED: %#08lx "
403 "@ %#08lx for sym %s in got offset %#lx\n",
404 (long) (reloc_data->sym_value + sec_vma),
405 (long) (htab->sgot->output_section->vma
406 + htab->sgot->output_offset + entry->offset),
407 symbol_name,
408 (long) entry->offset);
409 }
410 }
411 break;
412 default:
413 BFD_ASSERT (0);
414 break;
415 }
416 entry->processed = TRUE;
417 }
418 }
419
420 return entry->offset;
421 }
422
423 static void
424 create_got_dynrelocs_for_single_entry (struct got_entry *list,
425 bfd *output_bfd,
426 struct bfd_link_info * info,
427 struct elf_link_hash_entry *h)
428 {
429 if (list == NULL)
430 return;
431
432 bfd_vma got_offset = list->offset;
433
434 if (list->type == GOT_NORMAL
435 && !list->created_dyn_relocation)
436 {
437 if (bfd_link_pic (info)
438 && h != NULL
439 && (info->symbolic || h->dynindx == -1)
440 && h->def_regular)
441 {
442 ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
443 }
444 /* Do not fully understand the side effects of this condition.
445 The relocation space might still being reserved. Perhaps
446 I should clear its value. */
447 else if (h != NULL && h->dynindx != -1)
448 {
449 ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0);
450 }
451 list->created_dyn_relocation = TRUE;
452 }
453 else if (list->existing_entries != TLS_GOT_NONE
454 && !list->created_dyn_relocation)
455 {
456 /* TODO TLS: This is not called for local symbols.
457 In order to correctly implement TLS, this should also
458 be called for all local symbols with tls got entries.
459 Should be moved to relocate_section in order to make it
460 work for local symbols. */
461 struct elf_link_hash_table *htab = elf_hash_table (info);
462 enum tls_got_entries e = list->existing_entries;
463
464 BFD_ASSERT (list->type != GOT_TLS_GD
465 || list->existing_entries == TLS_GOT_MOD_AND_OFF);
466
467 bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx;
468
469 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
470 {
471 ADD_RELA (output_bfd, got, got_offset, dynindx,
472 R_ARC_TLS_DTPMOD, 0);
473 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
474 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n",
475 list->type,
476 (long) got_offset,
477 (long) (htab->sgot->output_section->vma
478 + htab->sgot->output_offset + got_offset),
479 (long) dynindx);
480 }
481
482 if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
483 {
484 bfd_vma addend = 0;
485 if (list->type == GOT_TLS_IE)
486 {
487 addend = bfd_get_32 (output_bfd,
488 htab->sgot->contents + got_offset);
489 }
490
491 ADD_RELA (output_bfd, got,
492 got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
493 dynindx,
494 (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF
495 : R_ARC_TLS_DTPOFF),
496 addend);
497
498 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
499 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
500 list->type,
501 (long) got_offset,
502 (long) (htab->sgot->output_section->vma
503 + htab->sgot->output_offset + got_offset),
504 (long) dynindx, (long) addend);
505 }
506 list->created_dyn_relocation = TRUE;
507 }
508 }
509
510 static void
511 create_got_dynrelocs_for_got_info (struct got_entry **list_p,
512 bfd *output_bfd,
513 struct bfd_link_info * info,
514 struct elf_link_hash_entry *h)
515 {
516 if (list_p == NULL)
517 return;
518
519 struct got_entry *list = *list_p;
520 /* Traverse the list of got entries for this symbol. */
521 while (list)
522 {
523 create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
524 list = list->next;
525 }
526 }
527
528 #undef ADD_SYMBOL_REF_SEC_AND_RELOC
529
530 #endif /* ARC_GOT_H */
This page took 0.060371 seconds and 5 git commands to generate.