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).
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
44 struct got_entry
*next
;
47 bfd_boolean processed
;
48 bfd_boolean created_dyn_relocation
;
49 enum tls_got_entries existing_entries
;
52 static struct got_entry
**
53 arc_get_local_got_ents (bfd
* abfd
)
55 static struct got_entry
**local_got_ents
= NULL
;
57 if (local_got_ents
== NULL
)
60 Elf_Internal_Shdr
*symtab_hdr
= &((elf_tdata (abfd
))->symtab_hdr
);
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
)
68 memset (local_got_ents
, 0, sizeof (struct got_entry
*) * size
);
69 elf_local_got_ents (abfd
) = local_got_ents
;
72 return local_got_ents
;
75 static struct got_entry
*
76 got_entry_for_type (struct got_entry
**list
,
79 struct got_entry
**p
= list
;
83 if ((*p
)->type
== type
)
91 new_got_entry_to_list (struct got_entry
**list
,
94 enum tls_got_entries existing_entries
)
96 /* Find list end. Avoid having multiple entries of the same
98 struct got_entry
**p
= list
;
99 struct got_entry
*entry
;
103 if ((*p
)->type
== type
)
108 entry
= (struct got_entry
*) xmalloc (sizeof (struct got_entry
));
111 entry
->offset
= offset
;
113 entry
->processed
= FALSE
;
114 entry
->created_dyn_relocation
= FALSE
;
115 entry
->existing_entries
= existing_entries
;
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
);
121 /* Add the entry to the end of the list. */
125 static enum tls_type_e
126 tls_type_for_reloc (reloc_howto_type
*howto
)
128 enum tls_type_e ret
= GOT_UNKNOWN
;
130 if (is_reloc_for_GOT (howto
))
135 case R_ARC_TLS_GD_GOT
:
138 case R_ARC_TLS_IE_GOT
:
141 case R_ARC_TLS_LE_32
:
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
)
159 return &h
->got
.glist
;
163 struct got_entry
**local_got_ents
164 = arc_get_local_got_ents (abfd
);
165 return &local_got_ents
[r_symndx
];
170 static enum tls_type_e
171 arc_got_entry_type_for_reloc (reloc_howto_type
*howto
)
173 enum tls_type_e type
= GOT_UNKNOWN
;
175 if (is_reloc_for_GOT (howto
))
178 if (is_reloc_for_TLS (howto
))
182 case R_ARC_TLS_GD_GOT
:
185 case R_ARC_TLS_IE_GOT
:
195 #define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \
196 htab->s##SECNAME->size; \
198 if (COND_FOR_RELOC) \
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)); \
207 if (h->dynindx == -1 && !h->forced_local) \
208 if (! bfd_elf_link_record_dynamic_symbol (info, H)) \
210 htab->s##SECNAME->size += 4; \
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
)
219 struct elf_link_hash_table
*htab
= elf_hash_table (info
);
221 if (got_entry_for_type (list
, type
) != NULL
)
229 = ADD_SYMBOL_REF_SEC_AND_RELOC (got
, bfd_link_pic (info
)
231 new_got_entry_to_list (list
, type
, offset
, TLS_GOT_NONE
);
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
);
249 = ADD_SYMBOL_REF_SEC_AND_RELOC (got
, TRUE
, h
);
250 new_got_entry_to_list (list
, type
, offset
, TLS_GOT_OFF
);
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
,
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
)
273 struct elf_link_hash_table
*htab
= elf_hash_table (info
);
274 struct got_entry
*entry
= NULL
;
276 if (list_p
== NULL
|| type
== GOT_UNKNOWN
|| type
== GOT_TLS_LE
)
279 entry
= got_entry_for_type (list_p
, type
);
283 || (! elf_hash_table (info
)->dynamic_sections_created
284 || (bfd_link_pic (info
)
285 && SYMBOL_REFERENCES_LOCAL (info
, h
))))
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;
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
;
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
;
302 tls_sec
= elf_hash_table (info
)->tls_sec
;
304 symbol_name
= h
->root
.root
.string
;
308 Elf_Internal_Sym
*sym
= local_syms
+ r_symndx
;
309 asection
*sec
= local_sections
[r_symndx
];
311 sym_value
= sym
->st_value
312 + sec
->output_section
->vma
313 + sec
->output_offset
;
315 tls_sec
= elf_hash_table (info
)->tls_sec
;
317 symbol_name
= local_name
;
321 if (entry
&& entry
->processed
== FALSE
)
327 BFD_ASSERT (tls_sec
&& tls_sec
->output_section
);
328 bfd_vma sec_vma
= tls_sec
->output_section
->vma
;
330 bfd_put_32 (output_bfd
,
332 htab
->sgot
->contents
+ entry
->offset
333 + (entry
->existing_entries
== TLS_GOT_MOD_AND_OFF
336 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
337 "@ %p, for symbol %s\n",
338 (entry
->type
== GOT_TLS_GD
? "GOT_TLS_GD" :
340 (long) (sym_value
- sec_vma
),
341 htab
->sgot
->contents
+ entry
->offset
342 + (entry
->existing_entries
== TLS_GOT_MOD_AND_OFF
350 BFD_ASSERT (tls_sec
&& tls_sec
->output_section
);
351 bfd_vma ATTRIBUTE_UNUSED sec_vma
352 = tls_sec
->output_section
->vma
;
354 ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx "
355 "@ %p, for symbol %s\n",
356 (entry
->type
== GOT_TLS_GD
? "GOT_TLS_GD" :
358 (long) (sym_value
- sec_vma
),
359 htab
->sgot
->contents
+ entry
->offset
360 + (entry
->existing_entries
== TLS_GOT_MOD_AND_OFF
369 = reloc_data
->sym_section
->output_section
->vma
370 + reloc_data
->sym_section
->output_offset
;
373 && h
->root
.type
== bfd_link_hash_undefweak
)
374 ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
375 "@ %#08lx for sym %s in got offset %#lx "
377 (long) (htab
->sgot
->output_section
->vma
378 + htab
->sgot
->output_offset
381 (long) entry
->offset
);
384 bfd_put_32 (output_bfd
,
385 reloc_data
->sym_value
+ sec_vma
,
386 htab
->sgot
->contents
+ entry
->offset
);
387 ARC_DEBUG ("arc_info: PATCHED: %#08lx "
388 "@ %#08lx for sym %s in got offset %#lx\n",
389 (long) (reloc_data
->sym_value
+ sec_vma
),
390 (long) (htab
->sgot
->output_section
->vma
391 + htab
->sgot
->output_offset
+ entry
->offset
),
393 (long) entry
->offset
);
401 entry
->processed
= TRUE
;
405 return entry
->offset
;
409 create_got_dynrelocs_for_single_entry (struct got_entry
*list
,
411 struct bfd_link_info
* info
,
412 struct elf_link_hash_entry
*h
)
417 bfd_vma got_offset
= list
->offset
;
419 if (list
->type
== GOT_NORMAL
420 && list
->created_dyn_relocation
== FALSE
)
422 if (bfd_link_pic (info
)
424 && (info
->symbolic
|| h
->dynindx
== -1)
427 ADD_RELA (output_bfd
, got
, got_offset
, 0, R_ARC_RELATIVE
, 0);
429 /* Do not fully understand the side effects of this condition.
430 The relocation space might still being reserved. Perhaps
431 I should clear its value. */
432 else if (h
!= NULL
&& h
->dynindx
!= -1)
434 ADD_RELA (output_bfd
, got
, got_offset
, h
->dynindx
, R_ARC_GLOB_DAT
, 0);
436 list
->created_dyn_relocation
= TRUE
;
438 else if (list
->existing_entries
!= TLS_GOT_NONE
439 && list
->created_dyn_relocation
== FALSE
)
441 /* TODO TLS: This is not called for local symbols.
442 In order to correctly implement TLS, this should also
443 be called for all local symbols with tls got entries.
444 Should be moved to relocate_section in order to make it
445 work for local symbols. */
446 struct elf_link_hash_table
*htab
= elf_hash_table (info
);
447 enum tls_got_entries e
= list
->existing_entries
;
449 BFD_ASSERT (list
->type
!= GOT_TLS_GD
450 || list
->existing_entries
== TLS_GOT_MOD_AND_OFF
);
452 bfd_vma dynindx
= (h
== NULL
|| h
->dynindx
== -1) ? 0 : h
->dynindx
;
454 if (e
== TLS_GOT_MOD_AND_OFF
|| e
== TLS_GOT_MOD
)
456 ADD_RELA (output_bfd
, got
, got_offset
, dynindx
,
457 R_ARC_TLS_DTPMOD
, 0);
458 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
459 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n",
462 (long) (htab
->sgot
->output_section
->vma
463 + htab
->sgot
->output_offset
+ got_offset
),
467 if (e
== TLS_GOT_MOD_AND_OFF
|| e
== TLS_GOT_OFF
)
470 if (list
->type
== GOT_TLS_IE
)
471 addend
= bfd_get_32 (output_bfd
,
472 htab
->sgot
->contents
+ got_offset
);
474 ADD_RELA (output_bfd
, got
,
475 got_offset
+ (e
== TLS_GOT_MOD_AND_OFF
? 4 : 0),
477 (list
->type
== GOT_TLS_IE
? R_ARC_TLS_TPOFF
481 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
482 GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n",
485 (long) (htab
->sgot
->output_section
->vma
486 + htab
->sgot
->output_offset
+ got_offset
),
487 (long) dynindx
, (long) addend
);
489 list
->created_dyn_relocation
= TRUE
;
494 create_got_dynrelocs_for_got_info (struct got_entry
**list_p
,
496 struct bfd_link_info
* info
,
497 struct elf_link_hash_entry
*h
)
502 struct got_entry
*list
= *list_p
;
503 /* Traverse the list of got entries for this symbol. */
506 create_got_dynrelocs_for_single_entry (list
, output_bfd
, info
, h
);
511 #undef ADD_SYMBOL_REF_SEC_AND_RELOC
513 #endif /* ARC_GOT_H */