/src/binutils-gdb/bfd/elf32-moxie.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* moxie-specific support for 32-bit ELF. |
2 | | Copyright (C) 2009-2025 Free Software Foundation, Inc. |
3 | | |
4 | | Copied from elf32-fr30.c which is.. |
5 | | Copyright (C) 1998-2025 Free Software Foundation, Inc. |
6 | | |
7 | | This file is part of BFD, the Binary File Descriptor library. |
8 | | |
9 | | This program is free software; you can redistribute it and/or modify |
10 | | it under the terms of the GNU General Public License as published by |
11 | | the Free Software Foundation; either version 3 of the License, or |
12 | | (at your option) any later version. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with this program; if not, write to the Free Software |
21 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
22 | | MA 02110-1301, USA. */ |
23 | | |
24 | | #include "sysdep.h" |
25 | | #include "bfd.h" |
26 | | #include "libbfd.h" |
27 | | #include "elf-bfd.h" |
28 | | #include "elf/moxie.h" |
29 | | |
30 | | /* Forward declarations. */ |
31 | | |
32 | | static reloc_howto_type moxie_elf_howto_table [] = |
33 | | { |
34 | | /* This reloc does nothing. */ |
35 | | HOWTO (R_MOXIE_NONE, /* type */ |
36 | | 0, /* rightshift */ |
37 | | 0, /* size */ |
38 | | 0, /* bitsize */ |
39 | | false, /* pc_relative */ |
40 | | 0, /* bitpos */ |
41 | | complain_overflow_dont, /* complain_on_overflow */ |
42 | | bfd_elf_generic_reloc, /* special_function */ |
43 | | "R_MOXIE_NONE", /* name */ |
44 | | false, /* partial_inplace */ |
45 | | 0, /* src_mask */ |
46 | | 0, /* dst_mask */ |
47 | | false), /* pcrel_offset */ |
48 | | |
49 | | /* A 32 bit absolute relocation. */ |
50 | | HOWTO (R_MOXIE_32, /* type */ |
51 | | 0, /* rightshift */ |
52 | | 4, /* size */ |
53 | | 32, /* bitsize */ |
54 | | false, /* pc_relative */ |
55 | | 0, /* bitpos */ |
56 | | complain_overflow_bitfield, /* complain_on_overflow */ |
57 | | bfd_elf_generic_reloc, /* special_function */ |
58 | | "R_MOXIE_32", /* name */ |
59 | | false, /* partial_inplace */ |
60 | | 0x00000000, /* src_mask */ |
61 | | 0xffffffff, /* dst_mask */ |
62 | | false), /* pcrel_offset */ |
63 | | |
64 | | /* A 10 bit PC-relative relocation. */ |
65 | | HOWTO (R_MOXIE_PCREL10, /* type. */ |
66 | | 1, /* rightshift. */ |
67 | | 2, /* size. */ |
68 | | 10, /* bitsize. */ |
69 | | true, /* pc_relative. */ |
70 | | 0, /* bitpos. */ |
71 | | complain_overflow_signed, /* complain_on_overflow. */ |
72 | | bfd_elf_generic_reloc, /* special_function. */ |
73 | | "R_MOXIE_PCREL10", /* name. */ |
74 | | false, /* partial_inplace. */ |
75 | | 0, /* src_mask. */ |
76 | | 0x000003FF, /* dst_mask. */ |
77 | | true), /* pcrel_offset. */ |
78 | | }; |
79 | | |
80 | | /* Map BFD reloc types to MOXIE ELF reloc types. */ |
81 | | |
82 | | struct moxie_reloc_map |
83 | | { |
84 | | bfd_reloc_code_real_type bfd_reloc_val; |
85 | | unsigned int moxie_reloc_val; |
86 | | }; |
87 | | |
88 | | static const struct moxie_reloc_map moxie_reloc_map [] = |
89 | | { |
90 | | { BFD_RELOC_NONE, R_MOXIE_NONE }, |
91 | | { BFD_RELOC_32, R_MOXIE_32 }, |
92 | | { BFD_RELOC_MOXIE_10_PCREL, R_MOXIE_PCREL10 }, |
93 | | }; |
94 | | |
95 | | static reloc_howto_type * |
96 | | moxie_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
97 | | bfd_reloc_code_real_type code) |
98 | 0 | { |
99 | 0 | unsigned int i; |
100 | |
|
101 | 0 | for (i = sizeof (moxie_reloc_map) / sizeof (moxie_reloc_map[0]); |
102 | 0 | i--;) |
103 | 0 | if (moxie_reloc_map [i].bfd_reloc_val == code) |
104 | 0 | return & moxie_elf_howto_table [moxie_reloc_map[i].moxie_reloc_val]; |
105 | | |
106 | 0 | return NULL; |
107 | 0 | } |
108 | | |
109 | | static reloc_howto_type * |
110 | | moxie_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) |
111 | 0 | { |
112 | 0 | unsigned int i; |
113 | |
|
114 | 0 | for (i = 0; |
115 | 0 | i < sizeof (moxie_elf_howto_table) / sizeof (moxie_elf_howto_table[0]); |
116 | 0 | i++) |
117 | 0 | if (moxie_elf_howto_table[i].name != NULL |
118 | 0 | && strcasecmp (moxie_elf_howto_table[i].name, r_name) == 0) |
119 | 0 | return &moxie_elf_howto_table[i]; |
120 | | |
121 | 0 | return NULL; |
122 | 0 | } |
123 | | |
124 | | /* Set the howto pointer for an MOXIE ELF reloc. */ |
125 | | |
126 | | static bool |
127 | | moxie_info_to_howto_rela (bfd *abfd, |
128 | | arelent *cache_ptr, |
129 | | Elf_Internal_Rela *dst) |
130 | 0 | { |
131 | 0 | unsigned int r_type; |
132 | |
|
133 | 0 | r_type = ELF32_R_TYPE (dst->r_info); |
134 | 0 | if (r_type >= (unsigned int) R_MOXIE_max) |
135 | 0 | { |
136 | | /* xgettext:c-format */ |
137 | 0 | _bfd_error_handler (_("%pB: unsupported relocation type %#x"), |
138 | 0 | abfd, r_type); |
139 | 0 | bfd_set_error (bfd_error_bad_value); |
140 | 0 | return false; |
141 | 0 | } |
142 | 0 | cache_ptr->howto = & moxie_elf_howto_table [r_type]; |
143 | 0 | return true; |
144 | 0 | } |
145 | | |
146 | | /* Perform a single relocation. By default we use the standard BFD |
147 | | routines, but a few relocs, we have to do them ourselves. */ |
148 | | |
149 | | static bfd_reloc_status_type |
150 | | moxie_final_link_relocate (reloc_howto_type *howto, |
151 | | bfd *input_bfd, |
152 | | asection *input_section, |
153 | | bfd_byte *contents, |
154 | | Elf_Internal_Rela *rel, |
155 | | bfd_vma relocation) |
156 | 0 | { |
157 | 0 | bfd_reloc_status_type r = bfd_reloc_ok; |
158 | |
|
159 | 0 | switch (howto->type) |
160 | 0 | { |
161 | 0 | default: |
162 | 0 | r = _bfd_final_link_relocate (howto, input_bfd, input_section, |
163 | 0 | contents, rel->r_offset, |
164 | 0 | relocation, rel->r_addend); |
165 | 0 | } |
166 | |
|
167 | 0 | return r; |
168 | 0 | } |
169 | | |
170 | | /* Relocate an MOXIE ELF section. |
171 | | |
172 | | The RELOCATE_SECTION function is called by the new ELF backend linker |
173 | | to handle the relocations for a section. |
174 | | |
175 | | The relocs are always passed as Rela structures; if the section |
176 | | actually uses Rel structures, the r_addend field will always be |
177 | | zero. |
178 | | |
179 | | This function is responsible for adjusting the section contents as |
180 | | necessary, and (if using Rela relocs and generating a relocatable |
181 | | output file) adjusting the reloc addend as necessary. |
182 | | |
183 | | This function does not have to worry about setting the reloc |
184 | | address or the reloc symbol index. |
185 | | |
186 | | LOCAL_SYMS is a pointer to the swapped in local symbols. |
187 | | |
188 | | LOCAL_SECTIONS is an array giving the section in the input file |
189 | | corresponding to the st_shndx field of each local symbol. |
190 | | |
191 | | The global hash table entry for the global symbols can be found |
192 | | via elf_sym_hashes (input_bfd). |
193 | | |
194 | | When generating relocatable output, this function must handle |
195 | | STB_LOCAL/STT_SECTION symbols specially. The output symbol is |
196 | | going to be the section symbol corresponding to the output |
197 | | section, which means that the addend must be adjusted |
198 | | accordingly. */ |
199 | | |
200 | | static int |
201 | | moxie_elf_relocate_section (bfd *output_bfd, |
202 | | struct bfd_link_info *info, |
203 | | bfd *input_bfd, |
204 | | asection *input_section, |
205 | | bfd_byte *contents, |
206 | | Elf_Internal_Rela *relocs, |
207 | | Elf_Internal_Sym *local_syms, |
208 | | asection **local_sections) |
209 | 0 | { |
210 | 0 | Elf_Internal_Shdr *symtab_hdr; |
211 | 0 | struct elf_link_hash_entry **sym_hashes; |
212 | 0 | Elf_Internal_Rela *rel; |
213 | 0 | Elf_Internal_Rela *relend; |
214 | |
|
215 | 0 | symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; |
216 | 0 | sym_hashes = elf_sym_hashes (input_bfd); |
217 | 0 | relend = relocs + input_section->reloc_count; |
218 | |
|
219 | 0 | for (rel = relocs; rel < relend; rel ++) |
220 | 0 | { |
221 | 0 | reloc_howto_type *howto; |
222 | 0 | unsigned long r_symndx; |
223 | 0 | Elf_Internal_Sym *sym; |
224 | 0 | asection *sec; |
225 | 0 | struct elf_link_hash_entry *h; |
226 | 0 | bfd_vma relocation; |
227 | 0 | bfd_reloc_status_type r; |
228 | 0 | const char *name; |
229 | 0 | int r_type; |
230 | |
|
231 | 0 | r_type = ELF32_R_TYPE (rel->r_info); |
232 | 0 | r_symndx = ELF32_R_SYM (rel->r_info); |
233 | 0 | howto = moxie_elf_howto_table + r_type; |
234 | 0 | h = NULL; |
235 | 0 | sym = NULL; |
236 | 0 | sec = NULL; |
237 | |
|
238 | 0 | if (r_symndx < symtab_hdr->sh_info) |
239 | 0 | { |
240 | 0 | sym = local_syms + r_symndx; |
241 | 0 | sec = local_sections [r_symndx]; |
242 | 0 | relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); |
243 | |
|
244 | 0 | name = bfd_elf_string_from_elf_section |
245 | 0 | (input_bfd, symtab_hdr->sh_link, sym->st_name); |
246 | 0 | name = name == NULL ? bfd_section_name (sec) : name; |
247 | 0 | } |
248 | 0 | else |
249 | 0 | { |
250 | 0 | bool unresolved_reloc, warned, ignored; |
251 | |
|
252 | 0 | RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, |
253 | 0 | r_symndx, symtab_hdr, sym_hashes, |
254 | 0 | h, sec, relocation, |
255 | 0 | unresolved_reloc, warned, ignored); |
256 | | |
257 | 0 | name = h->root.root.string; |
258 | 0 | } |
259 | | |
260 | 0 | if (sec != NULL && discarded_section (sec)) |
261 | 0 | RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, |
262 | 0 | rel, 1, relend, howto, 0, contents); |
263 | |
|
264 | 0 | if (bfd_link_relocatable (info)) |
265 | 0 | continue; |
266 | | |
267 | 0 | r = moxie_final_link_relocate (howto, input_bfd, input_section, |
268 | 0 | contents, rel, relocation); |
269 | |
|
270 | 0 | if (r != bfd_reloc_ok) |
271 | 0 | { |
272 | 0 | const char * msg = NULL; |
273 | |
|
274 | 0 | switch (r) |
275 | 0 | { |
276 | 0 | case bfd_reloc_overflow: |
277 | 0 | (*info->callbacks->reloc_overflow) |
278 | 0 | (info, (h ? &h->root : NULL), name, howto->name, |
279 | 0 | (bfd_vma) 0, input_bfd, input_section, rel->r_offset); |
280 | 0 | break; |
281 | | |
282 | 0 | case bfd_reloc_undefined: |
283 | 0 | (*info->callbacks->undefined_symbol) |
284 | 0 | (info, name, input_bfd, input_section, rel->r_offset, true); |
285 | 0 | break; |
286 | | |
287 | 0 | case bfd_reloc_outofrange: |
288 | 0 | msg = _("internal error: out of range error"); |
289 | 0 | break; |
290 | | |
291 | 0 | case bfd_reloc_notsupported: |
292 | 0 | msg = _("internal error: unsupported relocation error"); |
293 | 0 | break; |
294 | | |
295 | 0 | case bfd_reloc_dangerous: |
296 | 0 | msg = _("internal error: dangerous relocation"); |
297 | 0 | break; |
298 | | |
299 | 0 | default: |
300 | 0 | msg = _("internal error: unknown error"); |
301 | 0 | break; |
302 | 0 | } |
303 | | |
304 | 0 | if (msg) |
305 | 0 | (*info->callbacks->warning) (info, msg, name, input_bfd, |
306 | 0 | input_section, rel->r_offset); |
307 | 0 | } |
308 | 0 | } |
309 | | |
310 | 0 | return true; |
311 | 0 | } |
312 | | |
313 | | /* Return the section that should be marked against GC for a given |
314 | | relocation. */ |
315 | | |
316 | | static asection * |
317 | | moxie_elf_gc_mark_hook (asection *sec, |
318 | | struct bfd_link_info *info, |
319 | | Elf_Internal_Rela *rel, |
320 | | struct elf_link_hash_entry *h, |
321 | | Elf_Internal_Sym *sym) |
322 | 0 | { |
323 | 0 | return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); |
324 | 0 | } |
325 | | |
326 | | /* Look through the relocs for a section during the first phase. |
327 | | Since we don't do .gots or .plts, we just need to consider the |
328 | | virtual table relocs for gc. */ |
329 | | |
330 | | static bool |
331 | | moxie_elf_check_relocs (bfd *abfd, |
332 | | struct bfd_link_info *info, |
333 | | asection *sec, |
334 | | const Elf_Internal_Rela *relocs) |
335 | 0 | { |
336 | 0 | Elf_Internal_Shdr *symtab_hdr; |
337 | 0 | struct elf_link_hash_entry **sym_hashes; |
338 | 0 | const Elf_Internal_Rela *rel; |
339 | 0 | const Elf_Internal_Rela *rel_end; |
340 | |
|
341 | 0 | if (bfd_link_relocatable (info)) |
342 | 0 | return true; |
343 | | |
344 | 0 | symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
345 | 0 | sym_hashes = elf_sym_hashes (abfd); |
346 | |
|
347 | 0 | rel_end = relocs + sec->reloc_count; |
348 | 0 | for (rel = relocs; rel < rel_end; rel++) |
349 | 0 | { |
350 | 0 | struct elf_link_hash_entry *h; |
351 | 0 | unsigned long r_symndx; |
352 | |
|
353 | 0 | r_symndx = ELF32_R_SYM (rel->r_info); |
354 | 0 | if (r_symndx < symtab_hdr->sh_info) |
355 | 0 | h = NULL; |
356 | 0 | else |
357 | 0 | { |
358 | 0 | h = sym_hashes[r_symndx - symtab_hdr->sh_info]; |
359 | 0 | while (h->root.type == bfd_link_hash_indirect |
360 | 0 | || h->root.type == bfd_link_hash_warning) |
361 | 0 | h = (struct elf_link_hash_entry *) h->root.u.i.link; |
362 | 0 | } |
363 | 0 | } |
364 | |
|
365 | 0 | return true; |
366 | 0 | } |
367 | | |
368 | | #define ELF_ARCH bfd_arch_moxie |
369 | | #define ELF_MACHINE_CODE EM_MOXIE |
370 | | #define ELF_MACHINE_ALT1 EM_MOXIE_OLD |
371 | | #define ELF_MAXPAGESIZE 0x1 |
372 | | |
373 | | #define TARGET_BIG_SYM moxie_elf32_be_vec |
374 | | #define TARGET_BIG_NAME "elf32-bigmoxie" |
375 | | #define TARGET_LITTLE_SYM moxie_elf32_le_vec |
376 | | #define TARGET_LITTLE_NAME "elf32-littlemoxie" |
377 | | |
378 | | #define elf_info_to_howto_rel NULL |
379 | | #define elf_info_to_howto moxie_info_to_howto_rela |
380 | | #define elf_backend_relocate_section moxie_elf_relocate_section |
381 | | #define elf_backend_gc_mark_hook moxie_elf_gc_mark_hook |
382 | | #define elf_backend_check_relocs moxie_elf_check_relocs |
383 | | |
384 | | #define elf_backend_can_gc_sections 1 |
385 | | #define elf_backend_rela_normal 1 |
386 | | |
387 | | #define bfd_elf32_bfd_reloc_type_lookup moxie_reloc_type_lookup |
388 | | #define bfd_elf32_bfd_reloc_name_lookup moxie_reloc_name_lookup |
389 | | |
390 | | #include "elf32-target.h" |