Commit | Line | Data |
---|---|---|
eac338cf | 1 | /* VxWorks support for ELF |
3db64b00 | 2 | Copyright 2005, 2007 Free Software Foundation, Inc. |
eac338cf PB |
3 | |
4 | This file is part of BFD, the Binary File Descriptor library. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
cd123cb7 | 8 | the Free Software Foundation; either version 3 of the License, or |
eac338cf PB |
9 | (at your option) any later version. |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
cd123cb7 NC |
18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
19 | MA 02111-1307, USA. */ | |
eac338cf PB |
20 | |
21 | /* This file provides routines used by all VxWorks targets. */ | |
22 | ||
eac338cf | 23 | #include "sysdep.h" |
3db64b00 | 24 | #include "bfd.h" |
eac338cf PB |
25 | #include "libbfd.h" |
26 | #include "elf-bfd.h" | |
27 | #include "elf-vxworks.h" | |
4d2c0abd | 28 | #include "elf/vxworks.h" |
eac338cf | 29 | |
55e6e397 RS |
30 | /* Return true if symbol NAME, as defined by ABFD, is one of the special |
31 | __GOTT_BASE__ or __GOTT_INDEX__ symbols. */ | |
32 | ||
33 | static bfd_boolean | |
34 | elf_vxworks_gott_symbol_p (bfd *abfd, const char *name) | |
35 | { | |
36 | char leading; | |
37 | ||
38 | leading = bfd_get_symbol_leading_char (abfd); | |
39 | if (leading) | |
40 | { | |
41 | if (*name != leading) | |
42 | return FALSE; | |
43 | name++; | |
44 | } | |
45 | return (strcmp (name, "__GOTT_BASE__") == 0 | |
46 | || strcmp (name, "__GOTT_INDEX__") == 0); | |
47 | } | |
48 | ||
eac338cf PB |
49 | /* Tweak magic VxWorks symbols as they are loaded. */ |
50 | bfd_boolean | |
55e6e397 | 51 | elf_vxworks_add_symbol_hook (bfd *abfd, |
eac338cf PB |
52 | struct bfd_link_info *info, |
53 | Elf_Internal_Sym *sym, | |
54 | const char **namep, | |
55 | flagword *flagsp, | |
56 | asection **secp ATTRIBUTE_UNUSED, | |
57 | bfd_vma *valp ATTRIBUTE_UNUSED) | |
58 | { | |
59 | /* Ideally these "magic" symbols would be exported by libc.so.1 | |
60 | which would be found via a DT_NEEDED tag, and then handled | |
61 | specially by the linker at runtime. Except shared libraries | |
62 | don't even link to libc.so.1 by default... | |
63 | If the symbol is imported from, or will be put in a shared library, | |
64 | give the symbol weak binding to get the desired samantics. | |
65 | This transformation will be undone in | |
66 | elf_i386_vxworks_link_output_symbol_hook. */ | |
67 | if ((info->shared || abfd->flags & DYNAMIC) | |
55e6e397 | 68 | && elf_vxworks_gott_symbol_p (abfd, *namep)) |
eac338cf PB |
69 | { |
70 | sym->st_info = ELF_ST_INFO (STB_WEAK, ELF_ST_TYPE (sym->st_info)); | |
71 | *flagsp |= BSF_WEAK; | |
72 | } | |
73 | ||
74 | return TRUE; | |
75 | } | |
76 | ||
711de32c RS |
77 | /* Perform VxWorks-specific handling of the create_dynamic_sections hook. |
78 | When creating an executable, set *SRELPLT2_OUT to the .rel(a).plt.unloaded | |
79 | section. */ | |
80 | ||
81 | bfd_boolean | |
82 | elf_vxworks_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info, | |
83 | asection **srelplt2_out) | |
84 | { | |
85 | struct elf_link_hash_table *htab; | |
86 | const struct elf_backend_data *bed; | |
87 | asection *s; | |
88 | ||
89 | htab = elf_hash_table (info); | |
90 | bed = get_elf_backend_data (dynobj); | |
91 | ||
92 | if (!info->shared) | |
93 | { | |
94 | s = bfd_make_section_with_flags (dynobj, | |
95 | bed->default_use_rela_p | |
96 | ? ".rela.plt.unloaded" | |
97 | : ".rel.plt.unloaded", | |
98 | SEC_HAS_CONTENTS | SEC_IN_MEMORY | |
99 | | SEC_READONLY | SEC_LINKER_CREATED); | |
100 | if (s == NULL | |
101 | || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) | |
102 | return FALSE; | |
103 | ||
104 | *srelplt2_out = s; | |
105 | } | |
106 | ||
107 | /* Mark the GOT and PLT symbols as having relocations; they might | |
108 | not, but we won't know for sure until we build the GOT in | |
109 | finish_dynamic_symbol. Also make sure that the GOT symbol | |
110 | is entered into the dynamic symbol table; the loader uses it | |
111 | to initialize __GOTT_BASE__[__GOTT_INDEX__]. */ | |
112 | if (htab->hgot) | |
113 | { | |
114 | htab->hgot->indx = -2; | |
115 | htab->hgot->other &= ~ELF_ST_VISIBILITY (-1); | |
116 | htab->hgot->forced_local = 0; | |
117 | if (!bfd_elf_link_record_dynamic_symbol (info, htab->hgot)) | |
118 | return FALSE; | |
119 | } | |
120 | if (htab->hplt) | |
121 | { | |
122 | htab->hplt->indx = -2; | |
123 | htab->hplt->type = STT_FUNC; | |
124 | } | |
125 | ||
126 | return TRUE; | |
127 | } | |
eac338cf PB |
128 | |
129 | /* Tweak magic VxWorks symbols as they are written to the output file. */ | |
130 | bfd_boolean | |
9c72ff84 RS |
131 | elf_vxworks_link_output_symbol_hook (struct bfd_link_info *info |
132 | ATTRIBUTE_UNUSED, | |
133 | const char *name, | |
134 | Elf_Internal_Sym *sym, | |
135 | asection *input_sec ATTRIBUTE_UNUSED, | |
55e6e397 | 136 | struct elf_link_hash_entry *h) |
eac338cf PB |
137 | { |
138 | /* Reverse the effects of the hack in elf_vxworks_add_symbol_hook. */ | |
55e6e397 RS |
139 | if (h |
140 | && h->root.type == bfd_link_hash_undefweak | |
141 | && elf_vxworks_gott_symbol_p (h->root.u.undef.abfd, name)) | |
eac338cf PB |
142 | sym->st_info = ELF_ST_INFO (STB_GLOBAL, ELF_ST_TYPE (sym->st_info)); |
143 | ||
144 | return TRUE; | |
145 | } | |
146 | ||
147 | ||
148 | /* Copy relocations into the output file. Fixes up relocations againt PLT | |
149 | entries, then calls the generic routine. */ | |
150 | ||
151 | bfd_boolean | |
152 | elf_vxworks_emit_relocs (bfd *output_bfd, | |
153 | asection *input_section, | |
154 | Elf_Internal_Shdr *input_rel_hdr, | |
155 | Elf_Internal_Rela *internal_relocs, | |
156 | struct elf_link_hash_entry **rel_hash) | |
157 | { | |
158 | const struct elf_backend_data *bed; | |
159 | Elf_Internal_Rela *irela; | |
160 | Elf_Internal_Rela *irelaend; | |
161 | int j; | |
162 | ||
163 | bed = get_elf_backend_data (output_bfd); | |
164 | ||
165 | irela = internal_relocs; | |
166 | irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) | |
167 | * bed->s->int_rels_per_ext_rel); | |
168 | while (irela < irelaend) | |
169 | { | |
170 | if ((output_bfd->flags & (DYNAMIC|EXEC_P)) | |
171 | && *rel_hash | |
172 | && (*rel_hash)->def_dynamic | |
173 | && !(*rel_hash)->def_regular | |
8776bb8a | 174 | && ((*rel_hash)->root.type == bfd_link_hash_defined |
c10564a9 | 175 | || (*rel_hash)->root.type == bfd_link_hash_defweak) |
eac338cf PB |
176 | && (*rel_hash)->root.u.def.section->output_section != NULL) |
177 | { | |
178 | /* This is a relocation from an executable or shared library | |
179 | against a symbol in a different shared library. We are | |
180 | creating a definition in the output file but it does not come | |
181 | from any of our normal (.o) files. ie. a PLT stub. | |
182 | Normally this would be a relocation against against SHN_UNDEF | |
183 | with the VMA of the PLT stub. This upsets the VxWorks loader. | |
184 | Convert it to a section-relative relocation. | |
185 | This gets some other symbols (for instance .dynbss), | |
186 | but is conservatively correct. */ | |
187 | for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) | |
188 | { | |
189 | asection *sec = (*rel_hash)->root.u.def.section; | |
55e6e397 | 190 | int this_idx = sec->output_section->target_index; |
eac338cf PB |
191 | |
192 | irela[j].r_info = ELF32_R_INFO (this_idx, | |
193 | ELF32_R_TYPE (irela[j].r_info)); | |
194 | irela[j].r_addend += (*rel_hash)->root.u.def.value; | |
195 | irela[j].r_addend += sec->output_offset; | |
196 | } | |
197 | /* Stop the generic routine adjusting this entry. */ | |
198 | *rel_hash = NULL; | |
199 | } | |
200 | irela += bed->s->int_rels_per_ext_rel; | |
201 | rel_hash++; | |
202 | } | |
203 | return _bfd_elf_link_output_relocs (output_bfd, input_section, | |
204 | input_rel_hdr, internal_relocs, | |
205 | rel_hash); | |
206 | } | |
207 | ||
208 | ||
209 | /* Set the sh_link and sh_info fields on the static plt relocation secton. */ | |
210 | ||
211 | void | |
212 | elf_vxworks_final_write_processing (bfd *abfd, | |
213 | bfd_boolean linker ATTRIBUTE_UNUSED) | |
214 | { | |
215 | asection * sec; | |
216 | struct bfd_elf_section_data *d; | |
217 | ||
218 | sec = bfd_get_section_by_name (abfd, ".rel.plt.unloaded"); | |
9d8504b1 PB |
219 | if (!sec) |
220 | sec = bfd_get_section_by_name (abfd, ".rela.plt.unloaded"); | |
eac338cf PB |
221 | if (!sec) |
222 | return; | |
223 | d = elf_section_data (sec); | |
224 | d->this_hdr.sh_link = elf_tdata (abfd)->symtab_section; | |
225 | sec = bfd_get_section_by_name (abfd, ".plt"); | |
226 | if (sec) | |
227 | d->this_hdr.sh_info = elf_section_data (sec)->this_idx; | |
228 | } | |
4d2c0abd NS |
229 | |
230 | /* Add the dynamic entries required by VxWorks. These point to the | |
231 | tls sections. */ | |
232 | ||
233 | bfd_boolean | |
234 | elf_vxworks_add_dynamic_entries (bfd *output_bfd, struct bfd_link_info *info) | |
235 | { | |
236 | if (bfd_get_section_by_name (output_bfd, ".tls_data")) | |
237 | { | |
238 | if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_START, 0) | |
239 | || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_SIZE, 0) | |
240 | || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_ALIGN, 0)) | |
241 | return FALSE; | |
242 | } | |
243 | if (bfd_get_section_by_name (output_bfd, ".tls_vars")) | |
244 | { | |
245 | if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_START, 0) | |
246 | || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_SIZE, 0)) | |
247 | return FALSE; | |
248 | } | |
249 | return TRUE; | |
250 | } | |
251 | ||
252 | /* If *DYN is one of the VxWorks-specific dynamic entries, then fill | |
253 | in the value now and return TRUE. Otherwise return FALSE. */ | |
254 | ||
255 | bfd_boolean | |
256 | elf_vxworks_finish_dynamic_entry (bfd *output_bfd, Elf_Internal_Dyn *dyn) | |
257 | { | |
258 | asection *sec; | |
259 | ||
260 | switch (dyn->d_tag) | |
261 | { | |
262 | default: | |
263 | return FALSE; | |
264 | ||
265 | case DT_VX_WRS_TLS_DATA_START: | |
266 | sec = bfd_get_section_by_name (output_bfd, ".tls_data"); | |
267 | dyn->d_un.d_ptr = sec->vma; | |
268 | break; | |
269 | ||
270 | case DT_VX_WRS_TLS_DATA_SIZE: | |
271 | sec = bfd_get_section_by_name (output_bfd, ".tls_data"); | |
272 | dyn->d_un.d_val = sec->size; | |
273 | break; | |
274 | ||
275 | case DT_VX_WRS_TLS_DATA_ALIGN: | |
276 | sec = bfd_get_section_by_name (output_bfd, ".tls_data"); | |
277 | dyn->d_un.d_val | |
278 | = (bfd_size_type)1 << bfd_get_section_alignment (abfd, sec); | |
279 | break; | |
280 | ||
281 | case DT_VX_WRS_TLS_VARS_START: | |
282 | sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); | |
283 | dyn->d_un.d_ptr = sec->vma; | |
284 | break; | |
285 | ||
286 | case DT_VX_WRS_TLS_VARS_SIZE: | |
287 | sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); | |
288 | dyn->d_un.d_val = sec->size; | |
289 | break; | |
290 | } | |
291 | return TRUE; | |
292 | } | |
293 | ||
294 |