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