S12Z: Emit RELOC_S12Z_OPR instead of RELOC_EXT24 where appropriate.
[external/binutils.git] / bfd / elf32-xgate.c
1 /* Freescale XGATE-specific support for 32-bit ELF
2    Copyright (C) 2010-2019 Free Software Foundation, Inc.
3    Contributed by Sean Keys(skeys@ipdatasys.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 #include "elf/xgate.h"
28 #include "opcode/xgate.h"
29 #include "libiberty.h"
30
31 /* Forward declarations.  */
32 static bfd_reloc_status_type xgate_elf_ignore_reloc
33   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
34 static bfd_reloc_status_type xgate_elf_special_reloc
35   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
36
37 /* Use REL instead of RELA to save space */
38 #define USE_REL 1
39
40 static reloc_howto_type elf_xgate_howto_table[] =
41 {
42   /* This reloc does nothing.  */
43   HOWTO (R_XGATE_NONE, /* type */
44          0, /* rightshift */
45          3, /* size (0 = byte, 1 = short, 2 = long) */
46          0, /* bitsize */
47          FALSE, /* pc_relative */
48          0, /* bitpos */
49          complain_overflow_dont,/* complain_on_overflow */
50          bfd_elf_generic_reloc, /* special_function */
51          "R_XGATE_NONE", /* name */
52          FALSE, /* partial_inplace */
53          0, /* src_mask */
54          0, /* dst_mask */
55          FALSE), /* pcrel_offset */
56
57   /* A 8 bit absolute relocation.  */
58   HOWTO (R_XGATE_8, /* type */
59          0, /* rightshift */
60          0, /* size (0 = byte, 1 = short, 2 = long) */
61          8, /* bitsize */
62          FALSE, /* pc_relative */
63          0, /* bitpos */
64          complain_overflow_bitfield, /* complain_on_overflow */
65          bfd_elf_generic_reloc, /* special_function */
66          "R_XGATE_8", /* name */
67          FALSE, /* partial_inplace */
68          0x00ff, /* src_mask */
69          0x00ff, /* dst_mask */
70          FALSE), /* pcrel_offset */
71
72   /* A 8 bit PC-rel relocation.  */
73   HOWTO (R_XGATE_PCREL_8, /* type */
74          0, /* rightshift */
75          0, /* size (0 = byte, 1 = short, 2 = long) */
76          8, /* bitsize */
77          TRUE, /* pc_relative */
78          0, /* bitpos */
79          complain_overflow_bitfield, /* complain_on_overflow */
80          bfd_elf_generic_reloc, /* special_function */
81          "R_XGATE_PCREL_8", /* name */
82          FALSE, /* partial_inplace */
83          0x00ff, /* src_mask */
84          0x00ff, /* dst_mask */
85          TRUE), /* pcrel_offset */
86
87   /* A 16 bit absolute relocation.  */
88   HOWTO (R_XGATE_16, /* type */
89          0, /* rightshift */
90          1, /* size (0 = byte, 1 = short, 2 = long) */
91          16, /* bitsize */
92          FALSE, /* pc_relative */
93          0, /* bitpos */
94          complain_overflow_dont /*bitfield */, /* complain_on_overflow */
95          bfd_elf_generic_reloc, /* special_function */
96          "R_XGATE_16", /* name */
97          FALSE, /* partial_inplace */
98          0xffff, /* src_mask */
99          0xffff, /* dst_mask */
100          FALSE), /* pcrel_offset */
101
102   /* A 32 bit absolute relocation.  This one is never used for the
103      code relocation.  It's used by gas for -gstabs generation.  */
104   HOWTO (R_XGATE_32, /* type */
105          0, /* rightshift */
106          2, /* size (0 = byte, 1 = short, 2 = long) */
107          32, /* bitsize */
108          FALSE, /* pc_relative */
109          0, /* bitpos */
110          complain_overflow_bitfield, /* complain_on_overflow */
111          bfd_elf_generic_reloc, /* special_function */
112          "R_XGATE_32", /* name */
113          FALSE, /* partial_inplace */
114          0xffffffff, /* src_mask */
115          0xffffffff, /* dst_mask */
116          FALSE), /* pcrel_offset */
117
118   /* A 16 bit PC-rel relocation.  */
119   HOWTO (R_XGATE_PCREL_16, /* type */
120          0, /* rightshift */
121          1, /* size (0 = byte, 1 = short, 2 = long) */
122          16, /* bitsize */
123          TRUE, /* pc_relative */
124          0, /* bitpos */
125          complain_overflow_dont, /* complain_on_overflow */
126          bfd_elf_generic_reloc, /* special_function */
127          "R_XGATE_PCREL_16", /* name */
128          FALSE, /* partial_inplace */
129          0xffff, /* src_mask */
130          0xffff, /* dst_mask */
131          TRUE), /* pcrel_offset */
132
133   /* GNU extension to record C++ vtable hierarchy.  */
134   HOWTO (R_XGATE_GNU_VTINHERIT, /* type */
135          0, /* rightshift */
136          1, /* size (0 = byte, 1 = short, 2 = long) */
137          0, /* bitsize */
138          FALSE, /* pc_relative */
139          0, /* bitpos */
140          complain_overflow_dont, /* complain_on_overflow */
141          NULL, /* special_function */
142          "R_XGATE_GNU_VTINHERIT", /* name */
143          FALSE, /* partial_inplace */
144          0, /* src_mask */
145          0, /* dst_mask */
146          FALSE), /* pcrel_offset */
147
148   /* GNU extension to record C++ vtable member usage.  */
149   HOWTO (R_XGATE_GNU_VTENTRY, /* type */
150          0, /* rightshift */
151          1, /* size (0 = byte, 1 = short, 2 = long) */
152          0, /* bitsize */
153          FALSE, /* pc_relative */
154          0, /* bitpos */
155          complain_overflow_dont, /* complain_on_overflow */
156          _bfd_elf_rel_vtable_reloc_fn, /* special_function */
157          "R_XGATE_GNU_VTENTRY", /* name */
158          FALSE, /* partial_inplace */
159          0, /* src_mask */
160          0, /* dst_mask */
161          FALSE), /* pcrel_offset */
162
163   /* A 24 bit relocation.  */
164   HOWTO (R_XGATE_24, /* type */
165          0, /* rightshift */
166          1, /* size (0 = byte, 1 = short, 2 = long) */
167          16, /* bitsize */
168          FALSE, /* pc_relative */
169          0, /* bitpos */
170          complain_overflow_dont, /* complain_on_overflow */
171          bfd_elf_generic_reloc, /* special_function */
172          "R_XGATE_IMM8_LO", /* name */
173          FALSE, /* partial_inplace */
174          0x00ff, /* src_mask */
175          0x00ff, /* dst_mask */
176          FALSE), /* pcrel_offset */
177
178   /* A 16-bit low relocation.  */
179   HOWTO (R_XGATE_LO16, /* type */
180          8, /* rightshift */
181          1, /* size (0 = byte, 1 = short, 2 = long) */
182          16, /* bitsize */
183          FALSE, /* pc_relative */
184          0, /* bitpos */
185          complain_overflow_dont, /* complain_on_overflow */
186          bfd_elf_generic_reloc, /* special_function */
187          "R_XGATE_IMM8_HI", /* name */
188          FALSE, /* partial_inplace */
189          0x00ff, /* src_mask */
190          0x00ff, /* dst_mask */
191          FALSE), /* pcrel_offset */
192
193   /* A page relocation.  */
194   HOWTO (R_XGATE_GPAGE, /* type */
195          0, /* rightshift */
196          0, /* size (0 = byte, 1 = short, 2 = long) */
197          8, /* bitsize */
198          FALSE, /* pc_relative */
199          0, /* bitpos */
200          complain_overflow_dont, /* complain_on_overflow */
201          xgate_elf_special_reloc,/* special_function */
202          "R_XGATE_GPAGE", /* name */
203          FALSE, /* partial_inplace */
204          0x00ff, /* src_mask */
205          0x00ff, /* dst_mask */
206          FALSE), /* pcrel_offset */
207
208   /* A 9 bit absolute relocation.   */
209   HOWTO (R_XGATE_PCREL_9, /* type */
210          0, /* rightshift */
211          1, /* size (0 = byte, 1 = short, 2 = long) */
212          9, /* bitsize */
213          TRUE, /* pc_relative */
214          0, /* bitpos */
215          complain_overflow_bitfield, /* complain_on_overflow */
216          bfd_elf_generic_reloc, /* special_function */
217          "R_XGATE_PCREL_9", /* name */
218          FALSE, /* partial_inplace */
219          0xffff, /* src_mask */
220          0xffff, /* dst_mask */
221          TRUE), /* pcrel_offset */
222
223   /* A 8 bit absolute relocation (upper address).  */
224   HOWTO (R_XGATE_PCREL_10, /* type */
225          8, /* rightshift */
226          0, /* size (0 = byte, 1 = short, 2 = long) */
227          10, /* bitsize */
228          TRUE, /* pc_relative */
229          0, /* bitpos */
230          complain_overflow_dont, /* complain_on_overflow */
231          bfd_elf_generic_reloc, /* special_function */
232          "R_XGATE_PCREL_10", /* name */
233          FALSE, /* partial_inplace */
234          0x00ff, /* src_mask */
235          0x00ff, /* dst_mask */
236          TRUE), /* pcrel_offset */
237
238   /* A 8 bit absolute relocation.  */
239   HOWTO (R_XGATE_IMM8_LO, /* type */
240          0, /* rightshift */
241          1, /* size (0 = byte, 1 = short, 2 = long) */
242          16, /* bitsize */
243          FALSE, /* pc_relative */
244          0, /* bitpos */
245          complain_overflow_dont, /* complain_on_overflow */
246          bfd_elf_generic_reloc, /* special_function */
247          "R_XGATE_IMM8_LO", /* name */
248          FALSE, /* partial_inplace */
249          0xffff, /* src_mask */
250          0xffff, /* dst_mask */
251          FALSE), /* pcrel_offset */
252
253   /* A 16 bit absolute relocation (upper address).  */
254   HOWTO (R_XGATE_IMM8_HI, /* type */
255          8, /* rightshift */
256          1, /* size (0 = byte, 1 = short, 2 = long) */
257          16, /* bitsize */
258          FALSE, /* pc_relative */
259          0, /* bitpos */
260          complain_overflow_dont, /* complain_on_overflow */
261          bfd_elf_generic_reloc, /* special_function */
262          "R_XGATE_IMM8_HI", /* name */
263          FALSE, /* partial_inplace */
264          0x00ff, /* src_mask */
265          0x00ff, /* dst_mask */
266          FALSE), /* pcrel_offset */
267
268   /* A 3 bit absolute relocation.  */
269   HOWTO (R_XGATE_IMM3, /* type */
270          8, /* rightshift */
271          1, /* size (0 = byte, 1 = short, 2 = long) */
272          16, /* bitsize */
273          FALSE, /* pc_relative */
274          0, /* bitpos */
275          complain_overflow_dont, /* complain_on_overflow */
276          bfd_elf_generic_reloc, /* special_function */
277          "R_XGATE_IMM3", /* name */
278          FALSE, /* partial_inplace */
279          0x00ff, /* src_mask */
280          0x00ff, /* dst_mask */
281          FALSE), /* pcrel_offset */
282
283   /* A 4 bit absolute relocation.  */
284   HOWTO (R_XGATE_IMM4, /* type */
285          8, /* rightshift */
286          1, /* size (0 = byte, 1 = short, 2 = long) */
287          16, /* bitsize */
288          FALSE, /* pc_relative */
289          0, /* bitpos */
290          complain_overflow_dont, /* complain_on_overflow */
291          bfd_elf_generic_reloc, /* special_function */
292          "R_XGATE_IMM4", /* name */
293          FALSE, /* partial_inplace */
294          0x00ff, /* src_mask */
295          0x00ff, /* dst_mask */
296          FALSE), /* pcrel_offset */
297
298   /* A 5 bit absolute relocation.  */
299   HOWTO (R_XGATE_IMM5, /* type */
300          8, /* rightshift */
301          1, /* size (0 = byte, 1 = short, 2 = long) */
302          16, /* bitsize */
303          FALSE, /* pc_relative */
304          0, /* bitpos */
305          complain_overflow_dont, /* complain_on_overflow */
306          bfd_elf_generic_reloc, /* special_function */
307          "R_XGATE_IMM5", /* name */
308          FALSE, /* partial_inplace */
309          0x00ff, /* src_mask */
310          0x00ff, /* dst_mask */
311          FALSE), /* pcrel_offset */
312
313   /* Mark beginning of a jump instruction (any form).  */
314   HOWTO (R_XGATE_RL_JUMP, /* type */
315          0, /* rightshift */
316          1, /* size (0 = byte, 1 = short, 2 = long) */
317          0, /* bitsize */
318          FALSE, /* pc_relative */
319          0, /* bitpos */
320          complain_overflow_dont, /* complain_on_overflow */
321          xgate_elf_ignore_reloc, /* special_function */
322          "R_XGATE_RL_JUMP", /* name */
323          TRUE, /* partial_inplace */
324          0, /* src_mask */
325          0, /* dst_mask */
326          TRUE), /* pcrel_offset */
327
328   /* Mark beginning of Gcc relaxation group instruction.  */
329   HOWTO (R_XGATE_RL_GROUP, /* type */
330          0, /* rightshift */
331          1, /* size (0 = byte, 1 = short, 2 = long) */
332          0, /* bitsize */
333          FALSE, /* pc_relative */
334          0, /* bitpos */
335          complain_overflow_dont, /* complain_on_overflow */
336          xgate_elf_ignore_reloc, /* special_function */
337          "R_XGATE_RL_GROUP", /* name */
338          TRUE, /* partial_inplace */
339          0, /* src_mask */
340          0, /* dst_mask */
341          TRUE), /* pcrel_offset */
342 };
343
344 /* Map BFD reloc types to XGATE ELF reloc types.  */
345
346 struct xgate_reloc_map
347 {
348   bfd_reloc_code_real_type bfd_reloc_val;
349   unsigned char elf_reloc_val;
350 };
351
352 static const struct xgate_reloc_map xgate_reloc_map[] =
353 {
354   {BFD_RELOC_NONE, R_XGATE_NONE},
355   {BFD_RELOC_8, R_XGATE_8},
356   {BFD_RELOC_8_PCREL, R_XGATE_PCREL_8},
357   {BFD_RELOC_16_PCREL, R_XGATE_PCREL_16},
358   {BFD_RELOC_16, R_XGATE_16},
359   {BFD_RELOC_32, R_XGATE_32},
360
361   {BFD_RELOC_VTABLE_INHERIT, R_XGATE_GNU_VTINHERIT},
362   {BFD_RELOC_VTABLE_ENTRY, R_XGATE_GNU_VTENTRY},
363
364   {BFD_RELOC_XGATE_LO16, R_XGATE_LO16},
365   {BFD_RELOC_XGATE_GPAGE, R_XGATE_GPAGE},
366   {BFD_RELOC_XGATE_24, R_XGATE_24},
367   {BFD_RELOC_XGATE_PCREL_9, R_XGATE_PCREL_9},
368   {BFD_RELOC_XGATE_PCREL_10,  R_XGATE_PCREL_10},
369   {BFD_RELOC_XGATE_IMM8_LO, R_XGATE_IMM8_LO},
370   {BFD_RELOC_XGATE_IMM8_HI, R_XGATE_IMM8_HI},
371   {BFD_RELOC_XGATE_IMM3, R_XGATE_IMM3},
372   {BFD_RELOC_XGATE_IMM4, R_XGATE_IMM4},
373   {BFD_RELOC_XGATE_IMM5, R_XGATE_IMM5},
374
375   {BFD_RELOC_XGATE_RL_JUMP, R_XGATE_RL_JUMP},
376   {BFD_RELOC_XGATE_RL_GROUP, R_XGATE_RL_GROUP},
377 };
378
379 static reloc_howto_type *
380 bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
381                                  bfd_reloc_code_real_type code)
382 {
383   unsigned int i;
384
385   for (i = 0; i < ARRAY_SIZE (xgate_reloc_map); i++)
386     if (xgate_reloc_map[i].bfd_reloc_val == code)
387       return &elf_xgate_howto_table[xgate_reloc_map[i].elf_reloc_val];
388   
389   return NULL;
390 }
391
392 static reloc_howto_type *
393 bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
394 {
395   unsigned int i;
396
397   for (i = 0; i < ARRAY_SIZE (elf_xgate_howto_table); i++)
398     if (elf_xgate_howto_table[i].name != NULL
399         && strcasecmp (elf_xgate_howto_table[i].name, r_name) == 0)
400       return &elf_xgate_howto_table[i];
401
402   return NULL;
403 }
404
405 /* Set the howto pointer for an XGATE ELF reloc.  */
406
407 static bfd_boolean
408 xgate_info_to_howto_rel (bfd *abfd,
409                          arelent *cache_ptr,
410                          Elf_Internal_Rela *dst)
411 {
412   unsigned int r_type;
413
414   r_type = ELF32_R_TYPE (dst->r_info);
415   if (r_type >= (unsigned int) R_XGATE_max)
416     {
417       /* xgettext:c-format */
418       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
419                           abfd, r_type);
420       bfd_set_error (bfd_error_bad_value);
421       return FALSE;
422     }
423   cache_ptr->howto = &elf_xgate_howto_table[r_type];
424   return TRUE;
425 }
426
427 /* Specific sections:
428  - The .page0 is a data section that is mapped in [0x0000..0x00FF].
429    Page0 accesses are faster on the M68HC12.
430  - The .vectors is the section that represents the interrupt
431    vectors.
432  - The .xgate section is starts in 0xE08800 or as xgate sees it 0x0800. */
433 static const struct bfd_elf_special_section elf32_xgate_special_sections[] =
434 {
435   { STRING_COMMA_LEN (".eeprom"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
436   { STRING_COMMA_LEN (".page0"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
437   { STRING_COMMA_LEN (".softregs"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
438   { STRING_COMMA_LEN (".vectors"), 0, SHT_PROGBITS, SHF_ALLOC },
439 /*{ STRING_COMMA_LEN (".xgate"),    0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
440   TODO finish this implementation */
441   { NULL, 0, 0, 0, 0 }
442 };
443
444 /* Hook called when reading symbols. */
445
446 static void
447 elf32_xgate_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
448                                        asymbol *sym)
449 {
450   /* Mark xgate symbols.  */
451   ((elf_symbol_type *) sym)->internal_elf_sym.st_target_internal = 1;
452 }
453
454 /* This function is used for relocs which are only used for relaxing,
455    which the linker should otherwise ignore.  */
456
457 static bfd_reloc_status_type
458 xgate_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED,
459                         arelent *reloc_entry,
460                         asymbol *symbol ATTRIBUTE_UNUSED,
461                         void *data ATTRIBUTE_UNUSED,
462                         asection *input_section,
463                         bfd *output_bfd,
464                         char **error_message ATTRIBUTE_UNUSED)
465 {
466   if (output_bfd != NULL)
467     reloc_entry->address += input_section->output_offset;
468   return bfd_reloc_ok;
469 }
470
471 static bfd_reloc_status_type
472 xgate_elf_special_reloc (bfd *abfd ATTRIBUTE_UNUSED,
473                          arelent *reloc_entry ATTRIBUTE_UNUSED,
474                          asymbol *symbol ATTRIBUTE_UNUSED,
475                          void *data ATTRIBUTE_UNUSED,
476                          asection *input_section ATTRIBUTE_UNUSED,
477                          bfd *output_bfd ATTRIBUTE_UNUSED,
478                          char **error_message ATTRIBUTE_UNUSED)
479 {
480   abort ();
481 }
482
483 static bfd_boolean
484 _bfd_xgate_elf_print_private_bfd_data (bfd *abfd, void *ptr)
485 {
486   FILE *file = (FILE *) ptr;
487
488   BFD_ASSERT (abfd != NULL && ptr != NULL);
489
490   /* Print normal ELF private data.  */
491   _bfd_elf_print_private_bfd_data (abfd, ptr);
492
493   /* xgettext:c-format */
494   fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
495
496   if (elf_elfheader (abfd)->e_flags & E_XGATE_I32)
497     fprintf (file, _("[abi=32-bit int, "));
498   else
499     fprintf (file, _("[abi=16-bit int, "));
500
501   if (elf_elfheader (abfd)->e_flags & E_XGATE_F64)
502     fprintf (file, _("64-bit double, "));
503   else
504     fprintf (file, _("32-bit double, "));
505   if (elf_elfheader (abfd)->e_flags & EF_XGATE_MACH)
506     fprintf (file, _("cpu=XGATE]"));
507   else
508     fprintf (file, _("error reading cpu type from elf private data"));
509   fputc ('\n', file);
510
511   return TRUE;
512 }
513
514 #define ELF_ARCH                             bfd_arch_xgate
515 #define ELF_MACHINE_CODE                     EM_XGATE
516
517 #define ELF_MAXPAGESIZE                      0x1000
518
519 #define TARGET_BIG_SYM                       xgate_elf32_vec
520 #define TARGET_BIG_NAME                      "elf32-xgate"
521
522 #define elf_info_to_howto_rel                xgate_info_to_howto_rel
523 #define elf_backend_special_sections         elf32_xgate_special_sections
524 #define elf_backend_symbol_processing        elf32_xgate_backend_symbol_processing
525 #define bfd_elf32_bfd_print_private_bfd_data _bfd_xgate_elf_print_private_bfd_data
526
527 #include "elf32-target.h"