x86-64: optimize certain commutative VEX-encoded insns
[external/binutils.git] / bfd / elf32-d30v.c
1 /* D30V-specific support for 32-bit ELF
2    Copyright (C) 1997-2019 Free Software Foundation, Inc.
3    Contributed 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 "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/d30v.h"
27
28 #define MAX32 ((bfd_signed_vma) 0x7fffffff)
29 #define MIN32 (- MAX32 - 1)
30
31 static bfd_reloc_status_type
32 bfd_elf_d30v_reloc (bfd *abfd,
33                     arelent *reloc_entry,
34                     asymbol *symbol,
35                     void * data,
36                     asection *input_section,
37                     bfd *output_bfd,
38                     char **error_message)
39 {
40   bfd_signed_vma relocation;
41   bfd_vma in1, in2, num;
42   bfd_vma tmp_addr = 0;
43   bfd_reloc_status_type r;
44   asection *reloc_target_output_section;
45   bfd_size_type addr = reloc_entry->address;
46   bfd_reloc_status_type flag = bfd_reloc_ok;
47   bfd_vma output_base = 0;
48   reloc_howto_type *howto = reloc_entry->howto;
49   int make_absolute = 0;
50
51   if (output_bfd != NULL)
52     {
53       /* Partial linking -- do nothing.  */
54       reloc_entry->address += input_section->output_offset;
55       return bfd_reloc_ok;
56     }
57
58   r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
59                              input_section, output_bfd, error_message);
60   if (r != bfd_reloc_continue)
61     return r;
62
63   /* A hacked-up version of bfd_perform_reloc() follows.  */
64  if (bfd_is_und_section (symbol->section)
65       && (symbol->flags & BSF_WEAK) == 0
66       && output_bfd == NULL)
67     flag = bfd_reloc_undefined;
68
69   /* Is the address of the relocation really within the section?  */
70   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
71     return bfd_reloc_outofrange;
72
73   /* Work out which section the relocation is targeted at and the
74      initial relocation command value.  */
75
76   /* Get symbol value.  (Common symbols are special.)  */
77   if (bfd_is_com_section (symbol->section))
78     relocation = 0;
79   else
80     relocation = symbol->value;
81
82   reloc_target_output_section = symbol->section->output_section;
83
84   /* Convert input-section-relative symbol value to absolute.  */
85   output_base = reloc_target_output_section->vma;
86   relocation += output_base + symbol->section->output_offset;
87
88   /* Add in supplied addend.  */
89   relocation += reloc_entry->addend;
90
91   /* Here the variable relocation holds the final address of the
92      symbol we are relocating against, plus any addend.  */
93   if (howto->pc_relative)
94     {
95       tmp_addr = input_section->output_section->vma
96         + input_section->output_offset
97         + reloc_entry->address;
98       relocation -= tmp_addr;
99     }
100
101   in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
102   in2 = bfd_get_32 (abfd, (bfd_byte *) data + addr + 4);
103
104   /* Extract the addend.  */
105   num = ((in2 & 0x3FFFF)
106          | ((in2 & 0xFF00000) >> 2)
107          | ((in1 & 0x3F) << 26));
108   in1 &= 0xFFFFFFC0;
109   in2 = 0x80000000;
110
111   relocation += num;
112
113   if (howto->pc_relative && howto->bitsize == 32)
114     {
115       /* The D30V has a PC that doesn't wrap and PC-relative jumps are
116          signed, so a PC-relative jump can't be more than +/- 2^31 bytes.
117          If one exceeds this, change it to an absolute jump.  */
118       if (relocation > MAX32 || relocation < MIN32)
119         {
120           relocation = (relocation + tmp_addr) & 0xffffffff;
121           make_absolute = 1;
122         }
123     }
124
125   in1 |= (relocation >> 26) & 0x3F;             /* Top 6 bits.  */
126   in2 |= ((relocation & 0x03FC0000) << 2);      /* Next 8 bits.  */
127   in2 |= relocation & 0x0003FFFF;               /* Bottom 18 bits.  */
128
129   /* Change a PC-relative instruction to its
130      absolute equivalent with this simple hack.  */
131   if (make_absolute)
132     in1 |= 0x00100000;
133
134   bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
135   bfd_put_32 (abfd, in2, (bfd_byte *) data + addr + 4);
136
137   return flag;
138 }
139
140 static bfd_reloc_status_type
141 bfd_elf_d30v_reloc_21 (bfd *abfd,
142                        arelent *reloc_entry,
143                        asymbol *symbol,
144                        void * data,
145                        asection *input_section,
146                        bfd *output_bfd,
147                        char **error_message)
148 {
149   bfd_vma relocation;
150   bfd_vma in1, num;
151   bfd_reloc_status_type r;
152   asection *reloc_target_output_section;
153   bfd_size_type addr = reloc_entry->address;
154   bfd_reloc_status_type flag = bfd_reloc_ok;
155   bfd_vma output_base = 0;
156   reloc_howto_type *howto = reloc_entry->howto;
157   int mask, max;
158
159   if (output_bfd != NULL)
160     {
161       /* Partial linking -- do nothing.  */
162       reloc_entry->address += input_section->output_offset;
163       return bfd_reloc_ok;
164     }
165
166   r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
167                              input_section, output_bfd, error_message);
168   if (r != bfd_reloc_continue)
169     return r;
170
171   /* A hacked-up version of bfd_perform_reloc() follows.  */
172   if (bfd_is_und_section (symbol->section)
173       && (symbol->flags & BSF_WEAK) == 0
174       && output_bfd == NULL)
175     flag = bfd_reloc_undefined;
176
177   /* Is the address of the relocation really within the section?  */
178   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
179     return bfd_reloc_outofrange;
180
181   /* Work out which section the relocation is targeted at and the
182      initial relocation command value.  */
183
184   /* Get symbol value.  (Common symbols are special.)  */
185   if (bfd_is_com_section (symbol->section))
186     relocation = 0;
187   else
188     relocation = symbol->value;
189
190   reloc_target_output_section = symbol->section->output_section;
191
192   /* Convert input-section-relative symbol value to absolute.  */
193   output_base = reloc_target_output_section->vma;
194   relocation += output_base + symbol->section->output_offset;
195
196   /* Add in supplied addend.  */
197   relocation += reloc_entry->addend;
198
199   /* Here the variable relocation holds the final address of the
200      symbol we are relocating against, plus any addend.  */
201
202   if (howto->pc_relative)
203     {
204       relocation -= (input_section->output_section->vma
205                      + input_section->output_offset);
206       if (howto->pcrel_offset)
207         relocation -= reloc_entry->address;
208     }
209
210   in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
211
212   mask =  (1 << howto->bitsize) - 1;
213   if (howto->bitsize == 6)
214     mask <<= 12;
215   max = (1 << (howto->bitsize + 2)) - 1;
216
217   /* Extract the addend.  */
218   num = in1 & mask;  /* 18 bits.  */
219   if (howto->bitsize == 6)
220     num >>= 12;
221   num <<= 3; /* shift left 3.  */
222   in1 &= ~mask;  /* Mask out addend.  */
223
224   relocation += num;
225   if (howto->type == R_D30V_21_PCREL_R
226       || howto->type == R_D30V_15_PCREL_R
227       || howto->type == R_D30V_9_PCREL_R)
228     relocation += 4;
229
230   if ((int) relocation < 0)
231     {
232       if (~ (int) relocation > max)
233         flag = bfd_reloc_overflow;
234     }
235   else
236     {
237       if ((int) relocation > max)
238         flag = bfd_reloc_overflow;
239     }
240
241   relocation >>= 3;
242   if (howto->bitsize == 6)
243     in1 |= ((relocation & (mask >> 12)) << 12);
244   else
245     in1 |= relocation & mask;
246
247   bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
248
249   return flag;
250 }
251
252 static reloc_howto_type elf_d30v_howto_table[] =
253 {
254   /* This reloc does nothing.  */
255   HOWTO (R_D30V_NONE,           /* Type.  */
256          0,                     /* Rightshift.  */
257          3,                     /* Size (0 = byte, 1 = short, 2 = long).  */
258          0,                     /* Bitsize.  */
259          FALSE,                 /* PC_relative.  */
260          0,                     /* Bitpos.  */
261          complain_overflow_dont, /* Complain_on_overflow.  */
262          bfd_elf_generic_reloc, /* Special_function.  */
263          "R_D30V_NONE",         /* Name.  */
264          FALSE,                 /* Partial_inplace.  */
265          0,                     /* Src_mask.  */
266          0,                     /* Dst_mask.  */
267          FALSE),                /* PCrel_offset.  */
268
269   /* A 6 bit absolute relocation.  */
270   HOWTO (R_D30V_6,              /* Type.  */
271          0,                     /* Rightshift.  */
272          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
273          6,                     /* Bitsize.  */
274          FALSE,                 /* PC_relative.  */
275          0,                     /* Bitpos.  */
276          complain_overflow_bitfield, /* Complain_on_overflow.  */
277          bfd_elf_generic_reloc, /* Special_function.  */
278          "R_D30V_6",            /* Name.  */
279          FALSE,                 /* Partial_inplace.  */
280          0x3f,                  /* Src_mask.  */
281          0x3f,                  /* Dst_mask.  */
282          FALSE),                /* PCrel_offset.  */
283
284   /* A relative 9 bit relocation, right shifted by 3.  */
285   HOWTO (R_D30V_9_PCREL,        /* Type.  */
286          3,                     /* Rightshift.  */
287          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
288          6,                     /* Bitsize.  */
289          TRUE,                  /* PC_relative.  */
290          0,                     /* Bitpos.  */
291          complain_overflow_signed, /* Complain_on_overflow.  */
292          bfd_elf_d30v_reloc_21, /* Special_function.  */
293          "R_D30V_9_PCREL",      /* Name.  */
294          FALSE,                 /* Partial_inplace.  */
295          0x3f,                  /* Src_mask.  */
296          0x3f,                  /* Dst_mask.  */
297          TRUE),                 /* PCrel_offset.  */
298
299   /* A relative 9 bit relocation, right shifted by 3.  */
300   HOWTO (R_D30V_9_PCREL_R,      /* Type.  */
301          3,                     /* Rightshift.  */
302          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
303          6,                     /* Bitsize.  */
304          TRUE,                  /* PC_relative.  */
305          0,                     /* Bitpos.  */
306          complain_overflow_signed, /* Complain_on_overflow.  */
307          bfd_elf_d30v_reloc_21, /* Special_function.  */
308          "R_D30V_9_PCREL_R",    /* Name.  */
309          FALSE,                 /* Partial_inplace.  */
310          0x3f,                  /* Src_mask.  */
311          0x3f,                  /* Dst_mask.  */
312          TRUE),                 /* PCrel_offset.  */
313
314   /* An absolute 15 bit relocation, right shifted by 3.  */
315   HOWTO (R_D30V_15,             /* Type.  */
316          3,                     /* Rightshift.  */
317          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
318          12,                    /* Bitsize.  */
319          FALSE,                 /* PC_relative.  */
320          0,                     /* Bitpos.  */
321          complain_overflow_signed, /* Complain_on_overflow.  */
322          bfd_elf_generic_reloc, /* Special_function.  */
323          "R_D30V_15",           /* Name.  */
324          FALSE,                 /* Partial_inplace.  */
325          0xfff,                 /* Src_mask.  */
326          0xfff,                 /* Dst_mask.  */
327          FALSE),                /* PCrel_offset.  */
328
329   /* A relative 15 bit relocation, right shifted by 3.  */
330   HOWTO (R_D30V_15_PCREL,       /* Type.  */
331          3,                     /* Rightshift.  */
332          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
333          12,                    /* Bitsize.  */
334          TRUE,                  /* PC_relative.  */
335          0,                     /* Bitpos.  */
336          complain_overflow_signed, /* Complain_on_overflow.  */
337          bfd_elf_d30v_reloc_21, /* Special_function.  */
338          "R_D30V_15_PCREL",     /* Name.  */
339          FALSE,                 /* Partial_inplace.  */
340          0xfff,                 /* Src_mask.  */
341          0xfff,                 /* Dst_mask.  */
342          TRUE),                 /* PCrel_offset.  */
343
344   /* A relative 15 bit relocation, right shifted by 3.  */
345   HOWTO (R_D30V_15_PCREL_R,     /* Type.  */
346          3,                     /* Rightshift.  */
347          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
348          12,                    /* Bitsize.  */
349          TRUE,                  /* PC_relative.  */
350          0,                     /* Bitpos.  */
351          complain_overflow_signed, /* Complain_on_overflow.  */
352          bfd_elf_d30v_reloc_21, /* Special_function.  */
353          "R_D30V_15_PCREL_R",   /* Name.  */
354          FALSE,                 /* Partial_inplace.  */
355          0xfff,                 /* Src_mask.  */
356          0xfff,                 /* Dst_mask.  */
357          TRUE),                 /* PCrel_offset.  */
358
359   /* An absolute 21 bit relocation, right shifted by 3.  */
360   HOWTO (R_D30V_21,             /* Type.  */
361          3,                     /* Rightshift.  */
362          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
363          18,                    /* Bitsize.  */
364          FALSE,                 /* PC_relative.  */
365          0,                     /* Bitpos.  */
366          complain_overflow_signed, /* Complain_on_overflow.  */
367          bfd_elf_generic_reloc, /* Special_function.  */
368          "R_D30V_21",           /* Name.  */
369          FALSE,                 /* Partial_inplace.  */
370          0x3ffff,               /* Src_mask.  */
371          0x3ffff,               /* Dst_mask.  */
372          FALSE),                /* PCrel_offset.  */
373
374   /* A relative 21 bit relocation, right shifted by 3.  */
375   HOWTO (R_D30V_21_PCREL,       /* Type.  */
376          3,                     /* Rightshift.  */
377          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
378          18,                    /* Bitsize.  */
379          TRUE,                  /* PC_relative.  */
380          0,                     /* Bitpos.  */
381          complain_overflow_signed, /* Complain_on_overflow.  */
382          bfd_elf_d30v_reloc_21, /* Special_function.  */
383          "R_D30V_21_PCREL",     /* Name.  */
384          FALSE,                 /* Partial_inplace.  */
385          0x3ffff,               /* Src_mask.  */
386          0x3ffff,               /* Dst_mask.  */
387          TRUE),                 /* PCrel_offset.  */
388
389   /* A relative 21 bit relocation, right shifted by 3, in the Right container.  */
390   HOWTO (R_D30V_21_PCREL_R,     /* Type.  */
391          3,                     /* Rightshift.  */
392          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
393          18,                    /* Bitsize.  */
394          TRUE,                  /* PC_relative.  */
395          0,                     /* Bitpos.  */
396          complain_overflow_signed, /* Complain_on_overflow.  */
397          bfd_elf_d30v_reloc_21, /* Special_function.  */
398          "R_D30V_21_PCREL_R",   /* Name.  */
399          FALSE,                 /* Partial_inplace.  */
400          0x3ffff,               /* Src_mask.  */
401          0x3ffff,               /* Dst_mask.  */
402          TRUE),                 /* PCrel_offset.  */
403
404   /* A D30V 32 bit absolute relocation.  */
405   HOWTO (R_D30V_32,             /* Type.  */
406          0,                     /* Rightshift.  */
407          4,                     /* Size (0 = byte, 1 = short, 2 = long).  */
408          32,                    /* Bitsize.  */
409          FALSE,                 /* PC_relative.  */
410          0,                     /* Bitpos.  */
411          complain_overflow_bitfield, /* Complain_on_overflow.  */
412          bfd_elf_d30v_reloc,    /* Special_function.  */
413          "R_D30V_32",           /* Name.  */
414          FALSE,                 /* Partial_inplace.  */
415          0xffffffff,            /* Src_mask.  */
416          0xffffffff,            /* Dst_mask.  */
417          FALSE),                /* PCrel_offset.  */
418
419   /* A relative 32 bit relocation.  */
420   HOWTO (R_D30V_32_PCREL,       /* Type.  */
421          0,                     /* Rightshift.  */
422          4,                     /* Size (0 = byte, 1 = short, 2 = long).  */
423          32,                    /* Bitsize.  */
424          TRUE,                  /* PC_relative.  */
425          0,                     /* Bitpos.  */
426          complain_overflow_signed, /* Complain_on_overflow.  */
427          bfd_elf_d30v_reloc,    /* Special_function.  */
428          "R_D30V_32_PCREL",     /* Name.  */
429          FALSE,                 /* Partial_inplace.  */
430          0xffffffff,            /* Src_mask.  */
431          0xffffffff,            /* Dst_mask.  */
432          TRUE),                 /* PCrel_offset.  */
433
434   /* A regular 32 bit absolute relocation.  */
435   HOWTO (R_D30V_32_NORMAL,      /* Type.  */
436          0,                     /* Rightshift.  */
437          2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
438          32,                    /* Bitsize.  */
439          FALSE,                 /* PC_relative.  */
440          0,                     /* Bitpos.  */
441          complain_overflow_bitfield, /* Complain_on_overflow.  */
442          bfd_elf_generic_reloc, /* Special_function.  */
443          "R_D30V_32_NORMAL",    /* Name.  */
444          FALSE,                 /* Partial_inplace.  */
445          0xffffffff,            /* Src_mask.  */
446          0xffffffff,            /* Dst_mask.  */
447          FALSE),                /* PCrel_offset.  */
448
449 };
450
451 /* Map BFD reloc types to D30V ELF reloc types.  */
452
453 struct d30v_reloc_map
454 {
455   bfd_reloc_code_real_type bfd_reloc_val;
456   unsigned char elf_reloc_val;
457 };
458
459 static const struct d30v_reloc_map d30v_reloc_map[] =
460 {
461   { BFD_RELOC_NONE, R_D30V_NONE, },
462   { BFD_RELOC_D30V_6, R_D30V_6 },
463   { BFD_RELOC_D30V_9_PCREL, R_D30V_9_PCREL },
464   { BFD_RELOC_D30V_9_PCREL_R, R_D30V_9_PCREL_R },
465   { BFD_RELOC_D30V_15, R_D30V_15 },
466   { BFD_RELOC_D30V_15_PCREL, R_D30V_15_PCREL },
467   { BFD_RELOC_D30V_15_PCREL_R, R_D30V_15_PCREL_R },
468   { BFD_RELOC_D30V_21, R_D30V_21 },
469   { BFD_RELOC_D30V_21_PCREL, R_D30V_21_PCREL },
470   { BFD_RELOC_D30V_21_PCREL_R, R_D30V_21_PCREL_R },
471   { BFD_RELOC_D30V_32, R_D30V_32 },
472   { BFD_RELOC_D30V_32_PCREL, R_D30V_32_PCREL },
473   { BFD_RELOC_32, R_D30V_32_NORMAL },
474 };
475
476 static reloc_howto_type *
477 bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
478                                  bfd_reloc_code_real_type code)
479 {
480   unsigned int i;
481
482   for (i = 0;
483        i < sizeof (d30v_reloc_map) / sizeof (struct d30v_reloc_map);
484        i++)
485     {
486       if (d30v_reloc_map[i].bfd_reloc_val == code)
487         return &elf_d30v_howto_table[d30v_reloc_map[i].elf_reloc_val];
488     }
489
490   return NULL;
491 }
492
493 static reloc_howto_type *
494 bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
495                                  const char *r_name)
496 {
497   unsigned int i;
498
499   for (i = 0;
500        i < sizeof (elf_d30v_howto_table) / sizeof (elf_d30v_howto_table[0]);
501        i++)
502     if (elf_d30v_howto_table[i].name != NULL
503         && strcasecmp (elf_d30v_howto_table[i].name, r_name) == 0)
504       return &elf_d30v_howto_table[i];
505
506   return NULL;
507 }
508
509 /* Set the howto pointer for an D30V ELF reloc (type REL).  */
510
511 static bfd_boolean
512 d30v_info_to_howto_rel (bfd *abfd,
513                         arelent *cache_ptr,
514                         Elf_Internal_Rela *dst)
515 {
516   unsigned int r_type;
517
518   r_type = ELF32_R_TYPE (dst->r_info);
519   if (r_type >= (unsigned int) R_D30V_max)
520     {
521       /* xgettext:c-format */
522       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
523                           abfd, r_type);
524       bfd_set_error (bfd_error_bad_value);
525       return FALSE;
526     }
527   cache_ptr->howto = &elf_d30v_howto_table[r_type];
528   return TRUE;
529 }
530
531 /* Set the howto pointer for an D30V ELF reloc (type RELA).  */
532
533 static bfd_boolean
534 d30v_info_to_howto_rela (bfd *abfd,
535                          arelent *cache_ptr,
536                          Elf_Internal_Rela *dst)
537 {
538   unsigned int r_type;
539
540   r_type = ELF32_R_TYPE (dst->r_info);
541   if (r_type >= (unsigned int) R_D30V_max)
542     {
543       /* xgettext:c-format */
544       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
545                           abfd, r_type);
546       bfd_set_error (bfd_error_bad_value);
547       return FALSE;
548     }
549   cache_ptr->howto = &elf_d30v_howto_table[r_type];
550   return TRUE;
551 }
552
553 #define ELF_ARCH                bfd_arch_d30v
554 #define ELF_MACHINE_CODE        EM_D30V
555 #define ELF_MACHINE_ALT1        EM_CYGNUS_D30V
556 #define ELF_MAXPAGESIZE         0x1000
557
558 #define TARGET_BIG_SYM          d30v_elf32_vec
559 #define TARGET_BIG_NAME         "elf32-d30v"
560
561 #define elf_info_to_howto       d30v_info_to_howto_rela
562 #define elf_info_to_howto_rel   d30v_info_to_howto_rel
563 #define elf_backend_object_p    0
564 #define elf_backend_final_write_processing      0
565
566 #include "elf32-target.h"