elf32-fr30.c revision 1.9 1 1.1 christos /* FR30-specific support for 32-bit ELF.
2 1.9 christos Copyright (C) 1998-2020 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This file is part of BFD, the Binary File Descriptor library.
5 1.1 christos
6 1.1 christos This program is free software; you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1 christos the Free Software Foundation; either version 3 of the License, or
9 1.1 christos (at your option) any later version.
10 1.1 christos
11 1.1 christos This program is distributed in the hope that it will be useful,
12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 1.1 christos GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program; if not, write to the Free Software
18 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 1.1 christos MA 02110-1301, USA. */
20 1.1 christos
21 1.1 christos #include "sysdep.h"
22 1.1 christos #include "bfd.h"
23 1.1 christos #include "libbfd.h"
24 1.1 christos #include "elf-bfd.h"
25 1.1 christos #include "elf/fr30.h"
26 1.1 christos
27 1.1 christos /* Forward declarations. */
28 1.1 christos static bfd_reloc_status_type
29 1.1 christos fr30_elf_i20_reloc (bfd *, arelent *, asymbol *, void * data,
30 1.1 christos asection *, bfd *, char **error_message);
31 1.1 christos static bfd_reloc_status_type
32 1.1 christos fr30_elf_i32_reloc (bfd *, arelent *, asymbol *, void *,
33 1.1 christos asection *, bfd *, char **);
34 1.1 christos
35 1.1 christos static reloc_howto_type fr30_elf_howto_table [] =
36 1.1 christos {
37 1.1 christos /* This reloc does nothing. */
38 1.1 christos HOWTO (R_FR30_NONE, /* type */
39 1.1 christos 0, /* rightshift */
40 1.5 christos 3, /* size (0 = byte, 1 = short, 2 = long) */
41 1.5 christos 0, /* bitsize */
42 1.1 christos FALSE, /* pc_relative */
43 1.1 christos 0, /* bitpos */
44 1.5 christos complain_overflow_dont, /* complain_on_overflow */
45 1.1 christos bfd_elf_generic_reloc, /* special_function */
46 1.1 christos "R_FR30_NONE", /* name */
47 1.1 christos FALSE, /* partial_inplace */
48 1.1 christos 0, /* src_mask */
49 1.1 christos 0, /* dst_mask */
50 1.1 christos FALSE), /* pcrel_offset */
51 1.1 christos
52 1.1 christos /* An 8 bit absolute relocation. */
53 1.1 christos HOWTO (R_FR30_8, /* type */
54 1.1 christos 0, /* rightshift */
55 1.1 christos 1, /* size (0 = byte, 1 = short, 2 = long) */
56 1.1 christos 8, /* bitsize */
57 1.1 christos FALSE, /* pc_relative */
58 1.1 christos 4, /* bitpos */
59 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
60 1.1 christos bfd_elf_generic_reloc, /* special_function */
61 1.1 christos "R_FR30_8", /* name */
62 1.1 christos FALSE, /* partial_inplace */
63 1.1 christos 0x0000, /* src_mask */
64 1.1 christos 0x0ff0, /* dst_mask */
65 1.1 christos FALSE), /* pcrel_offset */
66 1.1 christos
67 1.1 christos /* A 20 bit absolute relocation. */
68 1.1 christos HOWTO (R_FR30_20, /* type */
69 1.1 christos 0, /* rightshift */
70 1.1 christos 2, /* size (0 = byte, 1 = short, 2 = long) */
71 1.1 christos 20, /* bitsize */
72 1.1 christos FALSE, /* pc_relative */
73 1.1 christos 0, /* bitpos */
74 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
75 1.1 christos fr30_elf_i20_reloc, /* special_function */
76 1.1 christos "R_FR30_20", /* name */
77 1.1 christos FALSE, /* partial_inplace */
78 1.1 christos 0x00000000, /* src_mask */
79 1.1 christos 0x00f0ffff, /* dst_mask */
80 1.1 christos FALSE), /* pcrel_offset */
81 1.1 christos
82 1.1 christos /* A 32 bit absolute relocation. */
83 1.1 christos HOWTO (R_FR30_32, /* type */
84 1.1 christos 0, /* rightshift */
85 1.1 christos 2, /* size (0 = byte, 1 = short, 2 = long) */
86 1.1 christos 32, /* bitsize */
87 1.1 christos FALSE, /* pc_relative */
88 1.1 christos 0, /* bitpos */
89 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
90 1.1 christos bfd_elf_generic_reloc, /* special_function */
91 1.1 christos "R_FR30_32", /* name */
92 1.1 christos FALSE, /* partial_inplace */
93 1.1 christos 0x00000000, /* src_mask */
94 1.1 christos 0xffffffff, /* dst_mask */
95 1.1 christos FALSE), /* pcrel_offset */
96 1.1 christos
97 1.1 christos /* A 32 bit into 48 bits absolute relocation. */
98 1.1 christos HOWTO (R_FR30_48, /* type */
99 1.1 christos 0, /* rightshift */
100 1.1 christos 2, /* size (0 = byte, 1 = short, 2 = long) */
101 1.1 christos 32, /* bitsize */
102 1.1 christos FALSE, /* pc_relative */
103 1.1 christos 0, /* bitpos */
104 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */
105 1.1 christos fr30_elf_i32_reloc, /* special_function */
106 1.1 christos "R_FR30_48", /* name */
107 1.1 christos FALSE, /* partial_inplace */
108 1.1 christos 0x00000000, /* src_mask */
109 1.1 christos 0xffffffff, /* dst_mask */
110 1.1 christos FALSE), /* pcrel_offset */
111 1.1 christos
112 1.1 christos /* A 6 bit absolute relocation. */
113 1.1 christos HOWTO (R_FR30_6_IN_4, /* type */
114 1.1 christos 2, /* rightshift */
115 1.1 christos 1, /* size (0 = byte, 1 = short, 2 = long) */
116 1.1 christos 6, /* bitsize */
117 1.1 christos FALSE, /* pc_relative */
118 1.1 christos 4, /* bitpos */
119 1.1 christos complain_overflow_unsigned, /* complain_on_overflow */
120 1.1 christos bfd_elf_generic_reloc, /* special_function */
121 1.1 christos "R_FR30_6_IN_4", /* name */
122 1.1 christos FALSE, /* partial_inplace */
123 1.1 christos 0x0000, /* src_mask */
124 1.1 christos 0x00f0, /* dst_mask */
125 1.1 christos FALSE), /* pcrel_offset */
126 1.1 christos
127 1.1 christos /* An 8 bit absolute relocation. */
128 1.1 christos HOWTO (R_FR30_8_IN_8, /* type */
129 1.1 christos 0, /* rightshift */
130 1.1 christos 1, /* size (0 = byte, 1 = short, 2 = long) */
131 1.1 christos 8, /* bitsize */
132 1.1 christos FALSE, /* pc_relative */
133 1.1 christos 4, /* bitpos */
134 1.1 christos complain_overflow_signed, /* complain_on_overflow */
135 1.1 christos bfd_elf_generic_reloc,/* special_function */
136 1.1 christos "R_FR30_8_IN_8", /* name */
137 1.1 christos FALSE, /* partial_inplace */
138 1.1 christos 0x0000, /* src_mask */
139 1.1 christos 0x0ff0, /* dst_mask */
140 1.1 christos FALSE), /* pcrel_offset */
141 1.1 christos
142 1.1 christos /* A 9 bit absolute relocation. */
143 1.1 christos HOWTO (R_FR30_9_IN_8, /* type */
144 1.1 christos 1, /* rightshift */
145 1.1 christos 1, /* size (0 = byte, 1 = short, 2 = long) */
146 1.1 christos 9, /* bitsize */
147 1.1 christos FALSE, /* pc_relative */
148 1.1 christos 4, /* bitpos */
149 1.1 christos complain_overflow_signed, /* complain_on_overflow */
150 1.1 christos bfd_elf_generic_reloc,/* special_function */
151 1.1 christos "R_FR30_9_IN_8", /* name */
152 1.1 christos FALSE, /* partial_inplace */
153 1.1 christos 0x0000, /* src_mask */
154 1.1 christos 0x0ff0, /* dst_mask */
155 1.1 christos FALSE), /* pcrel_offset */
156 1.1 christos
157 1.1 christos /* A 10 bit absolute relocation. */
158 1.1 christos HOWTO (R_FR30_10_IN_8, /* type */
159 1.1 christos 2, /* rightshift */
160 1.1 christos 1, /* size (0 = byte, 1 = short, 2 = long) */
161 1.1 christos 10, /* bitsize */
162 1.1 christos FALSE, /* pc_relative */
163 1.1 christos 4, /* bitpos */
164 1.1 christos complain_overflow_signed, /* complain_on_overflow */
165 1.1 christos bfd_elf_generic_reloc,/* special_function */
166 1.1 christos "R_FR30_10_IN_8", /* name */
167 1.1 christos FALSE, /* partial_inplace */
168 1.1 christos 0x0000, /* src_mask */
169 1.1 christos 0x0ff0, /* dst_mask */
170 1.1 christos FALSE), /* pcrel_offset */
171 1.1 christos
172 1.1 christos /* A PC relative 9 bit relocation, right shifted by 1. */
173 1.1 christos HOWTO (R_FR30_9_PCREL, /* type */
174 1.1 christos 1, /* rightshift */
175 1.1 christos 1, /* size (0 = byte, 1 = short, 2 = long) */
176 1.1 christos 9, /* bitsize */
177 1.1 christos TRUE, /* pc_relative */
178 1.1 christos 0, /* bitpos */
179 1.1 christos complain_overflow_signed, /* complain_on_overflow */
180 1.1 christos bfd_elf_generic_reloc, /* special_function */
181 1.1 christos "R_FR30_9_PCREL", /* name */
182 1.1 christos FALSE, /* partial_inplace */
183 1.1 christos 0x0000, /* src_mask */
184 1.1 christos 0x00ff, /* dst_mask */
185 1.1 christos FALSE), /* pcrel_offset */
186 1.1 christos
187 1.1 christos /* A PC relative 12 bit relocation, right shifted by 1. */
188 1.1 christos HOWTO (R_FR30_12_PCREL, /* type */
189 1.1 christos 1, /* rightshift */
190 1.1 christos 1, /* size (0 = byte, 1 = short, 2 = long) */
191 1.1 christos 12, /* bitsize */
192 1.1 christos TRUE, /* pc_relative */
193 1.1 christos 0, /* bitpos */
194 1.1 christos complain_overflow_signed, /* complain_on_overflow */
195 1.1 christos bfd_elf_generic_reloc, /* special_function */
196 1.1 christos "R_FR30_12_PCREL", /* name */
197 1.1 christos FALSE, /* partial_inplace */
198 1.1 christos 0x0000, /* src_mask */
199 1.1 christos 0x07ff, /* dst_mask */
200 1.1 christos FALSE), /* pcrel_offset */
201 1.1 christos /* GNU extension to record C++ vtable hierarchy */
202 1.1 christos HOWTO (R_FR30_GNU_VTINHERIT, /* type */
203 1.8 christos 0, /* rightshift */
204 1.8 christos 2, /* size (0 = byte, 1 = short, 2 = long) */
205 1.8 christos 0, /* bitsize */
206 1.8 christos FALSE, /* pc_relative */
207 1.8 christos 0, /* bitpos */
208 1.8 christos complain_overflow_dont, /* complain_on_overflow */
209 1.8 christos NULL, /* special_function */
210 1.8 christos "R_FR30_GNU_VTINHERIT", /* name */
211 1.8 christos FALSE, /* partial_inplace */
212 1.8 christos 0, /* src_mask */
213 1.8 christos 0, /* dst_mask */
214 1.8 christos FALSE), /* pcrel_offset */
215 1.1 christos
216 1.1 christos /* GNU extension to record C++ vtable member usage */
217 1.8 christos HOWTO (R_FR30_GNU_VTENTRY, /* type */
218 1.8 christos 0, /* rightshift */
219 1.8 christos 2, /* size (0 = byte, 1 = short, 2 = long) */
220 1.8 christos 0, /* bitsize */
221 1.8 christos FALSE, /* pc_relative */
222 1.8 christos 0, /* bitpos */
223 1.8 christos complain_overflow_dont, /* complain_on_overflow */
224 1.8 christos _bfd_elf_rel_vtable_reloc_fn, /* special_function */
225 1.8 christos "R_FR30_GNU_VTENTRY", /* name */
226 1.8 christos FALSE, /* partial_inplace */
227 1.8 christos 0, /* src_mask */
228 1.8 christos 0, /* dst_mask */
229 1.8 christos FALSE), /* pcrel_offset */
230 1.1 christos };
231 1.1 christos
232 1.1 christos /* Utility to actually perform an R_FR30_20 reloc. */
234 1.1 christos
235 1.1 christos static bfd_reloc_status_type
236 1.1 christos fr30_elf_i20_reloc (bfd *abfd,
237 1.1 christos arelent *reloc_entry,
238 1.1 christos asymbol *symbol,
239 1.1 christos void * data,
240 1.1 christos asection *input_section,
241 1.1 christos bfd *output_bfd,
242 1.1 christos char **error_message ATTRIBUTE_UNUSED)
243 1.1 christos {
244 1.1 christos bfd_vma relocation;
245 1.1 christos unsigned long x;
246 1.1 christos
247 1.1 christos /* This part is from bfd_elf_generic_reloc. */
248 1.1 christos if (output_bfd != (bfd *) NULL
249 1.1 christos && (symbol->flags & BSF_SECTION_SYM) == 0
250 1.1 christos && (! reloc_entry->howto->partial_inplace
251 1.1 christos || reloc_entry->addend == 0))
252 1.1 christos {
253 1.1 christos reloc_entry->address += input_section->output_offset;
254 1.1 christos return bfd_reloc_ok;
255 1.1 christos }
256 1.1 christos
257 1.1 christos if (output_bfd != NULL)
258 1.1 christos /* FIXME: See bfd_perform_relocation. Is this right? */
259 1.1 christos return bfd_reloc_ok;
260 1.1 christos
261 1.1 christos relocation =
262 1.1 christos symbol->value
263 1.1 christos + symbol->section->output_section->vma
264 1.1 christos + symbol->section->output_offset
265 1.1 christos + reloc_entry->addend;
266 1.1 christos
267 1.1 christos if (relocation > (((bfd_vma) 1 << 20) - 1))
268 1.1 christos return bfd_reloc_overflow;
269 1.1 christos
270 1.1 christos x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
271 1.1 christos x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
272 1.1 christos bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
273 1.1 christos
274 1.1 christos return bfd_reloc_ok;
275 1.1 christos }
276 1.1 christos
277 1.1 christos /* Utility to actually perform a R_FR30_48 reloc. */
279 1.1 christos
280 1.1 christos static bfd_reloc_status_type
281 1.1 christos fr30_elf_i32_reloc (bfd *abfd,
282 1.1 christos arelent *reloc_entry,
283 1.1 christos asymbol *symbol,
284 1.1 christos void * data,
285 1.1 christos asection *input_section,
286 1.1 christos bfd *output_bfd,
287 1.1 christos char **error_message ATTRIBUTE_UNUSED)
288 1.1 christos {
289 1.1 christos bfd_vma relocation;
290 1.1 christos
291 1.1 christos /* This part is from bfd_elf_generic_reloc. */
292 1.1 christos if (output_bfd != (bfd *) NULL
293 1.1 christos && (symbol->flags & BSF_SECTION_SYM) == 0
294 1.1 christos && (! reloc_entry->howto->partial_inplace
295 1.1 christos || reloc_entry->addend == 0))
296 1.1 christos {
297 1.1 christos reloc_entry->address += input_section->output_offset;
298 1.1 christos return bfd_reloc_ok;
299 1.1 christos }
300 1.1 christos
301 1.1 christos if (output_bfd != NULL)
302 1.1 christos /* FIXME: See bfd_perform_relocation. Is this right? */
303 1.1 christos return bfd_reloc_ok;
304 1.1 christos
305 1.1 christos relocation =
306 1.1 christos symbol->value
307 1.1 christos + symbol->section->output_section->vma
308 1.1 christos + symbol->section->output_offset
309 1.1 christos + reloc_entry->addend;
310 1.1 christos
311 1.1 christos bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
312 1.1 christos
313 1.1 christos return bfd_reloc_ok;
314 1.1 christos }
315 1.1 christos
316 1.1 christos /* Map BFD reloc types to FR30 ELF reloc types. */
318 1.1 christos
319 1.1 christos struct fr30_reloc_map
320 1.1 christos {
321 1.1 christos bfd_reloc_code_real_type bfd_reloc_val;
322 1.1 christos unsigned int fr30_reloc_val;
323 1.1 christos };
324 1.8 christos
325 1.8 christos static const struct fr30_reloc_map fr30_reloc_map [] =
326 1.8 christos {
327 1.8 christos { BFD_RELOC_NONE, R_FR30_NONE },
328 1.8 christos { BFD_RELOC_8, R_FR30_8 },
329 1.1 christos { BFD_RELOC_FR30_20, R_FR30_20 },
330 1.1 christos { BFD_RELOC_32, R_FR30_32 },
331 1.1 christos { BFD_RELOC_FR30_48, R_FR30_48 },
332 1.1 christos { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
333 1.1 christos { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
334 1.1 christos { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
335 1.1 christos { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
336 1.1 christos { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
337 1.1 christos { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
338 1.1 christos { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
339 1.1 christos { BFD_RELOC_VTABLE_ENTRY, R_FR30_GNU_VTENTRY },
340 1.1 christos };
341 1.1 christos
342 1.1 christos static reloc_howto_type *
343 1.1 christos fr30_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
344 1.1 christos bfd_reloc_code_real_type code)
345 1.1 christos {
346 1.5 christos unsigned int i;
347 1.1 christos
348 1.1 christos for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
349 1.1 christos i--;)
350 1.1 christos if (fr30_reloc_map [i].bfd_reloc_val == code)
351 1.1 christos return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
352 1.1 christos
353 1.1 christos return NULL;
354 1.1 christos }
355 1.1 christos
356 1.1 christos static reloc_howto_type *
357 1.1 christos fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
358 1.1 christos {
359 1.1 christos unsigned int i;
360 1.1 christos
361 1.1 christos for (i = 0;
362 1.1 christos i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
363 1.1 christos i++)
364 1.1 christos if (fr30_elf_howto_table[i].name != NULL
365 1.1 christos && strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0)
366 1.1 christos return &fr30_elf_howto_table[i];
367 1.1 christos
368 1.1 christos return NULL;
369 1.1 christos }
370 1.8 christos
371 1.1 christos /* Set the howto pointer for an FR30 ELF reloc. */
372 1.1 christos
373 1.1 christos static bfd_boolean
374 1.1 christos fr30_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
375 1.1 christos arelent *cache_ptr,
376 1.1 christos Elf_Internal_Rela *dst)
377 1.1 christos {
378 1.3 christos unsigned int r_type;
379 1.3 christos
380 1.7 christos r_type = ELF32_R_TYPE (dst->r_info);
381 1.8 christos if (r_type >= (unsigned int) R_FR30_max)
382 1.8 christos {
383 1.8 christos /* xgettext:c-format */
384 1.8 christos _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
385 1.3 christos abfd, r_type);
386 1.1 christos bfd_set_error (bfd_error_bad_value);
387 1.8 christos return FALSE;
388 1.1 christos }
389 1.1 christos cache_ptr->howto = & fr30_elf_howto_table [r_type];
390 1.1 christos return TRUE;
391 1.1 christos }
392 1.1 christos
393 1.1 christos /* Perform a single relocation. By default we use the standard BFD
395 1.1 christos routines, but a few relocs, we have to do them ourselves. */
396 1.1 christos
397 1.1 christos static bfd_reloc_status_type
398 1.1 christos fr30_final_link_relocate (reloc_howto_type *howto,
399 1.1 christos bfd *input_bfd,
400 1.1 christos asection *input_section,
401 1.1 christos bfd_byte *contents,
402 1.1 christos Elf_Internal_Rela *rel,
403 1.1 christos bfd_vma relocation)
404 1.1 christos {
405 1.1 christos bfd_reloc_status_type r = bfd_reloc_ok;
406 1.1 christos bfd_vma x;
407 1.1 christos bfd_signed_vma srel;
408 1.1 christos
409 1.1 christos switch (howto->type)
410 1.1 christos {
411 1.1 christos case R_FR30_20:
412 1.1 christos contents += rel->r_offset;
413 1.1 christos relocation += rel->r_addend;
414 1.1 christos
415 1.1 christos if (relocation > ((1 << 20) - 1))
416 1.1 christos return bfd_reloc_overflow;
417 1.1 christos
418 1.1 christos x = bfd_get_32 (input_bfd, contents);
419 1.1 christos x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
420 1.1 christos bfd_put_32 (input_bfd, x, contents);
421 1.1 christos break;
422 1.1 christos
423 1.1 christos case R_FR30_48:
424 1.1 christos contents += rel->r_offset + 2;
425 1.1 christos relocation += rel->r_addend;
426 1.1 christos bfd_put_32 (input_bfd, relocation, contents);
427 1.1 christos break;
428 1.1 christos
429 1.1 christos case R_FR30_9_PCREL:
430 1.1 christos contents += rel->r_offset + 1;
431 1.1 christos srel = (bfd_signed_vma) relocation;
432 1.1 christos srel += rel->r_addend;
433 1.1 christos srel -= rel->r_offset;
434 1.1 christos srel -= 2; /* Branch instructions add 2 to the PC... */
435 1.1 christos srel -= (input_section->output_section->vma +
436 1.1 christos input_section->output_offset);
437 1.1 christos
438 1.1 christos if (srel & 1)
439 1.1 christos return bfd_reloc_outofrange;
440 1.1 christos if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
441 1.1 christos return bfd_reloc_overflow;
442 1.1 christos
443 1.1 christos bfd_put_8 (input_bfd, srel >> 1, contents);
444 1.1 christos break;
445 1.1 christos
446 1.1 christos case R_FR30_12_PCREL:
447 1.1 christos contents += rel->r_offset;
448 1.1 christos srel = (bfd_signed_vma) relocation;
449 1.1 christos srel += rel->r_addend;
450 1.1 christos srel -= rel->r_offset;
451 1.1 christos srel -= 2; /* Branch instructions add 2 to the PC... */
452 1.1 christos srel -= (input_section->output_section->vma +
453 1.1 christos input_section->output_offset);
454 1.1 christos
455 1.1 christos if (srel & 1)
456 1.1 christos return bfd_reloc_outofrange;
457 1.1 christos if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
458 1.1 christos return bfd_reloc_overflow;
459 1.1 christos
460 1.1 christos x = bfd_get_16 (input_bfd, contents);
461 1.1 christos x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
462 1.1 christos bfd_put_16 (input_bfd, x, contents);
463 1.1 christos break;
464 1.1 christos
465 1.1 christos default:
466 1.1 christos r = _bfd_final_link_relocate (howto, input_bfd, input_section,
467 1.1 christos contents, rel->r_offset,
468 1.1 christos relocation, rel->r_addend);
469 1.1 christos }
470 1.1 christos
471 1.1 christos return r;
472 1.1 christos }
473 1.1 christos
474 1.1 christos /* Relocate an FR30 ELF section.
476 1.1 christos
477 1.1 christos The RELOCATE_SECTION function is called by the new ELF backend linker
478 1.1 christos to handle the relocations for a section.
479 1.1 christos
480 1.1 christos The relocs are always passed as Rela structures; if the section
481 1.1 christos actually uses Rel structures, the r_addend field will always be
482 1.1 christos zero.
483 1.1 christos
484 1.1 christos This function is responsible for adjusting the section contents as
485 1.1 christos necessary, and (if using Rela relocs and generating a relocatable
486 1.1 christos output file) adjusting the reloc addend as necessary.
487 1.1 christos
488 1.1 christos This function does not have to worry about setting the reloc
489 1.1 christos address or the reloc symbol index.
490 1.1 christos
491 1.1 christos LOCAL_SYMS is a pointer to the swapped in local symbols.
492 1.1 christos
493 1.1 christos LOCAL_SECTIONS is an array giving the section in the input file
494 1.1 christos corresponding to the st_shndx field of each local symbol.
495 1.1 christos
496 1.1 christos The global hash table entry for the global symbols can be found
497 1.1 christos via elf_sym_hashes (input_bfd).
498 1.1 christos
499 1.1 christos When generating relocatable output, this function must handle
500 1.1 christos STB_LOCAL/STT_SECTION symbols specially. The output symbol is
501 1.1 christos going to be the section symbol corresponding to the output
502 1.1 christos section, which means that the addend must be adjusted
503 1.1 christos accordingly. */
504 1.1 christos
505 1.1 christos static bfd_boolean
506 1.1 christos fr30_elf_relocate_section (bfd *output_bfd,
507 1.1 christos struct bfd_link_info *info,
508 1.1 christos bfd *input_bfd,
509 1.1 christos asection *input_section,
510 1.1 christos bfd_byte *contents,
511 1.1 christos Elf_Internal_Rela *relocs,
512 1.1 christos Elf_Internal_Sym *local_syms,
513 1.1 christos asection **local_sections)
514 1.1 christos {
515 1.1 christos Elf_Internal_Shdr *symtab_hdr;
516 1.1 christos struct elf_link_hash_entry **sym_hashes;
517 1.1 christos Elf_Internal_Rela *rel;
518 1.1 christos Elf_Internal_Rela *relend;
519 1.1 christos
520 1.1 christos symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
521 1.1 christos sym_hashes = elf_sym_hashes (input_bfd);
522 1.1 christos relend = relocs + input_section->reloc_count;
523 1.1 christos
524 1.1 christos for (rel = relocs; rel < relend; rel ++)
525 1.1 christos {
526 1.1 christos reloc_howto_type *howto;
527 1.1 christos unsigned long r_symndx;
528 1.1 christos Elf_Internal_Sym *sym;
529 1.1 christos asection *sec;
530 1.1 christos struct elf_link_hash_entry *h;
531 1.1 christos bfd_vma relocation;
532 1.1 christos bfd_reloc_status_type r;
533 1.1 christos const char *name;
534 1.1 christos int r_type;
535 1.1 christos
536 1.1 christos r_type = ELF32_R_TYPE (rel->r_info);
537 1.1 christos
538 1.1 christos if ( r_type == R_FR30_GNU_VTINHERIT
539 1.1 christos || r_type == R_FR30_GNU_VTENTRY)
540 1.1 christos continue;
541 1.1 christos
542 1.1 christos r_symndx = ELF32_R_SYM (rel->r_info);
543 1.1 christos
544 1.1 christos howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
545 1.1 christos h = NULL;
546 1.1 christos sym = NULL;
547 1.1 christos sec = NULL;
548 1.1 christos
549 1.1 christos if (r_symndx < symtab_hdr->sh_info)
550 1.1 christos {
551 1.1 christos sym = local_syms + r_symndx;
552 1.9 christos sec = local_sections [r_symndx];
553 1.1 christos relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
554 1.1 christos
555 1.1 christos name = bfd_elf_string_from_elf_section
556 1.1 christos (input_bfd, symtab_hdr->sh_link, sym->st_name);
557 1.1 christos name = name == NULL ? bfd_section_name (sec) : name;
558 1.1 christos }
559 1.1 christos else
560 1.1 christos {
561 1.1 christos bfd_boolean unresolved_reloc, warned, ignored;
562 1.1 christos
563 1.1 christos RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
564 1.1 christos r_symndx, symtab_hdr, sym_hashes,
565 1.1 christos h, sec, relocation,
566 1.1 christos unresolved_reloc, warned, ignored);
567 1.1 christos
568 1.1 christos name = h->root.root.string;
569 1.1 christos }
570 1.6 christos
571 1.1 christos if (sec != NULL && discarded_section (sec))
572 1.1 christos RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
573 1.1 christos rel, 1, relend, howto, 0, contents);
574 1.1 christos
575 1.1 christos if (bfd_link_relocatable (info))
576 1.1 christos continue;
577 1.1 christos
578 1.1 christos r = fr30_final_link_relocate (howto, input_bfd, input_section,
579 1.1 christos contents, rel, relocation);
580 1.1 christos
581 1.1 christos if (r != bfd_reloc_ok)
582 1.1 christos {
583 1.6 christos const char * msg = (const char *) NULL;
584 1.1 christos
585 1.1 christos switch (r)
586 1.1 christos {
587 1.1 christos case bfd_reloc_overflow:
588 1.1 christos (*info->callbacks->reloc_overflow)
589 1.6 christos (info, (h ? &h->root : NULL), name, howto->name,
590 1.6 christos (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
591 1.1 christos break;
592 1.1 christos
593 1.1 christos case bfd_reloc_undefined:
594 1.1 christos (*info->callbacks->undefined_symbol)
595 1.1 christos (info, name, input_bfd, input_section, rel->r_offset, TRUE);
596 1.1 christos break;
597 1.1 christos
598 1.1 christos case bfd_reloc_outofrange:
599 1.1 christos msg = _("internal error: out of range error");
600 1.1 christos break;
601 1.1 christos
602 1.1 christos case bfd_reloc_notsupported:
603 1.1 christos msg = _("internal error: unsupported relocation error");
604 1.1 christos break;
605 1.1 christos
606 1.1 christos case bfd_reloc_dangerous:
607 1.1 christos msg = _("internal error: dangerous relocation");
608 1.1 christos break;
609 1.1 christos
610 1.1 christos default:
611 1.6 christos msg = _("internal error: unknown error");
612 1.6 christos break;
613 1.1 christos }
614 1.1 christos
615 1.1 christos if (msg)
616 1.1 christos (*info->callbacks->warning) (info, msg, name, input_bfd,
617 1.1 christos input_section, rel->r_offset);
618 1.1 christos }
619 1.1 christos }
620 1.1 christos
621 1.1 christos return TRUE;
622 1.1 christos }
623 1.1 christos
624 1.1 christos /* Return the section that should be marked against GC for a given
626 1.1 christos relocation. */
627 1.1 christos
628 1.1 christos static asection *
629 1.1 christos fr30_elf_gc_mark_hook (asection *sec,
630 1.1 christos struct bfd_link_info *info,
631 1.1 christos Elf_Internal_Rela *rel,
632 1.1 christos struct elf_link_hash_entry *h,
633 1.1 christos Elf_Internal_Sym *sym)
634 1.1 christos {
635 1.1 christos if (h != NULL)
636 1.1 christos switch (ELF32_R_TYPE (rel->r_info))
637 1.1 christos {
638 1.1 christos case R_FR30_GNU_VTINHERIT:
639 1.1 christos case R_FR30_GNU_VTENTRY:
640 1.1 christos return NULL;
641 1.1 christos }
642 1.1 christos
643 1.1 christos return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
644 1.1 christos }
645 1.1 christos
646 1.1 christos /* Look through the relocs for a section during the first phase.
647 1.1 christos Since we don't do .gots or .plts, we just need to consider the
648 1.1 christos virtual table relocs for gc. */
649 1.1 christos
650 1.1 christos static bfd_boolean
651 1.1 christos fr30_elf_check_relocs (bfd *abfd,
652 1.1 christos struct bfd_link_info *info,
653 1.1 christos asection *sec,
654 1.1 christos const Elf_Internal_Rela *relocs)
655 1.6 christos {
656 1.1 christos Elf_Internal_Shdr *symtab_hdr;
657 1.1 christos struct elf_link_hash_entry **sym_hashes;
658 1.1 christos const Elf_Internal_Rela *rel;
659 1.1 christos const Elf_Internal_Rela *rel_end;
660 1.1 christos
661 1.1 christos if (bfd_link_relocatable (info))
662 1.1 christos return TRUE;
663 1.1 christos
664 1.1 christos symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
665 1.1 christos sym_hashes = elf_sym_hashes (abfd);
666 1.1 christos
667 1.1 christos rel_end = relocs + sec->reloc_count;
668 1.1 christos for (rel = relocs; rel < rel_end; rel++)
669 1.8 christos {
670 1.1 christos struct elf_link_hash_entry *h;
671 1.1 christos unsigned long r_symndx;
672 1.1 christos
673 1.1 christos r_symndx = ELF32_R_SYM (rel->r_info);
674 1.1 christos if (r_symndx < symtab_hdr->sh_info)
675 1.1 christos h = NULL;
676 1.1 christos else
677 1.1 christos {
678 1.1 christos h = sym_hashes[r_symndx - symtab_hdr->sh_info];
679 1.8 christos while (h->root.type == bfd_link_hash_indirect
680 1.8 christos || h->root.type == bfd_link_hash_warning)
681 1.8 christos h = (struct elf_link_hash_entry *) h->root.u.i.link;
682 1.8 christos }
683 1.8 christos
684 1.8 christos switch (ELF32_R_TYPE (rel->r_info))
685 1.8 christos {
686 1.8 christos /* This relocation describes the C++ object vtable hierarchy.
687 1.8 christos Reconstruct it for later use during GC. */
688 1.8 christos case R_FR30_GNU_VTINHERIT:
689 1.8 christos if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
690 1.9 christos return FALSE;
691 1.8 christos break;
692 1.8 christos
693 1.8 christos /* This relocation describes which C++ vtable entries are actually
694 1.1 christos used. Record for later use during GC. */
695 1.1 christos case R_FR30_GNU_VTENTRY:
696 1.1 christos if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
697 1.1 christos return FALSE;
698 1.1 christos break;
699 1.1 christos }
700 1.1 christos }
701 1.1 christos
702 1.1 christos return TRUE;
703 1.1 christos }
704 1.8 christos
705 1.1 christos #define ELF_ARCH bfd_arch_fr30
707 1.1 christos #define ELF_MACHINE_CODE EM_FR30
708 1.1 christos #define ELF_MACHINE_ALT1 EM_CYGNUS_FR30
709 1.1 christos #define ELF_MAXPAGESIZE 0x1000
710 1.1 christos
711 1.8 christos #define TARGET_BIG_SYM fr30_elf32_vec
712 1.1 christos #define TARGET_BIG_NAME "elf32-fr30"
713 1.1 christos
714 1.1 christos #define elf_info_to_howto_rel NULL
715 1.1 christos #define elf_info_to_howto fr30_info_to_howto_rela
716 1.1 christos #define elf_backend_relocate_section fr30_elf_relocate_section
717 1.8 christos #define elf_backend_gc_mark_hook fr30_elf_gc_mark_hook
718 1.1 christos #define elf_backend_check_relocs fr30_elf_check_relocs
719 1.1 christos
720 #define elf_backend_can_gc_sections 1
721 #define elf_backend_rela_normal 1
722
723 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
724 #define bfd_elf32_bfd_reloc_name_lookup fr30_reloc_name_lookup
725
726 #include "elf32-target.h"
727