15796c8dcSSimon Schubert /* VxWorks support for ELF
2*ef5ccd6cSJohn Marino Copyright 2005, 2006, 2007, 2009, 2012 Free Software Foundation, Inc.
35796c8dcSSimon Schubert
45796c8dcSSimon Schubert This file is part of BFD, the Binary File Descriptor library.
55796c8dcSSimon Schubert
65796c8dcSSimon Schubert This program is free software; you can redistribute it and/or modify
75796c8dcSSimon Schubert it under the terms of the GNU General Public License as published by
85796c8dcSSimon Schubert the Free Software Foundation; either version 3 of the License, or
95796c8dcSSimon Schubert (at your option) any later version.
105796c8dcSSimon Schubert
115796c8dcSSimon Schubert This program is distributed in the hope that it will be useful,
125796c8dcSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of
135796c8dcSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
145796c8dcSSimon Schubert GNU General Public License for more details.
155796c8dcSSimon Schubert
165796c8dcSSimon Schubert You should have received a copy of the GNU General Public License
175796c8dcSSimon Schubert along with this program; if not, write to the Free Software
185796c8dcSSimon Schubert Foundation, Inc., 59 Temple Place - Suite 330, Boston,
195796c8dcSSimon Schubert MA 02111-1307, USA. */
205796c8dcSSimon Schubert
215796c8dcSSimon Schubert /* This file provides routines used by all VxWorks targets. */
225796c8dcSSimon Schubert
235796c8dcSSimon Schubert #include "sysdep.h"
245796c8dcSSimon Schubert #include "bfd.h"
255796c8dcSSimon Schubert #include "libbfd.h"
265796c8dcSSimon Schubert #include "elf-bfd.h"
275796c8dcSSimon Schubert #include "elf-vxworks.h"
285796c8dcSSimon Schubert #include "elf/vxworks.h"
295796c8dcSSimon Schubert
305796c8dcSSimon Schubert /* Return true if symbol NAME, as defined by ABFD, is one of the special
315796c8dcSSimon Schubert __GOTT_BASE__ or __GOTT_INDEX__ symbols. */
325796c8dcSSimon Schubert
335796c8dcSSimon Schubert static bfd_boolean
elf_vxworks_gott_symbol_p(bfd * abfd,const char * name)345796c8dcSSimon Schubert elf_vxworks_gott_symbol_p (bfd *abfd, const char *name)
355796c8dcSSimon Schubert {
365796c8dcSSimon Schubert char leading;
375796c8dcSSimon Schubert
385796c8dcSSimon Schubert leading = bfd_get_symbol_leading_char (abfd);
395796c8dcSSimon Schubert if (leading)
405796c8dcSSimon Schubert {
415796c8dcSSimon Schubert if (*name != leading)
425796c8dcSSimon Schubert return FALSE;
435796c8dcSSimon Schubert name++;
445796c8dcSSimon Schubert }
455796c8dcSSimon Schubert return (strcmp (name, "__GOTT_BASE__") == 0
465796c8dcSSimon Schubert || strcmp (name, "__GOTT_INDEX__") == 0);
475796c8dcSSimon Schubert }
485796c8dcSSimon Schubert
495796c8dcSSimon Schubert /* Tweak magic VxWorks symbols as they are loaded. */
505796c8dcSSimon Schubert bfd_boolean
elf_vxworks_add_symbol_hook(bfd * abfd,struct bfd_link_info * info,Elf_Internal_Sym * sym,const char ** namep,flagword * flagsp,asection ** secp ATTRIBUTE_UNUSED,bfd_vma * valp ATTRIBUTE_UNUSED)515796c8dcSSimon Schubert elf_vxworks_add_symbol_hook (bfd *abfd,
525796c8dcSSimon Schubert struct bfd_link_info *info,
535796c8dcSSimon Schubert Elf_Internal_Sym *sym,
545796c8dcSSimon Schubert const char **namep,
555796c8dcSSimon Schubert flagword *flagsp,
565796c8dcSSimon Schubert asection **secp ATTRIBUTE_UNUSED,
575796c8dcSSimon Schubert bfd_vma *valp ATTRIBUTE_UNUSED)
585796c8dcSSimon Schubert {
595796c8dcSSimon Schubert /* Ideally these "magic" symbols would be exported by libc.so.1
605796c8dcSSimon Schubert which would be found via a DT_NEEDED tag, and then handled
615796c8dcSSimon Schubert specially by the linker at runtime. Except shared libraries
625796c8dcSSimon Schubert don't even link to libc.so.1 by default...
635796c8dcSSimon Schubert If the symbol is imported from, or will be put in a shared library,
645796c8dcSSimon Schubert give the symbol weak binding to get the desired samantics.
655796c8dcSSimon Schubert This transformation will be undone in
665796c8dcSSimon Schubert elf_i386_vxworks_link_output_symbol_hook. */
675796c8dcSSimon Schubert if ((info->shared || abfd->flags & DYNAMIC)
685796c8dcSSimon Schubert && elf_vxworks_gott_symbol_p (abfd, *namep))
695796c8dcSSimon Schubert {
705796c8dcSSimon Schubert sym->st_info = ELF_ST_INFO (STB_WEAK, ELF_ST_TYPE (sym->st_info));
715796c8dcSSimon Schubert *flagsp |= BSF_WEAK;
725796c8dcSSimon Schubert }
735796c8dcSSimon Schubert
745796c8dcSSimon Schubert return TRUE;
755796c8dcSSimon Schubert }
765796c8dcSSimon Schubert
775796c8dcSSimon Schubert /* Perform VxWorks-specific handling of the create_dynamic_sections hook.
785796c8dcSSimon Schubert When creating an executable, set *SRELPLT2_OUT to the .rel(a).plt.unloaded
795796c8dcSSimon Schubert section. */
805796c8dcSSimon Schubert
815796c8dcSSimon Schubert bfd_boolean
elf_vxworks_create_dynamic_sections(bfd * dynobj,struct bfd_link_info * info,asection ** srelplt2_out)825796c8dcSSimon Schubert elf_vxworks_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info,
835796c8dcSSimon Schubert asection **srelplt2_out)
845796c8dcSSimon Schubert {
855796c8dcSSimon Schubert struct elf_link_hash_table *htab;
865796c8dcSSimon Schubert const struct elf_backend_data *bed;
875796c8dcSSimon Schubert asection *s;
885796c8dcSSimon Schubert
895796c8dcSSimon Schubert htab = elf_hash_table (info);
905796c8dcSSimon Schubert bed = get_elf_backend_data (dynobj);
915796c8dcSSimon Schubert
925796c8dcSSimon Schubert if (!info->shared)
935796c8dcSSimon Schubert {
94*ef5ccd6cSJohn Marino s = bfd_make_section_anyway_with_flags (dynobj,
955796c8dcSSimon Schubert bed->default_use_rela_p
965796c8dcSSimon Schubert ? ".rela.plt.unloaded"
975796c8dcSSimon Schubert : ".rel.plt.unloaded",
985796c8dcSSimon Schubert SEC_HAS_CONTENTS | SEC_IN_MEMORY
99*ef5ccd6cSJohn Marino | SEC_READONLY
100*ef5ccd6cSJohn Marino | SEC_LINKER_CREATED);
1015796c8dcSSimon Schubert if (s == NULL
1025796c8dcSSimon Schubert || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align))
1035796c8dcSSimon Schubert return FALSE;
1045796c8dcSSimon Schubert
1055796c8dcSSimon Schubert *srelplt2_out = s;
1065796c8dcSSimon Schubert }
1075796c8dcSSimon Schubert
1085796c8dcSSimon Schubert /* Mark the GOT and PLT symbols as having relocations; they might
1095796c8dcSSimon Schubert not, but we won't know for sure until we build the GOT in
1105796c8dcSSimon Schubert finish_dynamic_symbol. Also make sure that the GOT symbol
1115796c8dcSSimon Schubert is entered into the dynamic symbol table; the loader uses it
1125796c8dcSSimon Schubert to initialize __GOTT_BASE__[__GOTT_INDEX__]. */
1135796c8dcSSimon Schubert if (htab->hgot)
1145796c8dcSSimon Schubert {
1155796c8dcSSimon Schubert htab->hgot->indx = -2;
1165796c8dcSSimon Schubert htab->hgot->other &= ~ELF_ST_VISIBILITY (-1);
1175796c8dcSSimon Schubert htab->hgot->forced_local = 0;
1185796c8dcSSimon Schubert if (!bfd_elf_link_record_dynamic_symbol (info, htab->hgot))
1195796c8dcSSimon Schubert return FALSE;
1205796c8dcSSimon Schubert }
1215796c8dcSSimon Schubert if (htab->hplt)
1225796c8dcSSimon Schubert {
1235796c8dcSSimon Schubert htab->hplt->indx = -2;
1245796c8dcSSimon Schubert htab->hplt->type = STT_FUNC;
1255796c8dcSSimon Schubert }
1265796c8dcSSimon Schubert
1275796c8dcSSimon Schubert return TRUE;
1285796c8dcSSimon Schubert }
1295796c8dcSSimon Schubert
1305796c8dcSSimon Schubert /* Tweak magic VxWorks symbols as they are written to the output file. */
1315796c8dcSSimon Schubert int
elf_vxworks_link_output_symbol_hook(struct bfd_link_info * info ATTRIBUTE_UNUSED,const char * name,Elf_Internal_Sym * sym,asection * input_sec ATTRIBUTE_UNUSED,struct elf_link_hash_entry * h)1325796c8dcSSimon Schubert elf_vxworks_link_output_symbol_hook (struct bfd_link_info *info
1335796c8dcSSimon Schubert ATTRIBUTE_UNUSED,
1345796c8dcSSimon Schubert const char *name,
1355796c8dcSSimon Schubert Elf_Internal_Sym *sym,
1365796c8dcSSimon Schubert asection *input_sec ATTRIBUTE_UNUSED,
1375796c8dcSSimon Schubert struct elf_link_hash_entry *h)
1385796c8dcSSimon Schubert {
1395796c8dcSSimon Schubert /* Reverse the effects of the hack in elf_vxworks_add_symbol_hook. */
1405796c8dcSSimon Schubert if (h
1415796c8dcSSimon Schubert && h->root.type == bfd_link_hash_undefweak
1425796c8dcSSimon Schubert && elf_vxworks_gott_symbol_p (h->root.u.undef.abfd, name))
1435796c8dcSSimon Schubert sym->st_info = ELF_ST_INFO (STB_GLOBAL, ELF_ST_TYPE (sym->st_info));
1445796c8dcSSimon Schubert
1455796c8dcSSimon Schubert return 1;
1465796c8dcSSimon Schubert }
1475796c8dcSSimon Schubert
1485796c8dcSSimon Schubert /* Copy relocations into the output file. Fixes up relocations against PLT
1495796c8dcSSimon Schubert entries, then calls the generic routine. */
1505796c8dcSSimon Schubert
1515796c8dcSSimon Schubert bfd_boolean
elf_vxworks_emit_relocs(bfd * output_bfd,asection * input_section,Elf_Internal_Shdr * input_rel_hdr,Elf_Internal_Rela * internal_relocs,struct elf_link_hash_entry ** rel_hash)1525796c8dcSSimon Schubert elf_vxworks_emit_relocs (bfd *output_bfd,
1535796c8dcSSimon Schubert asection *input_section,
1545796c8dcSSimon Schubert Elf_Internal_Shdr *input_rel_hdr,
1555796c8dcSSimon Schubert Elf_Internal_Rela *internal_relocs,
1565796c8dcSSimon Schubert struct elf_link_hash_entry **rel_hash)
1575796c8dcSSimon Schubert {
1585796c8dcSSimon Schubert const struct elf_backend_data *bed;
1595796c8dcSSimon Schubert int j;
1605796c8dcSSimon Schubert
1615796c8dcSSimon Schubert bed = get_elf_backend_data (output_bfd);
1625796c8dcSSimon Schubert
1635796c8dcSSimon Schubert if (output_bfd->flags & (DYNAMIC|EXEC_P))
1645796c8dcSSimon Schubert {
1655796c8dcSSimon Schubert Elf_Internal_Rela *irela;
1665796c8dcSSimon Schubert Elf_Internal_Rela *irelaend;
1675796c8dcSSimon Schubert struct elf_link_hash_entry **hash_ptr;
1685796c8dcSSimon Schubert
1695796c8dcSSimon Schubert for (irela = internal_relocs,
1705796c8dcSSimon Schubert irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
1715796c8dcSSimon Schubert * bed->s->int_rels_per_ext_rel),
1725796c8dcSSimon Schubert hash_ptr = rel_hash;
1735796c8dcSSimon Schubert irela < irelaend;
1745796c8dcSSimon Schubert irela += bed->s->int_rels_per_ext_rel,
1755796c8dcSSimon Schubert hash_ptr++)
1765796c8dcSSimon Schubert {
1775796c8dcSSimon Schubert if (*hash_ptr
1785796c8dcSSimon Schubert && (*hash_ptr)->def_dynamic
1795796c8dcSSimon Schubert && !(*hash_ptr)->def_regular
1805796c8dcSSimon Schubert && ((*hash_ptr)->root.type == bfd_link_hash_defined
1815796c8dcSSimon Schubert || (*hash_ptr)->root.type == bfd_link_hash_defweak)
1825796c8dcSSimon Schubert && (*hash_ptr)->root.u.def.section->output_section != NULL)
1835796c8dcSSimon Schubert {
1845796c8dcSSimon Schubert /* This is a relocation from an executable or shared
1855796c8dcSSimon Schubert library against a symbol in a different shared
1865796c8dcSSimon Schubert library. We are creating a definition in the output
1875796c8dcSSimon Schubert file but it does not come from any of our normal (.o)
1885796c8dcSSimon Schubert files. ie. a PLT stub. Normally this would be a
1895796c8dcSSimon Schubert relocation against against SHN_UNDEF with the VMA of
1905796c8dcSSimon Schubert the PLT stub. This upsets the VxWorks loader.
1915796c8dcSSimon Schubert Convert it to a section-relative relocation. This
1925796c8dcSSimon Schubert gets some other symbols (for instance .dynbss), but
1935796c8dcSSimon Schubert is conservatively correct. */
1945796c8dcSSimon Schubert for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
1955796c8dcSSimon Schubert {
1965796c8dcSSimon Schubert asection *sec = (*hash_ptr)->root.u.def.section;
1975796c8dcSSimon Schubert int this_idx = sec->output_section->target_index;
1985796c8dcSSimon Schubert
1995796c8dcSSimon Schubert irela[j].r_info
2005796c8dcSSimon Schubert = ELF32_R_INFO (this_idx, ELF32_R_TYPE (irela[j].r_info));
2015796c8dcSSimon Schubert irela[j].r_addend += (*hash_ptr)->root.u.def.value;
2025796c8dcSSimon Schubert irela[j].r_addend += sec->output_offset;
2035796c8dcSSimon Schubert }
2045796c8dcSSimon Schubert /* Stop the generic routine adjusting this entry. */
2055796c8dcSSimon Schubert *hash_ptr = NULL;
2065796c8dcSSimon Schubert }
2075796c8dcSSimon Schubert }
2085796c8dcSSimon Schubert }
2095796c8dcSSimon Schubert return _bfd_elf_link_output_relocs (output_bfd, input_section,
2105796c8dcSSimon Schubert input_rel_hdr, internal_relocs,
2115796c8dcSSimon Schubert rel_hash);
2125796c8dcSSimon Schubert }
2135796c8dcSSimon Schubert
2145796c8dcSSimon Schubert
2155796c8dcSSimon Schubert /* Set the sh_link and sh_info fields on the static plt relocation secton. */
2165796c8dcSSimon Schubert
2175796c8dcSSimon Schubert void
elf_vxworks_final_write_processing(bfd * abfd,bfd_boolean linker ATTRIBUTE_UNUSED)2185796c8dcSSimon Schubert elf_vxworks_final_write_processing (bfd *abfd,
2195796c8dcSSimon Schubert bfd_boolean linker ATTRIBUTE_UNUSED)
2205796c8dcSSimon Schubert {
2215796c8dcSSimon Schubert asection * sec;
2225796c8dcSSimon Schubert struct bfd_elf_section_data *d;
2235796c8dcSSimon Schubert
2245796c8dcSSimon Schubert sec = bfd_get_section_by_name (abfd, ".rel.plt.unloaded");
2255796c8dcSSimon Schubert if (!sec)
2265796c8dcSSimon Schubert sec = bfd_get_section_by_name (abfd, ".rela.plt.unloaded");
2275796c8dcSSimon Schubert if (!sec)
2285796c8dcSSimon Schubert return;
2295796c8dcSSimon Schubert d = elf_section_data (sec);
230*ef5ccd6cSJohn Marino d->this_hdr.sh_link = elf_onesymtab (abfd);
2315796c8dcSSimon Schubert sec = bfd_get_section_by_name (abfd, ".plt");
2325796c8dcSSimon Schubert if (sec)
2335796c8dcSSimon Schubert d->this_hdr.sh_info = elf_section_data (sec)->this_idx;
2345796c8dcSSimon Schubert }
2355796c8dcSSimon Schubert
2365796c8dcSSimon Schubert /* Add the dynamic entries required by VxWorks. These point to the
2375796c8dcSSimon Schubert tls sections. */
2385796c8dcSSimon Schubert
2395796c8dcSSimon Schubert bfd_boolean
elf_vxworks_add_dynamic_entries(bfd * output_bfd,struct bfd_link_info * info)2405796c8dcSSimon Schubert elf_vxworks_add_dynamic_entries (bfd *output_bfd, struct bfd_link_info *info)
2415796c8dcSSimon Schubert {
2425796c8dcSSimon Schubert if (bfd_get_section_by_name (output_bfd, ".tls_data"))
2435796c8dcSSimon Schubert {
2445796c8dcSSimon Schubert if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_START, 0)
2455796c8dcSSimon Schubert || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_SIZE, 0)
2465796c8dcSSimon Schubert || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_ALIGN, 0))
2475796c8dcSSimon Schubert return FALSE;
2485796c8dcSSimon Schubert }
2495796c8dcSSimon Schubert if (bfd_get_section_by_name (output_bfd, ".tls_vars"))
2505796c8dcSSimon Schubert {
2515796c8dcSSimon Schubert if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_START, 0)
2525796c8dcSSimon Schubert || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_SIZE, 0))
2535796c8dcSSimon Schubert return FALSE;
2545796c8dcSSimon Schubert }
2555796c8dcSSimon Schubert return TRUE;
2565796c8dcSSimon Schubert }
2575796c8dcSSimon Schubert
2585796c8dcSSimon Schubert /* If *DYN is one of the VxWorks-specific dynamic entries, then fill
2595796c8dcSSimon Schubert in the value now and return TRUE. Otherwise return FALSE. */
2605796c8dcSSimon Schubert
2615796c8dcSSimon Schubert bfd_boolean
elf_vxworks_finish_dynamic_entry(bfd * output_bfd,Elf_Internal_Dyn * dyn)2625796c8dcSSimon Schubert elf_vxworks_finish_dynamic_entry (bfd *output_bfd, Elf_Internal_Dyn *dyn)
2635796c8dcSSimon Schubert {
2645796c8dcSSimon Schubert asection *sec;
2655796c8dcSSimon Schubert
2665796c8dcSSimon Schubert switch (dyn->d_tag)
2675796c8dcSSimon Schubert {
2685796c8dcSSimon Schubert default:
2695796c8dcSSimon Schubert return FALSE;
2705796c8dcSSimon Schubert
2715796c8dcSSimon Schubert case DT_VX_WRS_TLS_DATA_START:
2725796c8dcSSimon Schubert sec = bfd_get_section_by_name (output_bfd, ".tls_data");
2735796c8dcSSimon Schubert dyn->d_un.d_ptr = sec->vma;
2745796c8dcSSimon Schubert break;
2755796c8dcSSimon Schubert
2765796c8dcSSimon Schubert case DT_VX_WRS_TLS_DATA_SIZE:
2775796c8dcSSimon Schubert sec = bfd_get_section_by_name (output_bfd, ".tls_data");
2785796c8dcSSimon Schubert dyn->d_un.d_val = sec->size;
2795796c8dcSSimon Schubert break;
2805796c8dcSSimon Schubert
2815796c8dcSSimon Schubert case DT_VX_WRS_TLS_DATA_ALIGN:
2825796c8dcSSimon Schubert sec = bfd_get_section_by_name (output_bfd, ".tls_data");
2835796c8dcSSimon Schubert dyn->d_un.d_val
284*ef5ccd6cSJohn Marino = (bfd_size_type)1 << bfd_get_section_alignment (output_bfd,
285*ef5ccd6cSJohn Marino sec);
2865796c8dcSSimon Schubert break;
2875796c8dcSSimon Schubert
2885796c8dcSSimon Schubert case DT_VX_WRS_TLS_VARS_START:
2895796c8dcSSimon Schubert sec = bfd_get_section_by_name (output_bfd, ".tls_vars");
2905796c8dcSSimon Schubert dyn->d_un.d_ptr = sec->vma;
2915796c8dcSSimon Schubert break;
2925796c8dcSSimon Schubert
2935796c8dcSSimon Schubert case DT_VX_WRS_TLS_VARS_SIZE:
2945796c8dcSSimon Schubert sec = bfd_get_section_by_name (output_bfd, ".tls_vars");
2955796c8dcSSimon Schubert dyn->d_un.d_val = sec->size;
2965796c8dcSSimon Schubert break;
2975796c8dcSSimon Schubert }
2985796c8dcSSimon Schubert return TRUE;
2995796c8dcSSimon Schubert }
3005796c8dcSSimon Schubert
3015796c8dcSSimon Schubert
302