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