RISC-V: Comments tidy and improvement.
[deliverable/binutils-gdb.git] / bfd / elfxx-riscv.c
1 /* RISC-V-specific support for ELF.
2 Copyright (C) 2011-2021 Free Software Foundation, Inc.
3
4 Contributed by Andrew Waterman (andrew@sifive.com).
5 Based on TILE-Gx and MIPS targets.
6
7 This file is part of BFD, the Binary File Descriptor library.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; see the file COPYING3. If not,
21 see <http://www.gnu.org/licenses/>. */
22
23 #include "sysdep.h"
24 #include "bfd.h"
25 #include "libbfd.h"
26 #include "elf-bfd.h"
27 #include "elf/riscv.h"
28 #include "libiberty.h"
29 #include "elfxx-riscv.h"
30 #include "safe-ctype.h"
31
32 #define MINUS_ONE ((bfd_vma)0 - 1)
33
34 /* Special handler for ADD/SUB relocations that allows them to be filled out
35 both in the pre-linked and post-linked file. This is necessary to make
36 pre-linked debug info work, as due to linker relaxations we need to emit
37 relocations for the debug info. */
38 static bfd_reloc_status_type riscv_elf_add_sub_reloc
39 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
40
41 /* The relocation table used for SHT_RELA sections. */
42
43 static reloc_howto_type howto_table[] =
44 {
45 /* No relocation. */
46 HOWTO (R_RISCV_NONE, /* type */
47 0, /* rightshift */
48 3, /* size */
49 0, /* bitsize */
50 FALSE, /* pc_relative */
51 0, /* bitpos */
52 complain_overflow_dont, /* complain_on_overflow */
53 bfd_elf_generic_reloc, /* special_function */
54 "R_RISCV_NONE", /* name */
55 FALSE, /* partial_inplace */
56 0, /* src_mask */
57 0, /* dst_mask */
58 FALSE), /* pcrel_offset */
59
60 /* 32 bit relocation. */
61 HOWTO (R_RISCV_32, /* type */
62 0, /* rightshift */
63 2, /* size */
64 32, /* bitsize */
65 FALSE, /* pc_relative */
66 0, /* bitpos */
67 complain_overflow_dont, /* complain_on_overflow */
68 bfd_elf_generic_reloc, /* special_function */
69 "R_RISCV_32", /* name */
70 FALSE, /* partial_inplace */
71 0, /* src_mask */
72 0xffffffff, /* dst_mask */
73 FALSE), /* pcrel_offset */
74
75 /* 64 bit relocation. */
76 HOWTO (R_RISCV_64, /* type */
77 0, /* rightshift */
78 4, /* size */
79 64, /* bitsize */
80 FALSE, /* pc_relative */
81 0, /* bitpos */
82 complain_overflow_dont, /* complain_on_overflow */
83 bfd_elf_generic_reloc, /* special_function */
84 "R_RISCV_64", /* name */
85 FALSE, /* partial_inplace */
86 0, /* src_mask */
87 MINUS_ONE, /* dst_mask */
88 FALSE), /* pcrel_offset */
89
90 /* Relocation against a local symbol in a shared object. */
91 HOWTO (R_RISCV_RELATIVE, /* type */
92 0, /* rightshift */
93 2, /* size */
94 32, /* bitsize */
95 FALSE, /* pc_relative */
96 0, /* bitpos */
97 complain_overflow_dont, /* complain_on_overflow */
98 bfd_elf_generic_reloc, /* special_function */
99 "R_RISCV_RELATIVE", /* name */
100 FALSE, /* partial_inplace */
101 0, /* src_mask */
102 0xffffffff, /* dst_mask */
103 FALSE), /* pcrel_offset */
104
105 HOWTO (R_RISCV_COPY, /* type */
106 0, /* rightshift */
107 0, /* this one is variable size */
108 0, /* bitsize */
109 FALSE, /* pc_relative */
110 0, /* bitpos */
111 complain_overflow_bitfield, /* complain_on_overflow */
112 bfd_elf_generic_reloc, /* special_function */
113 "R_RISCV_COPY", /* name */
114 FALSE, /* partial_inplace */
115 0, /* src_mask */
116 0, /* dst_mask */
117 FALSE), /* pcrel_offset */
118
119 HOWTO (R_RISCV_JUMP_SLOT, /* type */
120 0, /* rightshift */
121 4, /* size */
122 64, /* bitsize */
123 FALSE, /* pc_relative */
124 0, /* bitpos */
125 complain_overflow_bitfield, /* complain_on_overflow */
126 bfd_elf_generic_reloc, /* special_function */
127 "R_RISCV_JUMP_SLOT", /* name */
128 FALSE, /* partial_inplace */
129 0, /* src_mask */
130 0, /* dst_mask */
131 FALSE), /* pcrel_offset */
132
133 /* Dynamic TLS relocations. */
134 HOWTO (R_RISCV_TLS_DTPMOD32, /* type */
135 0, /* rightshift */
136 2, /* size */
137 32, /* bitsize */
138 FALSE, /* pc_relative */
139 0, /* bitpos */
140 complain_overflow_dont, /* complain_on_overflow */
141 bfd_elf_generic_reloc, /* special_function */
142 "R_RISCV_TLS_DTPMOD32", /* name */
143 FALSE, /* partial_inplace */
144 0, /* src_mask */
145 0xffffffff, /* dst_mask */
146 FALSE), /* pcrel_offset */
147
148 HOWTO (R_RISCV_TLS_DTPMOD64, /* type */
149 0, /* rightshift */
150 4, /* size */
151 64, /* bitsize */
152 FALSE, /* pc_relative */
153 0, /* bitpos */
154 complain_overflow_dont, /* complain_on_overflow */
155 bfd_elf_generic_reloc, /* special_function */
156 "R_RISCV_TLS_DTPMOD64", /* name */
157 FALSE, /* partial_inplace */
158 0, /* src_mask */
159 MINUS_ONE, /* dst_mask */
160 FALSE), /* pcrel_offset */
161
162 HOWTO (R_RISCV_TLS_DTPREL32, /* type */
163 0, /* rightshift */
164 2, /* size */
165 32, /* bitsize */
166 FALSE, /* pc_relative */
167 0, /* bitpos */
168 complain_overflow_dont, /* complain_on_overflow */
169 bfd_elf_generic_reloc, /* special_function */
170 "R_RISCV_TLS_DTPREL32", /* name */
171 TRUE, /* partial_inplace */
172 0, /* src_mask */
173 0xffffffff, /* dst_mask */
174 FALSE), /* pcrel_offset */
175
176 HOWTO (R_RISCV_TLS_DTPREL64, /* type */
177 0, /* rightshift */
178 4, /* size */
179 64, /* bitsize */
180 FALSE, /* pc_relative */
181 0, /* bitpos */
182 complain_overflow_dont, /* complain_on_overflow */
183 bfd_elf_generic_reloc, /* special_function */
184 "R_RISCV_TLS_DTPREL64", /* name */
185 TRUE, /* partial_inplace */
186 0, /* src_mask */
187 MINUS_ONE, /* dst_mask */
188 FALSE), /* pcrel_offset */
189
190 HOWTO (R_RISCV_TLS_TPREL32, /* type */
191 0, /* rightshift */
192 2, /* size */
193 32, /* bitsize */
194 FALSE, /* pc_relative */
195 0, /* bitpos */
196 complain_overflow_dont, /* complain_on_overflow */
197 bfd_elf_generic_reloc, /* special_function */
198 "R_RISCV_TLS_TPREL32", /* name */
199 FALSE, /* partial_inplace */
200 0, /* src_mask */
201 0xffffffff, /* dst_mask */
202 FALSE), /* pcrel_offset */
203
204 HOWTO (R_RISCV_TLS_TPREL64, /* type */
205 0, /* rightshift */
206 4, /* size */
207 64, /* bitsize */
208 FALSE, /* pc_relative */
209 0, /* bitpos */
210 complain_overflow_dont, /* complain_on_overflow */
211 bfd_elf_generic_reloc, /* special_function */
212 "R_RISCV_TLS_TPREL64", /* name */
213 FALSE, /* partial_inplace */
214 0, /* src_mask */
215 MINUS_ONE, /* dst_mask */
216 FALSE), /* pcrel_offset */
217
218 /* Reserved for future relocs that the dynamic linker must understand. */
219 EMPTY_HOWTO (12),
220 EMPTY_HOWTO (13),
221 EMPTY_HOWTO (14),
222 EMPTY_HOWTO (15),
223
224 /* 12-bit PC-relative branch offset. */
225 HOWTO (R_RISCV_BRANCH, /* type */
226 0, /* rightshift */
227 2, /* size */
228 32, /* bitsize */
229 TRUE, /* pc_relative */
230 0, /* bitpos */
231 complain_overflow_signed, /* complain_on_overflow */
232 bfd_elf_generic_reloc, /* special_function */
233 "R_RISCV_BRANCH", /* name */
234 FALSE, /* partial_inplace */
235 0, /* src_mask */
236 ENCODE_SBTYPE_IMM (-1U), /* dst_mask */
237 TRUE), /* pcrel_offset */
238
239 /* 20-bit PC-relative jump offset. */
240 HOWTO (R_RISCV_JAL, /* type */
241 0, /* rightshift */
242 2, /* size */
243 32, /* bitsize */
244 TRUE, /* pc_relative */
245 0, /* bitpos */
246 complain_overflow_dont, /* complain_on_overflow */
247 bfd_elf_generic_reloc, /* special_function */
248 "R_RISCV_JAL", /* name */
249 FALSE, /* partial_inplace */
250 0, /* src_mask */
251 ENCODE_UJTYPE_IMM (-1U), /* dst_mask */
252 TRUE), /* pcrel_offset */
253
254 /* 32-bit PC-relative function call (AUIPC/JALR). */
255 HOWTO (R_RISCV_CALL, /* type */
256 0, /* rightshift */
257 4, /* size */
258 64, /* bitsize */
259 TRUE, /* pc_relative */
260 0, /* bitpos */
261 complain_overflow_dont, /* complain_on_overflow */
262 bfd_elf_generic_reloc, /* special_function */
263 "R_RISCV_CALL", /* name */
264 FALSE, /* partial_inplace */
265 0, /* src_mask */
266 ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
267 /* dst_mask */
268 TRUE), /* pcrel_offset */
269
270 /* Like R_RISCV_CALL, but not locally binding. */
271 HOWTO (R_RISCV_CALL_PLT, /* type */
272 0, /* rightshift */
273 4, /* size */
274 64, /* bitsize */
275 TRUE, /* pc_relative */
276 0, /* bitpos */
277 complain_overflow_dont, /* complain_on_overflow */
278 bfd_elf_generic_reloc, /* special_function */
279 "R_RISCV_CALL_PLT", /* name */
280 FALSE, /* partial_inplace */
281 0, /* src_mask */
282 ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
283 /* dst_mask */
284 TRUE), /* pcrel_offset */
285
286 /* High 20 bits of 32-bit PC-relative GOT access. */
287 HOWTO (R_RISCV_GOT_HI20, /* type */
288 0, /* rightshift */
289 2, /* size */
290 32, /* bitsize */
291 TRUE, /* pc_relative */
292 0, /* bitpos */
293 complain_overflow_dont, /* complain_on_overflow */
294 bfd_elf_generic_reloc, /* special_function */
295 "R_RISCV_GOT_HI20", /* name */
296 FALSE, /* partial_inplace */
297 0, /* src_mask */
298 ENCODE_UTYPE_IMM (-1U), /* dst_mask */
299 FALSE), /* pcrel_offset */
300
301 /* High 20 bits of 32-bit PC-relative TLS IE GOT access. */
302 HOWTO (R_RISCV_TLS_GOT_HI20, /* type */
303 0, /* rightshift */
304 2, /* size */
305 32, /* bitsize */
306 TRUE, /* pc_relative */
307 0, /* bitpos */
308 complain_overflow_dont, /* complain_on_overflow */
309 bfd_elf_generic_reloc, /* special_function */
310 "R_RISCV_TLS_GOT_HI20", /* name */
311 FALSE, /* partial_inplace */
312 0, /* src_mask */
313 ENCODE_UTYPE_IMM (-1U), /* dst_mask */
314 FALSE), /* pcrel_offset */
315
316 /* High 20 bits of 32-bit PC-relative TLS GD GOT reference. */
317 HOWTO (R_RISCV_TLS_GD_HI20, /* type */
318 0, /* rightshift */
319 2, /* size */
320 32, /* bitsize */
321 TRUE, /* pc_relative */
322 0, /* bitpos */
323 complain_overflow_dont, /* complain_on_overflow */
324 bfd_elf_generic_reloc, /* special_function */
325 "R_RISCV_TLS_GD_HI20", /* name */
326 FALSE, /* partial_inplace */
327 0, /* src_mask */
328 ENCODE_UTYPE_IMM (-1U), /* dst_mask */
329 FALSE), /* pcrel_offset */
330
331 /* High 20 bits of 32-bit PC-relative reference. */
332 HOWTO (R_RISCV_PCREL_HI20, /* type */
333 0, /* rightshift */
334 2, /* size */
335 32, /* bitsize */
336 TRUE, /* pc_relative */
337 0, /* bitpos */
338 complain_overflow_dont, /* complain_on_overflow */
339 bfd_elf_generic_reloc, /* special_function */
340 "R_RISCV_PCREL_HI20", /* name */
341 FALSE, /* partial_inplace */
342 0, /* src_mask */
343 ENCODE_UTYPE_IMM (-1U), /* dst_mask */
344 TRUE), /* pcrel_offset */
345
346 /* Low 12 bits of a 32-bit PC-relative load or add. */
347 HOWTO (R_RISCV_PCREL_LO12_I, /* type */
348 0, /* rightshift */
349 2, /* size */
350 32, /* bitsize */
351 FALSE, /* pc_relative */
352 0, /* bitpos */
353 complain_overflow_dont, /* complain_on_overflow */
354 bfd_elf_generic_reloc, /* special_function */
355 "R_RISCV_PCREL_LO12_I", /* name */
356 FALSE, /* partial_inplace */
357 0, /* src_mask */
358 ENCODE_ITYPE_IMM (-1U), /* dst_mask */
359 FALSE), /* pcrel_offset */
360
361 /* Low 12 bits of a 32-bit PC-relative store. */
362 HOWTO (R_RISCV_PCREL_LO12_S, /* type */
363 0, /* rightshift */
364 2, /* size */
365 32, /* bitsize */
366 FALSE, /* pc_relative */
367 0, /* bitpos */
368 complain_overflow_dont, /* complain_on_overflow */
369 bfd_elf_generic_reloc, /* special_function */
370 "R_RISCV_PCREL_LO12_S", /* name */
371 FALSE, /* partial_inplace */
372 0, /* src_mask */
373 ENCODE_STYPE_IMM (-1U), /* dst_mask */
374 FALSE), /* pcrel_offset */
375
376 /* High 20 bits of 32-bit absolute address. */
377 HOWTO (R_RISCV_HI20, /* type */
378 0, /* rightshift */
379 2, /* size */
380 32, /* bitsize */
381 FALSE, /* pc_relative */
382 0, /* bitpos */
383 complain_overflow_dont, /* complain_on_overflow */
384 bfd_elf_generic_reloc, /* special_function */
385 "R_RISCV_HI20", /* name */
386 FALSE, /* partial_inplace */
387 0, /* src_mask */
388 ENCODE_UTYPE_IMM (-1U), /* dst_mask */
389 FALSE), /* pcrel_offset */
390
391 /* High 12 bits of 32-bit load or add. */
392 HOWTO (R_RISCV_LO12_I, /* type */
393 0, /* rightshift */
394 2, /* size */
395 32, /* bitsize */
396 FALSE, /* pc_relative */
397 0, /* bitpos */
398 complain_overflow_dont, /* complain_on_overflow */
399 bfd_elf_generic_reloc, /* special_function */
400 "R_RISCV_LO12_I", /* name */
401 FALSE, /* partial_inplace */
402 0, /* src_mask */
403 ENCODE_ITYPE_IMM (-1U), /* dst_mask */
404 FALSE), /* pcrel_offset */
405
406 /* High 12 bits of 32-bit store. */
407 HOWTO (R_RISCV_LO12_S, /* type */
408 0, /* rightshift */
409 2, /* size */
410 32, /* bitsize */
411 FALSE, /* pc_relative */
412 0, /* bitpos */
413 complain_overflow_dont, /* complain_on_overflow */
414 bfd_elf_generic_reloc, /* special_function */
415 "R_RISCV_LO12_S", /* name */
416 FALSE, /* partial_inplace */
417 0, /* src_mask */
418 ENCODE_STYPE_IMM (-1U), /* dst_mask */
419 FALSE), /* pcrel_offset */
420
421 /* High 20 bits of TLS LE thread pointer offset. */
422 HOWTO (R_RISCV_TPREL_HI20, /* type */
423 0, /* rightshift */
424 2, /* size */
425 32, /* bitsize */
426 FALSE, /* pc_relative */
427 0, /* bitpos */
428 complain_overflow_signed, /* complain_on_overflow */
429 bfd_elf_generic_reloc, /* special_function */
430 "R_RISCV_TPREL_HI20", /* name */
431 TRUE, /* partial_inplace */
432 0, /* src_mask */
433 ENCODE_UTYPE_IMM (-1U), /* dst_mask */
434 FALSE), /* pcrel_offset */
435
436 /* Low 12 bits of TLS LE thread pointer offset for loads and adds. */
437 HOWTO (R_RISCV_TPREL_LO12_I, /* type */
438 0, /* rightshift */
439 2, /* size */
440 32, /* bitsize */
441 FALSE, /* pc_relative */
442 0, /* bitpos */
443 complain_overflow_signed, /* complain_on_overflow */
444 bfd_elf_generic_reloc, /* special_function */
445 "R_RISCV_TPREL_LO12_I", /* name */
446 FALSE, /* partial_inplace */
447 0, /* src_mask */
448 ENCODE_ITYPE_IMM (-1U), /* dst_mask */
449 FALSE), /* pcrel_offset */
450
451 /* Low 12 bits of TLS LE thread pointer offset for stores. */
452 HOWTO (R_RISCV_TPREL_LO12_S, /* type */
453 0, /* rightshift */
454 2, /* size */
455 32, /* bitsize */
456 FALSE, /* pc_relative */
457 0, /* bitpos */
458 complain_overflow_signed, /* complain_on_overflow */
459 bfd_elf_generic_reloc, /* special_function */
460 "R_RISCV_TPREL_LO12_S", /* name */
461 FALSE, /* partial_inplace */
462 0, /* src_mask */
463 ENCODE_STYPE_IMM (-1U), /* dst_mask */
464 FALSE), /* pcrel_offset */
465
466 /* TLS LE thread pointer usage. May be relaxed. */
467 HOWTO (R_RISCV_TPREL_ADD, /* type */
468 0, /* rightshift */
469 3, /* size */
470 0, /* bitsize */
471 FALSE, /* pc_relative */
472 0, /* bitpos */
473 complain_overflow_dont, /* complain_on_overflow */
474 bfd_elf_generic_reloc, /* special_function */
475 "R_RISCV_TPREL_ADD", /* name */
476 FALSE, /* partial_inplace */
477 0, /* src_mask */
478 0, /* dst_mask */
479 FALSE), /* pcrel_offset */
480
481 /* 8-bit in-place addition, for local label subtraction. */
482 HOWTO (R_RISCV_ADD8, /* type */
483 0, /* rightshift */
484 0, /* size */
485 8, /* bitsize */
486 FALSE, /* pc_relative */
487 0, /* bitpos */
488 complain_overflow_dont, /* complain_on_overflow */
489 riscv_elf_add_sub_reloc, /* special_function */
490 "R_RISCV_ADD8", /* name */
491 FALSE, /* partial_inplace */
492 0, /* src_mask */
493 0xff, /* dst_mask */
494 FALSE), /* pcrel_offset */
495
496 /* 16-bit in-place addition, for local label subtraction. */
497 HOWTO (R_RISCV_ADD16, /* type */
498 0, /* rightshift */
499 1, /* size */
500 16, /* bitsize */
501 FALSE, /* pc_relative */
502 0, /* bitpos */
503 complain_overflow_dont, /* complain_on_overflow */
504 riscv_elf_add_sub_reloc, /* special_function */
505 "R_RISCV_ADD16", /* name */
506 FALSE, /* partial_inplace */
507 0, /* src_mask */
508 0xffff, /* dst_mask */
509 FALSE), /* pcrel_offset */
510
511 /* 32-bit in-place addition, for local label subtraction. */
512 HOWTO (R_RISCV_ADD32, /* type */
513 0, /* rightshift */
514 2, /* size */
515 32, /* bitsize */
516 FALSE, /* pc_relative */
517 0, /* bitpos */
518 complain_overflow_dont, /* complain_on_overflow */
519 riscv_elf_add_sub_reloc, /* special_function */
520 "R_RISCV_ADD32", /* name */
521 FALSE, /* partial_inplace */
522 0, /* src_mask */
523 0xffffffff, /* dst_mask */
524 FALSE), /* pcrel_offset */
525
526 /* 64-bit in-place addition, for local label subtraction. */
527 HOWTO (R_RISCV_ADD64, /* type */
528 0, /* rightshift */
529 4, /* size */
530 64, /* bitsize */
531 FALSE, /* pc_relative */
532 0, /* bitpos */
533 complain_overflow_dont, /* complain_on_overflow */
534 riscv_elf_add_sub_reloc, /* special_function */
535 "R_RISCV_ADD64", /* name */
536 FALSE, /* partial_inplace */
537 0, /* src_mask */
538 MINUS_ONE, /* dst_mask */
539 FALSE), /* pcrel_offset */
540
541 /* 8-bit in-place addition, for local label subtraction. */
542 HOWTO (R_RISCV_SUB8, /* type */
543 0, /* rightshift */
544 0, /* size */
545 8, /* bitsize */
546 FALSE, /* pc_relative */
547 0, /* bitpos */
548 complain_overflow_dont, /* complain_on_overflow */
549 riscv_elf_add_sub_reloc, /* special_function */
550 "R_RISCV_SUB8", /* name */
551 FALSE, /* partial_inplace */
552 0, /* src_mask */
553 0xff, /* dst_mask */
554 FALSE), /* pcrel_offset */
555
556 /* 16-bit in-place addition, for local label subtraction. */
557 HOWTO (R_RISCV_SUB16, /* type */
558 0, /* rightshift */
559 1, /* size */
560 16, /* bitsize */
561 FALSE, /* pc_relative */
562 0, /* bitpos */
563 complain_overflow_dont, /* complain_on_overflow */
564 riscv_elf_add_sub_reloc, /* special_function */
565 "R_RISCV_SUB16", /* name */
566 FALSE, /* partial_inplace */
567 0, /* src_mask */
568 0xffff, /* dst_mask */
569 FALSE), /* pcrel_offset */
570
571 /* 32-bit in-place addition, for local label subtraction. */
572 HOWTO (R_RISCV_SUB32, /* type */
573 0, /* rightshift */
574 2, /* size */
575 32, /* bitsize */
576 FALSE, /* pc_relative */
577 0, /* bitpos */
578 complain_overflow_dont, /* complain_on_overflow */
579 riscv_elf_add_sub_reloc, /* special_function */
580 "R_RISCV_SUB32", /* name */
581 FALSE, /* partial_inplace */
582 0, /* src_mask */
583 0xffffffff, /* dst_mask */
584 FALSE), /* pcrel_offset */
585
586 /* 64-bit in-place addition, for local label subtraction. */
587 HOWTO (R_RISCV_SUB64, /* type */
588 0, /* rightshift */
589 4, /* size */
590 64, /* bitsize */
591 FALSE, /* pc_relative */
592 0, /* bitpos */
593 complain_overflow_dont, /* complain_on_overflow */
594 riscv_elf_add_sub_reloc, /* special_function */
595 "R_RISCV_SUB64", /* name */
596 FALSE, /* partial_inplace */
597 0, /* src_mask */
598 MINUS_ONE, /* dst_mask */
599 FALSE), /* pcrel_offset */
600
601 /* GNU extension to record C++ vtable hierarchy */
602 HOWTO (R_RISCV_GNU_VTINHERIT, /* type */
603 0, /* rightshift */
604 4, /* size */
605 0, /* bitsize */
606 FALSE, /* pc_relative */
607 0, /* bitpos */
608 complain_overflow_dont, /* complain_on_overflow */
609 NULL, /* special_function */
610 "R_RISCV_GNU_VTINHERIT", /* name */
611 FALSE, /* partial_inplace */
612 0, /* src_mask */
613 0, /* dst_mask */
614 FALSE), /* pcrel_offset */
615
616 /* GNU extension to record C++ vtable member usage */
617 HOWTO (R_RISCV_GNU_VTENTRY, /* type */
618 0, /* rightshift */
619 4, /* size */
620 0, /* bitsize */
621 FALSE, /* pc_relative */
622 0, /* bitpos */
623 complain_overflow_dont, /* complain_on_overflow */
624 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
625 "R_RISCV_GNU_VTENTRY", /* name */
626 FALSE, /* partial_inplace */
627 0, /* src_mask */
628 0, /* dst_mask */
629 FALSE), /* pcrel_offset */
630
631 /* Indicates an alignment statement. The addend field encodes how many
632 bytes of NOPs follow the statement. The desired alignment is the
633 addend rounded up to the next power of two. */
634 HOWTO (R_RISCV_ALIGN, /* type */
635 0, /* rightshift */
636 3, /* size */
637 0, /* bitsize */
638 FALSE, /* pc_relative */
639 0, /* bitpos */
640 complain_overflow_dont, /* complain_on_overflow */
641 bfd_elf_generic_reloc, /* special_function */
642 "R_RISCV_ALIGN", /* name */
643 FALSE, /* partial_inplace */
644 0, /* src_mask */
645 0, /* dst_mask */
646 FALSE), /* pcrel_offset */
647
648 /* 8-bit PC-relative branch offset. */
649 HOWTO (R_RISCV_RVC_BRANCH, /* type */
650 0, /* rightshift */
651 1, /* size */
652 16, /* bitsize */
653 TRUE, /* pc_relative */
654 0, /* bitpos */
655 complain_overflow_signed, /* complain_on_overflow */
656 bfd_elf_generic_reloc, /* special_function */
657 "R_RISCV_RVC_BRANCH", /* name */
658 FALSE, /* partial_inplace */
659 0, /* src_mask */
660 ENCODE_RVC_B_IMM (-1U), /* dst_mask */
661 TRUE), /* pcrel_offset */
662
663 /* 11-bit PC-relative jump offset. */
664 HOWTO (R_RISCV_RVC_JUMP, /* type */
665 0, /* rightshift */
666 1, /* size */
667 16, /* bitsize */
668 TRUE, /* pc_relative */
669 0, /* bitpos */
670 complain_overflow_dont, /* complain_on_overflow */
671 bfd_elf_generic_reloc, /* special_function */
672 "R_RISCV_RVC_JUMP", /* name */
673 FALSE, /* partial_inplace */
674 0, /* src_mask */
675 ENCODE_RVC_J_IMM (-1U), /* dst_mask */
676 TRUE), /* pcrel_offset */
677
678 /* High 6 bits of 18-bit absolute address. */
679 HOWTO (R_RISCV_RVC_LUI, /* type */
680 0, /* rightshift */
681 1, /* size */
682 16, /* bitsize */
683 FALSE, /* pc_relative */
684 0, /* bitpos */
685 complain_overflow_dont, /* complain_on_overflow */
686 bfd_elf_generic_reloc, /* special_function */
687 "R_RISCV_RVC_LUI", /* name */
688 FALSE, /* partial_inplace */
689 0, /* src_mask */
690 ENCODE_RVC_IMM (-1U), /* dst_mask */
691 FALSE), /* pcrel_offset */
692
693 /* GP-relative load. */
694 HOWTO (R_RISCV_GPREL_I, /* type */
695 0, /* rightshift */
696 2, /* size */
697 32, /* bitsize */
698 FALSE, /* pc_relative */
699 0, /* bitpos */
700 complain_overflow_dont, /* complain_on_overflow */
701 bfd_elf_generic_reloc, /* special_function */
702 "R_RISCV_GPREL_I", /* name */
703 FALSE, /* partial_inplace */
704 0, /* src_mask */
705 ENCODE_ITYPE_IMM (-1U), /* dst_mask */
706 FALSE), /* pcrel_offset */
707
708 /* GP-relative store. */
709 HOWTO (R_RISCV_GPREL_S, /* type */
710 0, /* rightshift */
711 2, /* size */
712 32, /* bitsize */
713 FALSE, /* pc_relative */
714 0, /* bitpos */
715 complain_overflow_dont, /* complain_on_overflow */
716 bfd_elf_generic_reloc, /* special_function */
717 "R_RISCV_GPREL_S", /* name */
718 FALSE, /* partial_inplace */
719 0, /* src_mask */
720 ENCODE_STYPE_IMM (-1U), /* dst_mask */
721 FALSE), /* pcrel_offset */
722
723 /* TP-relative TLS LE load. */
724 HOWTO (R_RISCV_TPREL_I, /* type */
725 0, /* rightshift */
726 2, /* size */
727 32, /* bitsize */
728 FALSE, /* pc_relative */
729 0, /* bitpos */
730 complain_overflow_signed, /* complain_on_overflow */
731 bfd_elf_generic_reloc, /* special_function */
732 "R_RISCV_TPREL_I", /* name */
733 FALSE, /* partial_inplace */
734 0, /* src_mask */
735 ENCODE_ITYPE_IMM (-1U), /* dst_mask */
736 FALSE), /* pcrel_offset */
737
738 /* TP-relative TLS LE store. */
739 HOWTO (R_RISCV_TPREL_S, /* type */
740 0, /* rightshift */
741 2, /* size */
742 32, /* bitsize */
743 FALSE, /* pc_relative */
744 0, /* bitpos */
745 complain_overflow_signed, /* complain_on_overflow */
746 bfd_elf_generic_reloc, /* special_function */
747 "R_RISCV_TPREL_S", /* name */
748 FALSE, /* partial_inplace */
749 0, /* src_mask */
750 ENCODE_STYPE_IMM (-1U), /* dst_mask */
751 FALSE), /* pcrel_offset */
752
753 /* The paired relocation may be relaxed. */
754 HOWTO (R_RISCV_RELAX, /* type */
755 0, /* rightshift */
756 3, /* size */
757 0, /* bitsize */
758 FALSE, /* pc_relative */
759 0, /* bitpos */
760 complain_overflow_dont, /* complain_on_overflow */
761 bfd_elf_generic_reloc, /* special_function */
762 "R_RISCV_RELAX", /* name */
763 FALSE, /* partial_inplace */
764 0, /* src_mask */
765 0, /* dst_mask */
766 FALSE), /* pcrel_offset */
767
768 /* 6-bit in-place addition, for local label subtraction. */
769 HOWTO (R_RISCV_SUB6, /* type */
770 0, /* rightshift */
771 0, /* size */
772 8, /* bitsize */
773 FALSE, /* pc_relative */
774 0, /* bitpos */
775 complain_overflow_dont, /* complain_on_overflow */
776 riscv_elf_add_sub_reloc, /* special_function */
777 "R_RISCV_SUB6", /* name */
778 FALSE, /* partial_inplace */
779 0, /* src_mask */
780 0x3f, /* dst_mask */
781 FALSE), /* pcrel_offset */
782
783 /* 6-bit in-place setting, for local label subtraction. */
784 HOWTO (R_RISCV_SET6, /* type */
785 0, /* rightshift */
786 0, /* size */
787 8, /* bitsize */
788 FALSE, /* pc_relative */
789 0, /* bitpos */
790 complain_overflow_dont, /* complain_on_overflow */
791 bfd_elf_generic_reloc, /* special_function */
792 "R_RISCV_SET6", /* name */
793 FALSE, /* partial_inplace */
794 0, /* src_mask */
795 0x3f, /* dst_mask */
796 FALSE), /* pcrel_offset */
797
798 /* 8-bit in-place setting, for local label subtraction. */
799 HOWTO (R_RISCV_SET8, /* type */
800 0, /* rightshift */
801 0, /* size */
802 8, /* bitsize */
803 FALSE, /* pc_relative */
804 0, /* bitpos */
805 complain_overflow_dont, /* complain_on_overflow */
806 bfd_elf_generic_reloc, /* special_function */
807 "R_RISCV_SET8", /* name */
808 FALSE, /* partial_inplace */
809 0, /* src_mask */
810 0xff, /* dst_mask */
811 FALSE), /* pcrel_offset */
812
813 /* 16-bit in-place setting, for local label subtraction. */
814 HOWTO (R_RISCV_SET16, /* type */
815 0, /* rightshift */
816 1, /* size */
817 16, /* bitsize */
818 FALSE, /* pc_relative */
819 0, /* bitpos */
820 complain_overflow_dont, /* complain_on_overflow */
821 bfd_elf_generic_reloc, /* special_function */
822 "R_RISCV_SET16", /* name */
823 FALSE, /* partial_inplace */
824 0, /* src_mask */
825 0xffff, /* dst_mask */
826 FALSE), /* pcrel_offset */
827
828 /* 32-bit in-place setting, for local label subtraction. */
829 HOWTO (R_RISCV_SET32, /* type */
830 0, /* rightshift */
831 2, /* size */
832 32, /* bitsize */
833 FALSE, /* pc_relative */
834 0, /* bitpos */
835 complain_overflow_dont, /* complain_on_overflow */
836 bfd_elf_generic_reloc, /* special_function */
837 "R_RISCV_SET32", /* name */
838 FALSE, /* partial_inplace */
839 0, /* src_mask */
840 0xffffffff, /* dst_mask */
841 FALSE), /* pcrel_offset */
842
843 /* 32-bit PC relative. */
844 HOWTO (R_RISCV_32_PCREL, /* type */
845 0, /* rightshift */
846 2, /* size */
847 32, /* bitsize */
848 TRUE, /* pc_relative */
849 0, /* bitpos */
850 complain_overflow_dont, /* complain_on_overflow */
851 bfd_elf_generic_reloc, /* special_function */
852 "R_RISCV_32_PCREL", /* name */
853 FALSE, /* partial_inplace */
854 0, /* src_mask */
855 0xffffffff, /* dst_mask */
856 FALSE), /* pcrel_offset */
857
858 /* Relocation against a local ifunc symbol in a shared object. */
859 HOWTO (R_RISCV_IRELATIVE, /* type */
860 0, /* rightshift */
861 2, /* size */
862 32, /* bitsize */
863 FALSE, /* pc_relative */
864 0, /* bitpos */
865 complain_overflow_dont, /* complain_on_overflow */
866 bfd_elf_generic_reloc, /* special_function */
867 "R_RISCV_IRELATIVE", /* name */
868 FALSE, /* partial_inplace */
869 0, /* src_mask */
870 0xffffffff, /* dst_mask */
871 FALSE), /* pcrel_offset */
872 };
873
874 /* A mapping from BFD reloc types to RISC-V ELF reloc types. */
875 struct elf_reloc_map
876 {
877 bfd_reloc_code_real_type bfd_val;
878 enum elf_riscv_reloc_type elf_val;
879 };
880
881 static const struct elf_reloc_map riscv_reloc_map[] =
882 {
883 { BFD_RELOC_NONE, R_RISCV_NONE },
884 { BFD_RELOC_32, R_RISCV_32 },
885 { BFD_RELOC_64, R_RISCV_64 },
886 { BFD_RELOC_RISCV_ADD8, R_RISCV_ADD8 },
887 { BFD_RELOC_RISCV_ADD16, R_RISCV_ADD16 },
888 { BFD_RELOC_RISCV_ADD32, R_RISCV_ADD32 },
889 { BFD_RELOC_RISCV_ADD64, R_RISCV_ADD64 },
890 { BFD_RELOC_RISCV_SUB8, R_RISCV_SUB8 },
891 { BFD_RELOC_RISCV_SUB16, R_RISCV_SUB16 },
892 { BFD_RELOC_RISCV_SUB32, R_RISCV_SUB32 },
893 { BFD_RELOC_RISCV_SUB64, R_RISCV_SUB64 },
894 { BFD_RELOC_CTOR, R_RISCV_64 },
895 { BFD_RELOC_12_PCREL, R_RISCV_BRANCH },
896 { BFD_RELOC_RISCV_HI20, R_RISCV_HI20 },
897 { BFD_RELOC_RISCV_LO12_I, R_RISCV_LO12_I },
898 { BFD_RELOC_RISCV_LO12_S, R_RISCV_LO12_S },
899 { BFD_RELOC_RISCV_PCREL_LO12_I, R_RISCV_PCREL_LO12_I },
900 { BFD_RELOC_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_S },
901 { BFD_RELOC_RISCV_CALL, R_RISCV_CALL },
902 { BFD_RELOC_RISCV_CALL_PLT, R_RISCV_CALL_PLT },
903 { BFD_RELOC_RISCV_PCREL_HI20, R_RISCV_PCREL_HI20 },
904 { BFD_RELOC_RISCV_JMP, R_RISCV_JAL },
905 { BFD_RELOC_RISCV_GOT_HI20, R_RISCV_GOT_HI20 },
906 { BFD_RELOC_RISCV_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 },
907 { BFD_RELOC_RISCV_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 },
908 { BFD_RELOC_RISCV_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 },
909 { BFD_RELOC_RISCV_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 },
910 { BFD_RELOC_RISCV_TLS_TPREL32, R_RISCV_TLS_TPREL32 },
911 { BFD_RELOC_RISCV_TLS_TPREL64, R_RISCV_TLS_TPREL64 },
912 { BFD_RELOC_RISCV_TPREL_HI20, R_RISCV_TPREL_HI20 },
913 { BFD_RELOC_RISCV_TPREL_ADD, R_RISCV_TPREL_ADD },
914 { BFD_RELOC_RISCV_TPREL_LO12_S, R_RISCV_TPREL_LO12_S },
915 { BFD_RELOC_RISCV_TPREL_LO12_I, R_RISCV_TPREL_LO12_I },
916 { BFD_RELOC_RISCV_TLS_GOT_HI20, R_RISCV_TLS_GOT_HI20 },
917 { BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 },
918 { BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN },
919 { BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH },
920 { BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP },
921 { BFD_RELOC_RISCV_RVC_LUI, R_RISCV_RVC_LUI },
922 { BFD_RELOC_RISCV_GPREL_I, R_RISCV_GPREL_I },
923 { BFD_RELOC_RISCV_GPREL_S, R_RISCV_GPREL_S },
924 { BFD_RELOC_RISCV_TPREL_I, R_RISCV_TPREL_I },
925 { BFD_RELOC_RISCV_TPREL_S, R_RISCV_TPREL_S },
926 { BFD_RELOC_RISCV_RELAX, R_RISCV_RELAX },
927 { BFD_RELOC_RISCV_SUB6, R_RISCV_SUB6 },
928 { BFD_RELOC_RISCV_SET6, R_RISCV_SET6 },
929 { BFD_RELOC_RISCV_SET8, R_RISCV_SET8 },
930 { BFD_RELOC_RISCV_SET16, R_RISCV_SET16 },
931 { BFD_RELOC_RISCV_SET32, R_RISCV_SET32 },
932 { BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL },
933 };
934
935 /* Given a BFD reloc type, return a howto structure. */
936
937 reloc_howto_type *
938 riscv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
939 bfd_reloc_code_real_type code)
940 {
941 unsigned int i;
942
943 for (i = 0; i < ARRAY_SIZE (riscv_reloc_map); i++)
944 if (riscv_reloc_map[i].bfd_val == code)
945 return &howto_table[(int) riscv_reloc_map[i].elf_val];
946
947 bfd_set_error (bfd_error_bad_value);
948 return NULL;
949 }
950
951 reloc_howto_type *
952 riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
953 {
954 unsigned int i;
955
956 for (i = 0; i < ARRAY_SIZE (howto_table); i++)
957 if (howto_table[i].name && strcasecmp (howto_table[i].name, r_name) == 0)
958 return &howto_table[i];
959
960 return NULL;
961 }
962
963 reloc_howto_type *
964 riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type)
965 {
966 if (r_type >= ARRAY_SIZE (howto_table))
967 {
968 (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"),
969 abfd, r_type);
970 bfd_set_error (bfd_error_bad_value);
971 return NULL;
972 }
973 return &howto_table[r_type];
974 }
975
976 /* Special_function of RISCV_ADD and RISCV_SUB relocations. */
977
978 static bfd_reloc_status_type
979 riscv_elf_add_sub_reloc (bfd *abfd,
980 arelent *reloc_entry,
981 asymbol *symbol,
982 void *data,
983 asection *input_section,
984 bfd *output_bfd,
985 char **error_message ATTRIBUTE_UNUSED)
986 {
987 reloc_howto_type *howto = reloc_entry->howto;
988 bfd_vma relocation;
989
990 if (output_bfd != NULL
991 && (symbol->flags & BSF_SECTION_SYM) == 0
992 && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0))
993 {
994 reloc_entry->address += input_section->output_offset;
995 return bfd_reloc_ok;
996 }
997
998 if (output_bfd != NULL)
999 return bfd_reloc_continue;
1000
1001 relocation = symbol->value + symbol->section->output_section->vma
1002 + symbol->section->output_offset + reloc_entry->addend;
1003 bfd_vma old_value = bfd_get (howto->bitsize, abfd,
1004 data + reloc_entry->address);
1005
1006 switch (howto->type)
1007 {
1008 case R_RISCV_ADD8:
1009 case R_RISCV_ADD16:
1010 case R_RISCV_ADD32:
1011 case R_RISCV_ADD64:
1012 relocation = old_value + relocation;
1013 break;
1014 case R_RISCV_SUB6:
1015 case R_RISCV_SUB8:
1016 case R_RISCV_SUB16:
1017 case R_RISCV_SUB32:
1018 case R_RISCV_SUB64:
1019 relocation = old_value - relocation;
1020 break;
1021 }
1022 bfd_put (howto->bitsize, abfd, relocation, data + reloc_entry->address);
1023
1024 return bfd_reloc_ok;
1025 }
1026
1027 /* Array is used to compare the orders of all extensions quickly.
1028
1029 Zero value: Preserved keyword.
1030 Negative value: Prefixed keyword (s, h, x, z).
1031 Positive value: Standard extension. */
1032
1033 static int riscv_ext_order[26] = {0};
1034
1035 /* Similar to the strcmp. It returns an integer less than, equal to,
1036 or greater than zero if `subset2` is found, respectively, to be less
1037 than, to match, or be greater than `subset1`. */
1038
1039 int
1040 riscv_compare_subsets (const char *subset1, const char *subset2)
1041 {
1042 int order1 = riscv_ext_order[(*subset1 - 'a')];
1043 int order2 = riscv_ext_order[(*subset2 - 'a')];
1044
1045 /* Compare the standard extension first. */
1046 if (order1 > 0 && order2 > 0)
1047 return order1 - order2;
1048
1049 if (order1 == order2 && order1 < 0)
1050 {
1051 /* Compare the standard addition z extensions. */
1052 if (*subset1 == 'z')
1053 {
1054 order1 = riscv_ext_order[(*++subset1 - 'a')];
1055 order2 = riscv_ext_order[(*++subset2 - 'a')];
1056 if (order1 != order2)
1057 return order1 - order2;
1058 }
1059 return strcasecmp (++subset1, ++subset2);
1060 }
1061
1062 return order2 - order1;
1063 }
1064
1065 /* Find subset in the list. Return TRUE and set `current` to the subset
1066 if it is found. Otherwise, return FALSE and set `current` to the place
1067 where we should insert the subset. However, return FALSE with the NULL
1068 `current` means we should insert the subset at the head of subset list,
1069 if needed. */
1070
1071 bfd_boolean
1072 riscv_lookup_subset (const riscv_subset_list_t *subset_list,
1073 const char *subset,
1074 riscv_subset_t **current)
1075 {
1076 riscv_subset_t *s, *pre_s = NULL;
1077
1078 for (s = subset_list->head;
1079 s != NULL;
1080 pre_s = s, s = s->next)
1081 {
1082 int cmp = riscv_compare_subsets (s->name, subset);
1083 if (cmp == 0)
1084 {
1085 *current = s;
1086 return TRUE;
1087 }
1088 else if (cmp > 0)
1089 break;
1090 }
1091 *current = pre_s;
1092 return FALSE;
1093 }
1094
1095 /* Add extension from ISA string to the last of the subset list. */
1096
1097 void
1098 riscv_add_subset (riscv_subset_list_t *subset_list,
1099 const char *subset,
1100 int major,
1101 int minor)
1102 {
1103 riscv_subset_t *s = xmalloc (sizeof *s);
1104
1105 if (subset_list->head == NULL)
1106 subset_list->head = s;
1107
1108 s->name = xstrdup (subset);
1109 s->major_version = major;
1110 s->minor_version = minor;
1111 s->next = NULL;
1112
1113 if (subset_list->tail != NULL)
1114 subset_list->tail->next = s;
1115 subset_list->tail = s;
1116 }
1117
1118 /* Add the implicit extension to the subset list. Search the
1119 list first, and then find the right place to add. */
1120
1121 static void
1122 riscv_add_implicit_subset (riscv_subset_list_t *subset_list,
1123 const char *subset,
1124 int major,
1125 int minor)
1126 {
1127 riscv_subset_t *current, *new;
1128
1129 if (riscv_lookup_subset (subset_list, subset, &current))
1130 return;
1131
1132 new = xmalloc (sizeof *new);
1133 new->name = xstrdup (subset);
1134 new->major_version = major;
1135 new->minor_version = minor;
1136 new->next = NULL;
1137
1138 if (current != NULL)
1139 {
1140 new->next = current->next;
1141 current->next = new;
1142 }
1143 else
1144 {
1145 new->next = subset_list->head;
1146 subset_list->head = new;
1147 }
1148 }
1149
1150 /* These extensions are added to the subset list for special purposes,
1151 with the explicit versions or the RISCV_UNKNOWN_VERSION versions.
1152 Therefore, we won't output them to the output ISA string in the
1153 riscv_arch_str1, if the versions are unknown. */
1154
1155 static bfd_boolean
1156 riscv_ext_dont_care_version (const char *subset)
1157 {
1158 if (strcmp (subset, "g") == 0
1159 || strcmp (subset, "zicsr") == 0
1160 || strcmp (subset, "zifencei") == 0)
1161 return TRUE;
1162 return FALSE;
1163 }
1164
1165 /* We have to add all extensions from ISA string first, and then start to
1166 add their implicit extensions. The extensions from ISA string must be
1167 set in order, so we can add them to the last of the subset list
1168 directly, without searching.
1169
1170 Find the default versions for the extension before adding them to
1171 the subset list, if their versions are RISCV_UNKNOWN_VERSION.
1172 Afterwards, report errors if we can not find their default versions. */
1173
1174 static void
1175 riscv_parse_add_subset (riscv_parse_subset_t *rps,
1176 const char *subset,
1177 int major,
1178 int minor,
1179 bfd_boolean implicit)
1180 {
1181 int major_version = major;
1182 int minor_version = minor;
1183
1184 if ((major_version == RISCV_UNKNOWN_VERSION
1185 || minor_version == RISCV_UNKNOWN_VERSION)
1186 && rps->get_default_version != NULL)
1187 rps->get_default_version (subset, &major_version, &minor_version);
1188
1189 if (!riscv_ext_dont_care_version (subset)
1190 && (major_version == RISCV_UNKNOWN_VERSION
1191 || minor_version == RISCV_UNKNOWN_VERSION))
1192 {
1193 /* We only add the implicit extension if it is supported in the
1194 chosen ISA spec. */
1195 if (implicit)
1196 return;
1197
1198 if (subset[0] == 'x')
1199 rps->error_handler
1200 (_("x ISA extension `%s' must be set with the versions"),
1201 subset);
1202 else
1203 rps->error_handler
1204 (_("cannot find default versions of the ISA extension `%s'"),
1205 subset);
1206 return;
1207 }
1208
1209 if (!implicit)
1210 riscv_add_subset (rps->subset_list, subset,
1211 major_version, minor_version);
1212 else
1213 riscv_add_implicit_subset (rps->subset_list, subset,
1214 major_version, minor_version);
1215 }
1216
1217 /* Release subset list. */
1218
1219 void
1220 riscv_release_subset_list (riscv_subset_list_t *subset_list)
1221 {
1222 while (subset_list->head != NULL)
1223 {
1224 riscv_subset_t *next = subset_list->head->next;
1225 free ((void *)subset_list->head->name);
1226 free (subset_list->head);
1227 subset_list->head = next;
1228 }
1229
1230 subset_list->tail = NULL;
1231 }
1232
1233 /* Parsing extension version.
1234
1235 Return Value:
1236 Points to the end of version
1237
1238 Arguments:
1239 `rps`: Hooks and status for parsing extensions.
1240 `march`: Full ISA string.
1241 `p`: Curent parsing position.
1242 `major_version`: Parsed major version.
1243 `minor_version`: Parsed minor version.
1244 `std_ext_p`: True if parsing standard extension. */
1245
1246 static const char *
1247 riscv_parsing_subset_version (riscv_parse_subset_t *rps,
1248 const char *march,
1249 const char *p,
1250 int *major_version,
1251 int *minor_version,
1252 bfd_boolean std_ext_p)
1253 {
1254 bfd_boolean major_p = TRUE;
1255 int version = 0;
1256 char np;
1257
1258 *major_version = 0;
1259 *minor_version = 0;
1260 for (; *p; ++p)
1261 {
1262 if (*p == 'p')
1263 {
1264 np = *(p + 1);
1265
1266 if (!ISDIGIT (np))
1267 {
1268 /* Might be beginning of `p` extension. */
1269 if (std_ext_p)
1270 {
1271 *major_version = version;
1272 *minor_version = 0;
1273 return p;
1274 }
1275 else
1276 {
1277 rps->error_handler
1278 (_("-march=%s: expect number after `%dp'"),
1279 march, version);
1280 return NULL;
1281 }
1282 }
1283
1284 *major_version = version;
1285 major_p = FALSE;
1286 version = 0;
1287 }
1288 else if (ISDIGIT (*p))
1289 version = (version * 10) + (*p - '0');
1290 else
1291 break;
1292 }
1293
1294 if (major_p)
1295 *major_version = version;
1296 else
1297 *minor_version = version;
1298
1299 /* We can not find any version in string. */
1300 if (*major_version == 0 && *minor_version == 0)
1301 {
1302 *major_version = RISCV_UNKNOWN_VERSION;
1303 *minor_version = RISCV_UNKNOWN_VERSION;
1304 }
1305
1306 return p;
1307 }
1308
1309 /* Return string which contain all supported standard extensions in
1310 canonical order. */
1311
1312 const char *
1313 riscv_supported_std_ext (void)
1314 {
1315 return "mafdqlcbjtpvn";
1316 }
1317
1318 /* Parsing function for standard extensions.
1319
1320 Return Value:
1321 Points to the end of extensions.
1322
1323 Arguments:
1324 `rps`: Hooks and status for parsing extensions.
1325 `march`: Full ISA string.
1326 `p`: Curent parsing position. */
1327
1328 static const char *
1329 riscv_parse_std_ext (riscv_parse_subset_t *rps,
1330 const char *march,
1331 const char *p)
1332 {
1333 const char *all_std_exts = riscv_supported_std_ext ();
1334 const char *std_exts = all_std_exts;
1335 int major_version;
1336 int minor_version;
1337 char subset[2] = {0, 0};
1338
1339 /* First letter must start with i, e or g. */
1340 switch (*p)
1341 {
1342 case 'i':
1343 p = riscv_parsing_subset_version (rps, march, ++p,
1344 &major_version,
1345 &minor_version, TRUE);
1346 riscv_parse_add_subset (rps, "i",
1347 major_version,
1348 minor_version, FALSE);
1349 break;
1350
1351 case 'e':
1352 p = riscv_parsing_subset_version (rps, march, ++p,
1353 &major_version,
1354 &minor_version, TRUE);
1355 riscv_parse_add_subset (rps, "e",
1356 major_version,
1357 minor_version, FALSE);
1358 /* i-ext must be enabled. */
1359 riscv_parse_add_subset (rps, "i",
1360 RISCV_UNKNOWN_VERSION,
1361 RISCV_UNKNOWN_VERSION, FALSE);
1362
1363 if (*rps->xlen > 32)
1364 {
1365 rps->error_handler
1366 (_("-march=%s: rv%de is not a valid base ISA"),
1367 march, *rps->xlen);
1368 return NULL;
1369 }
1370 break;
1371
1372 case 'g':
1373 p = riscv_parsing_subset_version (rps, march, ++p,
1374 &major_version,
1375 &minor_version, TRUE);
1376 /* i-ext must be enabled. */
1377 riscv_parse_add_subset (rps, "i",
1378 RISCV_UNKNOWN_VERSION,
1379 RISCV_UNKNOWN_VERSION, FALSE);
1380 /* g-ext is used to add the implicit extensions, but will
1381 not be output to the ISA string. */
1382 riscv_parse_add_subset (rps, "g",
1383 major_version,
1384 minor_version, FALSE);
1385 for ( ; *std_exts != 'q'; std_exts++)
1386 {
1387 subset[0] = *std_exts;
1388 riscv_parse_add_subset (rps, subset,
1389 RISCV_UNKNOWN_VERSION,
1390 RISCV_UNKNOWN_VERSION, FALSE);
1391 }
1392 break;
1393
1394 default:
1395 rps->error_handler
1396 (_("-march=%s: first ISA extension must be `e', `i' or `g'"),
1397 march);
1398 return NULL;
1399 }
1400
1401 while (p != NULL && *p != '\0')
1402 {
1403 if (*p == 'x' || *p == 's' || *p == 'h' || *p == 'z')
1404 break;
1405
1406 if (*p == '_')
1407 {
1408 p++;
1409 continue;
1410 }
1411
1412 /* Checking canonical order. */
1413 char std_ext = *p;
1414 while (*std_exts && std_ext != *std_exts)
1415 std_exts++;
1416
1417 if (std_ext != *std_exts)
1418 {
1419 if (strchr (all_std_exts, std_ext) == NULL)
1420 rps->error_handler
1421 (_("-march=%s: unknown standard ISA extension `%c'"),
1422 march, std_ext);
1423 else
1424 rps->error_handler
1425 (_("-march=%s: standard ISA extension `%c' is not "
1426 "in canonical order"), march, std_ext);
1427 return NULL;
1428 }
1429
1430 std_exts++;
1431 subset[0] = std_ext;
1432 p = riscv_parsing_subset_version (rps, march, ++p,
1433 &major_version,
1434 &minor_version, TRUE);
1435 riscv_parse_add_subset (rps, subset,
1436 major_version,
1437 minor_version, FALSE);
1438 }
1439
1440 return p;
1441 }
1442
1443 /* Classify ARCH into one of riscv_isa_ext_class_t. */
1444
1445 riscv_isa_ext_class_t
1446 riscv_get_prefix_class (const char *arch)
1447 {
1448 switch (*arch)
1449 {
1450 case 's': return RV_ISA_CLASS_S;
1451 case 'h': return RV_ISA_CLASS_H;
1452 case 'x': return RV_ISA_CLASS_X;
1453 case 'z': return RV_ISA_CLASS_Z;
1454 default: return RV_ISA_CLASS_UNKNOWN;
1455 }
1456 }
1457
1458 /* Structure describing parameters to use when parsing a particular
1459 riscv_isa_ext_class_t. One of these should be provided for each
1460 possible class, except RV_ISA_CLASS_UNKNOWN. */
1461 typedef struct riscv_parse_config
1462 {
1463 /* Class of the extension. */
1464 riscv_isa_ext_class_t class;
1465
1466 /* Prefix string for error printing and internal parser usage. */
1467 const char *prefix;
1468
1469 /* Predicate which is used for checking whether this is a "known"
1470 extension. For 'x', it always returns true since they are by
1471 definition non-standard and cannot be known. */
1472 bfd_boolean (*ext_valid_p) (const char *);
1473 } riscv_parse_config_t;
1474
1475 /* Parsing function for prefixed extensions.
1476
1477 Return Value:
1478 Points to the end of extension.
1479
1480 Arguments:
1481 `rps`: Hooks and status for parsing extensions.
1482 `march`: Full ISA string.
1483 `p`: Curent parsing position.
1484 `config`: What class and predicate function to use for the
1485 extension. */
1486
1487 static const char *
1488 riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
1489 const char *march,
1490 const char *p,
1491 const riscv_parse_config_t *config)
1492 {
1493 int major_version;
1494 int minor_version;
1495 const char *last_name;
1496 riscv_isa_ext_class_t class;
1497
1498 while (*p)
1499 {
1500 if (*p == '_')
1501 {
1502 p++;
1503 continue;
1504 }
1505
1506 /* Assert that the current extension specifier matches our parsing
1507 class. */
1508 class = riscv_get_prefix_class (p);
1509 if (class != config->class
1510 || class == RV_ISA_CLASS_UNKNOWN)
1511 break;
1512
1513 char *subset = xstrdup (p);
1514 char *q = subset;
1515 const char *end_of_version;
1516
1517 while (*++q != '\0' && *q != '_' && !ISDIGIT (*q))
1518 ;
1519
1520 end_of_version =
1521 riscv_parsing_subset_version (rps, march, q,
1522 &major_version,
1523 &minor_version, FALSE);
1524 *q = '\0';
1525
1526 if (end_of_version == NULL)
1527 {
1528 free (subset);
1529 return NULL;
1530 }
1531
1532 /* Check that the prefix extension is known.
1533 For 'x', anything goes but it cannot simply be 'x'.
1534 For 's', it must be known from a list and cannot simply be 's'.
1535 For 'h', it must be known from a list and cannot simply be 'h'.
1536 For 'z', it must be known from a list and cannot simply be 'z'. */
1537
1538 /* Check that the extension name is well-formed. */
1539 if (!config->ext_valid_p (subset))
1540 {
1541 rps->error_handler
1542 (_("-march=%s: unknown %s ISA extension `%s'"),
1543 march, config->prefix, subset);
1544 free (subset);
1545 return NULL;
1546 }
1547
1548 /* Check that the extension isn't duplicate. */
1549 last_name = rps->subset_list->tail->name;
1550 if (!strcasecmp (last_name, subset))
1551 {
1552 rps->error_handler
1553 (_("-march=%s: duplicate %s ISA extension `%s'"),
1554 march, config->prefix, subset);
1555 free (subset);
1556 return NULL;
1557 }
1558
1559 /* Check that the extension is in alphabetical order. */
1560 if (riscv_compare_subsets (last_name, subset) > 0)
1561 {
1562 rps->error_handler
1563 (_("-march=%s: %s ISA extension `%s' is not in alphabetical "
1564 "order. It must come before `%s'"),
1565 march, config->prefix, subset, last_name);
1566 free (subset);
1567 return NULL;
1568 }
1569
1570 riscv_parse_add_subset (rps, subset,
1571 major_version,
1572 minor_version, FALSE);
1573 p += end_of_version - subset;
1574 free (subset);
1575
1576 if (*p != '\0' && *p != '_')
1577 {
1578 rps->error_handler
1579 (_("-march=%s: %s ISA extension must separate with _"),
1580 march, config->prefix);
1581 return NULL;
1582 }
1583 }
1584
1585 return p;
1586 }
1587
1588 /* Lists of prefixed class extensions that binutils should know about.
1589 Whether or not a particular entry is in these lists will dictate if
1590 gas/ld will accept its presence in the architecture string.
1591
1592 Please add the extensions to the lists in lower case. However, keep
1593 these subsets in alphabetical order in these tables is recommended,
1594 although there is no impact on the current implementation. */
1595
1596 static const char * const riscv_std_z_ext_strtab[] =
1597 {
1598 "zicsr", "zifencei", "zihintpause", "zba", "zbb", "zbc", NULL
1599 };
1600
1601 static const char * const riscv_std_s_ext_strtab[] =
1602 {
1603 NULL
1604 };
1605
1606 static const char * const riscv_std_h_ext_strtab[] =
1607 {
1608 NULL
1609 };
1610
1611 /* For the extension `ext`, search through the list of known extensions
1612 `known_exts` for a match, and return TRUE if found. */
1613
1614 static bfd_boolean
1615 riscv_multi_letter_ext_valid_p (const char *ext,
1616 const char *const *known_exts)
1617 {
1618 size_t i;
1619
1620 for (i = 0; known_exts[i]; ++i)
1621 if (!strcmp (ext, known_exts[i]))
1622 return TRUE;
1623
1624 return FALSE;
1625 }
1626
1627 /* Predicator function for x-prefixed extensions.
1628 Anything goes, except the literal 'x'. */
1629
1630 static bfd_boolean
1631 riscv_ext_x_valid_p (const char *arg)
1632 {
1633 if (!strcasecmp (arg, "x"))
1634 return FALSE;
1635
1636 return TRUE;
1637 }
1638
1639 /* Predicator functions for z-prefixed extensions.
1640 Only known z-extensions are permitted. */
1641
1642 static bfd_boolean
1643 riscv_ext_z_valid_p (const char *arg)
1644 {
1645 return riscv_multi_letter_ext_valid_p (arg, riscv_std_z_ext_strtab);
1646 }
1647
1648 /* Predicator function for 's' prefixed extensions.
1649 Only known s-extensions are permitted. */
1650
1651 static bfd_boolean
1652 riscv_ext_s_valid_p (const char *arg)
1653 {
1654 return riscv_multi_letter_ext_valid_p (arg, riscv_std_s_ext_strtab);
1655 }
1656
1657 /* Predicator function for 'h' prefixed extensions.
1658 Only known h-extensions are permitted. */
1659
1660 static bfd_boolean
1661 riscv_ext_h_valid_p (const char *arg)
1662 {
1663 return riscv_multi_letter_ext_valid_p (arg, riscv_std_h_ext_strtab);
1664 }
1665
1666 /* Parsing order of the prefixed extensions that is specified by
1667 the ISA spec. */
1668 static const riscv_parse_config_t parse_config[] =
1669 {
1670 {RV_ISA_CLASS_S, "s", riscv_ext_s_valid_p},
1671 {RV_ISA_CLASS_H, "h", riscv_ext_h_valid_p},
1672 {RV_ISA_CLASS_Z, "z", riscv_ext_z_valid_p},
1673 {RV_ISA_CLASS_X, "x", riscv_ext_x_valid_p},
1674 {RV_ISA_CLASS_UNKNOWN, NULL, NULL}
1675 };
1676
1677 /* Init the riscv_ext_order array. */
1678
1679 static void
1680 riscv_init_ext_order (void)
1681 {
1682 static bfd_boolean inited = FALSE;
1683 const char *std_base_exts = "eig";
1684 const char *std_remain_exts = riscv_supported_std_ext ();
1685 const char *ext;
1686 unsigned int i;
1687 int order;
1688
1689 if (inited)
1690 return;
1691
1692 /* The orders of all standard extensions are positive. */
1693 order = 1;
1694
1695 /* Init the standard base extensions first. */
1696 for (ext = std_base_exts; *ext; ext++)
1697 riscv_ext_order[(*ext - 'a')] = order++;
1698
1699 /* Init the standard remaining extensions. */
1700 for (ext = std_remain_exts; *ext; ext++)
1701 riscv_ext_order[(*ext - 'a')] = order++;
1702
1703 /* Init the order for prefixed keywords. The orders are negative. */
1704 order = -1;
1705 for (i = 0; parse_config[i].class != RV_ISA_CLASS_UNKNOWN; i++)
1706 {
1707 ext = parse_config[i].prefix;
1708 riscv_ext_order[(*ext - 'a')] = order--;
1709 }
1710
1711 inited = TRUE;
1712 }
1713
1714 /* Add the implicit extensions. */
1715
1716 static void
1717 riscv_parse_add_implicit_subsets (riscv_parse_subset_t *rps)
1718 {
1719 riscv_subset_t *subset = NULL;
1720
1721 /* Add the zicsr and zifencei only when the i's version less than 2.1. */
1722 if ((riscv_lookup_subset (rps->subset_list, "i", &subset))
1723 && (subset->major_version < 2
1724 || (subset->major_version == 2
1725 && subset->minor_version < 1)))
1726 {
1727 riscv_parse_add_subset (rps, "zicsr",
1728 RISCV_UNKNOWN_VERSION,
1729 RISCV_UNKNOWN_VERSION, TRUE);
1730 riscv_parse_add_subset (rps, "zifencei",
1731 RISCV_UNKNOWN_VERSION,
1732 RISCV_UNKNOWN_VERSION, TRUE);
1733 }
1734
1735 if ((riscv_lookup_subset (rps->subset_list, "q", &subset)))
1736 {
1737 riscv_parse_add_subset (rps, "d",
1738 RISCV_UNKNOWN_VERSION,
1739 RISCV_UNKNOWN_VERSION, TRUE);
1740 riscv_parse_add_subset (rps, "f",
1741 RISCV_UNKNOWN_VERSION,
1742 RISCV_UNKNOWN_VERSION, TRUE);
1743 riscv_parse_add_subset (rps, "zicsr",
1744 RISCV_UNKNOWN_VERSION,
1745 RISCV_UNKNOWN_VERSION, TRUE);
1746 }
1747 else if ((riscv_lookup_subset (rps->subset_list, "d", &subset)))
1748 {
1749 riscv_parse_add_subset (rps, "f",
1750 RISCV_UNKNOWN_VERSION,
1751 RISCV_UNKNOWN_VERSION, TRUE);
1752 riscv_parse_add_subset (rps, "zicsr",
1753 RISCV_UNKNOWN_VERSION,
1754 RISCV_UNKNOWN_VERSION, TRUE);
1755 }
1756 else if ((riscv_lookup_subset (rps->subset_list, "f", &subset)))
1757 riscv_parse_add_subset (rps, "zicsr",
1758 RISCV_UNKNOWN_VERSION,
1759 RISCV_UNKNOWN_VERSION, TRUE);
1760
1761 if ((riscv_lookup_subset (rps->subset_list, "g", &subset)))
1762 {
1763 riscv_parse_add_subset (rps, "zicsr",
1764 RISCV_UNKNOWN_VERSION,
1765 RISCV_UNKNOWN_VERSION, TRUE);
1766 riscv_parse_add_subset (rps, "zifencei",
1767 RISCV_UNKNOWN_VERSION,
1768 RISCV_UNKNOWN_VERSION, TRUE);
1769 }
1770 }
1771
1772 /* Function for parsing ISA string.
1773
1774 Return Value:
1775 Return TRUE on success.
1776
1777 Arguments:
1778 `rps`: Hooks and status for parsing extensions.
1779 `arch`: Full ISA string. */
1780
1781 bfd_boolean
1782 riscv_parse_subset (riscv_parse_subset_t *rps,
1783 const char *arch)
1784 {
1785 riscv_subset_t *subset = NULL;
1786 const char *p;
1787 size_t i;
1788 bfd_boolean no_conflict = TRUE;
1789
1790 for (p = arch; *p != '\0'; p++)
1791 {
1792 if (ISUPPER (*p))
1793 {
1794 rps->error_handler
1795 (_("-march=%s: ISA string cannot contain uppercase letters"),
1796 arch);
1797 return FALSE;
1798 }
1799 }
1800
1801 p = arch;
1802 if (strncmp (p, "rv32", 4) == 0)
1803 {
1804 *rps->xlen = 32;
1805 p += 4;
1806 }
1807 else if (strncmp (p, "rv64", 4) == 0)
1808 {
1809 *rps->xlen = 64;
1810 p += 4;
1811 }
1812 else
1813 {
1814 /* ISA string shouldn't be NULL or empty here. However,
1815 it might be empty only when we failed to merge the ISA
1816 string in the riscv_merge_attributes. We have already
1817 issued the correct error message in another side, so do
1818 not issue this error when the ISA string is empty. */
1819 if (strlen (arch))
1820 rps->error_handler (
1821 _("-march=%s: ISA string must begin with rv32 or rv64"),
1822 arch);
1823 return FALSE;
1824 }
1825
1826 /* Init the riscv_ext_order array to compare the order of extensions
1827 quickly. */
1828 riscv_init_ext_order ();
1829
1830 /* Parsing standard extension. */
1831 p = riscv_parse_std_ext (rps, arch, p);
1832
1833 if (p == NULL)
1834 return FALSE;
1835
1836 /* Parse the different classes of extensions in the specified order. */
1837 for (i = 0; i < ARRAY_SIZE (parse_config); ++i)
1838 {
1839 p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i]);
1840
1841 if (p == NULL)
1842 return FALSE;
1843 }
1844
1845 if (*p != '\0')
1846 {
1847 rps->error_handler (_("-march=%s: unexpected ISA string at end: %s"),
1848 arch, p);
1849 return FALSE;
1850 }
1851
1852 /* Finally add implicit extensions according to the current
1853 extensions. */
1854 riscv_parse_add_implicit_subsets (rps);
1855
1856 /* Check the conflicts. */
1857 if (riscv_lookup_subset (rps->subset_list, "e", &subset)
1858 && riscv_lookup_subset (rps->subset_list, "f", &subset))
1859 {
1860 rps->error_handler
1861 (_("-march=%s: rv32e does not support the `f' extension"),
1862 arch);
1863 no_conflict = FALSE;
1864 }
1865 if (riscv_lookup_subset (rps->subset_list, "q", &subset)
1866 && *rps->xlen < 64)
1867 {
1868 rps->error_handler
1869 (_("-march=%s: rv32 does not support the `q' extension"),
1870 arch);
1871 no_conflict = FALSE;
1872 }
1873 return no_conflict;
1874 }
1875
1876 /* Return the number of digits for the input. */
1877
1878 size_t
1879 riscv_estimate_digit (unsigned num)
1880 {
1881 size_t digit = 0;
1882 if (num == 0)
1883 return 1;
1884
1885 for (digit = 0; num ; num /= 10)
1886 digit++;
1887
1888 return digit;
1889 }
1890
1891 /* Auxiliary function to estimate string length of subset list. */
1892
1893 static size_t
1894 riscv_estimate_arch_strlen1 (const riscv_subset_t *subset)
1895 {
1896 if (subset == NULL)
1897 return 6; /* For rv32/rv64/rv128 and string terminator. */
1898
1899 return riscv_estimate_arch_strlen1 (subset->next)
1900 + strlen (subset->name)
1901 + riscv_estimate_digit (subset->major_version)
1902 + 1 /* For version seperator 'p'. */
1903 + riscv_estimate_digit (subset->minor_version)
1904 + 1 /* For underscore. */;
1905 }
1906
1907 /* Estimate the string length of this subset list. */
1908
1909 static size_t
1910 riscv_estimate_arch_strlen (const riscv_subset_list_t *subset_list)
1911 {
1912 return riscv_estimate_arch_strlen1 (subset_list->head);
1913 }
1914
1915 /* Auxiliary function to convert subset info to string. */
1916
1917 static void
1918 riscv_arch_str1 (riscv_subset_t *subset,
1919 char *attr_str, char *buf, size_t bufsz)
1920 {
1921 const char *underline = "_";
1922 riscv_subset_t *subset_t = subset;
1923
1924 if (subset_t == NULL)
1925 return;
1926
1927 /* No underline between rvXX and i/e. */
1928 if ((strcasecmp (subset_t->name, "i") == 0)
1929 || (strcasecmp (subset_t->name, "e") == 0))
1930 underline = "";
1931
1932 snprintf (buf, bufsz, "%s%s%dp%d",
1933 underline,
1934 subset_t->name,
1935 subset_t->major_version,
1936 subset_t->minor_version);
1937
1938 strncat (attr_str, buf, bufsz);
1939
1940 /* Skip 'i' extension after 'e', or skip extensions which
1941 versions are unknown. */
1942 while (subset_t->next
1943 && ((strcmp (subset_t->name, "e") == 0
1944 && strcmp (subset_t->next->name, "i") == 0)
1945 || subset_t->next->major_version == RISCV_UNKNOWN_VERSION
1946 || subset_t->next->minor_version == RISCV_UNKNOWN_VERSION))
1947 subset_t = subset_t->next;
1948
1949 riscv_arch_str1 (subset_t->next, attr_str, buf, bufsz);
1950 }
1951
1952 /* Convert subset information into string with explicit versions. */
1953
1954 char *
1955 riscv_arch_str (unsigned xlen, const riscv_subset_list_t *subset)
1956 {
1957 size_t arch_str_len = riscv_estimate_arch_strlen (subset);
1958 char *attr_str = xmalloc (arch_str_len);
1959 char *buf = xmalloc (arch_str_len);
1960
1961 snprintf (attr_str, arch_str_len, "rv%u", xlen);
1962
1963 riscv_arch_str1 (subset->head, attr_str, buf, arch_str_len);
1964 free (buf);
1965
1966 return attr_str;
1967 }
This page took 0.120634 seconds and 4 git commands to generate.