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