xref: /netbsd-src/external/gpl3/gdb.old/dist/bfd/elfxx-riscv.c (revision 2718af68c3efc72c9769069b5c7f9ed36f6b9def)
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 }
1576