]>
Commit | Line | Data |
---|---|---|
eac338cf | 1 | /* VxWorks support for ELF |
fd67aa11 | 2 | Copyright (C) 2005-2024 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 | |
08832196 | 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
eac338cf PB |
18 | |
19 | /* This file provides routines used by all VxWorks targets. */ | |
20 | ||
eac338cf | 21 | #include "sysdep.h" |
3db64b00 | 22 | #include "bfd.h" |
eac338cf PB |
23 | #include "libbfd.h" |
24 | #include "elf-bfd.h" | |
25 | #include "elf-vxworks.h" | |
4d2c0abd | 26 | #include "elf/vxworks.h" |
eac338cf | 27 | |
55e6e397 RS |
28 | /* Return true if symbol NAME, as defined by ABFD, is one of the special |
29 | __GOTT_BASE__ or __GOTT_INDEX__ symbols. */ | |
30 | ||
0a1b45a2 | 31 | static bool |
55e6e397 RS |
32 | elf_vxworks_gott_symbol_p (bfd *abfd, const char *name) |
33 | { | |
34 | char leading; | |
35 | ||
36 | leading = bfd_get_symbol_leading_char (abfd); | |
37 | if (leading) | |
38 | { | |
39 | if (*name != leading) | |
0a1b45a2 | 40 | return false; |
55e6e397 RS |
41 | name++; |
42 | } | |
43 | return (strcmp (name, "__GOTT_BASE__") == 0 | |
44 | || strcmp (name, "__GOTT_INDEX__") == 0); | |
45 | } | |
46 | ||
eac338cf | 47 | /* Tweak magic VxWorks symbols as they are loaded. */ |
0a1b45a2 | 48 | bool |
55e6e397 | 49 | elf_vxworks_add_symbol_hook (bfd *abfd, |
eac338cf PB |
50 | struct bfd_link_info *info, |
51 | Elf_Internal_Sym *sym, | |
52 | const char **namep, | |
53 | flagword *flagsp, | |
54 | asection **secp ATTRIBUTE_UNUSED, | |
55 | bfd_vma *valp ATTRIBUTE_UNUSED) | |
56 | { | |
57 | /* Ideally these "magic" symbols would be exported by libc.so.1 | |
58 | which would be found via a DT_NEEDED tag, and then handled | |
59 | specially by the linker at runtime. Except shared libraries | |
60 | don't even link to libc.so.1 by default... | |
61 | If the symbol is imported from, or will be put in a shared library, | |
62 | give the symbol weak binding to get the desired samantics. | |
63 | This transformation will be undone in | |
64 | elf_i386_vxworks_link_output_symbol_hook. */ | |
0e1862bb | 65 | if ((bfd_link_pic (info) || abfd->flags & DYNAMIC) |
55e6e397 | 66 | && elf_vxworks_gott_symbol_p (abfd, *namep)) |
eac338cf PB |
67 | { |
68 | sym->st_info = ELF_ST_INFO (STB_WEAK, ELF_ST_TYPE (sym->st_info)); | |
69 | *flagsp |= BSF_WEAK; | |
70 | } | |
71 | ||
0a1b45a2 | 72 | return true; |
eac338cf PB |
73 | } |
74 | ||
711de32c RS |
75 | /* Perform VxWorks-specific handling of the create_dynamic_sections hook. |
76 | When creating an executable, set *SRELPLT2_OUT to the .rel(a).plt.unloaded | |
77 | section. */ | |
78 | ||
0a1b45a2 | 79 | bool |
711de32c RS |
80 | elf_vxworks_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info, |
81 | asection **srelplt2_out) | |
82 | { | |
83 | struct elf_link_hash_table *htab; | |
84 | const struct elf_backend_data *bed; | |
85 | asection *s; | |
86 | ||
87 | htab = elf_hash_table (info); | |
88 | bed = get_elf_backend_data (dynobj); | |
89 | ||
0e1862bb | 90 | if (!bfd_link_pic (info)) |
711de32c | 91 | { |
3d4d4302 AM |
92 | s = bfd_make_section_anyway_with_flags (dynobj, |
93 | bed->default_use_rela_p | |
94 | ? ".rela.plt.unloaded" | |
95 | : ".rel.plt.unloaded", | |
96 | SEC_HAS_CONTENTS | SEC_IN_MEMORY | |
97 | | SEC_READONLY | |
98 | | SEC_LINKER_CREATED); | |
711de32c | 99 | if (s == NULL |
fd361982 | 100 | || !bfd_set_section_alignment (s, bed->s->log_file_align)) |
0a1b45a2 | 101 | return false; |
711de32c RS |
102 | |
103 | *srelplt2_out = s; | |
104 | } | |
105 | ||
106 | /* Mark the GOT and PLT symbols as having relocations; they might | |
107 | not, but we won't know for sure until we build the GOT in | |
108 | finish_dynamic_symbol. Also make sure that the GOT symbol | |
109 | is entered into the dynamic symbol table; the loader uses it | |
110 | to initialize __GOTT_BASE__[__GOTT_INDEX__]. */ | |
111 | if (htab->hgot) | |
112 | { | |
113 | htab->hgot->indx = -2; | |
114 | htab->hgot->other &= ~ELF_ST_VISIBILITY (-1); | |
115 | htab->hgot->forced_local = 0; | |
116 | if (!bfd_elf_link_record_dynamic_symbol (info, htab->hgot)) | |
0a1b45a2 | 117 | return false; |
711de32c RS |
118 | } |
119 | if (htab->hplt) | |
120 | { | |
121 | htab->hplt->indx = -2; | |
122 | htab->hplt->type = STT_FUNC; | |
123 | } | |
124 | ||
0a1b45a2 | 125 | return true; |
711de32c | 126 | } |
eac338cf PB |
127 | |
128 | /* Tweak magic VxWorks symbols as they are written to the output file. */ | |
6e0b88f1 | 129 | int |
9c72ff84 RS |
130 | elf_vxworks_link_output_symbol_hook (struct bfd_link_info *info |
131 | ATTRIBUTE_UNUSED, | |
132 | const char *name, | |
133 | Elf_Internal_Sym *sym, | |
134 | asection *input_sec ATTRIBUTE_UNUSED, | |
55e6e397 | 135 | struct elf_link_hash_entry *h) |
eac338cf PB |
136 | { |
137 | /* Reverse the effects of the hack in elf_vxworks_add_symbol_hook. */ | |
55e6e397 RS |
138 | if (h |
139 | && h->root.type == bfd_link_hash_undefweak | |
140 | && elf_vxworks_gott_symbol_p (h->root.u.undef.abfd, name)) | |
eac338cf PB |
141 | sym->st_info = ELF_ST_INFO (STB_GLOBAL, ELF_ST_TYPE (sym->st_info)); |
142 | ||
6e0b88f1 | 143 | return 1; |
eac338cf PB |
144 | } |
145 | ||
6b60be10 | 146 | /* Copy relocations into the output file. Fixes up relocations against PLT |
eac338cf PB |
147 | entries, then calls the generic routine. */ |
148 | ||
0a1b45a2 | 149 | bool |
eac338cf PB |
150 | elf_vxworks_emit_relocs (bfd *output_bfd, |
151 | asection *input_section, | |
152 | Elf_Internal_Shdr *input_rel_hdr, | |
153 | Elf_Internal_Rela *internal_relocs, | |
154 | struct elf_link_hash_entry **rel_hash) | |
155 | { | |
156 | const struct elf_backend_data *bed; | |
eac338cf PB |
157 | int j; |
158 | ||
159 | bed = get_elf_backend_data (output_bfd); | |
160 | ||
6b60be10 | 161 | if (output_bfd->flags & (DYNAMIC|EXEC_P)) |
eac338cf | 162 | { |
6b60be10 NS |
163 | Elf_Internal_Rela *irela; |
164 | Elf_Internal_Rela *irelaend; | |
165 | struct elf_link_hash_entry **hash_ptr; | |
166 | ||
167 | for (irela = internal_relocs, | |
168 | irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) | |
169 | * bed->s->int_rels_per_ext_rel), | |
170 | hash_ptr = rel_hash; | |
171 | irela < irelaend; | |
172 | irela += bed->s->int_rels_per_ext_rel, | |
173 | hash_ptr++) | |
eac338cf | 174 | { |
eebad48e | 175 | if (*hash_ptr) |
eac338cf | 176 | { |
eebad48e L |
177 | (*hash_ptr)->has_reloc = 1; |
178 | if ((*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) | |
6b60be10 | 183 | { |
eebad48e L |
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 | |
9b441c41 | 189 | relocation against SHN_UNDEF with the VMA of |
eebad48e L |
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, | |
201 | ELF32_R_TYPE (irela[j].r_info)); | |
202 | irela[j].r_addend += (*hash_ptr)->root.u.def.value; | |
203 | irela[j].r_addend += sec->output_offset; | |
204 | } | |
205 | /* Stop the generic routine adjusting this entry. */ | |
206 | *hash_ptr = NULL; | |
6b60be10 | 207 | } |
eac338cf | 208 | } |
eac338cf | 209 | } |
eac338cf PB |
210 | } |
211 | return _bfd_elf_link_output_relocs (output_bfd, input_section, | |
212 | input_rel_hdr, internal_relocs, | |
213 | rel_hash); | |
214 | } | |
215 | ||
216 | ||
217 | /* Set the sh_link and sh_info fields on the static plt relocation secton. */ | |
218 | ||
0a1b45a2 | 219 | bool |
cc364be6 | 220 | elf_vxworks_final_write_processing (bfd *abfd) |
eac338cf PB |
221 | { |
222 | asection * sec; | |
223 | struct bfd_elf_section_data *d; | |
224 | ||
225 | sec = bfd_get_section_by_name (abfd, ".rel.plt.unloaded"); | |
9d8504b1 PB |
226 | if (!sec) |
227 | sec = bfd_get_section_by_name (abfd, ".rela.plt.unloaded"); | |
eac338cf | 228 | if (sec) |
c5e20471 AM |
229 | { |
230 | d = elf_section_data (sec); | |
231 | d->this_hdr.sh_link = elf_onesymtab (abfd); | |
232 | sec = bfd_get_section_by_name (abfd, ".plt"); | |
233 | if (sec) | |
234 | d->this_hdr.sh_info = elf_section_data (sec)->this_idx; | |
235 | } | |
cc364be6 | 236 | return _bfd_elf_final_write_processing (abfd); |
eac338cf | 237 | } |
4d2c0abd NS |
238 | |
239 | /* Add the dynamic entries required by VxWorks. These point to the | |
240 | tls sections. */ | |
241 | ||
0a1b45a2 | 242 | bool |
4d2c0abd NS |
243 | elf_vxworks_add_dynamic_entries (bfd *output_bfd, struct bfd_link_info *info) |
244 | { | |
245 | if (bfd_get_section_by_name (output_bfd, ".tls_data")) | |
246 | { | |
247 | if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_START, 0) | |
248 | || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_SIZE, 0) | |
249 | || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_ALIGN, 0)) | |
0a1b45a2 | 250 | return false; |
4d2c0abd NS |
251 | } |
252 | if (bfd_get_section_by_name (output_bfd, ".tls_vars")) | |
253 | { | |
254 | if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_START, 0) | |
255 | || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_SIZE, 0)) | |
0a1b45a2 | 256 | return false; |
4d2c0abd | 257 | } |
0a1b45a2 | 258 | return true; |
4d2c0abd NS |
259 | } |
260 | ||
261 | /* If *DYN is one of the VxWorks-specific dynamic entries, then fill | |
262 | in the value now and return TRUE. Otherwise return FALSE. */ | |
263 | ||
0a1b45a2 | 264 | bool |
4d2c0abd NS |
265 | elf_vxworks_finish_dynamic_entry (bfd *output_bfd, Elf_Internal_Dyn *dyn) |
266 | { | |
267 | asection *sec; | |
68ffbac6 | 268 | |
4d2c0abd NS |
269 | switch (dyn->d_tag) |
270 | { | |
271 | default: | |
0a1b45a2 | 272 | return false; |
68ffbac6 | 273 | |
4d2c0abd NS |
274 | case DT_VX_WRS_TLS_DATA_START: |
275 | sec = bfd_get_section_by_name (output_bfd, ".tls_data"); | |
276 | dyn->d_un.d_ptr = sec->vma; | |
277 | break; | |
68ffbac6 | 278 | |
4d2c0abd NS |
279 | case DT_VX_WRS_TLS_DATA_SIZE: |
280 | sec = bfd_get_section_by_name (output_bfd, ".tls_data"); | |
281 | dyn->d_un.d_val = sec->size; | |
282 | break; | |
68ffbac6 | 283 | |
4d2c0abd NS |
284 | case DT_VX_WRS_TLS_DATA_ALIGN: |
285 | sec = bfd_get_section_by_name (output_bfd, ".tls_data"); | |
fd361982 | 286 | dyn->d_un.d_val = (bfd_size_type) 1 << bfd_section_alignment (sec); |
4d2c0abd | 287 | break; |
68ffbac6 | 288 | |
4d2c0abd NS |
289 | case DT_VX_WRS_TLS_VARS_START: |
290 | sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); | |
291 | dyn->d_un.d_ptr = sec->vma; | |
292 | break; | |
68ffbac6 | 293 | |
4d2c0abd NS |
294 | case DT_VX_WRS_TLS_VARS_SIZE: |
295 | sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); | |
296 | dyn->d_un.d_val = sec->size; | |
297 | break; | |
298 | } | |
0a1b45a2 | 299 | return true; |
4d2c0abd NS |
300 | } |
301 | ||
3084d7a2 | 302 | /* Add dynamic tags. */ |
4d2c0abd | 303 | |
0a1b45a2 | 304 | bool |
3084d7a2 L |
305 | _bfd_elf_maybe_vxworks_add_dynamic_tags (bfd *output_bfd, |
306 | struct bfd_link_info *info, | |
0a1b45a2 | 307 | bool need_dynamic_reloc) |
3084d7a2 L |
308 | { |
309 | struct elf_link_hash_table *htab = elf_hash_table (info); | |
310 | return (_bfd_elf_add_dynamic_tags (output_bfd, info, | |
311 | need_dynamic_reloc) | |
312 | && (!htab->dynamic_sections_created | |
313 | || htab->target_os != is_vxworks | |
314 | || elf_vxworks_add_dynamic_entries (output_bfd, info))); | |
315 | } |