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