readelf: Support RELR in -S and -d and output
[binutils-gdb.git] / bfd / elfxx-riscv.c
blob65bb1cab756daaa81b0cbac9f8bba70a039a0555
1 /* RISC-V-specific support for ELF.
2 Copyright (C) 2011-2021 Free Software Foundation, Inc.
4 Contributed by Andrew Waterman (andrew@sifive.com).
5 Based on TILE-Gx and MIPS targets.
7 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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/>. */
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"
33 #define MINUS_ONE ((bfd_vma)0 - 1)
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 **);
42 /* The relocation table used for SHT_RELA sections. */
44 static reloc_howto_type howto_table[] =
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 */
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 0xffffffff, /* dst_mask */
74 false), /* pcrel_offset */
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 */
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 0xffffffff, /* dst_mask */
104 false), /* pcrel_offset */
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 */
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 */
134 /* Dynamic TLS relocations. */
135 HOWTO (R_RISCV_TLS_DTPMOD32, /* type */
136 0, /* rightshift */
137 2, /* 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 0xffffffff, /* dst_mask */
147 false), /* pcrel_offset */
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 */
163 HOWTO (R_RISCV_TLS_DTPREL32, /* type */
164 0, /* rightshift */
165 2, /* 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 0xffffffff, /* dst_mask */
175 false), /* pcrel_offset */
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 */
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 0xffffffff, /* dst_mask */
203 false), /* pcrel_offset */
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 */
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),
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_BTYPE_IMM (-1U), /* dst_mask */
238 true), /* pcrel_offset */
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_JTYPE_IMM (-1U), /* dst_mask */
253 true), /* pcrel_offset */
255 /* 32-bit PC-relative function call (AUIPC/JALR). */
256 HOWTO (R_RISCV_CALL, /* type */
257 0, /* rightshift */
258 4, /* 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 */
271 /* Like R_RISCV_CALL, but not locally binding. */
272 HOWTO (R_RISCV_CALL_PLT, /* type */
273 0, /* rightshift */
274 4, /* 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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
467 /* TLS LE thread pointer usage. May be relaxed. */
468 HOWTO (R_RISCV_TPREL_ADD, /* type */
469 0, /* rightshift */
470 3, /* size */
471 0, /* 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 false, /* partial_inplace */
478 0, /* src_mask */
479 0, /* dst_mask */
480 false), /* pcrel_offset */
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 0xff, /* dst_mask */
495 false), /* pcrel_offset */
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 0xffff, /* dst_mask */
510 false), /* pcrel_offset */
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 0xffffffff, /* dst_mask */
525 false), /* pcrel_offset */
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 */
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 0xff, /* dst_mask */
555 false), /* pcrel_offset */
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 0xffff, /* dst_mask */
570 false), /* pcrel_offset */
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 0xffffffff, /* dst_mask */
585 false), /* pcrel_offset */
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 */
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 */
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 */
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 3, /* 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 false), /* pcrel_offset */
649 /* 8-bit PC-relative branch offset. */
650 HOWTO (R_RISCV_RVC_BRANCH, /* type */
651 0, /* rightshift */
652 1, /* size */
653 16, /* 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_CBTYPE_IMM (-1U), /* dst_mask */
662 true), /* pcrel_offset */
664 /* 11-bit PC-relative jump offset. */
665 HOWTO (R_RISCV_RVC_JUMP, /* type */
666 0, /* rightshift */
667 1, /* size */
668 16, /* 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_CJTYPE_IMM (-1U), /* dst_mask */
677 true), /* pcrel_offset */
679 /* High 6 bits of 18-bit absolute address. */
680 HOWTO (R_RISCV_RVC_LUI, /* type */
681 0, /* rightshift */
682 1, /* size */
683 16, /* 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_CITYPE_IMM (-1U), /* dst_mask */
692 false), /* pcrel_offset */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 0xff, /* dst_mask */
812 false), /* pcrel_offset */
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 0xffff, /* dst_mask */
827 false), /* pcrel_offset */
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 0xffffffff, /* dst_mask */
842 false), /* pcrel_offset */
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 0xffffffff, /* dst_mask */
857 false), /* pcrel_offset */
859 /* Relocation against a local ifunc symbol in a shared object. */
860 HOWTO (R_RISCV_IRELATIVE, /* type */
861 0, /* rightshift */
862 2, /* size */
863 32, /* bitsize */
864 false, /* pc_relative */
865 0, /* bitpos */
866 complain_overflow_dont, /* complain_on_overflow */
867 bfd_elf_generic_reloc, /* special_function */
868 "R_RISCV_IRELATIVE", /* name */
869 false, /* partial_inplace */
870 0, /* src_mask */
871 0xffffffff, /* dst_mask */
872 false), /* pcrel_offset */
875 /* A mapping from BFD reloc types to RISC-V ELF reloc types. */
876 struct elf_reloc_map
878 bfd_reloc_code_real_type bfd_val;
879 enum elf_riscv_reloc_type elf_val;
882 static const struct elf_reloc_map riscv_reloc_map[] =
884 { BFD_RELOC_NONE, R_RISCV_NONE },
885 { BFD_RELOC_32, R_RISCV_32 },
886 { BFD_RELOC_64, R_RISCV_64 },
887 { BFD_RELOC_RISCV_ADD8, R_RISCV_ADD8 },
888 { BFD_RELOC_RISCV_ADD16, R_RISCV_ADD16 },
889 { BFD_RELOC_RISCV_ADD32, R_RISCV_ADD32 },
890 { BFD_RELOC_RISCV_ADD64, R_RISCV_ADD64 },
891 { BFD_RELOC_RISCV_SUB8, R_RISCV_SUB8 },
892 { BFD_RELOC_RISCV_SUB16, R_RISCV_SUB16 },
893 { BFD_RELOC_RISCV_SUB32, R_RISCV_SUB32 },
894 { BFD_RELOC_RISCV_SUB64, R_RISCV_SUB64 },
895 { BFD_RELOC_CTOR, R_RISCV_64 },
896 { BFD_RELOC_12_PCREL, R_RISCV_BRANCH },
897 { BFD_RELOC_RISCV_HI20, R_RISCV_HI20 },
898 { BFD_RELOC_RISCV_LO12_I, R_RISCV_LO12_I },
899 { BFD_RELOC_RISCV_LO12_S, R_RISCV_LO12_S },
900 { BFD_RELOC_RISCV_PCREL_LO12_I, R_RISCV_PCREL_LO12_I },
901 { BFD_RELOC_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_S },
902 { BFD_RELOC_RISCV_CALL, R_RISCV_CALL },
903 { BFD_RELOC_RISCV_CALL_PLT, R_RISCV_CALL_PLT },
904 { BFD_RELOC_RISCV_PCREL_HI20, R_RISCV_PCREL_HI20 },
905 { BFD_RELOC_RISCV_JMP, R_RISCV_JAL },
906 { BFD_RELOC_RISCV_GOT_HI20, R_RISCV_GOT_HI20 },
907 { BFD_RELOC_RISCV_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 },
908 { BFD_RELOC_RISCV_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 },
909 { BFD_RELOC_RISCV_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 },
910 { BFD_RELOC_RISCV_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 },
911 { BFD_RELOC_RISCV_TLS_TPREL32, R_RISCV_TLS_TPREL32 },
912 { BFD_RELOC_RISCV_TLS_TPREL64, R_RISCV_TLS_TPREL64 },
913 { BFD_RELOC_RISCV_TPREL_HI20, R_RISCV_TPREL_HI20 },
914 { BFD_RELOC_RISCV_TPREL_ADD, R_RISCV_TPREL_ADD },
915 { BFD_RELOC_RISCV_TPREL_LO12_S, R_RISCV_TPREL_LO12_S },
916 { BFD_RELOC_RISCV_TPREL_LO12_I, R_RISCV_TPREL_LO12_I },
917 { BFD_RELOC_RISCV_TLS_GOT_HI20, R_RISCV_TLS_GOT_HI20 },
918 { BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 },
919 { BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN },
920 { BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH },
921 { BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP },
922 { BFD_RELOC_RISCV_RVC_LUI, R_RISCV_RVC_LUI },
923 { BFD_RELOC_RISCV_GPREL_I, R_RISCV_GPREL_I },
924 { BFD_RELOC_RISCV_GPREL_S, R_RISCV_GPREL_S },
925 { BFD_RELOC_RISCV_TPREL_I, R_RISCV_TPREL_I },
926 { BFD_RELOC_RISCV_TPREL_S, R_RISCV_TPREL_S },
927 { BFD_RELOC_RISCV_RELAX, R_RISCV_RELAX },
928 { BFD_RELOC_RISCV_SUB6, R_RISCV_SUB6 },
929 { BFD_RELOC_RISCV_SET6, R_RISCV_SET6 },
930 { BFD_RELOC_RISCV_SET8, R_RISCV_SET8 },
931 { BFD_RELOC_RISCV_SET16, R_RISCV_SET16 },
932 { BFD_RELOC_RISCV_SET32, R_RISCV_SET32 },
933 { BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL },
936 /* Given a BFD reloc type, return a howto structure. */
938 reloc_howto_type *
939 riscv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
940 bfd_reloc_code_real_type code)
942 unsigned int i;
944 for (i = 0; i < ARRAY_SIZE (riscv_reloc_map); i++)
945 if (riscv_reloc_map[i].bfd_val == code)
946 return &howto_table[(int) riscv_reloc_map[i].elf_val];
948 bfd_set_error (bfd_error_bad_value);
949 return NULL;
952 reloc_howto_type *
953 riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
955 unsigned int i;
957 for (i = 0; i < ARRAY_SIZE (howto_table); i++)
958 if (howto_table[i].name && strcasecmp (howto_table[i].name, r_name) == 0)
959 return &howto_table[i];
961 return NULL;
964 reloc_howto_type *
965 riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type)
967 if (r_type >= ARRAY_SIZE (howto_table))
969 (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"),
970 abfd, r_type);
971 bfd_set_error (bfd_error_bad_value);
972 return NULL;
974 return &howto_table[r_type];
977 /* Special_function of RISCV_ADD and RISCV_SUB relocations. */
979 static bfd_reloc_status_type
980 riscv_elf_add_sub_reloc (bfd *abfd,
981 arelent *reloc_entry,
982 asymbol *symbol,
983 void *data,
984 asection *input_section,
985 bfd *output_bfd,
986 char **error_message ATTRIBUTE_UNUSED)
988 reloc_howto_type *howto = reloc_entry->howto;
989 bfd_vma relocation;
991 if (output_bfd != NULL
992 && (symbol->flags & BSF_SECTION_SYM) == 0
993 && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0))
995 reloc_entry->address += input_section->output_offset;
996 return bfd_reloc_ok;
999 if (output_bfd != NULL)
1000 return bfd_reloc_continue;
1002 relocation = symbol->value + symbol->section->output_section->vma
1003 + symbol->section->output_offset + reloc_entry->addend;
1005 bfd_size_type octets = reloc_entry->address
1006 * bfd_octets_per_byte (abfd, input_section);
1007 if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
1008 input_section, octets))
1009 return bfd_reloc_outofrange;
1011 bfd_vma old_value = bfd_get (howto->bitsize, abfd,
1012 data + reloc_entry->address);
1014 switch (howto->type)
1016 case R_RISCV_ADD8:
1017 case R_RISCV_ADD16:
1018 case R_RISCV_ADD32:
1019 case R_RISCV_ADD64:
1020 relocation = old_value + relocation;
1021 break;
1022 case R_RISCV_SUB6:
1023 case R_RISCV_SUB8:
1024 case R_RISCV_SUB16:
1025 case R_RISCV_SUB32:
1026 case R_RISCV_SUB64:
1027 relocation = old_value - relocation;
1028 break;
1030 bfd_put (howto->bitsize, abfd, relocation, data + reloc_entry->address);
1032 return bfd_reloc_ok;
1035 /* Always add the IMPLICIT for the SUBSET. */
1037 static bool
1038 check_implicit_always (const char *implicit ATTRIBUTE_UNUSED,
1039 riscv_subset_t *subset ATTRIBUTE_UNUSED)
1041 return true;
1044 /* Add the IMPLICIT only when the version of SUBSET less than 2.1. */
1046 static bool
1047 check_implicit_for_i (const char *implicit ATTRIBUTE_UNUSED,
1048 riscv_subset_t *subset)
1050 return (subset->major_version < 2
1051 || (subset->major_version == 2
1052 && subset->minor_version < 1));
1055 /* Record all implicit information for the subsets. */
1056 struct riscv_implicit_subset
1058 const char *subset_name;
1059 const char *implicit_name;
1060 /* A function to determine if we need to add the implicit subset. */
1061 bool (*check_func) (const char *, riscv_subset_t *);
1063 static struct riscv_implicit_subset riscv_implicit_subsets[] =
1065 {"e", "i", check_implicit_always},
1066 {"i", "zicsr", check_implicit_for_i},
1067 {"i", "zifencei", check_implicit_for_i},
1068 {"g", "i", check_implicit_always},
1069 {"g", "m", check_implicit_always},
1070 {"g", "a", check_implicit_always},
1071 {"g", "f", check_implicit_always},
1072 {"g", "d", check_implicit_always},
1073 {"g", "zicsr", check_implicit_always},
1074 {"g", "zifencei", check_implicit_always},
1075 {"q", "d", check_implicit_always},
1076 {"d", "f", check_implicit_always},
1077 {"f", "zicsr", check_implicit_always},
1078 {NULL, NULL, NULL}
1081 /* For default_enable field, decide if the extension should
1082 be enbaled by default. */
1084 #define EXT_DEFAULT 0x1
1086 /* List all extensions that binutils should know about. */
1088 struct riscv_supported_ext
1090 const char *name;
1091 enum riscv_spec_class isa_spec_class;
1092 int major_version;
1093 int minor_version;
1094 unsigned long default_enable;
1097 /* The standard extensions must be added in canonical order. */
1099 static struct riscv_supported_ext riscv_supported_std_ext[] =
1101 {"e", ISA_SPEC_CLASS_20191213, 1, 9, 0 },
1102 {"e", ISA_SPEC_CLASS_20190608, 1, 9, 0 },
1103 {"e", ISA_SPEC_CLASS_2P2, 1, 9, 0 },
1104 {"i", ISA_SPEC_CLASS_20191213, 2, 1, 0 },
1105 {"i", ISA_SPEC_CLASS_20190608, 2, 1, 0 },
1106 {"i", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
1107 /* The g is a special case which we don't want to output it,
1108 but still need it when adding implicit extensions. */
1109 {"g", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, EXT_DEFAULT },
1110 {"m", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
1111 {"m", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
1112 {"m", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
1113 {"a", ISA_SPEC_CLASS_20191213, 2, 1, 0 },
1114 {"a", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
1115 {"a", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
1116 {"f", ISA_SPEC_CLASS_20191213, 2, 2, 0 },
1117 {"f", ISA_SPEC_CLASS_20190608, 2, 2, 0 },
1118 {"f", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
1119 {"d", ISA_SPEC_CLASS_20191213, 2, 2, 0 },
1120 {"d", ISA_SPEC_CLASS_20190608, 2, 2, 0 },
1121 {"d", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
1122 {"q", ISA_SPEC_CLASS_20191213, 2, 2, 0 },
1123 {"q", ISA_SPEC_CLASS_20190608, 2, 2, 0 },
1124 {"q", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
1125 {"l", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
1126 {"c", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
1127 {"c", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
1128 {"c", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
1129 {"b", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
1130 {"j", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
1131 {"t", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
1132 {"p", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
1133 {"v", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
1134 {"n", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
1135 {NULL, 0, 0, 0, 0}
1138 static struct riscv_supported_ext riscv_supported_std_z_ext[] =
1140 {"zicsr", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
1141 {"zicsr", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
1142 {"zifencei", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
1143 {"zifencei", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
1144 {"zihintpause", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
1145 {"zbb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
1146 {"zba", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
1147 {"zbc", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
1148 {"zbs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
1149 {NULL, 0, 0, 0, 0}
1152 static struct riscv_supported_ext riscv_supported_std_s_ext[] =
1154 {NULL, 0, 0, 0, 0}
1157 static struct riscv_supported_ext riscv_supported_std_h_ext[] =
1159 {NULL, 0, 0, 0, 0}
1162 static struct riscv_supported_ext riscv_supported_std_zxm_ext[] =
1164 {NULL, 0, 0, 0, 0}
1167 const struct riscv_supported_ext *riscv_all_supported_ext[] =
1169 riscv_supported_std_ext,
1170 riscv_supported_std_z_ext,
1171 riscv_supported_std_s_ext,
1172 riscv_supported_std_h_ext,
1173 riscv_supported_std_zxm_ext,
1174 NULL
1177 /* ISA extension prefixed name class. Must define them in parsing order. */
1178 enum riscv_prefix_ext_class
1180 RV_ISA_CLASS_Z = 1,
1181 RV_ISA_CLASS_S,
1182 RV_ISA_CLASS_H,
1183 RV_ISA_CLASS_ZXM,
1184 RV_ISA_CLASS_X,
1185 RV_ISA_CLASS_UNKNOWN
1188 /* Record the strings of the prefixed extensions, and their corresponding
1189 classes. The more letters of the prefix string, the more forward it must
1190 be defined. Otherwise, the riscv_get_prefix_class will map it to the
1191 wrong classes. */
1192 struct riscv_parse_prefix_config
1194 /* Class of the extension. */
1195 enum riscv_prefix_ext_class class;
1197 /* Prefix string for error printing and internal parser usage. */
1198 const char *prefix;
1200 static const struct riscv_parse_prefix_config parse_config[] =
1202 {RV_ISA_CLASS_ZXM, "zxm"},
1203 {RV_ISA_CLASS_Z, "z"},
1204 {RV_ISA_CLASS_S, "s"},
1205 {RV_ISA_CLASS_H, "h"},
1206 {RV_ISA_CLASS_X, "x"},
1207 {RV_ISA_CLASS_UNKNOWN, NULL}
1210 /* Get the prefixed name class for the extensions, the class also
1211 means the order of the prefixed extensions. */
1213 static enum riscv_prefix_ext_class
1214 riscv_get_prefix_class (const char *arch)
1216 int i = 0;
1217 while (parse_config[i].class != RV_ISA_CLASS_UNKNOWN)
1219 if (strncmp (arch, parse_config[i].prefix,
1220 strlen (parse_config[i].prefix)) == 0)
1221 return parse_config[i].class;
1222 i++;
1224 return RV_ISA_CLASS_UNKNOWN;
1227 /* Check KNOWN_EXTS to see if the EXT is supported. */
1229 static bool
1230 riscv_known_prefixed_ext (const char *ext,
1231 struct riscv_supported_ext *known_exts)
1233 size_t i;
1234 for (i = 0; known_exts[i].name != NULL; ++i)
1235 if (strcmp (ext, known_exts[i].name) == 0)
1236 return true;
1237 return false;
1240 /* Check whether the prefixed extension is recognized or not. Return
1241 true if recognized, otehrwise return false. */
1243 static bool
1244 riscv_recognized_prefixed_ext (const char *ext)
1246 enum riscv_prefix_ext_class class = riscv_get_prefix_class (ext);
1247 switch (class)
1249 case RV_ISA_CLASS_Z:
1250 return riscv_known_prefixed_ext (ext, riscv_supported_std_z_ext);
1251 case RV_ISA_CLASS_ZXM:
1252 return riscv_known_prefixed_ext (ext, riscv_supported_std_zxm_ext);
1253 case RV_ISA_CLASS_S:
1254 return riscv_known_prefixed_ext (ext, riscv_supported_std_s_ext);
1255 case RV_ISA_CLASS_H:
1256 return riscv_known_prefixed_ext (ext, riscv_supported_std_h_ext);
1257 case RV_ISA_CLASS_X:
1258 /* Only the single x is unrecognized. */
1259 if (strcmp (ext, "x") != 0)
1260 return true;
1261 default:
1262 break;
1264 return false;
1267 /* Array is used to compare the orders of standard extensions quickly. */
1268 static int riscv_ext_order[26] = {0};
1270 /* Init the riscv_ext_order array. */
1272 static void
1273 riscv_init_ext_order (void)
1275 static bool inited = false;
1276 if (inited)
1277 return;
1279 /* The orders of all standard extensions are positive. */
1280 int order = 1;
1282 int i = 0;
1283 while (riscv_supported_std_ext[i].name != NULL)
1285 const char *ext = riscv_supported_std_ext[i].name;
1286 riscv_ext_order[(*ext - 'a')] = order++;
1287 i++;
1288 while (riscv_supported_std_ext[i].name
1289 && strcmp (ext, riscv_supported_std_ext[i].name) == 0)
1290 i++;
1293 /* Some of the prefixed keyword are not single letter, so we set
1294 their prefixed orders in the riscv_compare_subsets directly,
1295 not through the riscv_ext_order. */
1297 inited = true;
1300 /* Similar to the strcmp. It returns an integer less than, equal to,
1301 or greater than zero if `subset2` is found, respectively, to be less
1302 than, to match, or be greater than `subset1`.
1304 The order values,
1305 Zero: Preserved keywords.
1306 Positive number: Standard extensions.
1307 Negative number: Prefixed keywords. */
1310 riscv_compare_subsets (const char *subset1, const char *subset2)
1312 int order1 = riscv_ext_order[(*subset1 - 'a')];
1313 int order2 = riscv_ext_order[(*subset2 - 'a')];
1315 /* Compare the standard extension first. */
1316 if (order1 > 0 && order2 > 0)
1317 return order1 - order2;
1319 /* Set the prefixed orders to negative numbers. */
1320 enum riscv_prefix_ext_class class1 = riscv_get_prefix_class (subset1);
1321 enum riscv_prefix_ext_class class2 = riscv_get_prefix_class (subset2);
1323 if (class1 != RV_ISA_CLASS_UNKNOWN)
1324 order1 = - (int) class1;
1325 if (class2 != RV_ISA_CLASS_UNKNOWN)
1326 order2 = - (int) class2;
1328 if (order1 == order2)
1330 /* Compare the standard addition z extensions. */
1331 if (class1 == RV_ISA_CLASS_Z)
1333 order1 = riscv_ext_order[(*++subset1 - 'a')];
1334 order2 = riscv_ext_order[(*++subset2 - 'a')];
1335 if (order1 != order2)
1336 return order1 - order2;
1338 return strcasecmp (++subset1, ++subset2);
1341 return order2 - order1;
1344 /* Find subset in the list. Return TRUE and set `current` to the subset
1345 if it is found. Otherwise, return FALSE and set `current` to the place
1346 where we should insert the subset. However, return FALSE with the NULL
1347 `current` means we should insert the subset at the head of subset list,
1348 if needed. */
1350 bool
1351 riscv_lookup_subset (const riscv_subset_list_t *subset_list,
1352 const char *subset,
1353 riscv_subset_t **current)
1355 riscv_subset_t *s, *pre_s = NULL;
1357 /* If the subset is added in order, then just add it at the tail. */
1358 if (subset_list->tail != NULL
1359 && riscv_compare_subsets (subset_list->tail->name, subset) < 0)
1361 *current = subset_list->tail;
1362 return false;
1365 for (s = subset_list->head;
1366 s != NULL;
1367 pre_s = s, s = s->next)
1369 int cmp = riscv_compare_subsets (s->name, subset);
1370 if (cmp == 0)
1372 *current = s;
1373 return true;
1375 else if (cmp > 0)
1376 break;
1378 *current = pre_s;
1380 return false;
1383 /* Add the extension to the subset list. Search the
1384 list first, and then find the right place to add. */
1386 void
1387 riscv_add_subset (riscv_subset_list_t *subset_list,
1388 const char *subset,
1389 int major,
1390 int minor)
1392 riscv_subset_t *current, *new;
1394 if (riscv_lookup_subset (subset_list, subset, &current))
1395 return;
1397 new = xmalloc (sizeof *new);
1398 new->name = xstrdup (subset);
1399 new->major_version = major;
1400 new->minor_version = minor;
1401 new->next = NULL;
1403 if (current != NULL)
1405 new->next = current->next;
1406 current->next = new;
1408 else
1410 new->next = subset_list->head;
1411 subset_list->head = new;
1414 if (new->next == NULL)
1415 subset_list->tail = new;
1418 /* Get the default versions from the riscv_supported_*ext tables. */
1420 static void
1421 riscv_get_default_ext_version (enum riscv_spec_class default_isa_spec,
1422 const char *name,
1423 int *major_version,
1424 int *minor_version)
1426 if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)
1427 return;
1429 struct riscv_supported_ext *table = NULL;
1430 enum riscv_prefix_ext_class class = riscv_get_prefix_class (name);
1431 switch (class)
1433 case RV_ISA_CLASS_ZXM: table = riscv_supported_std_zxm_ext; break;
1434 case RV_ISA_CLASS_Z: table = riscv_supported_std_z_ext; break;
1435 case RV_ISA_CLASS_S: table = riscv_supported_std_s_ext; break;
1436 case RV_ISA_CLASS_H: table = riscv_supported_std_h_ext; break;
1437 case RV_ISA_CLASS_X:
1438 break;
1439 default:
1440 table = riscv_supported_std_ext;
1443 int i = 0;
1444 while (table != NULL && table[i].name != NULL)
1446 if (strcmp (table[i].name, name) == 0
1447 && (table[i].isa_spec_class == ISA_SPEC_CLASS_DRAFT
1448 || table[i].isa_spec_class == default_isa_spec))
1450 *major_version = table[i].major_version;
1451 *minor_version = table[i].minor_version;
1452 return;
1454 i++;
1458 /* Find the default versions for the extension before adding them to
1459 the subset list, if their versions are RISCV_UNKNOWN_VERSION.
1460 Afterwards, report errors if we can not find their default versions. */
1462 static void
1463 riscv_parse_add_subset (riscv_parse_subset_t *rps,
1464 const char *subset,
1465 int major,
1466 int minor,
1467 bool implicit)
1469 int major_version = major;
1470 int minor_version = minor;
1472 if (major_version == RISCV_UNKNOWN_VERSION
1473 || minor_version == RISCV_UNKNOWN_VERSION)
1474 riscv_get_default_ext_version (rps->isa_spec, subset,
1475 &major_version, &minor_version);
1477 /* We don't care the versions of the implicit extensions. */
1478 if (!implicit
1479 && (major_version == RISCV_UNKNOWN_VERSION
1480 || minor_version == RISCV_UNKNOWN_VERSION))
1482 if (subset[0] == 'x')
1483 rps->error_handler
1484 (_("x ISA extension `%s' must be set with the versions"),
1485 subset);
1486 else
1487 rps->error_handler
1488 (_("cannot find default versions of the ISA extension `%s'"),
1489 subset);
1490 return;
1493 riscv_add_subset (rps->subset_list, subset,
1494 major_version, minor_version);
1497 /* Release subset list. */
1499 void
1500 riscv_release_subset_list (riscv_subset_list_t *subset_list)
1502 while (subset_list->head != NULL)
1504 riscv_subset_t *next = subset_list->head->next;
1505 free ((void *)subset_list->head->name);
1506 free (subset_list->head);
1507 subset_list->head = next;
1510 subset_list->tail = NULL;
1513 /* Parsing extension version.
1515 Return Value:
1516 Points to the end of version
1518 Arguments:
1519 `p`: Curent parsing position.
1520 `major_version`: Parsed major version.
1521 `minor_version`: Parsed minor version. */
1523 static const char *
1524 riscv_parsing_subset_version (const char *p,
1525 int *major_version,
1526 int *minor_version)
1528 bool major_p = true;
1529 int version = 0;
1530 char np;
1532 *major_version = 0;
1533 *minor_version = 0;
1534 for (; *p; ++p)
1536 if (*p == 'p')
1538 np = *(p + 1);
1540 /* Might be beginning of `p` extension. */
1541 if (!ISDIGIT (np))
1542 break;
1544 *major_version = version;
1545 major_p = false;
1546 version = 0;
1548 else if (ISDIGIT (*p))
1549 version = (version * 10) + (*p - '0');
1550 else
1551 break;
1554 if (major_p)
1555 *major_version = version;
1556 else
1557 *minor_version = version;
1559 /* We can not find any version in string. */
1560 if (*major_version == 0 && *minor_version == 0)
1562 *major_version = RISCV_UNKNOWN_VERSION;
1563 *minor_version = RISCV_UNKNOWN_VERSION;
1566 return p;
1569 /* Parsing function for standard extensions.
1571 Return Value:
1572 Points to the end of extensions.
1574 Arguments:
1575 `rps`: Hooks and status for parsing extensions.
1576 `arch`: Full ISA string.
1577 `p`: Curent parsing position. */
1579 static const char *
1580 riscv_parse_std_ext (riscv_parse_subset_t *rps,
1581 const char *arch,
1582 const char *p)
1584 /* First letter must start with i, e or g. */
1585 if (*p != 'e' && *p != 'i' && *p != 'g')
1587 rps->error_handler
1588 (_("%s: first ISA extension must be `e', `i' or `g'"),
1589 arch);
1590 return NULL;
1593 while (p != NULL && *p != '\0')
1595 /* Stop when we parsed the known prefix class. */
1596 enum riscv_prefix_ext_class class = riscv_get_prefix_class (p);
1597 if (class != RV_ISA_CLASS_UNKNOWN)
1598 break;
1600 if (*p == '_')
1602 p++;
1603 continue;
1606 bool implicit = false;
1607 int major = RISCV_UNKNOWN_VERSION;
1608 int minor = RISCV_UNKNOWN_VERSION;
1609 char subset[2] = {0, 0};
1611 subset[0] = *p;
1613 /* Check if the standard extension is supported. */
1614 if (riscv_ext_order[(subset[0] - 'a')] == 0)
1616 rps->error_handler
1617 (_("%s: unknown standard ISA extension `%c'"),
1618 arch, subset[0]);
1619 return NULL;
1622 /* Checking canonical order. */
1623 if (rps->subset_list->tail != NULL
1624 && riscv_compare_subsets (rps->subset_list->tail->name, subset) > 0)
1626 rps->error_handler
1627 (_("%s: standard ISA extension `%c' is not "
1628 "in canonical order"), arch, subset[0]);
1629 return NULL;
1632 p = riscv_parsing_subset_version (++p, &major, &minor);
1633 /* Added g as an implicit extension. */
1634 if (subset[0] == 'g')
1636 implicit = true;
1637 major = RISCV_UNKNOWN_VERSION;
1638 minor = RISCV_UNKNOWN_VERSION;
1640 riscv_parse_add_subset (rps, subset, major, minor, implicit);
1643 return p;
1646 /* Parsing function for prefixed extensions.
1648 Return Value:
1649 Points to the end of extension.
1651 Arguments:
1652 `rps`: Hooks and status for parsing extensions.
1653 `arch`: Full ISA string.
1654 `p`: Curent parsing position. */
1656 static const char *
1657 riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
1658 const char *arch,
1659 const char *p)
1661 int major_version;
1662 int minor_version;
1663 const char *last_name;
1664 enum riscv_prefix_ext_class class;
1666 while (*p)
1668 if (*p == '_')
1670 p++;
1671 continue;
1674 class = riscv_get_prefix_class (p);
1675 if (class == RV_ISA_CLASS_UNKNOWN)
1677 rps->error_handler
1678 (_("%s: unknown prefix class for the ISA extension `%s'"),
1679 arch, p);
1680 return NULL;
1683 char *subset = xstrdup (p);
1684 char *q = subset;
1685 const char *end_of_version;
1687 /* Extract the whole prefixed extension by '_'. */
1688 while (*++q != '\0' && *q != '_')
1690 /* Look forward to the first letter which is not <major>p<minor>. */
1691 bool find_any_version = false;
1692 bool find_minor_version = false;
1693 while (1)
1695 q--;
1696 if (ISDIGIT (*q))
1697 find_any_version = true;
1698 else if (find_any_version
1699 && !find_minor_version
1700 && *q == 'p'
1701 && ISDIGIT (*(q - 1)))
1702 find_minor_version = true;
1703 else
1704 break;
1706 q++;
1708 /* Check if the end of extension is 'p' or not. If yes, then
1709 the second letter from the end cannot be number. */
1710 if (*(q - 1) == 'p' && ISDIGIT (*(q - 2)))
1712 *q = '\0';
1713 rps->error_handler
1714 (_("%s: invalid prefixed ISA extension `%s' ends with <number>p"),
1715 arch, subset);
1716 free (subset);
1717 return NULL;
1720 end_of_version =
1721 riscv_parsing_subset_version (q, &major_version, &minor_version);
1722 *q = '\0';
1723 if (end_of_version == NULL)
1725 free (subset);
1726 return NULL;
1729 /* Check that the extension name is well-formed. */
1730 if (rps->check_unknown_prefixed_ext
1731 && !riscv_recognized_prefixed_ext (subset))
1733 rps->error_handler
1734 (_("%s: unknown prefixed ISA extension `%s'"),
1735 arch, subset);
1736 free (subset);
1737 return NULL;
1740 /* Check that the extension isn't duplicate. */
1741 last_name = rps->subset_list->tail->name;
1742 if (!strcasecmp (last_name, subset))
1744 rps->error_handler
1745 (_("%s: duplicate prefixed ISA extension `%s'"),
1746 arch, subset);
1747 free (subset);
1748 return NULL;
1751 /* Check that the extension is in expected order. */
1752 if (riscv_compare_subsets (last_name, subset) > 0)
1754 rps->error_handler
1755 (_("%s: prefixed ISA extension `%s' is not in expected "
1756 "order. It must come before `%s'"),
1757 arch, subset, last_name);
1758 free (subset);
1759 return NULL;
1762 riscv_parse_add_subset (rps, subset,
1763 major_version,
1764 minor_version, false);
1765 p += end_of_version - subset;
1766 free (subset);
1768 if (*p != '\0' && *p != '_')
1770 rps->error_handler
1771 (_("%s: prefixed ISA extension must separate with _"),
1772 arch);
1773 return NULL;
1777 return p;
1780 /* Add the implicit extensions. */
1782 static void
1783 riscv_parse_add_implicit_subsets (riscv_parse_subset_t *rps)
1785 struct riscv_implicit_subset *t = riscv_implicit_subsets;
1786 for (; t->subset_name; t++)
1788 riscv_subset_t *subset = NULL;
1789 if (riscv_lookup_subset (rps->subset_list, t->subset_name, &subset)
1790 && t->check_func (t->implicit_name, subset))
1791 riscv_parse_add_subset (rps, t->implicit_name,
1792 RISCV_UNKNOWN_VERSION,
1793 RISCV_UNKNOWN_VERSION, true);
1797 /* Check extensions conflicts. */
1799 static bool
1800 riscv_parse_check_conflicts (riscv_parse_subset_t *rps)
1802 riscv_subset_t *subset = NULL;
1803 int xlen = *rps->xlen;
1804 bool no_conflict = true;
1806 if (riscv_lookup_subset (rps->subset_list, "e", &subset)
1807 && xlen > 32)
1809 rps->error_handler
1810 (_("rv%d does not support the `e' extension"), xlen);
1811 no_conflict = false;
1813 if (riscv_lookup_subset (rps->subset_list, "q", &subset)
1814 && xlen < 64)
1816 rps->error_handler
1817 (_("rv%d does not support the `q' extension"), xlen);
1818 no_conflict = false;
1820 if (riscv_lookup_subset (rps->subset_list, "e", &subset)
1821 && riscv_lookup_subset (rps->subset_list, "f", &subset))
1823 rps->error_handler
1824 (_("rv32e does not support the `f' extension"));
1825 no_conflict = false;
1827 return no_conflict;
1830 /* Set the default subset list according to the default_enable field
1831 of riscv_supported_*ext tables. */
1833 static void
1834 riscv_set_default_arch (riscv_parse_subset_t *rps)
1836 unsigned long enable = EXT_DEFAULT;
1837 int i, j;
1838 for (i = 0; riscv_all_supported_ext[i] != NULL; i++)
1840 const struct riscv_supported_ext *table = riscv_all_supported_ext[i];
1841 for (j = 0; table[j].name != NULL; j++)
1843 bool implicit = false;
1844 if (strcmp (table[j].name, "g") == 0)
1845 implicit = true;
1846 if (table[j].default_enable & enable)
1847 riscv_parse_add_subset (rps, table[j].name,
1848 RISCV_UNKNOWN_VERSION,
1849 RISCV_UNKNOWN_VERSION, implicit);
1854 /* Function for parsing ISA string.
1856 Return Value:
1857 Return TRUE on success.
1859 Arguments:
1860 `rps`: Hooks and status for parsing extensions.
1861 `arch`: Full ISA string. */
1863 bool
1864 riscv_parse_subset (riscv_parse_subset_t *rps,
1865 const char *arch)
1867 const char *p;
1869 /* Init the riscv_ext_order array to compare the order of extensions
1870 quickly. */
1871 riscv_init_ext_order ();
1873 if (arch == NULL)
1875 riscv_set_default_arch (rps);
1876 riscv_parse_add_implicit_subsets (rps);
1877 return riscv_parse_check_conflicts (rps);
1880 for (p = arch; *p != '\0'; p++)
1882 if (ISUPPER (*p))
1884 rps->error_handler
1885 (_("%s: ISA string cannot contain uppercase letters"),
1886 arch);
1887 return false;
1891 p = arch;
1892 if (startswith (p, "rv32"))
1894 *rps->xlen = 32;
1895 p += 4;
1897 else if (startswith (p, "rv64"))
1899 *rps->xlen = 64;
1900 p += 4;
1902 else
1904 /* ISA string shouldn't be NULL or empty here. For linker,
1905 it might be empty when we failed to merge the ISA string
1906 in the riscv_merge_attributes. For assembler, we might
1907 give an empty string by .attribute arch, "" or -march=.
1908 However, We have already issued the correct error message
1909 in another side, so do not issue this error when the ISA
1910 string is empty. */
1911 if (strlen (arch))
1912 rps->error_handler (
1913 _("%s: ISA string must begin with rv32 or rv64"),
1914 arch);
1915 return false;
1918 /* Parsing standard extension. */
1919 p = riscv_parse_std_ext (rps, arch, p);
1921 if (p == NULL)
1922 return false;
1924 /* Parse the different classes of extensions in the specified order. */
1925 while (*p != '\0')
1927 p = riscv_parse_prefixed_ext (rps, arch, p);
1929 if (p == NULL)
1930 return false;
1933 /* Finally add implicit extensions according to the current
1934 extensions. */
1935 riscv_parse_add_implicit_subsets (rps);
1937 /* Check the conflicts. */
1938 return riscv_parse_check_conflicts (rps);
1941 /* Return the number of digits for the input. */
1943 size_t
1944 riscv_estimate_digit (unsigned num)
1946 size_t digit = 0;
1947 if (num == 0)
1948 return 1;
1950 for (digit = 0; num ; num /= 10)
1951 digit++;
1953 return digit;
1956 /* Auxiliary function to estimate string length of subset list. */
1958 static size_t
1959 riscv_estimate_arch_strlen1 (const riscv_subset_t *subset)
1961 if (subset == NULL)
1962 return 6; /* For rv32/rv64/rv128 and string terminator. */
1964 return riscv_estimate_arch_strlen1 (subset->next)
1965 + strlen (subset->name)
1966 + riscv_estimate_digit (subset->major_version)
1967 + 1 /* For version seperator 'p'. */
1968 + riscv_estimate_digit (subset->minor_version)
1969 + 1 /* For underscore. */;
1972 /* Estimate the string length of this subset list. */
1974 static size_t
1975 riscv_estimate_arch_strlen (const riscv_subset_list_t *subset_list)
1977 return riscv_estimate_arch_strlen1 (subset_list->head);
1980 /* Auxiliary function to convert subset info to string. */
1982 static void
1983 riscv_arch_str1 (riscv_subset_t *subset,
1984 char *attr_str, char *buf, size_t bufsz)
1986 const char *underline = "_";
1987 riscv_subset_t *subset_t = subset;
1989 if (subset_t == NULL)
1990 return;
1992 /* No underline between rvXX and i/e. */
1993 if ((strcasecmp (subset_t->name, "i") == 0)
1994 || (strcasecmp (subset_t->name, "e") == 0))
1995 underline = "";
1997 snprintf (buf, bufsz, "%s%s%dp%d",
1998 underline,
1999 subset_t->name,
2000 subset_t->major_version,
2001 subset_t->minor_version);
2003 strncat (attr_str, buf, bufsz);
2005 /* Skip 'i' extension after 'e', or skip extensions which
2006 versions are unknown. */
2007 while (subset_t->next
2008 && ((strcmp (subset_t->name, "e") == 0
2009 && strcmp (subset_t->next->name, "i") == 0)
2010 || subset_t->next->major_version == RISCV_UNKNOWN_VERSION
2011 || subset_t->next->minor_version == RISCV_UNKNOWN_VERSION))
2012 subset_t = subset_t->next;
2014 riscv_arch_str1 (subset_t->next, attr_str, buf, bufsz);
2017 /* Convert subset information into string with explicit versions. */
2019 char *
2020 riscv_arch_str (unsigned xlen, const riscv_subset_list_t *subset)
2022 size_t arch_str_len = riscv_estimate_arch_strlen (subset);
2023 char *attr_str = xmalloc (arch_str_len);
2024 char *buf = xmalloc (arch_str_len);
2026 snprintf (attr_str, arch_str_len, "rv%u", xlen);
2028 riscv_arch_str1 (subset->head, attr_str, buf, arch_str_len);
2029 free (buf);
2031 return attr_str;
2034 /* Remove the SUBSET from the subset list. */
2036 static void
2037 riscv_remove_subset (riscv_subset_list_t *subset_list,
2038 const char *subset)
2040 riscv_subset_t *current = subset_list->head;
2041 riscv_subset_t *pre = NULL;
2042 for (; current != NULL; pre = current, current = current->next)
2044 if (strcmp (current->name, subset) == 0)
2046 if (pre == NULL)
2047 subset_list->head = current->next;
2048 else
2049 pre->next = current->next;
2050 if (current->next == NULL)
2051 subset_list->tail = pre;
2052 free ((void *) current->name);
2053 free (current);
2054 break;
2059 /* Add/Remove an extension to/from the subset list. This is used for
2060 the .option rvc or norvc. */
2062 bool
2063 riscv_update_subset (riscv_parse_subset_t *rps,
2064 const char *subset,
2065 bool removed)
2067 if (strlen (subset) == 0
2068 || (strlen (subset) == 1
2069 && riscv_ext_order[(*subset - 'a')] == 0)
2070 || (strlen (subset) > 1
2071 && rps->check_unknown_prefixed_ext
2072 && !riscv_recognized_prefixed_ext (subset)))
2074 rps->error_handler
2075 (_("riscv_update_subset: unknown ISA extension `%s'"), subset);
2076 return false;
2079 if (removed)
2081 if (strcmp (subset, "i") == 0)
2083 rps->error_handler
2084 (_("riscv_update_subset: cannot remove extension i from "
2085 "the subset list"));
2086 return false;
2088 riscv_remove_subset (rps->subset_list, subset);
2090 else
2091 riscv_parse_add_subset (rps, subset,
2092 RISCV_UNKNOWN_VERSION,
2093 RISCV_UNKNOWN_VERSION, true);
2095 riscv_parse_add_implicit_subsets (rps);
2096 return riscv_parse_check_conflicts (rps);