packaging: Enable testing infrastructure
[external/binutils.git] / bfd / elfxx-riscv.c
1 /* RISC-V-specific support for ELF.
2    Copyright (C) 2011-2019 Free Software Foundation, Inc.
3
4    Contributed by Andrew Waterman (andrew@sifive.com).
5    Based on TILE-Gx and MIPS targets.
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; see the file COPYING3. If not,
21    see <http://www.gnu.org/licenses/>.  */
22
23 #include "sysdep.h"
24 #include "bfd.h"
25 #include "libbfd.h"
26 #include "elf-bfd.h"
27 #include "elf/riscv.h"
28 #include "opcode/riscv.h"
29 #include "libiberty.h"
30 #include "elfxx-riscv.h"
31 #include "safe-ctype.h"
32
33 #define MINUS_ONE ((bfd_vma)0 - 1)
34
35 /* Special handler for ADD/SUB relocations that allows them to be filled out
36    both in the pre-linked and post-linked file.  This is necessary to make
37    pre-linked debug info work, as due to linker relaxations we need to emit
38    relocations for the debug info.  */
39 static bfd_reloc_status_type riscv_elf_add_sub_reloc
40   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
41
42 /* The relocation table used for SHT_RELA sections.  */
43
44 static reloc_howto_type howto_table[] =
45 {
46   /* No relocation.  */
47   HOWTO (R_RISCV_NONE,                  /* type */
48          0,                             /* rightshift */
49          3,                             /* size */
50          0,                             /* bitsize */
51          FALSE,                         /* pc_relative */
52          0,                             /* bitpos */
53          complain_overflow_dont,        /* complain_on_overflow */
54          bfd_elf_generic_reloc,         /* special_function */
55          "R_RISCV_NONE",                /* name */
56          FALSE,                         /* partial_inplace */
57          0,                             /* src_mask */
58          0,                             /* dst_mask */
59          FALSE),                        /* pcrel_offset */
60
61   /* 32 bit relocation.  */
62   HOWTO (R_RISCV_32,                    /* type */
63          0,                             /* rightshift */
64          2,                             /* size */
65          32,                            /* bitsize */
66          FALSE,                         /* pc_relative */
67          0,                             /* bitpos */
68          complain_overflow_dont,        /* complain_on_overflow */
69          bfd_elf_generic_reloc,         /* special_function */
70          "R_RISCV_32",                  /* name */
71          FALSE,                         /* partial_inplace */
72          0,                             /* src_mask */
73          MINUS_ONE,                     /* dst_mask */
74          FALSE),                        /* pcrel_offset */
75
76   /* 64 bit relocation.  */
77   HOWTO (R_RISCV_64,                    /* type */
78          0,                             /* rightshift */
79          4,                             /* size */
80          64,                            /* bitsize */
81          FALSE,                         /* pc_relative */
82          0,                             /* bitpos */
83          complain_overflow_dont,        /* complain_on_overflow */
84          bfd_elf_generic_reloc,         /* special_function */
85          "R_RISCV_64",                  /* name */
86          FALSE,                         /* partial_inplace */
87          0,                             /* src_mask */
88          MINUS_ONE,                     /* dst_mask */
89          FALSE),                        /* pcrel_offset */
90
91   /* Relocation against a local symbol in a shared object.  */
92   HOWTO (R_RISCV_RELATIVE,              /* type */
93          0,                             /* rightshift */
94          2,                             /* size */
95          32,                            /* bitsize */
96          FALSE,                         /* pc_relative */
97          0,                             /* bitpos */
98          complain_overflow_dont,        /* complain_on_overflow */
99          bfd_elf_generic_reloc,         /* special_function */
100          "R_RISCV_RELATIVE",            /* name */
101          FALSE,                         /* partial_inplace */
102          0,                             /* src_mask */
103          MINUS_ONE,                     /* dst_mask */
104          FALSE),                        /* pcrel_offset */
105
106   HOWTO (R_RISCV_COPY,                  /* type */
107          0,                             /* rightshift */
108          0,                             /* this one is variable size */
109          0,                             /* bitsize */
110          FALSE,                         /* pc_relative */
111          0,                             /* bitpos */
112          complain_overflow_bitfield,    /* complain_on_overflow */
113          bfd_elf_generic_reloc,         /* special_function */
114          "R_RISCV_COPY",                /* name */
115          FALSE,                         /* partial_inplace */
116          0,                             /* src_mask */
117          0,                             /* dst_mask */
118          FALSE),                        /* pcrel_offset */
119
120   HOWTO (R_RISCV_JUMP_SLOT,             /* type */
121          0,                             /* rightshift */
122          4,                             /* size */
123          64,                            /* bitsize */
124          FALSE,                         /* pc_relative */
125          0,                             /* bitpos */
126          complain_overflow_bitfield,    /* complain_on_overflow */
127          bfd_elf_generic_reloc,         /* special_function */
128          "R_RISCV_JUMP_SLOT",           /* name */
129          FALSE,                         /* partial_inplace */
130          0,                             /* src_mask */
131          0,                             /* dst_mask */
132          FALSE),                        /* pcrel_offset */
133
134   /* Dynamic TLS relocations.  */
135   HOWTO (R_RISCV_TLS_DTPMOD32,          /* type */
136          0,                             /* rightshift */
137          4,                             /* size */
138          32,                            /* bitsize */
139          FALSE,                         /* pc_relative */
140          0,                             /* bitpos */
141          complain_overflow_dont,        /* complain_on_overflow */
142          bfd_elf_generic_reloc,         /* special_function */
143          "R_RISCV_TLS_DTPMOD32",        /* name */
144          FALSE,                         /* partial_inplace */
145          0,                             /* src_mask */
146          MINUS_ONE,                     /* dst_mask */
147          FALSE),                        /* pcrel_offset */
148
149   HOWTO (R_RISCV_TLS_DTPMOD64,          /* type */
150          0,                             /* rightshift */
151          4,                             /* size */
152          64,                            /* bitsize */
153          FALSE,                         /* pc_relative */
154          0,                             /* bitpos */
155          complain_overflow_dont,        /* complain_on_overflow */
156          bfd_elf_generic_reloc,         /* special_function */
157          "R_RISCV_TLS_DTPMOD64",        /* name */
158          FALSE,                         /* partial_inplace */
159          0,                             /* src_mask */
160          MINUS_ONE,                     /* dst_mask */
161          FALSE),                        /* pcrel_offset */
162
163   HOWTO (R_RISCV_TLS_DTPREL32,          /* type */
164          0,                             /* rightshift */
165          4,                             /* size */
166          32,                            /* bitsize */
167          FALSE,                         /* pc_relative */
168          0,                             /* bitpos */
169          complain_overflow_dont,        /* complain_on_overflow */
170          bfd_elf_generic_reloc,         /* special_function */
171          "R_RISCV_TLS_DTPREL32",        /* name */
172          TRUE,                          /* partial_inplace */
173          0,                             /* src_mask */
174          MINUS_ONE,                     /* dst_mask */
175          FALSE),                        /* pcrel_offset */
176
177   HOWTO (R_RISCV_TLS_DTPREL64,          /* type */
178          0,                             /* rightshift */
179          4,                             /* size */
180          64,                            /* bitsize */
181          FALSE,                         /* pc_relative */
182          0,                             /* bitpos */
183          complain_overflow_dont,        /* complain_on_overflow */
184          bfd_elf_generic_reloc,         /* special_function */
185          "R_RISCV_TLS_DTPREL64",        /* name */
186          TRUE,                          /* partial_inplace */
187          0,                             /* src_mask */
188          MINUS_ONE,                     /* dst_mask */
189          FALSE),                        /* pcrel_offset */
190
191   HOWTO (R_RISCV_TLS_TPREL32,           /* type */
192          0,                             /* rightshift */
193          2,                             /* size */
194          32,                            /* bitsize */
195          FALSE,                         /* pc_relative */
196          0,                             /* bitpos */
197          complain_overflow_dont,        /* complain_on_overflow */
198          bfd_elf_generic_reloc,         /* special_function */
199          "R_RISCV_TLS_TPREL32",         /* name */
200          FALSE,                         /* partial_inplace */
201          0,                             /* src_mask */
202          MINUS_ONE,                     /* dst_mask */
203          FALSE),                        /* pcrel_offset */
204
205   HOWTO (R_RISCV_TLS_TPREL64,           /* type */
206          0,                             /* rightshift */
207          4,                             /* size */
208          64,                            /* bitsize */
209          FALSE,                         /* pc_relative */
210          0,                             /* bitpos */
211          complain_overflow_dont,        /* complain_on_overflow */
212          bfd_elf_generic_reloc,         /* special_function */
213          "R_RISCV_TLS_TPREL64",         /* name */
214          FALSE,                         /* partial_inplace */
215          0,                             /* src_mask */
216          MINUS_ONE,                     /* dst_mask */
217          FALSE),                        /* pcrel_offset */
218
219   /* Reserved for future relocs that the dynamic linker must understand.  */
220   EMPTY_HOWTO (12),
221   EMPTY_HOWTO (13),
222   EMPTY_HOWTO (14),
223   EMPTY_HOWTO (15),
224
225   /* 12-bit PC-relative branch offset.  */
226   HOWTO (R_RISCV_BRANCH,                /* type */
227          0,                             /* rightshift */
228          2,                             /* size */
229          32,                            /* bitsize */
230          TRUE,                          /* pc_relative */
231          0,                             /* bitpos */
232          complain_overflow_signed,      /* complain_on_overflow */
233          bfd_elf_generic_reloc,         /* special_function */
234          "R_RISCV_BRANCH",              /* name */
235          FALSE,                         /* partial_inplace */
236          0,                             /* src_mask */
237          ENCODE_SBTYPE_IMM (-1U),       /* dst_mask */
238          TRUE),                         /* pcrel_offset */
239
240   /* 20-bit PC-relative jump offset.  */
241   HOWTO (R_RISCV_JAL,                   /* type */
242          0,                             /* rightshift */
243          2,                             /* size */
244          32,                            /* bitsize */
245          TRUE,                          /* pc_relative */
246          0,                             /* bitpos */
247          complain_overflow_dont,        /* complain_on_overflow */
248          bfd_elf_generic_reloc,         /* special_function */
249          "R_RISCV_JAL",                 /* name */
250          FALSE,                         /* partial_inplace */
251          0,                             /* src_mask */
252          ENCODE_UJTYPE_IMM (-1U),       /* dst_mask */
253          TRUE),                         /* pcrel_offset */
254
255   /* 32-bit PC-relative function call (AUIPC/JALR).  */
256   HOWTO (R_RISCV_CALL,                  /* type */
257          0,                             /* rightshift */
258          2,                             /* size */
259          64,                            /* bitsize */
260          TRUE,                          /* pc_relative */
261          0,                             /* bitpos */
262          complain_overflow_dont,        /* complain_on_overflow */
263          bfd_elf_generic_reloc,         /* special_function */
264          "R_RISCV_CALL",                /* name */
265          FALSE,                         /* partial_inplace */
266          0,                             /* src_mask */
267          ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
268                                         /* dst_mask */
269          TRUE),                         /* pcrel_offset */
270
271   /* Like R_RISCV_CALL, but not locally binding.  */
272   HOWTO (R_RISCV_CALL_PLT,              /* type */
273          0,                             /* rightshift */
274          2,                             /* size */
275          64,                            /* bitsize */
276          TRUE,                          /* pc_relative */
277          0,                             /* bitpos */
278          complain_overflow_dont,        /* complain_on_overflow */
279          bfd_elf_generic_reloc,         /* special_function */
280          "R_RISCV_CALL_PLT",            /* name */
281          FALSE,                         /* partial_inplace */
282          0,                             /* src_mask */
283          ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
284                                         /* dst_mask */
285          TRUE),                         /* pcrel_offset */
286
287   /* High 20 bits of 32-bit PC-relative GOT access.  */
288   HOWTO (R_RISCV_GOT_HI20,              /* type */
289          0,                             /* rightshift */
290          2,                             /* size */
291          32,                            /* bitsize */
292          TRUE,                          /* pc_relative */
293          0,                             /* bitpos */
294          complain_overflow_dont,        /* complain_on_overflow */
295          bfd_elf_generic_reloc,         /* special_function */
296          "R_RISCV_GOT_HI20",            /* name */
297          FALSE,                         /* partial_inplace */
298          0,                             /* src_mask */
299          ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
300          FALSE),                        /* pcrel_offset */
301
302   /* High 20 bits of 32-bit PC-relative TLS IE GOT access.  */
303   HOWTO (R_RISCV_TLS_GOT_HI20,          /* type */
304          0,                             /* rightshift */
305          2,                             /* size */
306          32,                            /* bitsize */
307          TRUE,                          /* pc_relative */
308          0,                             /* bitpos */
309          complain_overflow_dont,        /* complain_on_overflow */
310          bfd_elf_generic_reloc,         /* special_function */
311          "R_RISCV_TLS_GOT_HI20",        /* name */
312          FALSE,                         /* partial_inplace */
313          0,                             /* src_mask */
314          ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
315          FALSE),                        /* pcrel_offset */
316
317   /* High 20 bits of 32-bit PC-relative TLS GD GOT reference.  */
318   HOWTO (R_RISCV_TLS_GD_HI20,           /* type */
319          0,                             /* rightshift */
320          2,                             /* size */
321          32,                            /* bitsize */
322          TRUE,                          /* pc_relative */
323          0,                             /* bitpos */
324          complain_overflow_dont,        /* complain_on_overflow */
325          bfd_elf_generic_reloc,         /* special_function */
326          "R_RISCV_TLS_GD_HI20",         /* name */
327          FALSE,                         /* partial_inplace */
328          0,                             /* src_mask */
329          ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
330          FALSE),                        /* pcrel_offset */
331
332   /* High 20 bits of 32-bit PC-relative reference.  */
333   HOWTO (R_RISCV_PCREL_HI20,            /* type */
334          0,                             /* rightshift */
335          2,                             /* size */
336          32,                            /* bitsize */
337          TRUE,                          /* pc_relative */
338          0,                             /* bitpos */
339          complain_overflow_dont,        /* complain_on_overflow */
340          bfd_elf_generic_reloc,         /* special_function */
341          "R_RISCV_PCREL_HI20",          /* name */
342          FALSE,                         /* partial_inplace */
343          0,                             /* src_mask */
344          ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
345          TRUE),                         /* pcrel_offset */
346
347   /* Low 12 bits of a 32-bit PC-relative load or add.  */
348   HOWTO (R_RISCV_PCREL_LO12_I,          /* type */
349          0,                             /* rightshift */
350          2,                             /* size */
351          32,                            /* bitsize */
352          FALSE,                         /* pc_relative */
353          0,                             /* bitpos */
354          complain_overflow_dont,        /* complain_on_overflow */
355          bfd_elf_generic_reloc,         /* special_function */
356          "R_RISCV_PCREL_LO12_I",        /* name */
357          FALSE,                         /* partial_inplace */
358          0,                             /* src_mask */
359          ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
360          FALSE),                        /* pcrel_offset */
361
362   /* Low 12 bits of a 32-bit PC-relative store.  */
363   HOWTO (R_RISCV_PCREL_LO12_S,          /* type */
364          0,                             /* rightshift */
365          2,                             /* size */
366          32,                            /* bitsize */
367          FALSE,                         /* pc_relative */
368          0,                             /* bitpos */
369          complain_overflow_dont,        /* complain_on_overflow */
370          bfd_elf_generic_reloc,         /* special_function */
371          "R_RISCV_PCREL_LO12_S",        /* name */
372          FALSE,                         /* partial_inplace */
373          0,                             /* src_mask */
374          ENCODE_STYPE_IMM (-1U),        /* dst_mask */
375          FALSE),                        /* pcrel_offset */
376
377   /* High 20 bits of 32-bit absolute address.  */
378   HOWTO (R_RISCV_HI20,                  /* type */
379          0,                             /* rightshift */
380          2,                             /* size */
381          32,                            /* bitsize */
382          FALSE,                         /* pc_relative */
383          0,                             /* bitpos */
384          complain_overflow_dont,        /* complain_on_overflow */
385          bfd_elf_generic_reloc,         /* special_function */
386          "R_RISCV_HI20",                /* name */
387          FALSE,                         /* partial_inplace */
388          0,                             /* src_mask */
389          ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
390          FALSE),                        /* pcrel_offset */
391
392   /* High 12 bits of 32-bit load or add.  */
393   HOWTO (R_RISCV_LO12_I,                /* type */
394          0,                             /* rightshift */
395          2,                             /* size */
396          32,                            /* bitsize */
397          FALSE,                         /* pc_relative */
398          0,                             /* bitpos */
399          complain_overflow_dont,        /* complain_on_overflow */
400          bfd_elf_generic_reloc,         /* special_function */
401          "R_RISCV_LO12_I",              /* name */
402          FALSE,                         /* partial_inplace */
403          0,                             /* src_mask */
404          ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
405          FALSE),                        /* pcrel_offset */
406
407   /* High 12 bits of 32-bit store.  */
408   HOWTO (R_RISCV_LO12_S,                /* type */
409          0,                             /* rightshift */
410          2,                             /* size */
411          32,                            /* bitsize */
412          FALSE,                         /* pc_relative */
413          0,                             /* bitpos */
414          complain_overflow_dont,        /* complain_on_overflow */
415          bfd_elf_generic_reloc,         /* special_function */
416          "R_RISCV_LO12_S",              /* name */
417          FALSE,                         /* partial_inplace */
418          0,                             /* src_mask */
419          ENCODE_STYPE_IMM (-1U),        /* dst_mask */
420          FALSE),                        /* pcrel_offset */
421
422   /* High 20 bits of TLS LE thread pointer offset.  */
423   HOWTO (R_RISCV_TPREL_HI20,            /* type */
424          0,                             /* rightshift */
425          2,                             /* size */
426          32,                            /* bitsize */
427          FALSE,                         /* pc_relative */
428          0,                             /* bitpos */
429          complain_overflow_signed,      /* complain_on_overflow */
430          bfd_elf_generic_reloc,         /* special_function */
431          "R_RISCV_TPREL_HI20",          /* name */
432          TRUE,                          /* partial_inplace */
433          0,                             /* src_mask */
434          ENCODE_UTYPE_IMM (-1U),        /* dst_mask */
435          FALSE),                        /* pcrel_offset */
436
437   /* Low 12 bits of TLS LE thread pointer offset for loads and adds.  */
438   HOWTO (R_RISCV_TPREL_LO12_I,          /* type */
439          0,                             /* rightshift */
440          2,                             /* size */
441          32,                            /* bitsize */
442          FALSE,                         /* pc_relative */
443          0,                             /* bitpos */
444          complain_overflow_signed,      /* complain_on_overflow */
445          bfd_elf_generic_reloc,         /* special_function */
446          "R_RISCV_TPREL_LO12_I",        /* name */
447          FALSE,                         /* partial_inplace */
448          0,                             /* src_mask */
449          ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
450          FALSE),                        /* pcrel_offset */
451
452   /* Low 12 bits of TLS LE thread pointer offset for stores.  */
453   HOWTO (R_RISCV_TPREL_LO12_S,          /* type */
454          0,                             /* rightshift */
455          2,                             /* size */
456          32,                            /* bitsize */
457          FALSE,                         /* pc_relative */
458          0,                             /* bitpos */
459          complain_overflow_signed,      /* complain_on_overflow */
460          bfd_elf_generic_reloc,         /* special_function */
461          "R_RISCV_TPREL_LO12_S",        /* name */
462          FALSE,                         /* partial_inplace */
463          0,                             /* src_mask */
464          ENCODE_STYPE_IMM (-1U),        /* dst_mask */
465          FALSE),                        /* pcrel_offset */
466
467   /* TLS LE thread pointer usage.  May be relaxed.  */
468   HOWTO (R_RISCV_TPREL_ADD,             /* type */
469          0,                             /* rightshift */
470          2,                             /* size */
471          32,                            /* bitsize */
472          FALSE,                         /* pc_relative */
473          0,                             /* bitpos */
474          complain_overflow_dont,        /* complain_on_overflow */
475          bfd_elf_generic_reloc,         /* special_function */
476          "R_RISCV_TPREL_ADD",           /* name */
477          TRUE,                          /* partial_inplace */
478          0,                             /* src_mask */
479          0,                             /* dst_mask */
480          FALSE),                        /* pcrel_offset */
481
482   /* 8-bit in-place addition, for local label subtraction.  */
483   HOWTO (R_RISCV_ADD8,                  /* type */
484          0,                             /* rightshift */
485          0,                             /* size */
486          8,                             /* bitsize */
487          FALSE,                         /* pc_relative */
488          0,                             /* bitpos */
489          complain_overflow_dont,        /* complain_on_overflow */
490          riscv_elf_add_sub_reloc,       /* special_function */
491          "R_RISCV_ADD8",                /* name */
492          FALSE,                         /* partial_inplace */
493          0,                             /* src_mask */
494          MINUS_ONE,                     /* dst_mask */
495          FALSE),                        /* pcrel_offset */
496
497   /* 16-bit in-place addition, for local label subtraction.  */
498   HOWTO (R_RISCV_ADD16,                 /* type */
499          0,                             /* rightshift */
500          1,                             /* size */
501          16,                            /* bitsize */
502          FALSE,                         /* pc_relative */
503          0,                             /* bitpos */
504          complain_overflow_dont,        /* complain_on_overflow */
505          riscv_elf_add_sub_reloc,       /* special_function */
506          "R_RISCV_ADD16",               /* name */
507          FALSE,                         /* partial_inplace */
508          0,                             /* src_mask */
509          MINUS_ONE,                     /* dst_mask */
510          FALSE),                        /* pcrel_offset */
511
512   /* 32-bit in-place addition, for local label subtraction.  */
513   HOWTO (R_RISCV_ADD32,                 /* type */
514          0,                             /* rightshift */
515          2,                             /* size */
516          32,                            /* bitsize */
517          FALSE,                         /* pc_relative */
518          0,                             /* bitpos */
519          complain_overflow_dont,        /* complain_on_overflow */
520          riscv_elf_add_sub_reloc,       /* special_function */
521          "R_RISCV_ADD32",               /* name */
522          FALSE,                         /* partial_inplace */
523          0,                             /* src_mask */
524          MINUS_ONE,                     /* dst_mask */
525          FALSE),                        /* pcrel_offset */
526
527   /* 64-bit in-place addition, for local label subtraction.  */
528   HOWTO (R_RISCV_ADD64,                 /* type */
529          0,                             /* rightshift */
530          4,                             /* size */
531          64,                            /* bitsize */
532          FALSE,                         /* pc_relative */
533          0,                             /* bitpos */
534          complain_overflow_dont,        /* complain_on_overflow */
535          riscv_elf_add_sub_reloc,       /* special_function */
536          "R_RISCV_ADD64",               /* name */
537          FALSE,                         /* partial_inplace */
538          0,                             /* src_mask */
539          MINUS_ONE,                     /* dst_mask */
540          FALSE),                        /* pcrel_offset */
541
542   /* 8-bit in-place addition, for local label subtraction.  */
543   HOWTO (R_RISCV_SUB8,                  /* type */
544          0,                             /* rightshift */
545          0,                             /* size */
546          8,                             /* bitsize */
547          FALSE,                         /* pc_relative */
548          0,                             /* bitpos */
549          complain_overflow_dont,        /* complain_on_overflow */
550          riscv_elf_add_sub_reloc,       /* special_function */
551          "R_RISCV_SUB8",                /* name */
552          FALSE,                         /* partial_inplace */
553          0,                             /* src_mask */
554          MINUS_ONE,                     /* dst_mask */
555          FALSE),                        /* pcrel_offset */
556
557   /* 16-bit in-place addition, for local label subtraction.  */
558   HOWTO (R_RISCV_SUB16,                 /* type */
559          0,                             /* rightshift */
560          1,                             /* size */
561          16,                            /* bitsize */
562          FALSE,                         /* pc_relative */
563          0,                             /* bitpos */
564          complain_overflow_dont,        /* complain_on_overflow */
565          riscv_elf_add_sub_reloc,       /* special_function */
566          "R_RISCV_SUB16",               /* name */
567          FALSE,                         /* partial_inplace */
568          0,                             /* src_mask */
569          MINUS_ONE,                     /* dst_mask */
570          FALSE),                        /* pcrel_offset */
571
572   /* 32-bit in-place addition, for local label subtraction.  */
573   HOWTO (R_RISCV_SUB32,                 /* type */
574          0,                             /* rightshift */
575          2,                             /* size */
576          32,                            /* bitsize */
577          FALSE,                         /* pc_relative */
578          0,                             /* bitpos */
579          complain_overflow_dont,        /* complain_on_overflow */
580          riscv_elf_add_sub_reloc,       /* special_function */
581          "R_RISCV_SUB32",               /* name */
582          FALSE,                         /* partial_inplace */
583          0,                             /* src_mask */
584          MINUS_ONE,                     /* dst_mask */
585          FALSE),                        /* pcrel_offset */
586
587   /* 64-bit in-place addition, for local label subtraction.  */
588   HOWTO (R_RISCV_SUB64,                 /* type */
589          0,                             /* rightshift */
590          4,                             /* size */
591          64,                            /* bitsize */
592          FALSE,                         /* pc_relative */
593          0,                             /* bitpos */
594          complain_overflow_dont,        /* complain_on_overflow */
595          riscv_elf_add_sub_reloc,       /* special_function */
596          "R_RISCV_SUB64",               /* name */
597          FALSE,                         /* partial_inplace */
598          0,                             /* src_mask */
599          MINUS_ONE,                     /* dst_mask */
600          FALSE),                        /* pcrel_offset */
601
602   /* GNU extension to record C++ vtable hierarchy */
603   HOWTO (R_RISCV_GNU_VTINHERIT,         /* type */
604          0,                             /* rightshift */
605          4,                             /* size */
606          0,                             /* bitsize */
607          FALSE,                         /* pc_relative */
608          0,                             /* bitpos */
609          complain_overflow_dont,        /* complain_on_overflow */
610          NULL,                          /* special_function */
611          "R_RISCV_GNU_VTINHERIT",       /* name */
612          FALSE,                         /* partial_inplace */
613          0,                             /* src_mask */
614          0,                             /* dst_mask */
615          FALSE),                        /* pcrel_offset */
616
617   /* GNU extension to record C++ vtable member usage */
618   HOWTO (R_RISCV_GNU_VTENTRY,           /* type */
619          0,                             /* rightshift */
620          4,                             /* size */
621          0,                             /* bitsize */
622          FALSE,                         /* pc_relative */
623          0,                             /* bitpos */
624          complain_overflow_dont,        /* complain_on_overflow */
625          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
626          "R_RISCV_GNU_VTENTRY",         /* name */
627          FALSE,                         /* partial_inplace */
628          0,                             /* src_mask */
629          0,                             /* dst_mask */
630          FALSE),                        /* pcrel_offset */
631
632   /* Indicates an alignment statement.  The addend field encodes how many
633      bytes of NOPs follow the statement.  The desired alignment is the
634      addend rounded up to the next power of two.  */
635   HOWTO (R_RISCV_ALIGN,                 /* type */
636          0,                             /* rightshift */
637          2,                             /* size */
638          0,                             /* bitsize */
639          FALSE,                         /* pc_relative */
640          0,                             /* bitpos */
641          complain_overflow_dont,        /* complain_on_overflow */
642          bfd_elf_generic_reloc,         /* special_function */
643          "R_RISCV_ALIGN",               /* name */
644          FALSE,                         /* partial_inplace */
645          0,                             /* src_mask */
646          0,                             /* dst_mask */
647          TRUE),                         /* pcrel_offset */
648
649   /* 8-bit PC-relative branch offset.  */
650   HOWTO (R_RISCV_RVC_BRANCH,            /* type */
651          0,                             /* rightshift */
652          2,                             /* size */
653          32,                            /* bitsize */
654          TRUE,                          /* pc_relative */
655          0,                             /* bitpos */
656          complain_overflow_signed,      /* complain_on_overflow */
657          bfd_elf_generic_reloc,         /* special_function */
658          "R_RISCV_RVC_BRANCH",          /* name */
659          FALSE,                         /* partial_inplace */
660          0,                             /* src_mask */
661          ENCODE_RVC_B_IMM (-1U),        /* dst_mask */
662          TRUE),                         /* pcrel_offset */
663
664   /* 11-bit PC-relative jump offset.  */
665   HOWTO (R_RISCV_RVC_JUMP,              /* type */
666          0,                             /* rightshift */
667          2,                             /* size */
668          32,                            /* bitsize */
669          TRUE,                          /* pc_relative */
670          0,                             /* bitpos */
671          complain_overflow_dont,        /* complain_on_overflow */
672          bfd_elf_generic_reloc,         /* special_function */
673          "R_RISCV_RVC_JUMP",            /* name */
674          FALSE,                         /* partial_inplace */
675          0,                             /* src_mask */
676          ENCODE_RVC_J_IMM (-1U),        /* dst_mask */
677          TRUE),                         /* pcrel_offset */
678
679   /* High 6 bits of 18-bit absolute address.  */
680   HOWTO (R_RISCV_RVC_LUI,               /* type */
681          0,                             /* rightshift */
682          2,                             /* size */
683          32,                            /* bitsize */
684          FALSE,                         /* pc_relative */
685          0,                             /* bitpos */
686          complain_overflow_dont,        /* complain_on_overflow */
687          bfd_elf_generic_reloc,         /* special_function */
688          "R_RISCV_RVC_LUI",             /* name */
689          FALSE,                         /* partial_inplace */
690          0,                             /* src_mask */
691          ENCODE_RVC_IMM (-1U),          /* dst_mask */
692          FALSE),                        /* pcrel_offset */
693
694   /* GP-relative load.  */
695   HOWTO (R_RISCV_GPREL_I,               /* type */
696          0,                             /* rightshift */
697          2,                             /* size */
698          32,                            /* bitsize */
699          FALSE,                         /* pc_relative */
700          0,                             /* bitpos */
701          complain_overflow_dont,        /* complain_on_overflow */
702          bfd_elf_generic_reloc,         /* special_function */
703          "R_RISCV_GPREL_I",             /* name */
704          FALSE,                         /* partial_inplace */
705          0,                             /* src_mask */
706          ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
707          FALSE),                        /* pcrel_offset */
708
709   /* GP-relative store.  */
710   HOWTO (R_RISCV_GPREL_S,               /* type */
711          0,                             /* rightshift */
712          2,                             /* size */
713          32,                            /* bitsize */
714          FALSE,                         /* pc_relative */
715          0,                             /* bitpos */
716          complain_overflow_dont,        /* complain_on_overflow */
717          bfd_elf_generic_reloc,         /* special_function */
718          "R_RISCV_GPREL_S",             /* name */
719          FALSE,                         /* partial_inplace */
720          0,                             /* src_mask */
721          ENCODE_STYPE_IMM (-1U),        /* dst_mask */
722          FALSE),                        /* pcrel_offset */
723
724   /* TP-relative TLS LE load.  */
725   HOWTO (R_RISCV_TPREL_I,               /* type */
726          0,                             /* rightshift */
727          2,                             /* size */
728          32,                            /* bitsize */
729          FALSE,                         /* pc_relative */
730          0,                             /* bitpos */
731          complain_overflow_signed,      /* complain_on_overflow */
732          bfd_elf_generic_reloc,         /* special_function */
733          "R_RISCV_TPREL_I",             /* name */
734          FALSE,                         /* partial_inplace */
735          0,                             /* src_mask */
736          ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
737          FALSE),                        /* pcrel_offset */
738
739   /* TP-relative TLS LE store.  */
740   HOWTO (R_RISCV_TPREL_S,               /* type */
741          0,                             /* rightshift */
742          2,                             /* size */
743          32,                            /* bitsize */
744          FALSE,                         /* pc_relative */
745          0,                             /* bitpos */
746          complain_overflow_signed,      /* complain_on_overflow */
747          bfd_elf_generic_reloc,         /* special_function */
748          "R_RISCV_TPREL_S",             /* name */
749          FALSE,                         /* partial_inplace */
750          0,                             /* src_mask */
751          ENCODE_STYPE_IMM (-1U),        /* dst_mask */
752          FALSE),                        /* pcrel_offset */
753
754   /* The paired relocation may be relaxed.  */
755   HOWTO (R_RISCV_RELAX,                 /* type */
756          0,                             /* rightshift */
757          3,                             /* size */
758          0,                             /* bitsize */
759          FALSE,                         /* pc_relative */
760          0,                             /* bitpos */
761          complain_overflow_dont,        /* complain_on_overflow */
762          bfd_elf_generic_reloc,         /* special_function */
763          "R_RISCV_RELAX",               /* name */
764          FALSE,                         /* partial_inplace */
765          0,                             /* src_mask */
766          0,                             /* dst_mask */
767          FALSE),                        /* pcrel_offset */
768
769   /* 6-bit in-place addition, for local label subtraction.  */
770   HOWTO (R_RISCV_SUB6,                  /* type */
771          0,                             /* rightshift */
772          0,                             /* size */
773          8,                             /* bitsize */
774          FALSE,                         /* pc_relative */
775          0,                             /* bitpos */
776          complain_overflow_dont,        /* complain_on_overflow */
777          riscv_elf_add_sub_reloc,       /* special_function */
778          "R_RISCV_SUB6",                /* name */
779          FALSE,                         /* partial_inplace */
780          0,                             /* src_mask */
781          0x3f,                          /* dst_mask */
782          FALSE),                        /* pcrel_offset */
783
784   /* 6-bit in-place setting, for local label subtraction.  */
785   HOWTO (R_RISCV_SET6,                  /* type */
786          0,                             /* rightshift */
787          0,                             /* size */
788          8,                             /* bitsize */
789          FALSE,                         /* pc_relative */
790          0,                             /* bitpos */
791          complain_overflow_dont,        /* complain_on_overflow */
792          bfd_elf_generic_reloc,         /* special_function */
793          "R_RISCV_SET6",                /* name */
794          FALSE,                         /* partial_inplace */
795          0,                             /* src_mask */
796          0x3f,                          /* dst_mask */
797          FALSE),                        /* pcrel_offset */
798
799   /* 8-bit in-place setting, for local label subtraction.  */
800   HOWTO (R_RISCV_SET8,                  /* type */
801          0,                             /* rightshift */
802          0,                             /* size */
803          8,                             /* bitsize */
804          FALSE,                         /* pc_relative */
805          0,                             /* bitpos */
806          complain_overflow_dont,        /* complain_on_overflow */
807          bfd_elf_generic_reloc,         /* special_function */
808          "R_RISCV_SET8",                /* name */
809          FALSE,                         /* partial_inplace */
810          0,                             /* src_mask */
811          MINUS_ONE,                     /* dst_mask */
812          FALSE),                        /* pcrel_offset */
813
814   /* 16-bit in-place setting, for local label subtraction.  */
815   HOWTO (R_RISCV_SET16,                 /* type */
816          0,                             /* rightshift */
817          1,                             /* size */
818          16,                            /* bitsize */
819          FALSE,                         /* pc_relative */
820          0,                             /* bitpos */
821          complain_overflow_dont,        /* complain_on_overflow */
822          bfd_elf_generic_reloc,         /* special_function */
823          "R_RISCV_SET16",               /* name */
824          FALSE,                         /* partial_inplace */
825          0,                             /* src_mask */
826          MINUS_ONE,                     /* dst_mask */
827          FALSE),                        /* pcrel_offset */
828
829   /* 32-bit in-place setting, for local label subtraction.  */
830   HOWTO (R_RISCV_SET32,                 /* type */
831          0,                             /* rightshift */
832          2,                             /* size */
833          32,                            /* bitsize */
834          FALSE,                         /* pc_relative */
835          0,                             /* bitpos */
836          complain_overflow_dont,        /* complain_on_overflow */
837          bfd_elf_generic_reloc,         /* special_function */
838          "R_RISCV_SET32",               /* name */
839          FALSE,                         /* partial_inplace */
840          0,                             /* src_mask */
841          MINUS_ONE,                     /* dst_mask */
842          FALSE),                        /* pcrel_offset */
843
844   /* 32-bit PC relative.  */
845   HOWTO (R_RISCV_32_PCREL,              /* type */
846          0,                             /* rightshift */
847          2,                             /* size */
848          32,                            /* bitsize */
849          TRUE,                          /* pc_relative */
850          0,                             /* bitpos */
851          complain_overflow_dont,        /* complain_on_overflow */
852          bfd_elf_generic_reloc,         /* special_function */
853          "R_RISCV_32_PCREL",            /* name */
854          FALSE,                         /* partial_inplace */
855          0,                             /* src_mask */
856          MINUS_ONE,                     /* dst_mask */
857          FALSE),                        /* pcrel_offset */
858 };
859
860 /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
861
862 struct elf_reloc_map
863 {
864   bfd_reloc_code_real_type bfd_val;
865   enum elf_riscv_reloc_type elf_val;
866 };
867
868 static const struct elf_reloc_map riscv_reloc_map[] =
869 {
870   { BFD_RELOC_NONE, R_RISCV_NONE },
871   { BFD_RELOC_32, R_RISCV_32 },
872   { BFD_RELOC_64, R_RISCV_64 },
873   { BFD_RELOC_RISCV_ADD8, R_RISCV_ADD8 },
874   { BFD_RELOC_RISCV_ADD16, R_RISCV_ADD16 },
875   { BFD_RELOC_RISCV_ADD32, R_RISCV_ADD32 },
876   { BFD_RELOC_RISCV_ADD64, R_RISCV_ADD64 },
877   { BFD_RELOC_RISCV_SUB8, R_RISCV_SUB8 },
878   { BFD_RELOC_RISCV_SUB16, R_RISCV_SUB16 },
879   { BFD_RELOC_RISCV_SUB32, R_RISCV_SUB32 },
880   { BFD_RELOC_RISCV_SUB64, R_RISCV_SUB64 },
881   { BFD_RELOC_CTOR, R_RISCV_64 },
882   { BFD_RELOC_12_PCREL, R_RISCV_BRANCH },
883   { BFD_RELOC_RISCV_HI20, R_RISCV_HI20 },
884   { BFD_RELOC_RISCV_LO12_I, R_RISCV_LO12_I },
885   { BFD_RELOC_RISCV_LO12_S, R_RISCV_LO12_S },
886   { BFD_RELOC_RISCV_PCREL_LO12_I, R_RISCV_PCREL_LO12_I },
887   { BFD_RELOC_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_S },
888   { BFD_RELOC_RISCV_CALL, R_RISCV_CALL },
889   { BFD_RELOC_RISCV_CALL_PLT, R_RISCV_CALL_PLT },
890   { BFD_RELOC_RISCV_PCREL_HI20, R_RISCV_PCREL_HI20 },
891   { BFD_RELOC_RISCV_JMP, R_RISCV_JAL },
892   { BFD_RELOC_RISCV_GOT_HI20, R_RISCV_GOT_HI20 },
893   { BFD_RELOC_RISCV_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 },
894   { BFD_RELOC_RISCV_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 },
895   { BFD_RELOC_RISCV_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 },
896   { BFD_RELOC_RISCV_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 },
897   { BFD_RELOC_RISCV_TLS_TPREL32, R_RISCV_TLS_TPREL32 },
898   { BFD_RELOC_RISCV_TLS_TPREL64, R_RISCV_TLS_TPREL64 },
899   { BFD_RELOC_RISCV_TPREL_HI20, R_RISCV_TPREL_HI20 },
900   { BFD_RELOC_RISCV_TPREL_ADD, R_RISCV_TPREL_ADD },
901   { BFD_RELOC_RISCV_TPREL_LO12_S, R_RISCV_TPREL_LO12_S },
902   { BFD_RELOC_RISCV_TPREL_LO12_I, R_RISCV_TPREL_LO12_I },
903   { BFD_RELOC_RISCV_TLS_GOT_HI20, R_RISCV_TLS_GOT_HI20 },
904   { BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 },
905   { BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN },
906   { BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH },
907   { BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP },
908   { BFD_RELOC_RISCV_RVC_LUI, R_RISCV_RVC_LUI },
909   { BFD_RELOC_RISCV_GPREL_I, R_RISCV_GPREL_I },
910   { BFD_RELOC_RISCV_GPREL_S, R_RISCV_GPREL_S },
911   { BFD_RELOC_RISCV_TPREL_I, R_RISCV_TPREL_I },
912   { BFD_RELOC_RISCV_TPREL_S, R_RISCV_TPREL_S },
913   { BFD_RELOC_RISCV_RELAX, R_RISCV_RELAX },
914   { BFD_RELOC_RISCV_SUB6, R_RISCV_SUB6 },
915   { BFD_RELOC_RISCV_SET6, R_RISCV_SET6 },
916   { BFD_RELOC_RISCV_SET8, R_RISCV_SET8 },
917   { BFD_RELOC_RISCV_SET16, R_RISCV_SET16 },
918   { BFD_RELOC_RISCV_SET32, R_RISCV_SET32 },
919   { BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL },
920 };
921
922 /* Given a BFD reloc type, return a howto structure.  */
923
924 reloc_howto_type *
925 riscv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
926                          bfd_reloc_code_real_type code)
927 {
928   unsigned int i;
929
930   for (i = 0; i < ARRAY_SIZE (riscv_reloc_map); i++)
931     if (riscv_reloc_map[i].bfd_val == code)
932       return &howto_table[(int) riscv_reloc_map[i].elf_val];
933
934   bfd_set_error (bfd_error_bad_value);
935   return NULL;
936 }
937
938 reloc_howto_type *
939 riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
940 {
941   unsigned int i;
942
943   for (i = 0; i < ARRAY_SIZE (howto_table); i++)
944     if (howto_table[i].name && strcasecmp (howto_table[i].name, r_name) == 0)
945       return &howto_table[i];
946
947   return NULL;
948 }
949
950 reloc_howto_type *
951 riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type)
952 {
953   if (r_type >= ARRAY_SIZE (howto_table))
954     {
955       (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"),
956                              abfd, r_type);
957       bfd_set_error (bfd_error_bad_value);
958       return NULL;
959     }
960   return &howto_table[r_type];
961 }
962
963 /* Special_function of RISCV_ADD and RISCV_SUB relocations.  */
964
965 static bfd_reloc_status_type
966 riscv_elf_add_sub_reloc (bfd *abfd,
967                          arelent *reloc_entry,
968                          asymbol *symbol,
969                          void *data,
970                          asection *input_section,
971                          bfd *output_bfd,
972                          char **error_message ATTRIBUTE_UNUSED)
973 {
974   reloc_howto_type *howto = reloc_entry->howto;
975   bfd_vma relocation;
976
977   if (output_bfd != NULL
978       && (symbol->flags & BSF_SECTION_SYM) == 0
979       && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0))
980     {
981       reloc_entry->address += input_section->output_offset;
982       return bfd_reloc_ok;
983     }
984
985   if (output_bfd != NULL)
986     return bfd_reloc_continue;
987
988   relocation = symbol->value + symbol->section->output_section->vma
989     + symbol->section->output_offset + reloc_entry->addend;
990   bfd_vma old_value = bfd_get (howto->bitsize, abfd,
991                                data + reloc_entry->address);
992
993   switch (howto->type)
994     {
995     case R_RISCV_ADD8:
996     case R_RISCV_ADD16:
997     case R_RISCV_ADD32:
998     case R_RISCV_ADD64:
999       relocation = old_value + relocation;
1000       break;
1001     case R_RISCV_SUB6:
1002     case R_RISCV_SUB8:
1003     case R_RISCV_SUB16:
1004     case R_RISCV_SUB32:
1005     case R_RISCV_SUB64:
1006       relocation = old_value - relocation;
1007       break;
1008     }
1009   bfd_put (howto->bitsize, abfd, relocation, data + reloc_entry->address);
1010
1011   return bfd_reloc_ok;
1012 }
1013
1014 /* Parsing subset version.
1015
1016    Return Value:
1017      Points to the end of version
1018
1019    Arguments:
1020      `rps`: Hooks and status for parsing subset.
1021      `march`: Full arch string.
1022      `p`: Curent parsing position.
1023      `major_version`: Parsing result of major version, using
1024       default_major_version if version is not present in arch string.
1025      `minor_version`: Parsing result of minor version, set to 0 if version is
1026      not present in arch string, but set to `default_minor_version` if
1027      `major_version` using default_major_version.
1028      `default_major_version`: Default major version.
1029      `default_minor_version`: Default minor version.
1030      `std_ext_p`: True if parsing std extension.  */
1031
1032 static const char *
1033 riscv_parsing_subset_version (riscv_parse_subset_t *rps,
1034                               const char *march,
1035                               const char *p,
1036                               unsigned *major_version,
1037                               unsigned *minor_version,
1038                               unsigned default_major_version,
1039                               unsigned default_minor_version,
1040                               bfd_boolean std_ext_p)
1041 {
1042   bfd_boolean major_p = TRUE;
1043   unsigned version = 0;
1044   unsigned major = 0;
1045   unsigned minor = 0;
1046   char np;
1047
1048   for (;*p; ++p)
1049     {
1050       if (*p == 'p')
1051         {
1052           np = *(p + 1);
1053
1054           if (!ISDIGIT (np))
1055             {
1056               /* Might be beginning of `p` extension.  */
1057               if (std_ext_p)
1058                 {
1059                   *major_version = version;
1060                   *minor_version = 0;
1061                   return p;
1062                 }
1063               else
1064                 {
1065                   rps->error_handler ("-march=%s: Expect number after `%dp'.",
1066                                       march, version);
1067                   return NULL;
1068                 }
1069             }
1070
1071           major = version;
1072           major_p = FALSE;
1073           version = 0;
1074         }
1075       else if (ISDIGIT (*p))
1076         version = (version * 10) + (*p - '0');
1077       else
1078         break;
1079     }
1080
1081   if (major_p)
1082     major = version;
1083   else
1084     minor = version;
1085
1086   if (major == 0 && minor == 0)
1087     {
1088       /* We don't found any version string, use default version.  */
1089       *major_version = default_major_version;
1090       *minor_version = default_minor_version;
1091     }
1092   else
1093     {
1094       *major_version = major;
1095       *minor_version = minor;
1096     }
1097   return p;
1098 }
1099
1100 /* Return string which contain all supported standard extensions in
1101    canonical order.  */
1102
1103 const char *
1104 riscv_supported_std_ext (void)
1105 {
1106   return "mafdqlcbjtpvn";
1107 }
1108
1109 /* Parsing function for standard extensions.
1110
1111    Return Value:
1112      Points to the end of extensions.
1113
1114    Arguments:
1115      `rps`: Hooks and status for parsing subset.
1116      `march`: Full arch string.
1117      `p`: Curent parsing position.  */
1118
1119 static const char *
1120 riscv_parse_std_ext (riscv_parse_subset_t *rps,
1121                      const char *march, const char *p)
1122 {
1123   const char *all_std_exts = riscv_supported_std_ext ();
1124   const char *std_exts = all_std_exts;
1125
1126   unsigned major_version = 0;
1127   unsigned minor_version = 0;
1128   char std_ext = '\0';
1129
1130   /* First letter must start with i, e or g.  */
1131   switch (*p)
1132     {
1133       case 'i':
1134         p++;
1135         p = riscv_parsing_subset_version (
1136               rps,
1137               march,
1138               p, &major_version, &minor_version,
1139               /* default_major_version= */ 2,
1140               /* default_minor_version= */ 0,
1141               /* std_ext_p= */TRUE);
1142         riscv_add_subset (rps->subset_list, "i", major_version, minor_version);
1143         break;
1144
1145       case 'e':
1146         p++;
1147         p = riscv_parsing_subset_version (
1148               rps,
1149               march,
1150               p, &major_version, &minor_version,
1151               /* default_major_version= */ 1,
1152               /* default_minor_version= */ 9,
1153               /* std_ext_p= */TRUE);
1154
1155         riscv_add_subset (rps->subset_list, "e", major_version, minor_version);
1156         riscv_add_subset (rps->subset_list, "i", 2, 0);
1157
1158         if (*rps->xlen > 32)
1159           {
1160             rps->error_handler ("-march=%s: rv%de is not a valid base ISA",
1161                                 march, *rps->xlen);
1162             return NULL;
1163           }
1164
1165         break;
1166
1167       case 'g':
1168         p++;
1169         p = riscv_parsing_subset_version (
1170               rps,
1171               march,
1172               p, &major_version, &minor_version,
1173               /* default_major_version= */ 2,
1174               /* default_minor_version= */ 0,
1175               /* std_ext_p= */TRUE);
1176         riscv_add_subset (rps->subset_list, "i", major_version, minor_version);
1177
1178         for ( ; *std_exts != 'q'; std_exts++)
1179           {
1180             const char subset[] = {*std_exts, '\0'};
1181             riscv_add_subset (
1182               rps->subset_list, subset, major_version, minor_version);
1183           }
1184         break;
1185
1186       default:
1187         rps->error_handler (
1188           "-march=%s: first ISA subset must be `e', `i' or `g'", march);
1189         return NULL;
1190     }
1191
1192   while (*p)
1193     {
1194       char subset[2] = {0, 0};
1195
1196       if (*p == 'x' || *p == 's')
1197         break;
1198
1199       if (*p == '_')
1200         {
1201           p++;
1202           continue;
1203         }
1204
1205       std_ext = *p;
1206
1207       /* Checking canonical order.  */
1208       while (*std_exts && std_ext != *std_exts) std_exts++;
1209
1210       if (std_ext != *std_exts)
1211         {
1212           if (strchr (all_std_exts, std_ext) == NULL)
1213             rps->error_handler (
1214               "-march=%s: unsupported ISA subset `%c'", march, *p);
1215           else
1216             rps->error_handler (
1217               "-march=%s: ISA string is not in canonical order. `%c'",
1218               march, *p);
1219           return NULL;
1220         }
1221
1222       std_exts++;
1223
1224       p++;
1225       p = riscv_parsing_subset_version (
1226             rps,
1227             march,
1228             p, &major_version, &minor_version,
1229             /* default_major_version= */ 2,
1230             /* default_minor_version= */ 0,
1231             /* std_ext_p= */TRUE);
1232
1233       subset[0] = std_ext;
1234
1235       riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
1236     }
1237   return p;
1238 }
1239
1240 /* Parsing function for non-standard and supervisor extensions.
1241
1242    Return Value:
1243      Points to the end of extensions.
1244
1245    Arguments:
1246      `rps`: Hooks and status for parsing subset.
1247      `march`: Full arch string.
1248      `p`: Curent parsing position.
1249      `ext_type`: What kind of extensions, 'x', 's' or 'sx'.
1250      `ext_type_str`: Full name for kind of extension.  */
1251
1252 static const char *
1253 riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps,
1254                                const char *march,
1255                                const char *p,
1256                                const char *ext_type,
1257                                const char *ext_type_str)
1258 {
1259   unsigned major_version = 0;
1260   unsigned minor_version = 0;
1261   size_t ext_type_len = strlen (ext_type);
1262
1263   while (*p)
1264     {
1265       if (*p == '_')
1266         {
1267           p++;
1268           continue;
1269         }
1270
1271       if (strncmp (p, ext_type, ext_type_len) != 0)
1272         break;
1273
1274       /* It's non-standard supervisor extension if it prefix with sx.  */
1275       if ((ext_type[0] == 's') && (ext_type_len == 1)
1276           && (*(p + 1) == 'x'))
1277         break;
1278
1279       char *subset = xstrdup (p);
1280       char *q = subset;
1281       const char *end_of_version;
1282
1283       while (*++q != '\0' && *q != '_' && !ISDIGIT (*q))
1284         ;
1285
1286       end_of_version =
1287         riscv_parsing_subset_version (
1288           rps,
1289           march,
1290           q, &major_version, &minor_version,
1291           /* default_major_version= */ 2,
1292           /* default_minor_version= */ 0,
1293           /* std_ext_p= */FALSE);
1294
1295       *q = '\0';
1296
1297       riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
1298       free (subset);
1299       p += end_of_version - subset;
1300
1301       if (*p != '\0' && *p != '_')
1302         {
1303           rps->error_handler ("-march=%s: %s must seperate with _",
1304                               march, ext_type_str);
1305           return NULL;
1306         }
1307     }
1308
1309   return p;
1310 }
1311
1312 /* Function for parsing arch string.
1313
1314    Return Value:
1315      Return TRUE on success.
1316
1317    Arguments:
1318      `rps`: Hooks and status for parsing subset.
1319      `arch`: Arch string.  */
1320
1321 bfd_boolean
1322 riscv_parse_subset (riscv_parse_subset_t *rps,
1323                     const char *arch)
1324 {
1325   const char *p = arch;
1326
1327   if (strncmp (p, "rv32", 4) == 0)
1328     {
1329       *rps->xlen = 32;
1330       p += 4;
1331     }
1332   else if (strncmp (p, "rv64", 4) == 0)
1333     {
1334       *rps->xlen = 64;
1335       p += 4;
1336     }
1337   else
1338     {
1339       rps->error_handler ("-march=%s: ISA string must begin with rv32 or rv64",
1340                           arch);
1341       return FALSE;
1342     }
1343
1344   /* Parsing standard extension.  */
1345   p = riscv_parse_std_ext (rps, arch, p);
1346
1347   if (p == NULL)
1348     return FALSE;
1349
1350   /* Parsing non-standard extension.  */
1351   p = riscv_parse_sv_or_non_std_ext (
1352         rps, arch, p, "x", "non-standard extension");
1353
1354   if (p == NULL)
1355     return FALSE;
1356
1357   /* Parsing supervisor extension.  */
1358   p = riscv_parse_sv_or_non_std_ext (
1359         rps, arch, p, "s", "supervisor extension");
1360
1361   if (p == NULL)
1362     return FALSE;
1363
1364   /* Parsing non-standard supervisor extension.  */
1365   p = riscv_parse_sv_or_non_std_ext (
1366         rps, arch, p, "sx", "non-standard supervisor extension");
1367
1368   if (p == NULL)
1369     return FALSE;
1370
1371   if (*p != '\0')
1372     {
1373       rps->error_handler ("-march=%s: unexpected ISA string at end: %s",
1374                           arch, p);
1375       return FALSE;
1376     }
1377
1378   if (riscv_lookup_subset (rps->subset_list, "e")
1379       && riscv_lookup_subset (rps->subset_list, "f"))
1380     {
1381       rps->error_handler ("-march=%s: rv32e does not support the `f' extension",
1382                           arch);
1383       return FALSE;
1384     }
1385
1386   if (riscv_lookup_subset (rps->subset_list, "d")
1387       && !riscv_lookup_subset (rps->subset_list, "f"))
1388     {
1389       rps->error_handler ("-march=%s: `d' extension requires `f' extension",
1390                           arch);
1391       return FALSE;
1392     }
1393
1394   if (riscv_lookup_subset (rps->subset_list, "q")
1395       && !riscv_lookup_subset (rps->subset_list, "d"))
1396     {
1397       rps->error_handler ("-march=%s: `q' extension requires `d' extension",
1398                           arch);
1399       return FALSE;
1400     }
1401
1402   if (riscv_lookup_subset (rps->subset_list, "q") && *rps->xlen < 64)
1403     {
1404       rps->error_handler ("-march=%s: rv32 does not support the `q' extension",
1405                           arch);
1406       return FALSE;
1407     }
1408   return TRUE;
1409 }
1410
1411 /* Add new subset to list.  */
1412
1413 void
1414 riscv_add_subset (riscv_subset_list_t *subset_list,
1415                   const char *subset,
1416                   int major, int minor)
1417 {
1418   riscv_subset_t *s = xmalloc (sizeof *s);
1419
1420   if (subset_list->head == NULL)
1421     subset_list->head = s;
1422
1423   s->name = xstrdup (subset);
1424   s->major_version = major;
1425   s->minor_version = minor;
1426   s->next = NULL;
1427
1428   if (subset_list->tail != NULL)
1429     subset_list->tail->next = s;
1430
1431   subset_list->tail = s;
1432 }
1433
1434 /* Find subset in list without version checking, return NULL if not found.  */
1435
1436 riscv_subset_t *
1437 riscv_lookup_subset (const riscv_subset_list_t *subset_list,
1438                      const char *subset)
1439 {
1440   return riscv_lookup_subset_version (
1441            subset_list, subset,
1442            RISCV_DONT_CARE_VERSION,
1443            RISCV_DONT_CARE_VERSION);
1444 }
1445
1446 /* Find subset in list with version checking, return NULL if not found.  */
1447
1448 riscv_subset_t *
1449 riscv_lookup_subset_version (const riscv_subset_list_t *subset_list,
1450                              const char *subset,
1451                              int major, int minor)
1452 {
1453   riscv_subset_t *s;
1454
1455   for (s = subset_list->head; s != NULL; s = s->next)
1456     if (strcasecmp (s->name, subset) == 0)
1457       {
1458         if ((major != RISCV_DONT_CARE_VERSION)
1459             && (s->major_version != major))
1460           return NULL;
1461
1462         if ((minor != RISCV_DONT_CARE_VERSION)
1463             && (s->minor_version != minor))
1464           return NULL;
1465
1466         return s;
1467       }
1468
1469   return NULL;
1470 }
1471
1472 /* Release subset list.  */
1473
1474 void
1475 riscv_release_subset_list (riscv_subset_list_t *subset_list)
1476 {
1477    while (subset_list->head != NULL)
1478     {
1479       riscv_subset_t *next = subset_list->head->next;
1480       free ((void *)subset_list->head->name);
1481       free (subset_list->head);
1482       subset_list->head = next;
1483     }
1484
1485   subset_list->tail = NULL;
1486 }
1487
1488 /* Return the number of digits for the input.  */
1489
1490 static size_t
1491 riscv_estimate_digit (unsigned num)
1492 {
1493   size_t digit = 0;
1494   if (num == 0)
1495     return 1;
1496
1497   for (digit = 0; num ; num /= 10)
1498     digit++;
1499
1500   return digit;
1501 }
1502
1503 /* Auxiliary function to estimate string length of subset list.  */
1504
1505 static size_t
1506 riscv_estimate_arch_strlen1 (const riscv_subset_t *subset)
1507 {
1508   if (subset == NULL)
1509     return 6; /* For rv32/rv64/rv128 and string terminator.  */
1510
1511   return riscv_estimate_arch_strlen1 (subset->next)
1512          + strlen (subset->name)
1513          + riscv_estimate_digit (subset->major_version)
1514          + 1 /* For version seperator: 'p'.  */
1515          + riscv_estimate_digit (subset->minor_version)
1516          + 1 /* For underscore.  */;
1517 }
1518
1519 /* Estimate the string length of this subset list.  */
1520
1521 static size_t
1522 riscv_estimate_arch_strlen (const riscv_subset_list_t *subset_list)
1523 {
1524   return riscv_estimate_arch_strlen1 (subset_list->head);
1525 }
1526
1527 /* Auxiliary function to convert subset info to string.  */
1528
1529 static void
1530 riscv_arch_str1 (riscv_subset_t *subset,
1531                  char *attr_str, char *buf, size_t bufsz)
1532 {
1533   const char *underline = "_";
1534
1535   if (subset == NULL)
1536     return;
1537
1538   /* No underline between rvXX and i/e.   */
1539   if ((strcasecmp (subset->name, "i") == 0)
1540       || (strcasecmp (subset->name, "e") == 0))
1541     underline = "";
1542
1543   snprintf (buf, bufsz, "%s%s%dp%d",
1544             underline,
1545             subset->name,
1546             subset->major_version,
1547             subset->minor_version);
1548
1549   strncat (attr_str, buf, bufsz);
1550
1551   /* Skip 'i' extension after 'e'.  */
1552   if ((strcasecmp (subset->name, "e") == 0)
1553       && subset->next
1554       && (strcasecmp (subset->next->name, "i") == 0))
1555     riscv_arch_str1 (subset->next->next, attr_str, buf, bufsz);
1556   else
1557     riscv_arch_str1 (subset->next, attr_str, buf, bufsz);
1558 }
1559
1560 /* Convert subset info to string with explicit version info.  */
1561
1562 char *
1563 riscv_arch_str (unsigned xlen, const riscv_subset_list_t *subset)
1564 {
1565   size_t arch_str_len = riscv_estimate_arch_strlen (subset);
1566   char *attr_str = xmalloc (arch_str_len);
1567   char *buf = xmalloc (arch_str_len);
1568
1569   snprintf (attr_str, arch_str_len, "rv%u", xlen);
1570
1571   riscv_arch_str1 (subset->head, attr_str, buf, arch_str_len);
1572   free (buf);
1573
1574   return attr_str;
1575 }