/src/binutils-gdb/bfd/elf32-s12z.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Freescale S12Z-specific support for 32-bit ELF |
2 | | Copyright (C) 1999-2025 Free Software Foundation, Inc. |
3 | | (Heavily copied from the D10V port by Martin Hunt (hunt@cygnus.com)) |
4 | | |
5 | | This file is part of BFD, the Binary File Descriptor library. |
6 | | |
7 | | This program is free software; you can redistribute it and/or modify |
8 | | it under the terms of the GNU General Public License as published by |
9 | | the Free Software Foundation; either version 3 of the License, or |
10 | | (at your option) any later version. |
11 | | |
12 | | This program is distributed in the hope that it will be useful, |
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | GNU General Public License for more details. |
16 | | |
17 | | You should have received a copy of the GNU General Public License |
18 | | along with this program; if not, write to the Free Software |
19 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
20 | | MA 02110-1301, USA. */ |
21 | | |
22 | | #include "sysdep.h" |
23 | | #include "bfd.h" |
24 | | #include "bfdlink.h" |
25 | | #include "libbfd.h" |
26 | | #include "elf-bfd.h" |
27 | | |
28 | | #include "elf/s12z.h" |
29 | | |
30 | | /* All users of this file have bfd_octets_per_byte (abfd, sec) == 1. */ |
31 | 0 | #define OCTETS_PER_BYTE(ABFD, SEC) 1 |
32 | | |
33 | | /* Relocation functions. */ |
34 | | static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup |
35 | | (bfd *, bfd_reloc_code_real_type); |
36 | | static bool s12z_info_to_howto_rel |
37 | | (bfd *, arelent *, Elf_Internal_Rela *); |
38 | | |
39 | | static bfd_reloc_status_type |
40 | | opru18_reloc (bfd *abfd, arelent *reloc_entry, struct bfd_symbol *symbol, |
41 | | void *data, asection *input_section ATTRIBUTE_UNUSED, |
42 | | bfd *output ATTRIBUTE_UNUSED, char **msg ATTRIBUTE_UNUSED) |
43 | 0 | { |
44 | | /* This reloc is used for 18 bit General Operand Addressing Postbyte in the |
45 | | INST opru18 form. This is an 18 bit reloc, but the most significant bit |
46 | | is shifted one place to the left of where it would normally be. See |
47 | | Appendix A.4 of the S12Z reference manual. */ |
48 | |
|
49 | 0 | bfd_size_type octets = (reloc_entry->address |
50 | 0 | * OCTETS_PER_BYTE (abfd, input_section)); |
51 | 0 | bfd_vma result = bfd_get_24 (abfd, (unsigned char *) data + octets); |
52 | 0 | bfd_vma val = bfd_asymbol_value (symbol); |
53 | | |
54 | | /* Keep the wanted bits and discard the rest. */ |
55 | 0 | result &= 0xFA0000; |
56 | |
|
57 | 0 | val += symbol->section->output_section->vma; |
58 | 0 | val += symbol->section->output_offset; |
59 | | |
60 | | /* The lowest 17 bits are copied verbatim. */ |
61 | 0 | result |= val & 0x1FFFF; |
62 | | |
63 | | /* The 18th bit is put into the 19th position. */ |
64 | 0 | result |= (val & 0x020000) << 1; |
65 | |
|
66 | 0 | bfd_put_24 (abfd, result, (unsigned char *) data + octets); |
67 | |
|
68 | 0 | return bfd_reloc_ok; |
69 | 0 | } |
70 | | |
71 | | |
72 | | static bfd_reloc_status_type |
73 | | shift_addend_reloc (bfd *abfd, arelent *reloc_entry, struct bfd_symbol *symbol ATTRIBUTE_UNUSED, |
74 | | void *data ATTRIBUTE_UNUSED, asection *input_section ATTRIBUTE_UNUSED, |
75 | | bfd *output ATTRIBUTE_UNUSED, char **msg ATTRIBUTE_UNUSED) |
76 | 0 | { |
77 | | /* This is a really peculiar reloc, which is done for compatibility |
78 | | with the Freescale toolchain. |
79 | | |
80 | | That toolchain appears to (ab)use the lowest 15 bits of the addend for |
81 | | the purpose of holding flags. The purpose of these flags are unknown. |
82 | | So in this function, when writing the bfd we left shift the addend by |
83 | | 15, and when reading we right shift it by 15 (discarding the lower bits). |
84 | | |
85 | | This allows the linker to work with object files generated by Freescale, |
86 | | as well as by Gas. */ |
87 | |
|
88 | 0 | if (abfd->is_linker_input) |
89 | 0 | reloc_entry->addend >>= 15; |
90 | 0 | else |
91 | 0 | reloc_entry->addend <<= 15; |
92 | |
|
93 | 0 | return bfd_reloc_continue; |
94 | 0 | } |
95 | | |
96 | | #define USE_REL 0 |
97 | | |
98 | | static reloc_howto_type elf_s12z_howto_table[] = |
99 | | { |
100 | | /* This reloc does nothing. */ |
101 | | HOWTO (R_S12Z_NONE, /* type */ |
102 | | 0, /* rightshift */ |
103 | | 0, /* size */ |
104 | | 0, /* bitsize */ |
105 | | false, /* pc_relative */ |
106 | | 0, /* bitpos */ |
107 | | complain_overflow_dont,/* complain_on_overflow */ |
108 | | bfd_elf_generic_reloc, /* special_function */ |
109 | | "R_S12Z_NONE", /* name */ |
110 | | false, /* partial_inplace */ |
111 | | 0, /* src_mask */ |
112 | | 0, /* dst_mask */ |
113 | | false), /* pcrel_offset */ |
114 | | |
115 | | /* A 24 bit absolute relocation emitted by the OPR mode operands */ |
116 | | HOWTO (R_S12Z_OPR, /* type */ |
117 | | 0, /* rightshift */ |
118 | | 3, /* size */ |
119 | | 24, /* bitsize */ |
120 | | false, /* pc_relative */ |
121 | | 0, /* bitpos */ |
122 | | complain_overflow_bitfield, /* complain_on_overflow */ |
123 | | shift_addend_reloc, |
124 | | "R_S12Z_OPR", /* name */ |
125 | | false, /* partial_inplace */ |
126 | | 0x00ffffff, /* src_mask */ |
127 | | 0x00ffffff, /* dst_mask */ |
128 | | false), /* pcrel_offset */ |
129 | | |
130 | | /* The purpose of this reloc is not known */ |
131 | | HOWTO (R_S12Z_UKNWN_2, /* type */ |
132 | | 0, /* rightshift */ |
133 | | 0, /* size */ |
134 | | 0, /* bitsize */ |
135 | | false, /* pc_relative */ |
136 | | 0, /* bitpos */ |
137 | | complain_overflow_dont,/* complain_on_overflow */ |
138 | | bfd_elf_generic_reloc, /* special_function */ |
139 | | "R_S12Z_UKNWN_2", /* name */ |
140 | | false, /* partial_inplace */ |
141 | | 0, /* src_mask */ |
142 | | 0, /* dst_mask */ |
143 | | false), /* pcrel_offset */ |
144 | | |
145 | | /* A 15 bit PC-rel relocation */ |
146 | | HOWTO (R_S12Z_PCREL_7_15, /* type */ |
147 | | 0, /* rightshift */ |
148 | | 2, /* size */ |
149 | | 15, /* bitsize */ |
150 | | true, /* pc_relative */ |
151 | | 0, /* bitpos */ |
152 | | complain_overflow_bitfield, /* complain_on_overflow */ |
153 | | shift_addend_reloc, |
154 | | "R_S12Z_PCREL_7_15", /* name */ |
155 | | false, /* partial_inplace */ |
156 | | 0x00, /* src_mask */ |
157 | | 0x007fff, /* dst_mask */ |
158 | | true), /* pcrel_offset */ |
159 | | |
160 | | /* A 24 bit absolute relocation emitted by EXT24 mode operands */ |
161 | | HOWTO (R_S12Z_EXT24, /* type */ |
162 | | 0, /* rightshift */ |
163 | | 3, /* size */ |
164 | | 24, /* bitsize */ |
165 | | false, /* pc_relative */ |
166 | | 0, /* bitpos */ |
167 | | complain_overflow_bitfield, /* complain_on_overflow */ |
168 | | bfd_elf_generic_reloc, /* special_function */ |
169 | | "R_S12Z_EXT24", /* name */ |
170 | | false, /* partial_inplace */ |
171 | | 0x00000000, /* src_mask */ |
172 | | 0x00ffffff, /* dst_mask */ |
173 | | false), /* pcrel_offset */ |
174 | | |
175 | | /* An 18 bit absolute relocation */ |
176 | | HOWTO (R_S12Z_EXT18, /* type */ |
177 | | 0, /* rightshift */ |
178 | | 3, /* size */ |
179 | | 18, /* bitsize */ |
180 | | false, /* pc_relative */ |
181 | | 0, /* bitpos */ |
182 | | complain_overflow_bitfield, /* complain_on_overflow */ |
183 | | opru18_reloc, /* special_function */ |
184 | | "R_S12Z_EXT18", /* name */ |
185 | | false, /* partial_inplace */ |
186 | | 0x00000000, /* src_mask */ |
187 | | 0x0005ffff, /* dst_mask */ |
188 | | false), /* pcrel_offset */ |
189 | | |
190 | | /* A 32 bit absolute relocation. This kind of relocation is |
191 | | schizophrenic - Although they appear in sections named .rela.debug.* |
192 | | in some sections they behave as RELA relocs, but in others they have |
193 | | an added of zero and behave as REL. |
194 | | |
195 | | It is not recommended that new code emits this reloc. It is here |
196 | | only to support existing elf files generated by third party |
197 | | applications. */ |
198 | | |
199 | | HOWTO (R_S12Z_CW32, /* type */ |
200 | | 0, /* rightshift */ |
201 | | 4, /* size */ |
202 | | 32, /* bitsize */ |
203 | | false, /* pc_relative */ |
204 | | 0, /* bitpos */ |
205 | | complain_overflow_bitfield, /* complain_on_overflow */ |
206 | | bfd_elf_generic_reloc, /* special_function */ |
207 | | "R_S12Z_CW32", /* name */ |
208 | | false, /* partial_inplace */ |
209 | | 0xffffffff, /* src_mask */ |
210 | | 0xffffffff, /* dst_mask */ |
211 | | false), /* pcrel_offset */ |
212 | | |
213 | | /* A 32 bit absolute relocation */ |
214 | | HOWTO (R_S12Z_EXT32, /* type */ |
215 | | 0, /* rightshift */ |
216 | | 4, /* size */ |
217 | | 32, /* bitsize */ |
218 | | false, /* pc_relative */ |
219 | | 0, /* bitpos */ |
220 | | complain_overflow_bitfield, /* complain_on_overflow */ |
221 | | bfd_elf_generic_reloc, /* special_function */ |
222 | | "R_S12Z_EXT32", /* name */ |
223 | | false, /* partial_inplace */ |
224 | | 0x00000000, /* src_mask */ |
225 | | 0xffffffff, /* dst_mask */ |
226 | | false), /* pcrel_offset */ |
227 | | }; |
228 | | |
229 | | /* Map BFD reloc types to S12Z ELF reloc types. */ |
230 | | |
231 | | struct s12z_reloc_map |
232 | | { |
233 | | bfd_reloc_code_real_type bfd_reloc_val; |
234 | | unsigned char elf_reloc_val; |
235 | | }; |
236 | | |
237 | | static const struct s12z_reloc_map s12z_reloc_map[] = |
238 | | { |
239 | | /* bfd reloc val */ /* elf reloc val */ |
240 | | {BFD_RELOC_NONE, R_S12Z_NONE}, |
241 | | {BFD_RELOC_32, R_S12Z_EXT32}, |
242 | | {BFD_RELOC_24, R_S12Z_EXT24}, |
243 | | {BFD_RELOC_16_PCREL, R_S12Z_PCREL_7_15}, |
244 | | {BFD_RELOC_S12Z_OPR, R_S12Z_OPR} |
245 | | }; |
246 | | |
247 | | static reloc_howto_type * |
248 | | bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
249 | | bfd_reloc_code_real_type code) |
250 | 0 | { |
251 | 0 | unsigned int i; |
252 | |
|
253 | 0 | for (i = 0; |
254 | 0 | i < sizeof (s12z_reloc_map) / sizeof (struct s12z_reloc_map); |
255 | 0 | i++) |
256 | 0 | { |
257 | 0 | if (s12z_reloc_map[i].bfd_reloc_val == code) |
258 | 0 | { |
259 | 0 | return &elf_s12z_howto_table[s12z_reloc_map[i].elf_reloc_val]; |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | 0 | printf ("%s:%d Not found type %d\n", __FILE__, __LINE__, code); |
264 | |
|
265 | 0 | return NULL; |
266 | 0 | } |
267 | | |
268 | | static reloc_howto_type * |
269 | | bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
270 | | const char *r_name) |
271 | 0 | { |
272 | 0 | unsigned int i; |
273 | |
|
274 | 0 | for (i = 0; |
275 | 0 | i < (sizeof (elf_s12z_howto_table) |
276 | 0 | / sizeof (elf_s12z_howto_table[0])); |
277 | 0 | i++) |
278 | 0 | if (elf_s12z_howto_table[i].name != NULL |
279 | 0 | && strcasecmp (elf_s12z_howto_table[i].name, r_name) == 0) |
280 | 0 | return &elf_s12z_howto_table[i]; |
281 | | |
282 | 0 | return NULL; |
283 | 0 | } |
284 | | |
285 | | /* Set the howto pointer for an S12Z ELF reloc. */ |
286 | | |
287 | | static bool |
288 | | s12z_info_to_howto_rel (bfd *abfd, |
289 | | arelent *cache_ptr, Elf_Internal_Rela *dst) |
290 | 0 | { |
291 | 0 | unsigned int r_type = ELF32_R_TYPE (dst->r_info); |
292 | |
|
293 | 0 | if (r_type >= (unsigned int) R_S12Z_max) |
294 | 0 | { |
295 | | /* xgettext:c-format */ |
296 | 0 | _bfd_error_handler (_("%pB: unsupported relocation type %#x"), |
297 | 0 | abfd, r_type); |
298 | 0 | bfd_set_error (bfd_error_bad_value); |
299 | 0 | return false; |
300 | 0 | } |
301 | | |
302 | 0 | cache_ptr->howto = &elf_s12z_howto_table[r_type]; |
303 | 0 | return true; |
304 | 0 | } |
305 | | |
306 | | static bool |
307 | | s12z_elf_set_mach_from_flags (bfd *abfd) |
308 | 3 | { |
309 | 3 | bfd_default_set_arch_mach (abfd, bfd_arch_s12z, 0); |
310 | | |
311 | 3 | return true; |
312 | 3 | } |
313 | | |
314 | | #define ELF_ARCH bfd_arch_s12z |
315 | | #define ELF_MACHINE_CODE EM_S12Z |
316 | | #define ELF_MAXPAGESIZE 0x1000 |
317 | | |
318 | | #define TARGET_BIG_SYM s12z_elf32_vec |
319 | | #define TARGET_BIG_NAME "elf32-s12z" |
320 | | |
321 | | #define elf_info_to_howto NULL |
322 | | #define elf_info_to_howto_rel s12z_info_to_howto_rel |
323 | | #define elf_backend_object_p s12z_elf_set_mach_from_flags |
324 | | |
325 | | #include "elf32-target.h" |