Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5197 | serge | 1 | /* VxWorks support for ELF |
2 | Copyright 2005, 2006, 2007, 2009, 2012 Free Software Foundation, Inc. |
||
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 |
||
8 | the Free Software Foundation; either version 3 of the License, or |
||
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 |
||
18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
||
19 | MA 02111-1307, USA. */ |
||
20 | |||
21 | /* This file provides routines used by all VxWorks targets. */ |
||
22 | |||
23 | #include "sysdep.h" |
||
24 | #include "bfd.h" |
||
25 | #include "libbfd.h" |
||
26 | #include "elf-bfd.h" |
||
27 | #include "elf-vxworks.h" |
||
28 | #include "elf/vxworks.h" |
||
29 | |||
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 | |||
49 | /* Tweak magic VxWorks symbols as they are loaded. */ |
||
50 | bfd_boolean |
||
51 | elf_vxworks_add_symbol_hook (bfd *abfd, |
||
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) |
||
68 | && elf_vxworks_gott_symbol_p (abfd, *namep)) |
||
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 | |||
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_anyway_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 |
||
100 | | SEC_LINKER_CREATED); |
||
101 | if (s == NULL |
||
102 | || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) |
||
103 | return FALSE; |
||
104 | |||
105 | *srelplt2_out = s; |
||
106 | } |
||
107 | |||
108 | /* Mark the GOT and PLT symbols as having relocations; they might |
||
109 | not, but we won't know for sure until we build the GOT in |
||
110 | finish_dynamic_symbol. Also make sure that the GOT symbol |
||
111 | is entered into the dynamic symbol table; the loader uses it |
||
112 | to initialize __GOTT_BASE__[__GOTT_INDEX__]. */ |
||
113 | if (htab->hgot) |
||
114 | { |
||
115 | htab->hgot->indx = -2; |
||
116 | htab->hgot->other &= ~ELF_ST_VISIBILITY (-1); |
||
117 | htab->hgot->forced_local = 0; |
||
118 | if (!bfd_elf_link_record_dynamic_symbol (info, htab->hgot)) |
||
119 | return FALSE; |
||
120 | } |
||
121 | if (htab->hplt) |
||
122 | { |
||
123 | htab->hplt->indx = -2; |
||
124 | htab->hplt->type = STT_FUNC; |
||
125 | } |
||
126 | |||
127 | return TRUE; |
||
128 | } |
||
129 | |||
130 | /* Tweak magic VxWorks symbols as they are written to the output file. */ |
||
131 | int |
||
132 | elf_vxworks_link_output_symbol_hook (struct bfd_link_info *info |
||
133 | ATTRIBUTE_UNUSED, |
||
134 | const char *name, |
||
135 | Elf_Internal_Sym *sym, |
||
136 | asection *input_sec ATTRIBUTE_UNUSED, |
||
137 | struct elf_link_hash_entry *h) |
||
138 | { |
||
139 | /* Reverse the effects of the hack in elf_vxworks_add_symbol_hook. */ |
||
140 | if (h |
||
141 | && h->root.type == bfd_link_hash_undefweak |
||
142 | && elf_vxworks_gott_symbol_p (h->root.u.undef.abfd, name)) |
||
143 | sym->st_info = ELF_ST_INFO (STB_GLOBAL, ELF_ST_TYPE (sym->st_info)); |
||
144 | |||
145 | return 1; |
||
146 | } |
||
147 | |||
148 | /* Copy relocations into the output file. Fixes up relocations against 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 | int j; |
||
160 | |||
161 | bed = get_elf_backend_data (output_bfd); |
||
162 | |||
163 | if (output_bfd->flags & (DYNAMIC|EXEC_P)) |
||
164 | { |
||
165 | Elf_Internal_Rela *irela; |
||
166 | Elf_Internal_Rela *irelaend; |
||
167 | struct elf_link_hash_entry **hash_ptr; |
||
168 | |||
169 | for (irela = internal_relocs, |
||
170 | irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) |
||
171 | * bed->s->int_rels_per_ext_rel), |
||
172 | hash_ptr = rel_hash; |
||
173 | irela < irelaend; |
||
174 | irela += bed->s->int_rels_per_ext_rel, |
||
175 | hash_ptr++) |
||
176 | { |
||
177 | if (*hash_ptr |
||
178 | && (*hash_ptr)->def_dynamic |
||
179 | && !(*hash_ptr)->def_regular |
||
180 | && ((*hash_ptr)->root.type == bfd_link_hash_defined |
||
181 | || (*hash_ptr)->root.type == bfd_link_hash_defweak) |
||
182 | && (*hash_ptr)->root.u.def.section->output_section != NULL) |
||
183 | { |
||
184 | /* This is a relocation from an executable or shared |
||
185 | library against a symbol in a different shared |
||
186 | library. We are creating a definition in the output |
||
187 | file but it does not come from any of our normal (.o) |
||
188 | files. ie. a PLT stub. Normally this would be a |
||
189 | relocation against against SHN_UNDEF with the VMA of |
||
190 | the PLT stub. This upsets the VxWorks loader. |
||
191 | Convert it to a section-relative relocation. This |
||
192 | gets some other symbols (for instance .dynbss), but |
||
193 | is conservatively correct. */ |
||
194 | for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) |
||
195 | { |
||
196 | asection *sec = (*hash_ptr)->root.u.def.section; |
||
197 | int this_idx = sec->output_section->target_index; |
||
198 | |||
199 | irela[j].r_info |
||
200 | = ELF32_R_INFO (this_idx, ELF32_R_TYPE (irela[j].r_info)); |
||
201 | irela[j].r_addend += (*hash_ptr)->root.u.def.value; |
||
202 | irela[j].r_addend += sec->output_offset; |
||
203 | } |
||
204 | /* Stop the generic routine adjusting this entry. */ |
||
205 | *hash_ptr = NULL; |
||
206 | } |
||
207 | } |
||
208 | } |
||
209 | return _bfd_elf_link_output_relocs (output_bfd, input_section, |
||
210 | input_rel_hdr, internal_relocs, |
||
211 | rel_hash); |
||
212 | } |
||
213 | |||
214 | |||
215 | /* Set the sh_link and sh_info fields on the static plt relocation secton. */ |
||
216 | |||
217 | void |
||
218 | elf_vxworks_final_write_processing (bfd *abfd, |
||
219 | bfd_boolean linker ATTRIBUTE_UNUSED) |
||
220 | { |
||
221 | asection * sec; |
||
222 | struct bfd_elf_section_data *d; |
||
223 | |||
224 | sec = bfd_get_section_by_name (abfd, ".rel.plt.unloaded"); |
||
225 | if (!sec) |
||
226 | sec = bfd_get_section_by_name (abfd, ".rela.plt.unloaded"); |
||
227 | if (!sec) |
||
228 | return; |
||
229 | d = elf_section_data (sec); |
||
230 | d->this_hdr.sh_link = elf_onesymtab (abfd); |
||
231 | sec = bfd_get_section_by_name (abfd, ".plt"); |
||
232 | if (sec) |
||
233 | d->this_hdr.sh_info = elf_section_data (sec)->this_idx; |
||
234 | } |
||
235 | |||
236 | /* Add the dynamic entries required by VxWorks. These point to the |
||
237 | tls sections. */ |
||
238 | |||
239 | bfd_boolean |
||
240 | elf_vxworks_add_dynamic_entries (bfd *output_bfd, struct bfd_link_info *info) |
||
241 | { |
||
242 | if (bfd_get_section_by_name (output_bfd, ".tls_data")) |
||
243 | { |
||
244 | if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_START, 0) |
||
245 | || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_SIZE, 0) |
||
246 | || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_ALIGN, 0)) |
||
247 | return FALSE; |
||
248 | } |
||
249 | if (bfd_get_section_by_name (output_bfd, ".tls_vars")) |
||
250 | { |
||
251 | if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_START, 0) |
||
252 | || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_SIZE, 0)) |
||
253 | return FALSE; |
||
254 | } |
||
255 | return TRUE; |
||
256 | } |
||
257 | |||
258 | /* If *DYN is one of the VxWorks-specific dynamic entries, then fill |
||
259 | in the value now and return TRUE. Otherwise return FALSE. */ |
||
260 | |||
261 | bfd_boolean |
||
262 | elf_vxworks_finish_dynamic_entry (bfd *output_bfd, Elf_Internal_Dyn *dyn) |
||
263 | { |
||
264 | asection *sec; |
||
265 | |||
266 | switch (dyn->d_tag) |
||
267 | { |
||
268 | default: |
||
269 | return FALSE; |
||
270 | |||
271 | case DT_VX_WRS_TLS_DATA_START: |
||
272 | sec = bfd_get_section_by_name (output_bfd, ".tls_data"); |
||
273 | dyn->d_un.d_ptr = sec->vma; |
||
274 | break; |
||
275 | |||
276 | case DT_VX_WRS_TLS_DATA_SIZE: |
||
277 | sec = bfd_get_section_by_name (output_bfd, ".tls_data"); |
||
278 | dyn->d_un.d_val = sec->size; |
||
279 | break; |
||
280 | |||
281 | case DT_VX_WRS_TLS_DATA_ALIGN: |
||
282 | sec = bfd_get_section_by_name (output_bfd, ".tls_data"); |
||
283 | dyn->d_un.d_val |
||
284 | = (bfd_size_type)1 << bfd_get_section_alignment (output_bfd, |
||
285 | sec); |
||
286 | break; |
||
287 | |||
288 | case DT_VX_WRS_TLS_VARS_START: |
||
289 | sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); |
||
290 | dyn->d_un.d_ptr = sec->vma; |
||
291 | break; |
||
292 | |||
293 | case DT_VX_WRS_TLS_VARS_SIZE: |
||
294 | sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); |
||
295 | dyn->d_un.d_val = sec->size; |
||
296 | break; |
||
297 | } |
||
298 | return TRUE; |
||
299 | }><>>> |
||
300 |