1214082Sdim/* VxWorks support for ELF 2214634Sdim Copyright 2005, 2007 Free Software Foundation, Inc. 3214082Sdim 4214082Sdim This file is part of BFD, the Binary File Descriptor library. 5214082Sdim 6214082Sdim This program is free software; you can redistribute it and/or modify 7214082Sdim it under the terms of the GNU General Public License as published by 8214082Sdim the Free Software Foundation; either version 2 of the License, or 9214082Sdim (at your option) any later version. 10214082Sdim 11214082Sdim This program is distributed in the hope that it will be useful, 12214082Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 13214082Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14214082Sdim GNU General Public License for more details. 15214082Sdim 16214082Sdim You should have received a copy of the GNU General Public License 17214082Sdim along with this program; if not, write to the Free Software 18214082Sdim Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19214082Sdim */ 20214082Sdim 21214082Sdim/* This file provides routines used by all VxWorks targets. */ 22214082Sdim 23214634Sdim#include "sysdep.h" 24214082Sdim#include "bfd.h" 25214082Sdim#include "libbfd.h" 26214082Sdim#include "elf-bfd.h" 27214082Sdim#include "elf-vxworks.h" 28214082Sdim 29214634Sdim/* Return true if symbol NAME, as defined by ABFD, is one of the special 30214634Sdim __GOTT_BASE__ or __GOTT_INDEX__ symbols. */ 31214634Sdim 32214634Sdimstatic bfd_boolean 33214634Sdimelf_vxworks_gott_symbol_p (bfd *abfd, const char *name) 34214634Sdim{ 35214634Sdim char leading; 36214634Sdim 37214634Sdim leading = bfd_get_symbol_leading_char (abfd); 38214634Sdim if (leading) 39214634Sdim { 40214634Sdim if (*name != leading) 41214634Sdim return FALSE; 42214634Sdim name++; 43214634Sdim } 44214634Sdim return (strcmp (name, "__GOTT_BASE__") == 0 45214634Sdim || strcmp (name, "__GOTT_INDEX__") == 0); 46214634Sdim} 47214634Sdim 48214082Sdim/* Tweak magic VxWorks symbols as they are loaded. */ 49214082Sdimbfd_boolean 50214634Sdimelf_vxworks_add_symbol_hook (bfd *abfd, 51214082Sdim struct bfd_link_info *info, 52214082Sdim Elf_Internal_Sym *sym, 53214082Sdim const char **namep, 54214082Sdim flagword *flagsp, 55214082Sdim asection **secp ATTRIBUTE_UNUSED, 56214082Sdim bfd_vma *valp ATTRIBUTE_UNUSED) 57214082Sdim{ 58214082Sdim /* Ideally these "magic" symbols would be exported by libc.so.1 59214082Sdim which would be found via a DT_NEEDED tag, and then handled 60214082Sdim specially by the linker at runtime. Except shared libraries 61214082Sdim don't even link to libc.so.1 by default... 62214082Sdim If the symbol is imported from, or will be put in a shared library, 63214082Sdim give the symbol weak binding to get the desired samantics. 64214082Sdim This transformation will be undone in 65214082Sdim elf_i386_vxworks_link_output_symbol_hook. */ 66214082Sdim if ((info->shared || abfd->flags & DYNAMIC) 67214634Sdim && elf_vxworks_gott_symbol_p (abfd, *namep)) 68214082Sdim { 69214082Sdim sym->st_info = ELF_ST_INFO (STB_WEAK, ELF_ST_TYPE (sym->st_info)); 70214082Sdim *flagsp |= BSF_WEAK; 71214082Sdim } 72214082Sdim 73214082Sdim return TRUE; 74214082Sdim} 75214082Sdim 76214082Sdim/* Perform VxWorks-specific handling of the create_dynamic_sections hook. 77214082Sdim When creating an executable, set *SRELPLT2_OUT to the .rel(a).plt.unloaded 78214082Sdim section. */ 79214082Sdim 80214082Sdimbfd_boolean 81214082Sdimelf_vxworks_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info, 82214082Sdim asection **srelplt2_out) 83214082Sdim{ 84214082Sdim struct elf_link_hash_table *htab; 85214082Sdim const struct elf_backend_data *bed; 86214082Sdim asection *s; 87214082Sdim 88214082Sdim htab = elf_hash_table (info); 89214082Sdim bed = get_elf_backend_data (dynobj); 90214082Sdim 91214082Sdim if (!info->shared) 92214082Sdim { 93214082Sdim s = bfd_make_section_with_flags (dynobj, 94214082Sdim bed->default_use_rela_p 95214082Sdim ? ".rela.plt.unloaded" 96214082Sdim : ".rel.plt.unloaded", 97214082Sdim SEC_HAS_CONTENTS | SEC_IN_MEMORY 98214082Sdim | SEC_READONLY | SEC_LINKER_CREATED); 99214082Sdim if (s == NULL 100214082Sdim || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) 101214082Sdim return FALSE; 102214082Sdim 103214082Sdim *srelplt2_out = s; 104214082Sdim } 105214082Sdim 106214082Sdim /* Mark the GOT and PLT symbols as having relocations; they might 107214082Sdim not, but we won't know for sure until we build the GOT in 108214082Sdim finish_dynamic_symbol. Also make sure that the GOT symbol 109214082Sdim is entered into the dynamic symbol table; the loader uses it 110214082Sdim to initialize __GOTT_BASE__[__GOTT_INDEX__]. */ 111214082Sdim if (htab->hgot) 112214082Sdim { 113214082Sdim htab->hgot->indx = -2; 114214082Sdim htab->hgot->other &= ~ELF_ST_VISIBILITY (-1); 115214082Sdim htab->hgot->forced_local = 0; 116214082Sdim if (!bfd_elf_link_record_dynamic_symbol (info, htab->hgot)) 117214082Sdim return FALSE; 118214082Sdim } 119214082Sdim if (htab->hplt) 120214082Sdim { 121214082Sdim htab->hplt->indx = -2; 122214082Sdim htab->hplt->type = STT_FUNC; 123214082Sdim } 124214082Sdim 125214082Sdim return TRUE; 126214082Sdim} 127214082Sdim 128214082Sdim/* Tweak magic VxWorks symbols as they are written to the output file. */ 129214082Sdimbfd_boolean 130214082Sdimelf_vxworks_link_output_symbol_hook (struct bfd_link_info *info 131214082Sdim ATTRIBUTE_UNUSED, 132214082Sdim const char *name, 133214082Sdim Elf_Internal_Sym *sym, 134214082Sdim asection *input_sec ATTRIBUTE_UNUSED, 135214634Sdim struct elf_link_hash_entry *h) 136214082Sdim{ 137214082Sdim /* Reverse the effects of the hack in elf_vxworks_add_symbol_hook. */ 138214634Sdim if (h 139214634Sdim && h->root.type == bfd_link_hash_undefweak 140214634Sdim && elf_vxworks_gott_symbol_p (h->root.u.undef.abfd, name)) 141214082Sdim sym->st_info = ELF_ST_INFO (STB_GLOBAL, ELF_ST_TYPE (sym->st_info)); 142214082Sdim 143214082Sdim return TRUE; 144214082Sdim} 145214082Sdim 146214082Sdim 147214082Sdim/* Copy relocations into the output file. Fixes up relocations againt PLT 148214082Sdim entries, then calls the generic routine. */ 149214082Sdim 150214082Sdimbfd_boolean 151214082Sdimelf_vxworks_emit_relocs (bfd *output_bfd, 152214082Sdim asection *input_section, 153214082Sdim Elf_Internal_Shdr *input_rel_hdr, 154214082Sdim Elf_Internal_Rela *internal_relocs, 155214082Sdim struct elf_link_hash_entry **rel_hash) 156214082Sdim{ 157214082Sdim const struct elf_backend_data *bed; 158214082Sdim Elf_Internal_Rela *irela; 159214082Sdim Elf_Internal_Rela *irelaend; 160214082Sdim int j; 161214082Sdim 162214082Sdim bed = get_elf_backend_data (output_bfd); 163214082Sdim 164214082Sdim irela = internal_relocs; 165214082Sdim irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) 166214082Sdim * bed->s->int_rels_per_ext_rel); 167214082Sdim while (irela < irelaend) 168214082Sdim { 169214082Sdim if ((output_bfd->flags & (DYNAMIC|EXEC_P)) 170214082Sdim && *rel_hash 171214082Sdim && (*rel_hash)->def_dynamic 172214082Sdim && !(*rel_hash)->def_regular 173214634Sdim && ((*rel_hash)->root.type == bfd_link_hash_defined 174214634Sdim || (*rel_hash)->root.type == bfd_link_hash_defweak) 175214082Sdim && (*rel_hash)->root.u.def.section->output_section != NULL) 176214082Sdim { 177214082Sdim /* This is a relocation from an executable or shared library 178214082Sdim against a symbol in a different shared library. We are 179214082Sdim creating a definition in the output file but it does not come 180214082Sdim from any of our normal (.o) files. ie. a PLT stub. 181214082Sdim Normally this would be a relocation against against SHN_UNDEF 182214082Sdim with the VMA of the PLT stub. This upsets the VxWorks loader. 183214082Sdim Convert it to a section-relative relocation. 184214082Sdim This gets some other symbols (for instance .dynbss), 185214082Sdim but is conservatively correct. */ 186214082Sdim for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) 187214082Sdim { 188214082Sdim asection *sec = (*rel_hash)->root.u.def.section; 189214634Sdim int this_idx = sec->output_section->target_index; 190214082Sdim 191214082Sdim irela[j].r_info = ELF32_R_INFO (this_idx, 192214082Sdim ELF32_R_TYPE (irela[j].r_info)); 193214082Sdim irela[j].r_addend += (*rel_hash)->root.u.def.value; 194214082Sdim irela[j].r_addend += sec->output_offset; 195214082Sdim } 196214082Sdim /* Stop the generic routine adjusting this entry. */ 197214082Sdim *rel_hash = NULL; 198214082Sdim } 199214082Sdim irela += bed->s->int_rels_per_ext_rel; 200214082Sdim rel_hash++; 201214082Sdim } 202214082Sdim return _bfd_elf_link_output_relocs (output_bfd, input_section, 203214082Sdim input_rel_hdr, internal_relocs, 204214082Sdim rel_hash); 205214082Sdim} 206214082Sdim 207214082Sdim 208214082Sdim/* Set the sh_link and sh_info fields on the static plt relocation secton. */ 209214082Sdim 210214082Sdimvoid 211214082Sdimelf_vxworks_final_write_processing (bfd *abfd, 212214082Sdim bfd_boolean linker ATTRIBUTE_UNUSED) 213214082Sdim{ 214214082Sdim asection * sec; 215214082Sdim struct bfd_elf_section_data *d; 216214082Sdim 217214082Sdim sec = bfd_get_section_by_name (abfd, ".rel.plt.unloaded"); 218214082Sdim if (!sec) 219214082Sdim sec = bfd_get_section_by_name (abfd, ".rela.plt.unloaded"); 220214082Sdim if (!sec) 221214082Sdim return; 222214082Sdim d = elf_section_data (sec); 223214082Sdim d->this_hdr.sh_link = elf_tdata (abfd)->symtab_section; 224214082Sdim sec = bfd_get_section_by_name (abfd, ".plt"); 225214082Sdim if (sec) 226214082Sdim d->this_hdr.sh_info = elf_section_data (sec)->this_idx; 227214082Sdim} 228