1 /* RISC-V-specific support for ELF.
2 Copyright (C) 2011-2020 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/>. */
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
[] =
47 HOWTO (R_RISCV_NONE
, /* type */
51 FALSE
, /* pc_relative */
53 complain_overflow_dont
, /* complain_on_overflow */
54 bfd_elf_generic_reloc
, /* special_function */
55 "R_RISCV_NONE", /* name */
56 FALSE
, /* partial_inplace */
59 FALSE
), /* pcrel_offset */
61 /* 32 bit relocation. */
62 HOWTO (R_RISCV_32
, /* type */
66 FALSE
, /* pc_relative */
68 complain_overflow_dont
, /* complain_on_overflow */
69 bfd_elf_generic_reloc
, /* special_function */
70 "R_RISCV_32", /* name */
71 FALSE
, /* partial_inplace */
73 MINUS_ONE
, /* dst_mask */
74 FALSE
), /* pcrel_offset */
76 /* 64 bit relocation. */
77 HOWTO (R_RISCV_64
, /* type */
81 FALSE
, /* pc_relative */
83 complain_overflow_dont
, /* complain_on_overflow */
84 bfd_elf_generic_reloc
, /* special_function */
85 "R_RISCV_64", /* name */
86 FALSE
, /* partial_inplace */
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 */
96 FALSE
, /* pc_relative */
98 complain_overflow_dont
, /* complain_on_overflow */
99 bfd_elf_generic_reloc
, /* special_function */
100 "R_RISCV_RELATIVE", /* name */
101 FALSE
, /* partial_inplace */
103 MINUS_ONE
, /* dst_mask */
104 FALSE
), /* pcrel_offset */
106 HOWTO (R_RISCV_COPY
, /* type */
108 0, /* this one is variable size */
110 FALSE
, /* pc_relative */
112 complain_overflow_bitfield
, /* complain_on_overflow */
113 bfd_elf_generic_reloc
, /* special_function */
114 "R_RISCV_COPY", /* name */
115 FALSE
, /* partial_inplace */
118 FALSE
), /* pcrel_offset */
120 HOWTO (R_RISCV_JUMP_SLOT
, /* type */
124 FALSE
, /* pc_relative */
126 complain_overflow_bitfield
, /* complain_on_overflow */
127 bfd_elf_generic_reloc
, /* special_function */
128 "R_RISCV_JUMP_SLOT", /* name */
129 FALSE
, /* partial_inplace */
132 FALSE
), /* pcrel_offset */
134 /* Dynamic TLS relocations. */
135 HOWTO (R_RISCV_TLS_DTPMOD32
, /* type */
139 FALSE
, /* pc_relative */
141 complain_overflow_dont
, /* complain_on_overflow */
142 bfd_elf_generic_reloc
, /* special_function */
143 "R_RISCV_TLS_DTPMOD32", /* name */
144 FALSE
, /* partial_inplace */
146 MINUS_ONE
, /* dst_mask */
147 FALSE
), /* pcrel_offset */
149 HOWTO (R_RISCV_TLS_DTPMOD64
, /* type */
153 FALSE
, /* pc_relative */
155 complain_overflow_dont
, /* complain_on_overflow */
156 bfd_elf_generic_reloc
, /* special_function */
157 "R_RISCV_TLS_DTPMOD64", /* name */
158 FALSE
, /* partial_inplace */
160 MINUS_ONE
, /* dst_mask */
161 FALSE
), /* pcrel_offset */
163 HOWTO (R_RISCV_TLS_DTPREL32
, /* type */
167 FALSE
, /* pc_relative */
169 complain_overflow_dont
, /* complain_on_overflow */
170 bfd_elf_generic_reloc
, /* special_function */
171 "R_RISCV_TLS_DTPREL32", /* name */
172 TRUE
, /* partial_inplace */
174 MINUS_ONE
, /* dst_mask */
175 FALSE
), /* pcrel_offset */
177 HOWTO (R_RISCV_TLS_DTPREL64
, /* type */
181 FALSE
, /* pc_relative */
183 complain_overflow_dont
, /* complain_on_overflow */
184 bfd_elf_generic_reloc
, /* special_function */
185 "R_RISCV_TLS_DTPREL64", /* name */
186 TRUE
, /* partial_inplace */
188 MINUS_ONE
, /* dst_mask */
189 FALSE
), /* pcrel_offset */
191 HOWTO (R_RISCV_TLS_TPREL32
, /* type */
195 FALSE
, /* pc_relative */
197 complain_overflow_dont
, /* complain_on_overflow */
198 bfd_elf_generic_reloc
, /* special_function */
199 "R_RISCV_TLS_TPREL32", /* name */
200 FALSE
, /* partial_inplace */
202 MINUS_ONE
, /* dst_mask */
203 FALSE
), /* pcrel_offset */
205 HOWTO (R_RISCV_TLS_TPREL64
, /* type */
209 FALSE
, /* pc_relative */
211 complain_overflow_dont
, /* complain_on_overflow */
212 bfd_elf_generic_reloc
, /* special_function */
213 "R_RISCV_TLS_TPREL64", /* name */
214 FALSE
, /* partial_inplace */
216 MINUS_ONE
, /* dst_mask */
217 FALSE
), /* pcrel_offset */
219 /* Reserved for future relocs that the dynamic linker must understand. */
225 /* 12-bit PC-relative branch offset. */
226 HOWTO (R_RISCV_BRANCH
, /* type */
230 TRUE
, /* pc_relative */
232 complain_overflow_signed
, /* complain_on_overflow */
233 bfd_elf_generic_reloc
, /* special_function */
234 "R_RISCV_BRANCH", /* name */
235 FALSE
, /* partial_inplace */
237 ENCODE_SBTYPE_IMM (-1U), /* dst_mask */
238 TRUE
), /* pcrel_offset */
240 /* 20-bit PC-relative jump offset. */
241 HOWTO (R_RISCV_JAL
, /* type */
245 TRUE
, /* pc_relative */
247 complain_overflow_dont
, /* complain_on_overflow */
248 bfd_elf_generic_reloc
, /* special_function */
249 "R_RISCV_JAL", /* name */
250 FALSE
, /* partial_inplace */
252 ENCODE_UJTYPE_IMM (-1U), /* dst_mask */
253 TRUE
), /* pcrel_offset */
255 /* 32-bit PC-relative function call (AUIPC/JALR). */
256 HOWTO (R_RISCV_CALL
, /* type */
260 TRUE
, /* pc_relative */
262 complain_overflow_dont
, /* complain_on_overflow */
263 bfd_elf_generic_reloc
, /* special_function */
264 "R_RISCV_CALL", /* name */
265 FALSE
, /* partial_inplace */
267 ENCODE_UTYPE_IMM (-1U) | ((bfd_vma
) ENCODE_ITYPE_IMM (-1U) << 32),
269 TRUE
), /* pcrel_offset */
271 /* Like R_RISCV_CALL, but not locally binding. */
272 HOWTO (R_RISCV_CALL_PLT
, /* type */
276 TRUE
, /* pc_relative */
278 complain_overflow_dont
, /* complain_on_overflow */
279 bfd_elf_generic_reloc
, /* special_function */
280 "R_RISCV_CALL_PLT", /* name */
281 FALSE
, /* partial_inplace */
283 ENCODE_UTYPE_IMM (-1U) | ((bfd_vma
) ENCODE_ITYPE_IMM (-1U) << 32),
285 TRUE
), /* pcrel_offset */
287 /* High 20 bits of 32-bit PC-relative GOT access. */
288 HOWTO (R_RISCV_GOT_HI20
, /* type */
292 TRUE
, /* pc_relative */
294 complain_overflow_dont
, /* complain_on_overflow */
295 bfd_elf_generic_reloc
, /* special_function */
296 "R_RISCV_GOT_HI20", /* name */
297 FALSE
, /* partial_inplace */
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 */
307 TRUE
, /* pc_relative */
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 */
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 */
322 TRUE
, /* pc_relative */
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 */
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 */
337 TRUE
, /* pc_relative */
339 complain_overflow_dont
, /* complain_on_overflow */
340 bfd_elf_generic_reloc
, /* special_function */
341 "R_RISCV_PCREL_HI20", /* name */
342 FALSE
, /* partial_inplace */
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 */
352 FALSE
, /* pc_relative */
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 */
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 */
367 FALSE
, /* pc_relative */
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 */
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 */
382 FALSE
, /* pc_relative */
384 complain_overflow_dont
, /* complain_on_overflow */
385 bfd_elf_generic_reloc
, /* special_function */
386 "R_RISCV_HI20", /* name */
387 FALSE
, /* partial_inplace */
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 */
397 FALSE
, /* pc_relative */
399 complain_overflow_dont
, /* complain_on_overflow */
400 bfd_elf_generic_reloc
, /* special_function */
401 "R_RISCV_LO12_I", /* name */
402 FALSE
, /* partial_inplace */
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 */
412 FALSE
, /* pc_relative */
414 complain_overflow_dont
, /* complain_on_overflow */
415 bfd_elf_generic_reloc
, /* special_function */
416 "R_RISCV_LO12_S", /* name */
417 FALSE
, /* partial_inplace */
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 */
427 FALSE
, /* pc_relative */
429 complain_overflow_signed
, /* complain_on_overflow */
430 bfd_elf_generic_reloc
, /* special_function */
431 "R_RISCV_TPREL_HI20", /* name */
432 TRUE
, /* partial_inplace */
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 */
442 FALSE
, /* pc_relative */
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 */
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 */
457 FALSE
, /* pc_relative */
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 */
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 */
472 FALSE
, /* pc_relative */
474 complain_overflow_dont
, /* complain_on_overflow */
475 bfd_elf_generic_reloc
, /* special_function */
476 "R_RISCV_TPREL_ADD", /* name */
477 TRUE
, /* partial_inplace */
480 FALSE
), /* pcrel_offset */
482 /* 8-bit in-place addition, for local label subtraction. */
483 HOWTO (R_RISCV_ADD8
, /* type */
487 FALSE
, /* pc_relative */
489 complain_overflow_dont
, /* complain_on_overflow */
490 riscv_elf_add_sub_reloc
, /* special_function */
491 "R_RISCV_ADD8", /* name */
492 FALSE
, /* partial_inplace */
494 MINUS_ONE
, /* dst_mask */
495 FALSE
), /* pcrel_offset */
497 /* 16-bit in-place addition, for local label subtraction. */
498 HOWTO (R_RISCV_ADD16
, /* type */
502 FALSE
, /* pc_relative */
504 complain_overflow_dont
, /* complain_on_overflow */
505 riscv_elf_add_sub_reloc
, /* special_function */
506 "R_RISCV_ADD16", /* name */
507 FALSE
, /* partial_inplace */
509 MINUS_ONE
, /* dst_mask */
510 FALSE
), /* pcrel_offset */
512 /* 32-bit in-place addition, for local label subtraction. */
513 HOWTO (R_RISCV_ADD32
, /* type */
517 FALSE
, /* pc_relative */
519 complain_overflow_dont
, /* complain_on_overflow */
520 riscv_elf_add_sub_reloc
, /* special_function */
521 "R_RISCV_ADD32", /* name */
522 FALSE
, /* partial_inplace */
524 MINUS_ONE
, /* dst_mask */
525 FALSE
), /* pcrel_offset */
527 /* 64-bit in-place addition, for local label subtraction. */
528 HOWTO (R_RISCV_ADD64
, /* type */
532 FALSE
, /* pc_relative */
534 complain_overflow_dont
, /* complain_on_overflow */
535 riscv_elf_add_sub_reloc
, /* special_function */
536 "R_RISCV_ADD64", /* name */
537 FALSE
, /* partial_inplace */
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 */
547 FALSE
, /* pc_relative */
549 complain_overflow_dont
, /* complain_on_overflow */
550 riscv_elf_add_sub_reloc
, /* special_function */
551 "R_RISCV_SUB8", /* name */
552 FALSE
, /* partial_inplace */
554 MINUS_ONE
, /* dst_mask */
555 FALSE
), /* pcrel_offset */
557 /* 16-bit in-place addition, for local label subtraction. */
558 HOWTO (R_RISCV_SUB16
, /* type */
562 FALSE
, /* pc_relative */
564 complain_overflow_dont
, /* complain_on_overflow */
565 riscv_elf_add_sub_reloc
, /* special_function */
566 "R_RISCV_SUB16", /* name */
567 FALSE
, /* partial_inplace */
569 MINUS_ONE
, /* dst_mask */
570 FALSE
), /* pcrel_offset */
572 /* 32-bit in-place addition, for local label subtraction. */
573 HOWTO (R_RISCV_SUB32
, /* type */
577 FALSE
, /* pc_relative */
579 complain_overflow_dont
, /* complain_on_overflow */
580 riscv_elf_add_sub_reloc
, /* special_function */
581 "R_RISCV_SUB32", /* name */
582 FALSE
, /* partial_inplace */
584 MINUS_ONE
, /* dst_mask */
585 FALSE
), /* pcrel_offset */
587 /* 64-bit in-place addition, for local label subtraction. */
588 HOWTO (R_RISCV_SUB64
, /* type */
592 FALSE
, /* pc_relative */
594 complain_overflow_dont
, /* complain_on_overflow */
595 riscv_elf_add_sub_reloc
, /* special_function */
596 "R_RISCV_SUB64", /* name */
597 FALSE
, /* partial_inplace */
599 MINUS_ONE
, /* dst_mask */
600 FALSE
), /* pcrel_offset */
602 /* GNU extension to record C++ vtable hierarchy */
603 HOWTO (R_RISCV_GNU_VTINHERIT
, /* type */
607 FALSE
, /* pc_relative */
609 complain_overflow_dont
, /* complain_on_overflow */
610 NULL
, /* special_function */
611 "R_RISCV_GNU_VTINHERIT", /* name */
612 FALSE
, /* partial_inplace */
615 FALSE
), /* pcrel_offset */
617 /* GNU extension to record C++ vtable member usage */
618 HOWTO (R_RISCV_GNU_VTENTRY
, /* type */
622 FALSE
, /* pc_relative */
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 */
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 */
639 FALSE
, /* pc_relative */
641 complain_overflow_dont
, /* complain_on_overflow */
642 bfd_elf_generic_reloc
, /* special_function */
643 "R_RISCV_ALIGN", /* name */
644 FALSE
, /* partial_inplace */
647 TRUE
), /* pcrel_offset */
649 /* 8-bit PC-relative branch offset. */
650 HOWTO (R_RISCV_RVC_BRANCH
, /* type */
654 TRUE
, /* pc_relative */
656 complain_overflow_signed
, /* complain_on_overflow */
657 bfd_elf_generic_reloc
, /* special_function */
658 "R_RISCV_RVC_BRANCH", /* name */
659 FALSE
, /* partial_inplace */
661 ENCODE_RVC_B_IMM (-1U), /* dst_mask */
662 TRUE
), /* pcrel_offset */
664 /* 11-bit PC-relative jump offset. */
665 HOWTO (R_RISCV_RVC_JUMP
, /* type */
669 TRUE
, /* pc_relative */
671 complain_overflow_dont
, /* complain_on_overflow */
672 bfd_elf_generic_reloc
, /* special_function */
673 "R_RISCV_RVC_JUMP", /* name */
674 FALSE
, /* partial_inplace */
676 ENCODE_RVC_J_IMM (-1U), /* dst_mask */
677 TRUE
), /* pcrel_offset */
679 /* High 6 bits of 18-bit absolute address. */
680 HOWTO (R_RISCV_RVC_LUI
, /* type */
684 FALSE
, /* pc_relative */
686 complain_overflow_dont
, /* complain_on_overflow */
687 bfd_elf_generic_reloc
, /* special_function */
688 "R_RISCV_RVC_LUI", /* name */
689 FALSE
, /* partial_inplace */
691 ENCODE_RVC_IMM (-1U), /* dst_mask */
692 FALSE
), /* pcrel_offset */
694 /* GP-relative load. */
695 HOWTO (R_RISCV_GPREL_I
, /* type */
699 FALSE
, /* pc_relative */
701 complain_overflow_dont
, /* complain_on_overflow */
702 bfd_elf_generic_reloc
, /* special_function */
703 "R_RISCV_GPREL_I", /* name */
704 FALSE
, /* partial_inplace */
706 ENCODE_ITYPE_IMM (-1U), /* dst_mask */
707 FALSE
), /* pcrel_offset */
709 /* GP-relative store. */
710 HOWTO (R_RISCV_GPREL_S
, /* type */
714 FALSE
, /* pc_relative */
716 complain_overflow_dont
, /* complain_on_overflow */
717 bfd_elf_generic_reloc
, /* special_function */
718 "R_RISCV_GPREL_S", /* name */
719 FALSE
, /* partial_inplace */
721 ENCODE_STYPE_IMM (-1U), /* dst_mask */
722 FALSE
), /* pcrel_offset */
724 /* TP-relative TLS LE load. */
725 HOWTO (R_RISCV_TPREL_I
, /* type */
729 FALSE
, /* pc_relative */
731 complain_overflow_signed
, /* complain_on_overflow */
732 bfd_elf_generic_reloc
, /* special_function */
733 "R_RISCV_TPREL_I", /* name */
734 FALSE
, /* partial_inplace */
736 ENCODE_ITYPE_IMM (-1U), /* dst_mask */
737 FALSE
), /* pcrel_offset */
739 /* TP-relative TLS LE store. */
740 HOWTO (R_RISCV_TPREL_S
, /* type */
744 FALSE
, /* pc_relative */
746 complain_overflow_signed
, /* complain_on_overflow */
747 bfd_elf_generic_reloc
, /* special_function */
748 "R_RISCV_TPREL_S", /* name */
749 FALSE
, /* partial_inplace */
751 ENCODE_STYPE_IMM (-1U), /* dst_mask */
752 FALSE
), /* pcrel_offset */
754 /* The paired relocation may be relaxed. */
755 HOWTO (R_RISCV_RELAX
, /* type */
759 FALSE
, /* pc_relative */
761 complain_overflow_dont
, /* complain_on_overflow */
762 bfd_elf_generic_reloc
, /* special_function */
763 "R_RISCV_RELAX", /* name */
764 FALSE
, /* partial_inplace */
767 FALSE
), /* pcrel_offset */
769 /* 6-bit in-place addition, for local label subtraction. */
770 HOWTO (R_RISCV_SUB6
, /* type */
774 FALSE
, /* pc_relative */
776 complain_overflow_dont
, /* complain_on_overflow */
777 riscv_elf_add_sub_reloc
, /* special_function */
778 "R_RISCV_SUB6", /* name */
779 FALSE
, /* partial_inplace */
782 FALSE
), /* pcrel_offset */
784 /* 6-bit in-place setting, for local label subtraction. */
785 HOWTO (R_RISCV_SET6
, /* type */
789 FALSE
, /* pc_relative */
791 complain_overflow_dont
, /* complain_on_overflow */
792 bfd_elf_generic_reloc
, /* special_function */
793 "R_RISCV_SET6", /* name */
794 FALSE
, /* partial_inplace */
797 FALSE
), /* pcrel_offset */
799 /* 8-bit in-place setting, for local label subtraction. */
800 HOWTO (R_RISCV_SET8
, /* type */
804 FALSE
, /* pc_relative */
806 complain_overflow_dont
, /* complain_on_overflow */
807 bfd_elf_generic_reloc
, /* special_function */
808 "R_RISCV_SET8", /* name */
809 FALSE
, /* partial_inplace */
811 MINUS_ONE
, /* dst_mask */
812 FALSE
), /* pcrel_offset */
814 /* 16-bit in-place setting, for local label subtraction. */
815 HOWTO (R_RISCV_SET16
, /* type */
819 FALSE
, /* pc_relative */
821 complain_overflow_dont
, /* complain_on_overflow */
822 bfd_elf_generic_reloc
, /* special_function */
823 "R_RISCV_SET16", /* name */
824 FALSE
, /* partial_inplace */
826 MINUS_ONE
, /* dst_mask */
827 FALSE
), /* pcrel_offset */
829 /* 32-bit in-place setting, for local label subtraction. */
830 HOWTO (R_RISCV_SET32
, /* type */
834 FALSE
, /* pc_relative */
836 complain_overflow_dont
, /* complain_on_overflow */
837 bfd_elf_generic_reloc
, /* special_function */
838 "R_RISCV_SET32", /* name */
839 FALSE
, /* partial_inplace */
841 MINUS_ONE
, /* dst_mask */
842 FALSE
), /* pcrel_offset */
844 /* 32-bit PC relative. */
845 HOWTO (R_RISCV_32_PCREL
, /* type */
849 TRUE
, /* pc_relative */
851 complain_overflow_dont
, /* complain_on_overflow */
852 bfd_elf_generic_reloc
, /* special_function */
853 "R_RISCV_32_PCREL", /* name */
854 FALSE
, /* partial_inplace */
856 MINUS_ONE
, /* dst_mask */
857 FALSE
), /* pcrel_offset */
860 /* A mapping from BFD reloc types to RISC-V ELF reloc types. */
864 bfd_reloc_code_real_type bfd_val
;
865 enum elf_riscv_reloc_type elf_val
;
868 static const struct elf_reloc_map riscv_reloc_map
[] =
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
},
922 /* Given a BFD reloc type, return a howto structure. */
925 riscv_reloc_type_lookup (bfd
*abfd ATTRIBUTE_UNUSED
,
926 bfd_reloc_code_real_type code
)
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
];
934 bfd_set_error (bfd_error_bad_value
);
939 riscv_reloc_name_lookup (bfd
*abfd ATTRIBUTE_UNUSED
, const char *r_name
)
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
];
951 riscv_elf_rtype_to_howto (bfd
*abfd
, unsigned int r_type
)
953 if (r_type
>= ARRAY_SIZE (howto_table
))
955 (*_bfd_error_handler
) (_("%pB: unsupported relocation type %#x"),
957 bfd_set_error (bfd_error_bad_value
);
960 return &howto_table
[r_type
];
963 /* Special_function of RISCV_ADD and RISCV_SUB relocations. */
965 static bfd_reloc_status_type
966 riscv_elf_add_sub_reloc (bfd
*abfd
,
967 arelent
*reloc_entry
,
970 asection
*input_section
,
972 char **error_message ATTRIBUTE_UNUSED
)
974 reloc_howto_type
*howto
= reloc_entry
->howto
;
977 if (output_bfd
!= NULL
978 && (symbol
->flags
& BSF_SECTION_SYM
) == 0
979 && (!reloc_entry
->howto
->partial_inplace
|| reloc_entry
->addend
== 0))
981 reloc_entry
->address
+= input_section
->output_offset
;
985 if (output_bfd
!= NULL
)
986 return bfd_reloc_continue
;
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
);
999 relocation
= old_value
+ relocation
;
1006 relocation
= old_value
- relocation
;
1009 bfd_put (howto
->bitsize
, abfd
, relocation
, data
+ reloc_entry
->address
);
1011 return bfd_reloc_ok
;
1014 /* Parsing subset version.
1017 Points to the end of version
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 `std_ext_p`: True if parsing std extension.
1029 `use_default_version`: Set it to True if we need the default version. */
1032 riscv_parsing_subset_version (riscv_parse_subset_t
*rps
,
1035 unsigned *major_version
,
1036 unsigned *minor_version
,
1037 bfd_boolean std_ext_p
,
1038 bfd_boolean
*use_default_version
)
1040 bfd_boolean major_p
= TRUE
;
1041 unsigned version
= 0;
1054 /* Might be beginning of `p` extension. */
1057 *major_version
= version
;
1064 (_("-march=%s: Expect number after `%dp'."),
1070 *major_version
= version
;
1074 else if (ISDIGIT (*p
))
1075 version
= (version
* 10) + (*p
- '0');
1081 *major_version
= version
;
1083 *minor_version
= version
;
1085 /* We can not find any version in string, need to parse default version. */
1086 if (use_default_version
!= NULL
1087 && *major_version
== 0
1088 && *minor_version
== 0)
1089 *use_default_version
= TRUE
;
1093 /* Return string which contain all supported standard extensions in
1097 riscv_supported_std_ext (void)
1099 return "mafdqlcbjtpvn";
1102 /* Parsing function for standard extensions.
1105 Points to the end of extensions.
1108 `rps`: Hooks and status for parsing subset.
1109 `march`: Full arch string.
1110 `p`: Curent parsing position. */
1113 riscv_parse_std_ext (riscv_parse_subset_t
*rps
,
1117 const char *all_std_exts
= riscv_supported_std_ext ();
1118 const char *std_exts
= all_std_exts
;
1119 unsigned major_version
= 0;
1120 unsigned minor_version
= 0;
1121 char std_ext
= '\0';
1122 bfd_boolean use_default_version
= FALSE
;
1124 /* First letter must start with i, e or g. */
1128 p
= riscv_parsing_subset_version (rps
,
1133 /* std_ext_p= */TRUE
,
1134 &use_default_version
);
1136 /* Find the default version if needed. */
1137 if (use_default_version
1138 && rps
->get_default_version
!= NULL
)
1139 rps
->get_default_version ("i",
1142 riscv_add_subset (rps
->subset_list
, "i",
1143 major_version
, minor_version
);
1147 p
= riscv_parsing_subset_version (rps
,
1152 /* std_ext_p= */TRUE
,
1153 &use_default_version
);
1155 /* Find the default version if needed. */
1156 if (use_default_version
1157 && rps
->get_default_version
!= NULL
)
1158 rps
->get_default_version ("e",
1161 riscv_add_subset (rps
->subset_list
, "e",
1162 major_version
, minor_version
);
1164 /* i-ext must be enabled. */
1165 if (rps
->get_default_version
!= NULL
)
1166 rps
->get_default_version ("i",
1169 riscv_add_subset (rps
->subset_list
, "i",
1170 major_version
, minor_version
);
1172 if (*rps
->xlen
> 32)
1175 (_("-march=%s: rv%de is not a valid base ISA"),
1182 /* The g-ext shouldn't has the version, so we just
1183 skip the setting if user set a version to it. */
1184 p
= riscv_parsing_subset_version (rps
,
1190 &use_default_version
);
1192 /* i-ext must be enabled. */
1193 if (rps
->get_default_version
!= NULL
)
1194 rps
->get_default_version ("i",
1197 riscv_add_subset (rps
->subset_list
, "i",
1198 major_version
, minor_version
);
1200 for ( ; *std_exts
!= 'q'; std_exts
++)
1202 const char subset
[] = {*std_exts
, '\0'};
1204 if (rps
->get_default_version
!= NULL
)
1205 rps
->get_default_version (subset
,
1208 riscv_add_subset (rps
->subset_list
, subset
,
1209 major_version
, minor_version
);
1215 (_("-march=%s: first ISA subset must be `e', `i' or `g'"), march
);
1219 /* The riscv_parsing_subset_version may set `p` to NULL, so I think we should
1220 skip parsing the string if `p` is NULL or value of `p` is `\0`. */
1221 while (p
!= NULL
&& *p
!= '\0')
1223 char subset
[2] = {0, 0};
1225 if (*p
== 'x' || *p
== 's' || *p
== 'z')
1236 /* Checking canonical order. */
1237 while (*std_exts
&& std_ext
!= *std_exts
) std_exts
++;
1239 if (std_ext
!= *std_exts
)
1241 if (strchr (all_std_exts
, std_ext
) == NULL
)
1243 (_("-march=%s: unsupported ISA subset `%c'"), march
, *p
);
1246 (_("-march=%s: ISA string is not in canonical order. `%c'"),
1253 use_default_version
= FALSE
;
1254 subset
[0] = std_ext
;
1255 p
= riscv_parsing_subset_version (rps
,
1261 &use_default_version
);
1263 /* Find the default version if needed. */
1264 if (use_default_version
1265 && rps
->get_default_version
!= NULL
)
1266 rps
->get_default_version (subset
,
1269 riscv_add_subset (rps
->subset_list
, subset
,
1270 major_version
, minor_version
);
1275 /* Classify the argument 'arch' into one of riscv_isa_ext_class_t. */
1277 riscv_isa_ext_class_t
1278 riscv_get_prefix_class (const char *arch
)
1282 case 's': return RV_ISA_CLASS_S
;
1283 case 'x': return RV_ISA_CLASS_X
;
1284 case 'z': return RV_ISA_CLASS_Z
;
1285 default: return RV_ISA_CLASS_UNKNOWN
;
1289 /* Structure describing parameters to use when parsing a particular
1290 riscv_isa_ext_class_t. One of these should be provided for each
1291 possible class, except RV_ISA_CLASS_UNKNOWN. */
1293 typedef struct riscv_parse_config
1295 /* Class of the extension. */
1296 riscv_isa_ext_class_t
class;
1298 /* Lower-case prefix string for error printing
1299 and internal parser usage, e.g. "z", "x". */
1302 /* Predicate which is used for checking whether
1303 this is a "known" extension. For 'x',
1304 it always returns true (since they are by
1305 definition non-standard and cannot be known. */
1306 bfd_boolean (*ext_valid_p
) (const char *);
1307 } riscv_parse_config_t
;
1309 /* Parse a generic prefixed extension.
1310 `rps`: Hooks and status for parsing subset.
1311 `march`: The full architecture string as passed in by "-march=...".
1312 `p`: Point from which to start parsing the -march string.
1313 `config`: What class of extensions to parse, predicate funcs,
1314 and strings to use in error reporting. */
1317 riscv_parse_prefixed_ext (riscv_parse_subset_t
*rps
,
1320 const riscv_parse_config_t
*config
)
1322 unsigned major_version
= 0;
1323 unsigned minor_version
= 0;
1324 const char *last_name
;
1325 riscv_isa_ext_class_t
class;
1326 bfd_boolean use_default_version
;
1336 /* Assert that the current extension specifier matches our parsing
1338 class = riscv_get_prefix_class (p
);
1339 if (class != config
->class)
1342 char *subset
= xstrdup (p
);
1344 const char *end_of_version
;
1346 while (*++q
!= '\0' && *q
!= '_' && !ISDIGIT (*q
))
1349 use_default_version
= FALSE
;
1351 riscv_parsing_subset_version (rps
, march
, q
, &major_version
,
1352 &minor_version
, FALSE
,
1353 &use_default_version
);
1356 /* Check that the name is valid.
1357 For 'x', anything goes but it cannot simply be 'x'.
1358 For 's', it must be known from a list and cannot simply be 's'.
1359 For 'z', it must be known from a list and cannot simply be 'z'. */
1361 /* Check that the extension name is well-formed. */
1362 if (!config
->ext_valid_p (subset
))
1365 (_("-march=%s: Invalid or unknown %s ISA extension: '%s'"),
1366 march
, config
->prefix
, subset
);
1371 /* Check that the last item is not the same as this. */
1372 last_name
= rps
->subset_list
->tail
->name
;
1373 if (!strcasecmp (last_name
, subset
))
1376 (_("-march=%s: Duplicate %s ISA extension: \'%s\'"),
1377 march
, config
->prefix
, subset
);
1382 /* Check that we are in alphabetical order within the subset. */
1383 if (!strncasecmp (last_name
, config
->prefix
, 1)
1384 && strcasecmp (last_name
, subset
) > 0)
1388 -march=%s: %s ISA extension not in alphabetical order: \'%s\' must come before \'%s\'."),
1389 march
, config
->prefix
, subset
, last_name
);
1394 /* Find the default version if needed. */
1395 if (use_default_version
1396 && rps
->get_default_version
!= NULL
)
1397 rps
->get_default_version (subset
,
1400 riscv_add_subset (rps
->subset_list
, subset
,
1401 major_version
, minor_version
);
1404 p
+= end_of_version
- subset
;
1406 if (*p
!= '\0' && *p
!= '_')
1408 rps
->error_handler (_("-march=%s: %s must separate with _"),
1409 march
, config
->prefix
);
1417 /* List of Z-class extensions that binutils should know about.
1418 Whether or not a particular entry is in this list will
1419 dictate if gas/ld will accept its presence in the -march
1422 Example: To add an extension called "Zbb" (bitmanip base extension),
1423 add "zbb" string to the list (all lowercase).
1425 Keep this list alphabetically ordered. */
1427 static const char * const riscv_std_z_ext_strtab
[] =
1432 /* Same as `riscv_std_z_ext_strtab', but for S-class extensions. */
1434 static const char * const riscv_std_s_ext_strtab
[] =
1439 /* For the extension EXT, search through the list of known extensions
1440 KNOWN_EXTS for a match, and return TRUE if found. */
1443 riscv_multi_letter_ext_valid_p (const char *ext
,
1444 const char *const *known_exts
)
1448 for (i
= 0; known_exts
[i
]; ++i
)
1449 if (!strcmp (ext
, known_exts
[i
]))
1455 /* Predicator function for x-prefixed extensions.
1456 Anything goes, except the literal 'x'. */
1459 riscv_ext_x_valid_p (const char *arg
)
1461 if (!strcasecmp (arg
, "x"))
1467 /* Predicator functions for z-prefixed extensions.
1468 Only known z-extensions are permitted. */
1471 riscv_ext_z_valid_p (const char *arg
)
1473 return riscv_multi_letter_ext_valid_p (arg
, riscv_std_z_ext_strtab
);
1476 /* Predicator function for 's' prefixed extensions.
1477 Must be either literal 's', or a known s-prefixed extension. */
1480 riscv_ext_s_valid_p (const char *arg
)
1482 return riscv_multi_letter_ext_valid_p (arg
, riscv_std_s_ext_strtab
);
1485 /* Parsing order that is specified by the ISA manual. */
1487 static const riscv_parse_config_t parse_config
[] =
1489 {RV_ISA_CLASS_S
, "s", riscv_ext_s_valid_p
},
1490 {RV_ISA_CLASS_Z
, "z", riscv_ext_z_valid_p
},
1491 {RV_ISA_CLASS_X
, "x", riscv_ext_x_valid_p
},
1492 {RV_ISA_CLASS_UNKNOWN
, NULL
, NULL
}
1495 /* Function for parsing arch string.
1498 Return TRUE on success.
1501 `rps`: Hooks and status for parsing subset.
1502 `arch`: Arch string. */
1505 riscv_parse_subset (riscv_parse_subset_t
*rps
,
1508 const char *p
= arch
;
1511 if (strncmp (p
, "rv32", 4) == 0)
1516 else if (strncmp (p
, "rv64", 4) == 0)
1524 (_("-march=%s: ISA string must begin with rv32 or rv64"),
1529 /* Parsing standard extension. */
1530 p
= riscv_parse_std_ext (rps
, arch
, p
);
1535 /* Parse the different classes of extensions in the specified order. */
1536 for (i
= 0; i
< ARRAY_SIZE (parse_config
); ++i
) {
1537 p
= riscv_parse_prefixed_ext (rps
, arch
, p
, &parse_config
[i
]);
1545 rps
->error_handler (_("-march=%s: unexpected ISA string at end: %s"),
1550 if (riscv_lookup_subset (rps
->subset_list
, "e")
1551 && riscv_lookup_subset (rps
->subset_list
, "f"))
1554 (_("-march=%s: rv32e does not support the `f' extension"),
1559 if (riscv_lookup_subset (rps
->subset_list
, "d")
1560 && !riscv_lookup_subset (rps
->subset_list
, "f"))
1563 (_("-march=%s: `d' extension requires `f' extension"),
1568 if (riscv_lookup_subset (rps
->subset_list
, "q")
1569 && !riscv_lookup_subset (rps
->subset_list
, "d"))
1572 (_("-march=%s: `q' extension requires `d' extension"),
1577 if (riscv_lookup_subset (rps
->subset_list
, "q") && *rps
->xlen
< 64)
1580 (_("-march=%s: rv32 does not support the `q' extension"),
1587 /* Add new subset to list. */
1590 riscv_add_subset (riscv_subset_list_t
*subset_list
,
1595 riscv_subset_t
*s
= xmalloc (sizeof *s
);
1597 if (subset_list
->head
== NULL
)
1598 subset_list
->head
= s
;
1600 s
->name
= xstrdup (subset
);
1601 s
->major_version
= major
;
1602 s
->minor_version
= minor
;
1605 if (subset_list
->tail
!= NULL
)
1606 subset_list
->tail
->next
= s
;
1608 subset_list
->tail
= s
;
1611 /* Find subset in list without version checking, return NULL if not found. */
1614 riscv_lookup_subset (const riscv_subset_list_t
*subset_list
,
1617 return riscv_lookup_subset_version
1618 (subset_list
, subset
,
1619 RISCV_DONT_CARE_VERSION
,
1620 RISCV_DONT_CARE_VERSION
);
1623 /* Find subset in list with version checking, return NULL if not found. */
1626 riscv_lookup_subset_version (const riscv_subset_list_t
*subset_list
,
1628 int major
, int minor
)
1632 for (s
= subset_list
->head
; s
!= NULL
; s
= s
->next
)
1633 if (strcasecmp (s
->name
, subset
) == 0)
1635 if ((major
!= RISCV_DONT_CARE_VERSION
)
1636 && (s
->major_version
!= major
))
1639 if ((minor
!= RISCV_DONT_CARE_VERSION
)
1640 && (s
->minor_version
!= minor
))
1649 /* Release subset list. */
1652 riscv_release_subset_list (riscv_subset_list_t
*subset_list
)
1654 while (subset_list
->head
!= NULL
)
1656 riscv_subset_t
*next
= subset_list
->head
->next
;
1657 free ((void *)subset_list
->head
->name
);
1658 free (subset_list
->head
);
1659 subset_list
->head
= next
;
1662 subset_list
->tail
= NULL
;
1665 /* Return the number of digits for the input. */
1668 riscv_estimate_digit (unsigned num
)
1674 for (digit
= 0; num
; num
/= 10)
1680 /* Auxiliary function to estimate string length of subset list. */
1683 riscv_estimate_arch_strlen1 (const riscv_subset_t
*subset
)
1686 return 6; /* For rv32/rv64/rv128 and string terminator. */
1688 return riscv_estimate_arch_strlen1 (subset
->next
)
1689 + strlen (subset
->name
)
1690 + riscv_estimate_digit (subset
->major_version
)
1691 + 1 /* For version seperator: 'p'. */
1692 + riscv_estimate_digit (subset
->minor_version
)
1693 + 1 /* For underscore. */;
1696 /* Estimate the string length of this subset list. */
1699 riscv_estimate_arch_strlen (const riscv_subset_list_t
*subset_list
)
1701 return riscv_estimate_arch_strlen1 (subset_list
->head
);
1704 /* Auxiliary function to convert subset info to string. */
1707 riscv_arch_str1 (riscv_subset_t
*subset
,
1708 char *attr_str
, char *buf
, size_t bufsz
)
1710 const char *underline
= "_";
1715 /* No underline between rvXX and i/e. */
1716 if ((strcasecmp (subset
->name
, "i") == 0)
1717 || (strcasecmp (subset
->name
, "e") == 0))
1720 snprintf (buf
, bufsz
, "%s%s%dp%d",
1723 subset
->major_version
,
1724 subset
->minor_version
);
1726 strncat (attr_str
, buf
, bufsz
);
1728 /* Skip 'i' extension after 'e'. */
1729 if ((strcasecmp (subset
->name
, "e") == 0)
1731 && (strcasecmp (subset
->next
->name
, "i") == 0))
1732 riscv_arch_str1 (subset
->next
->next
, attr_str
, buf
, bufsz
);
1734 riscv_arch_str1 (subset
->next
, attr_str
, buf
, bufsz
);
1737 /* Convert subset info to string with explicit version info. */
1740 riscv_arch_str (unsigned xlen
, const riscv_subset_list_t
*subset
)
1742 size_t arch_str_len
= riscv_estimate_arch_strlen (subset
);
1743 char *attr_str
= xmalloc (arch_str_len
);
1744 char *buf
= xmalloc (arch_str_len
);
1746 snprintf (attr_str
, arch_str_len
, "rv%u", xlen
);
1748 riscv_arch_str1 (subset
->head
, attr_str
, buf
, arch_str_len
);