1 /* tc-loongarch.c -- Assemble for the LoongArch ISA
3 Copyright (C) 2021-2023 Free Software Foundation, Inc.
4 Contributed by Loongson Ltd.
6 This file is part of GAS.
8 GAS is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the license, or
11 (at your option) any later version.
13 GAS is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING3. If not,
20 see <http://www.gnu.org/licenses/>. */
23 #include "dw2gencfi.h"
24 #include "loongarch-lex.h"
25 #include "elf/loongarch.h"
26 #include "opcode/loongarch.h"
28 #include "bfd/elfxx-loongarch.h"
34 /* All information about an instruction during assemble. */
35 struct loongarch_cl_insn
37 /* First split string. */
39 const char *arg_strs
[MAX_ARG_NUM_PLUS_2
];
42 /* Second analyze name_str and each actual args string to match the insn
43 in 'loongarch-opc.c'. And actual args may need be relocated.
44 We get length of insn. If 'insn_length == 0 && insn_mo->macro != NULL',
45 it's a macro insntruction and we call 'md_assemble' recursively
46 after expanding it. */
50 const struct loongarch_opcode
*insn
;
53 offsetT args
[MAX_ARG_NUM_PLUS_2
];
54 struct reloc_info reloc_info
[MAX_RELOC_NUMBER_A_INSN
];
57 /* For relax reserved. We not support relax now.
58 'insn_length < relax_max_length' means need to relax.
59 And 'insn_length == relax_max_length' means no need to relax. */
60 size_t relax_max_length
;
61 relax_substateT subtype
;
63 /* Then we get the binary representation of insn
64 and write it in to section. */
67 /* The frag that contains the instruction. */
69 /* The offset into FRAG of the first instruction byte. */
71 /* The relocs associated with the instruction, if any. */
72 fixS
*fixp
[MAX_RELOC_NUMBER_A_INSN
];
76 #define DEFAULT_ARCH "loongarch64"
79 /* This array holds the chars that always start a comment. If the
80 pre-processor is disabled, these aren't very useful. */
81 const char comment_chars
[] = "#";
83 /* This array holds the chars that only start a comment at the beginning of
84 a line. If the line seems to have the form '# 123 filename'
85 .line and .file directives will appear in the pre-processed output. */
86 /* Note that input_file.c hand checks for '#' at the beginning of the
87 first line of the input file. This is because the compiler outputs
88 #NO_APP at the beginning of its output. */
89 /* Also note that C style comments are always supported. */
90 const char line_comment_chars
[] = "#";
92 /* This array holds machine specific line separator characters. */
93 const char line_separator_chars
[] = ";";
95 /* Chars that can be used to separate mant from exp in floating point nums. */
96 const char EXP_CHARS
[] = "eE";
98 /* Chars that mean this number is a floating point constant. */
100 /* or 0d1.2345e12. */
101 const char FLT_CHARS
[] = "rRsSfFdDxXpP";
103 const char *md_shortopts
= "O::g::G:";
105 static const char default_arch
[] = DEFAULT_ARCH
;
109 OPTION_IGNORE
= OPTION_MD_BASE
,
116 OPTION_LA_LOCAL_WITH_ABS
,
117 OPTION_LA_GLOBAL_WITH_PCREL
,
118 OPTION_LA_GLOBAL_WITH_ABS
,
123 struct option md_longopts
[] =
125 { "mabi", required_argument
, NULL
, OPTION_ABI
},
127 { "mfpu", required_argument
, NULL
, OPTION_FLOAT_ISA
},
129 { "mla-local-with-abs", no_argument
, NULL
, OPTION_LA_LOCAL_WITH_ABS
},
130 { "mla-global-with-pcrel", no_argument
, NULL
, OPTION_LA_GLOBAL_WITH_PCREL
},
131 { "mla-global-with-abs", no_argument
, NULL
, OPTION_LA_GLOBAL_WITH_ABS
},
133 { NULL
, no_argument
, NULL
, 0 }
136 size_t md_longopts_size
= sizeof (md_longopts
);
139 md_parse_option (int c
, const char *arg
)
143 char ilp32
[256] = "";
144 unsigned char *suf
= (unsigned char *)arg
;
146 lp64
['s'] = lp64
['S'] = EF_LOONGARCH_ABI_SOFT_FLOAT
;
147 lp64
['f'] = lp64
['F'] = EF_LOONGARCH_ABI_SINGLE_FLOAT
;
148 lp64
['d'] = lp64
['D'] = EF_LOONGARCH_ABI_DOUBLE_FLOAT
;
150 ilp32
['s'] = ilp32
['S'] = EF_LOONGARCH_ABI_SOFT_FLOAT
;
151 ilp32
['f'] = ilp32
['F'] = EF_LOONGARCH_ABI_SINGLE_FLOAT
;
152 ilp32
['d'] = ilp32
['D'] = EF_LOONGARCH_ABI_DOUBLE_FLOAT
;
157 if (strncasecmp (arg
, "lp64", 4) == 0 && lp64
[suf
[4]] != 0)
159 LARCH_opts
.ase_ilp32
= 1;
160 LARCH_opts
.ase_lp64
= 1;
161 LARCH_opts
.ase_abi
= lp64
[suf
[4]];
163 else if (strncasecmp (arg
, "ilp32", 5) == 0 && ilp32
[suf
[5]] != 0)
165 LARCH_opts
.ase_abi
= ilp32
[suf
[5]];
166 LARCH_opts
.ase_ilp32
= 1;
172 case OPTION_FLOAT_ISA
:
173 if (strcasecmp (arg
, "soft") == 0)
174 LARCH_opts
.ase_nf
= 1;
175 else if (strcasecmp (arg
, "single") == 0)
176 LARCH_opts
.ase_sf
= 1;
177 else if (strcasecmp (arg
, "double") == 0)
179 LARCH_opts
.ase_sf
= 1;
180 LARCH_opts
.ase_df
= 1;
186 case OPTION_LA_LOCAL_WITH_ABS
:
187 LARCH_opts
.ase_labs
= 1;
190 case OPTION_LA_GLOBAL_WITH_PCREL
:
191 LARCH_opts
.ase_gpcr
= 1;
194 case OPTION_LA_GLOBAL_WITH_ABS
:
195 LARCH_opts
.ase_gabs
= 1;
208 static struct htab
*r_htab
= NULL
;
209 static struct htab
*f_htab
= NULL
;
210 static struct htab
*c_htab
= NULL
;
211 static struct htab
*cr_htab
= NULL
;
212 static struct htab
*v_htab
= NULL
;
213 static struct htab
*x_htab
= NULL
;
216 loongarch_after_parse_args ()
218 /* Set default ABI/ISA LP64D. */
219 if (!LARCH_opts
.ase_ilp32
)
221 if (strcmp (default_arch
, "loongarch64") == 0)
223 LARCH_opts
.ase_abi
= EF_LOONGARCH_ABI_DOUBLE_FLOAT
;
224 LARCH_opts
.ase_ilp32
= 1;
225 LARCH_opts
.ase_lp64
= 1;
227 else if (strcmp (default_arch
, "loongarch32") == 0)
229 LARCH_opts
.ase_abi
= EF_LOONGARCH_ABI_DOUBLE_FLOAT
;
230 LARCH_opts
.ase_ilp32
= 1;
233 as_bad ("unknown default architecture `%s'", default_arch
);
236 LARCH_opts
.ase_abi
|= EF_LOONGARCH_OBJABI_V1
;
237 /* Set default ISA double-float. */
238 if (!LARCH_opts
.ase_nf
239 && !LARCH_opts
.ase_sf
240 && !LARCH_opts
.ase_df
)
242 LARCH_opts
.ase_sf
= 1;
243 LARCH_opts
.ase_df
= 1;
248 assert(LARCH_opts
.ase_ilp32
);
250 /* Init ilp32/lp64 registers names. */
252 r_htab
= str_htab_create (), str_hash_insert (r_htab
, "", 0, 0);
254 for (i
= 0; i
< ARRAY_SIZE (loongarch_r_normal_name
); i
++)
255 str_hash_insert (r_htab
, loongarch_r_normal_name
[i
], (void *) (i
+ 1), 0);
258 cr_htab
= str_htab_create (), str_hash_insert (cr_htab
, "", 0, 0);
260 for (i
= 0; i
< ARRAY_SIZE (loongarch_cr_normal_name
); i
++)
261 str_hash_insert (cr_htab
, loongarch_cr_normal_name
[i
], (void *) (i
+ 1), 0);
263 /* Init single/double float registers names. */
264 if (LARCH_opts
.ase_sf
|| LARCH_opts
.ase_df
)
267 f_htab
= str_htab_create (), str_hash_insert (f_htab
, "", 0, 0);
269 for (i
= 0; i
< ARRAY_SIZE (loongarch_f_normal_name
); i
++)
270 str_hash_insert (f_htab
, loongarch_f_normal_name
[i
], (void *) (i
+ 1),
274 c_htab
= str_htab_create (), str_hash_insert (c_htab
, "", 0, 0);
276 for (i
= 0; i
< ARRAY_SIZE (loongarch_c_normal_name
); i
++)
277 str_hash_insert (c_htab
, loongarch_c_normal_name
[i
], (void *) (i
+ 1),
282 /* Init lsx registers names. */
283 if (LARCH_opts
.ase_lsx
)
286 v_htab
= str_htab_create (), str_hash_insert (v_htab
, "", 0, 0);
287 for (i
= 0; i
< ARRAY_SIZE (loongarch_v_normal_name
); i
++)
288 str_hash_insert (v_htab
, loongarch_v_normal_name
[i
], (void *) (i
+ 1),
292 /* Init lasx registers names. */
293 if (LARCH_opts
.ase_lasx
)
296 x_htab
= str_htab_create (), str_hash_insert (x_htab
, "", 0, 0);
297 for (i
= 0; i
< ARRAY_SIZE (loongarch_x_normal_name
); i
++)
298 str_hash_insert (x_htab
, loongarch_x_normal_name
[i
], (void *) (i
+ 1),
302 /* Init lp64 registers alias. */
303 if (LARCH_opts
.ase_lp64
)
305 for (i
= 0; i
< ARRAY_SIZE (loongarch_r_lp64_name
); i
++)
306 str_hash_insert (r_htab
, loongarch_r_lp64_name
[i
], (void *) (i
+ 1),
308 for (i
= 0; i
< ARRAY_SIZE (loongarch_r_lp64_name1
); i
++)
309 str_hash_insert (r_htab
, loongarch_r_lp64_name1
[i
], (void *) (i
+ 1),
313 /* Init float-lp64 registers alias */
314 if ((LARCH_opts
.ase_sf
|| LARCH_opts
.ase_df
) && LARCH_opts
.ase_lp64
)
316 for (i
= 0; i
< ARRAY_SIZE (loongarch_f_lp64_name
); i
++)
317 str_hash_insert (f_htab
, loongarch_f_lp64_name
[i
],
318 (void *) (i
+ 1), 0);
319 for (i
= 0; i
< ARRAY_SIZE (loongarch_f_lp64_name1
); i
++)
320 str_hash_insert (f_htab
, loongarch_f_lp64_name1
[i
],
321 (void *) (i
+ 1), 0);
326 loongarch_target_format ()
328 return LARCH_opts
.ase_lp64
? "elf64-loongarch" : "elf32-loongarch";
334 const struct loongarch_opcode
*it
;
335 struct loongarch_ase
*ase
;
336 for (ase
= loongarch_ASEs
; ase
->enabled
; ase
++)
337 for (it
= ase
->opcodes
; it
->name
; it
++)
339 if (loongarch_check_format (it
->format
) != 0)
340 as_fatal (_("insn name: %s\tformat: %s\tsyntax error"),
341 it
->name
, it
->format
);
342 if (it
->mask
== 0 && it
->macro
== 0)
343 as_fatal (_("insn name: %s\nformat: %s\nwe want macro but "
345 it
->name
, it
->format
);
347 && loongarch_check_macro (it
->format
, it
->macro
) != 0)
348 as_fatal (_("insn name: %s\nformat: %s\nmacro: %s\tsyntax error"),
349 it
->name
, it
->format
, it
->macro
);
352 /* FIXME: expressionS use 'offsetT' as constant,
353 * we want this is 64-bit type. */
354 assert (8 <= sizeof (offsetT
));
358 loongarch_mach (void)
360 return LARCH_opts
.ase_lp64
? bfd_mach_loongarch64
: bfd_mach_loongarch32
;
363 static const expressionS const_0
= { .X_op
= O_constant
, .X_add_number
= 0 };
366 s_loongarch_align (int arg
)
368 const char *t
= input_line_pointer
;
369 while (!is_end_of_line
[(unsigned char) *t
] && *t
!= ',')
377 /* Handle the .dtprelword and .dtpreldword pseudo-ops. They generate
378 a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
379 use in DWARF debug information. */
389 if (ex
.X_op
!= O_symbol
)
391 as_bad (_("Unsupported use of %s"),
392 (bytes
== 8 ? ".dtpreldword" : ".dtprelword"));
393 ignore_rest_of_line ();
396 p
= frag_more (bytes
);
397 md_number_to_chars (p
, 0, bytes
);
398 fix_new_exp (frag_now
, p
- frag_now
->fr_literal
, bytes
, &ex
, FALSE
,
400 ? BFD_RELOC_LARCH_TLS_DTPREL64
401 : BFD_RELOC_LARCH_TLS_DTPREL32
));
403 demand_empty_rest_of_line ();
406 static const pseudo_typeS loongarch_pseudo_table
[] =
408 { "align", s_loongarch_align
, -4 },
409 { "dword", cons
, 8 },
412 { "dtprelword", s_dtprel
, 4 },
413 { "dtpreldword", s_dtprel
, 8 },
418 loongarch_pop_insert (void)
420 pop_insert (loongarch_pseudo_table
);
423 #define INTERNAL_LABEL_SPECIAL 10
424 static unsigned long internal_label_count
[INTERNAL_LABEL_SPECIAL
] = { 0 };
427 loongarch_internal_label_name (unsigned long label
, int augend
)
429 static char symbol_name_build
[24];
430 unsigned long want_label
;
433 want_label
= internal_label_count
[label
] + augend
;
435 p
= symbol_name_build
;
436 #ifdef LOCAL_LABEL_PREFIX
437 *p
++ = LOCAL_LABEL_PREFIX
;
440 for (; label
; label
/= 10)
441 *p
++ = label
% 10 + '0';
442 /* Make sure internal label never belong to normal label namespace. */
444 for (; want_label
; want_label
/= 10)
445 *p
++ = want_label
% 10 + '0';
447 return symbol_name_build
;
451 setup_internal_label_here (unsigned long label
)
453 assert (label
< INTERNAL_LABEL_SPECIAL
);
454 internal_label_count
[label
]++;
455 colon (loongarch_internal_label_name (label
, 0));
459 get_internal_label (expressionS
*label_expr
, unsigned long label
,
460 int augend
/* 0 for previous, 1 for next. */)
462 assert (label
< INTERNAL_LABEL_SPECIAL
);
463 if (augend
== 0 && internal_label_count
[label
] == 0)
464 as_fatal (_("internal error: we have no internal label yet"));
465 label_expr
->X_op
= O_symbol
;
466 label_expr
->X_add_symbol
=
467 symbol_find_or_make (loongarch_internal_label_name (label
, augend
));
468 label_expr
->X_add_number
= 0;
472 is_internal_label (const char *c_str
)
479 if (!('0' <= *c_str
&& *c_str
<= '9'))
481 while ('0' <= *c_str
&& *c_str
<= '9')
483 if (*c_str
!= 'b' && *c_str
!= 'f')
486 return *c_str
== '\0';
493 is_label (const char *c_str
)
495 if (is_internal_label (c_str
))
497 else if ('0' <= *c_str
&& *c_str
<= '9')
500 while ('0' <= *c_str
&& *c_str
<= '9')
502 return *c_str
== 'b' || *c_str
== 'f';
504 else if (is_name_beginner (*c_str
))
506 /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */
508 while (is_part_of_name (*c_str
))
510 return *c_str
== '\0';
517 is_label_with_addend (const char *c_str
)
519 if (is_internal_label (c_str
))
521 else if ('0' <= *c_str
&& *c_str
<= '9')
524 while ('0' <= *c_str
&& *c_str
<= '9')
526 if (*c_str
== 'b' || *c_str
== 'f')
530 return *c_str
== '\0'
531 || ((*c_str
== '-' || *c_str
== '+')
532 && is_unsigned (c_str
+ 1));
534 else if (is_name_beginner (*c_str
))
536 /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */
538 while (is_part_of_name (*c_str
))
540 return *c_str
== '\0'
541 || ((*c_str
== '-' || *c_str
== '+')
542 && is_unsigned (c_str
+ 1));
549 loongarch_args_parser_can_match_arg_helper (char esc_ch1
, char esc_ch2
,
550 const char *bit_field
,
551 const char *arg
, void *context
)
553 struct loongarch_cl_insn
*ip
= context
;
554 offsetT imm
, ret
= 0;
555 size_t reloc_num_we_have
= MAX_RELOC_NUMBER_A_INSN
- ip
->reloc_num
;
556 size_t reloc_num
= 0;
567 ip
->match_now
= is_label (arg
);
568 if (!ip
->match_now
&& is_label_with_addend (arg
))
569 as_fatal (_("This label shouldn't be with addend."));
572 ip
->match_now
= is_label_with_addend (arg
);
579 loongarch_parse_expr (arg
, ip
->reloc_info
+ ip
->reloc_num
,
580 reloc_num_we_have
, &reloc_num
, &imm
) == 0;
588 bfd_reloc_code_real_type reloc_type
= BFD_RELOC_NONE
;
589 reloc_num_we_have
-= reloc_num
;
590 if (reloc_num_we_have
== 0)
591 as_fatal (_("expr too huge") /* Want one more reloc. */);
594 if (strncmp (bit_field
, "10:12", strlen ("10:12")) == 0)
595 reloc_type
= BFD_RELOC_LARCH_SOP_POP_32_U_10_12
;
597 else if (esc_ch1
== 's')
599 if (strncmp (bit_field
, "10:16<<2", strlen ("10:16<<2")) == 0)
600 reloc_type
= BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2
;
601 else if (strncmp (bit_field
, "0:5|10:16<<2",
602 strlen ("0:5|10:16<<2")) == 0)
603 reloc_type
= BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2
;
604 else if (strncmp (bit_field
, "0:10|10:16<<2",
605 strlen ("0:10|10:16<<2")) == 0)
606 reloc_type
= BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2
;
607 else if (strncmp (bit_field
, "10:12", strlen ("10:12")) == 0)
608 reloc_type
= BFD_RELOC_LARCH_SOP_POP_32_S_10_12
;
609 else if (strncmp (bit_field
, "5:20", strlen ("5:20")) == 0)
610 reloc_type
= BFD_RELOC_LARCH_SOP_POP_32_S_5_20
;
611 else if (strncmp (bit_field
, "10:16", strlen ("10:16")) == 0)
612 reloc_type
= BFD_RELOC_LARCH_SOP_POP_32_S_10_16
;
613 else if (strncmp (bit_field
, "10:5", strlen ("10:5")) == 0)
614 reloc_type
= BFD_RELOC_LARCH_SOP_POP_32_S_10_5
;
616 if (reloc_type
== BFD_RELOC_NONE
)
618 _("not support reloc bit-field\nfmt: %c%c %s\nargs: %s"),
619 esc_ch1
, esc_ch2
, bit_field
, arg
);
620 if (ip
->reloc_info
[0].type
>= BFD_RELOC_LARCH_B16
621 && ip
->reloc_info
[0].type
< BFD_RELOC_LARCH_RELAX
)
623 /* As we compact stack-relocs, it is no need for pop operation.
624 But break out until here in order to check the imm field.
625 May be reloc_num > 1 if implement relax? */
626 ip
->reloc_num
+= reloc_num
;
630 ip
->reloc_num
+= reloc_num
;
631 ip
->reloc_info
[ip
->reloc_num
- 1].type
= reloc_type
;
632 ip
->reloc_info
[ip
->reloc_num
- 1].value
= const_0
;
636 imm
= (intptr_t) str_hash_find (r_htab
, arg
);
637 ip
->match_now
= 0 < imm
;
641 imm
= (intptr_t) str_hash_find (f_htab
, arg
);
642 ip
->match_now
= 0 < imm
;
649 imm
= (intptr_t) str_hash_find (cr_htab
, arg
);
652 imm
= (intptr_t) str_hash_find (c_htab
, arg
);
654 ip
->match_now
= 0 < imm
;
658 imm
= (intptr_t) str_hash_find (v_htab
, arg
);
659 ip
->match_now
= 0 < imm
;
663 imm
= (intptr_t) str_hash_find (x_htab
, arg
);
664 ip
->match_now
= 0 < imm
;
668 ip
->all_match
= ip
->match_now
;
670 ip
->insn
->mask
? loongarch_insn_length (ip
->insn
->match
) : 0;
671 /* FIXME: now we have no relax insn. */
672 ip
->relax_max_length
= ip
->insn_length
;
675 as_fatal (_("unknown escape"));
680 /* Check imm overflow. */
681 int bit_width
, bits_needed_s
, bits_needed_u
;
690 bit_width
= loongarch_get_bit_field_width (bit_field
, &t
);
693 /* No specify bit width. */
697 if (t
[0] == '<' && t
[1] == '<')
699 int i
= strtol (t
+= 2, &t
, 10), j
;
700 for (j
= i
; 0 < j
; j
--, imm
>>= 1)
702 as_fatal (_("require imm low %d bit is 0."), i
);
706 imm
-= strtol (t
, &t
, 10);
708 bits_needed_s
= loongarch_bits_imm_needed (imm
, 1);
709 bits_needed_u
= loongarch_bits_imm_needed (imm
, 0);
711 if ((esc_ch1
== 's' && bit_width
< bits_needed_s
)
712 || (esc_ch1
!= 's' && bit_width
< bits_needed_u
))
713 /* How to do after we detect overflow. */
714 as_fatal (_("Immediate overflow.\n"
717 esc_ch1
, esc_ch2
, bit_field
, arg
);
723 ip
->args
[ip
->arg_num
] = ret
;
730 get_loongarch_opcode (struct loongarch_cl_insn
*insn
)
732 const struct loongarch_opcode
*it
;
733 struct loongarch_ase
*ase
;
734 for (ase
= loongarch_ASEs
; ase
->enabled
; ase
++)
736 if (!*ase
->enabled
|| (ase
->include
&& !*ase
->include
)
737 || (ase
->exclude
&& *ase
->exclude
))
740 if (!ase
->name_hash_entry
)
742 ase
->name_hash_entry
= str_htab_create ();
743 for (it
= ase
->opcodes
; it
->name
; it
++)
745 if ((!it
->include
|| (it
->include
&& *it
->include
))
746 && (!it
->exclude
|| (it
->exclude
&& !(*it
->exclude
))))
747 str_hash_insert (ase
->name_hash_entry
, it
->name
,
752 if ((it
= str_hash_find (ase
->name_hash_entry
, insn
->name
)) == NULL
)
762 insn
->insn_bin
= (loongarch_foreach_args
763 (it
->format
, insn
->arg_strs
,
764 loongarch_args_parser_can_match_arg_helper
,
766 if (insn
->all_match
&& !(it
->include
&& !*it
->include
)
767 && !(it
->exclude
&& *it
->exclude
))
769 insn
->insn_bin
|= it
->match
;
774 while (it
->name
&& strcasecmp (it
->name
, insn
->name
) == 0);
779 check_this_insn_before_appending (struct loongarch_cl_insn
*ip
)
783 if (strncmp (ip
->name
, "la.abs", 6) == 0)
785 ip
->reloc_info
[ip
->reloc_num
].type
= BFD_RELOC_LARCH_MARK_LA
;
786 ip
->reloc_info
[ip
->reloc_num
].value
= const_0
;
789 else if (ip
->insn
->mask
== 0xffff8000
790 /* amswap.w rd, rk, rj */
791 && ((ip
->insn_bin
& 0xfff00000) == 0x38600000
792 /* ammax_db.wu rd, rk, rj */
793 || (ip
->insn_bin
& 0xffff0000) == 0x38700000
794 /* ammin_db.wu rd, rk, rj */
795 || (ip
->insn_bin
& 0xffff0000) == 0x38710000))
797 /* For AMO insn amswap.[wd], amadd.[wd], etc. */
799 && (ip
->args
[0] == ip
->args
[1] || ip
->args
[0] == ip
->args
[2]))
800 as_fatal (_("AMO insns require rd != base && rd != rt"
801 " when rd isn't $r0"));
803 else if ((ip
->insn
->mask
== 0xffe08000
804 /* bstrins.w rd, rj, msbw, lsbw */
805 && (ip
->insn_bin
& 0xffe00000) == 0x00600000)
806 || (ip
->insn
->mask
== 0xffc00000
807 /* bstrins.d rd, rj, msbd, lsbd */
808 && (ip
->insn_bin
& 0xff800000) == 0x00800000))
810 /* For bstr(ins|pick).[wd]. */
811 if (ip
->args
[2] < ip
->args
[3])
812 as_fatal (_("bstr(ins|pick).[wd] require msbd >= lsbd"));
814 else if (ip
->insn
->mask
!= 0 && (ip
->insn_bin
& 0xfe0003c0) == 0x04000000
815 /* csrxchg rd, rj, csr_num */
816 && (strcmp ("csrxchg", ip
->name
) == 0))
817 as_fatal (_("csrxchg require rj != $r0 && rj != $r1"));
823 install_insn (const struct loongarch_cl_insn
*insn
)
825 char *f
= insn
->frag
->fr_literal
+ insn
->where
;
826 if (0 < insn
->insn_length
)
827 md_number_to_chars (f
, insn
->insn_bin
, insn
->insn_length
);
831 move_insn (struct loongarch_cl_insn
*insn
, fragS
*frag
, long where
)
836 for (i
= 0; i
< insn
->reloc_num
; i
++)
838 insn
->fixp
[i
]->fx_frag
= frag
;
839 insn
->fixp
[i
]->fx_where
= where
;
844 /* Add INSN to the end of the output. */
846 append_fixed_insn (struct loongarch_cl_insn
*insn
)
848 char *f
= frag_more (insn
->insn_length
);
849 move_insn (insn
, frag_now
, f
- frag_now
->fr_literal
);
853 append_fixp_and_insn (struct loongarch_cl_insn
*ip
)
855 reloc_howto_type
*howto
;
856 bfd_reloc_code_real_type reloc_type
;
857 struct reloc_info
*reloc_info
= ip
->reloc_info
;
860 dwarf2_emit_insn (0);
862 for (i
= 0; i
< ip
->reloc_num
; i
++)
864 reloc_type
= reloc_info
[i
].type
;
865 howto
= bfd_reloc_type_lookup (stdoutput
, reloc_type
);
867 as_fatal (_("no HOWTO loong relocation number %d"), reloc_type
);
870 fix_new_exp (ip
->frag
, ip
->where
, bfd_get_reloc_size (howto
),
871 &reloc_info
[i
].value
, FALSE
, reloc_type
);
874 if (ip
->insn_length
< ip
->relax_max_length
)
875 as_fatal (_("Internal error: not support relax now"));
877 append_fixed_insn (ip
);
880 /* Ask helper for returning a malloced c_str or NULL. */
882 assember_macro_helper (const char *const args
[], void *context_ptr
)
884 struct loongarch_cl_insn
*insn
= context_ptr
;
886 if ( strcmp (insn
->name
, "li.w") == 0 || strcmp (insn
->name
, "li.d") == 0)
888 char args_buf
[50], insns_buf
[200];
889 const char *arg_strs
[6];
892 /* We pay attention to sign extend beacause it is chance of reduce insn.
893 The exception is 12-bit and hi-12-bit unsigned,
894 we need a 'ori' or a 'lu52i.d' accordingly. */
895 char all0_bit_vec
, sign_bit_vec
, allf_bit_vec
, paritial_is_sext_of_prev
;
897 lo32
= insn
->args
[1] & 0xffffffff;
898 hi32
= insn
->args
[1] >> 32;
900 if (strcmp (insn
->name
, "li.w") == 0)
902 if (hi32
!= 0 && hi32
!= 0xffffffff)
903 as_fatal (_("li overflow: hi32:0x%x lo32:0x%x"), hi32
, lo32
);
904 hi32
= lo32
& 0x80000000 ? 0xffffffff : 0;
907 if (strcmp (insn
->name
, "li.d") == 0 && !LARCH_opts
.ase_lp64
)
908 as_fatal (_("we can't li.d on 32bit-arch"));
910 snprintf (args_buf
, sizeof (args_buf
), "0x%x,0x%x,0x%x,0x%x,%s",
911 (hi32
>> 20) & 0xfff, hi32
& 0xfffff, (lo32
>> 12) & 0xfffff,
912 lo32
& 0xfff, args
[0]);
913 loongarch_split_args_by_comma (args_buf
, arg_strs
);
916 ((((hi32
& 0xfff00000) == 0) << 3) | (((hi32
& 0x000fffff) == 0) << 2)
917 | (((lo32
& 0xfffff000) == 0) << 1) | ((lo32
& 0x00000fff) == 0));
919 ((((hi32
& 0x80000000) != 0) << 3) | (((hi32
& 0x00080000) != 0) << 2)
920 | (((lo32
& 0x80000000) != 0) << 1) | ((lo32
& 0x00000800) != 0));
922 ((((hi32
& 0xfff00000) == 0xfff00000) << 3)
923 | (((hi32
& 0x000fffff) == 0x000fffff) << 2)
924 | (((lo32
& 0xfffff000) == 0xfffff000) << 1)
925 | ((lo32
& 0x00000fff) == 0x00000fff));
926 paritial_is_sext_of_prev
=
927 (all0_bit_vec
^ allf_bit_vec
) & (all0_bit_vec
^ (sign_bit_vec
<< 1));
929 static const char *const li_32bit
[] =
931 "lu12i.w %5,%3&0x80000?%3-0x100000:%3;ori %5,%5,%4;",
932 "lu12i.w %5,%3&0x80000?%3-0x100000:%3;",
933 "addi.w %5,$r0,%4&0x800?%4-0x1000:%4;",
936 static const char *const li_hi_32bit
[] =
938 "lu32i.d %5,%2&0x80000?%2-0x100000:%2;"
939 "lu52i.d %5,%5,%1&0x800?%1-0x1000:%1;",
940 "lu52i.d %5,%5,%1&0x800?%1-0x1000:%1;",
941 "lu32i.d %5,%2&0x80000?%2-0x100000:%2;",
947 if (paritial_is_sext_of_prev
== 0x7)
949 strcat (insns_buf
, "lu52i.d %5,$r0,%1&0x800?%1-0x1000:%1;");
952 if ((all0_bit_vec
& 0x3) == 0x2)
953 strcat (insns_buf
, "ori %5,$r0,%4;");
955 strcat (insns_buf
, li_32bit
[paritial_is_sext_of_prev
& 0x3]);
956 strcat (insns_buf
, li_hi_32bit
[paritial_is_sext_of_prev
>> 2]);
960 ret
= loongarch_expand_macro (insns_buf
, arg_strs
, NULL
, NULL
,
967 /* Accept instructions separated by ';'
968 * assuming 'not starting with space and not ending with space' or pass in
971 loongarch_assemble_INSNs (char *str
)
974 size_t len_str
= strlen(str
);
976 for (rest
= str
; *rest
!= ';' && *rest
!= '\0'; rest
++);
983 setup_internal_label_here (strtol (str
, &str
, 10));
992 struct loongarch_cl_insn the_one
= { 0 };
995 for (; *str
&& *str
!= ' '; str
++)
1000 loongarch_split_args_by_comma (str
, the_one
.arg_strs
);
1001 get_loongarch_opcode (&the_one
);
1003 if (!the_one
.all_match
)
1005 char *ss
= loongarch_cat_splited_strs (the_one
.arg_strs
);
1006 as_bad (_("no match insn: %s\t%s"), the_one
.name
, ss
? ss
: "");
1011 if (check_this_insn_before_appending (&the_one
) != 0)
1014 append_fixp_and_insn (&the_one
);
1015 if (the_one
.insn_length
== 0 && the_one
.insn
->macro
)
1017 char *c_str
= loongarch_expand_macro (the_one
.insn
->macro
,
1019 assember_macro_helper
,
1021 loongarch_assemble_INSNs (c_str
);
1028 loongarch_assemble_INSNs (rest
);
1032 md_assemble (char *str
)
1034 loongarch_assemble_INSNs (str
);
1038 md_atof (int type
, char *litP
, int *sizeP
)
1040 return ieee_md_atof (type
, litP
, sizeP
, FALSE
);
1044 md_number_to_chars (char *buf
, valueT val
, int n
)
1046 number_to_chars_littleendian (buf
, val
, n
);
1049 /* The location from which a PC relative jump should be calculated,
1050 given a PC relative reloc. */
1052 md_pcrel_from (fixS
*fixP ATTRIBUTE_UNUSED
)
1057 static void fix_reloc_insn (fixS
*fixP
, bfd_vma reloc_val
, char *buf
)
1059 reloc_howto_type
*howto
;
1061 howto
= bfd_reloc_type_lookup (stdoutput
, fixP
->fx_r_type
);
1063 insn
= bfd_getl32 (buf
);
1065 if (!loongarch_adjust_reloc_bitsfield(howto
, &reloc_val
))
1066 as_warn_where (fixP
->fx_file
, fixP
->fx_line
, "Reloc overflow");
1068 insn
= (insn
& (insn_t
)howto
->src_mask
)
1069 | ((insn
& (~(insn_t
)howto
->dst_mask
)) | reloc_val
);
1071 bfd_putl32 (insn
, buf
);
1075 md_apply_fix (fixS
*fixP
, valueT
*valP
, segT seg ATTRIBUTE_UNUSED
)
1077 static int64_t stack_top
;
1078 static int last_reloc_is_sop_push_pcrel_1
= 0;
1079 int last_reloc_is_sop_push_pcrel
= last_reloc_is_sop_push_pcrel_1
;
1081 last_reloc_is_sop_push_pcrel_1
= 0;
1083 char *buf
= fixP
->fx_frag
->fr_literal
+ fixP
->fx_where
;
1084 switch (fixP
->fx_r_type
)
1086 case BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL
:
1087 case BFD_RELOC_LARCH_SOP_PUSH_TLS_GD
:
1088 case BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT
:
1089 case BFD_RELOC_LARCH_TLS_LE_HI20
:
1090 case BFD_RELOC_LARCH_TLS_LE_LO12
:
1091 case BFD_RELOC_LARCH_TLS_LE64_LO20
:
1092 case BFD_RELOC_LARCH_TLS_LE64_HI12
:
1093 case BFD_RELOC_LARCH_TLS_IE_PC_HI20
:
1094 case BFD_RELOC_LARCH_TLS_IE_PC_LO12
:
1095 case BFD_RELOC_LARCH_TLS_IE64_PC_LO20
:
1096 case BFD_RELOC_LARCH_TLS_IE64_PC_HI12
:
1097 case BFD_RELOC_LARCH_TLS_IE_HI20
:
1098 case BFD_RELOC_LARCH_TLS_IE_LO12
:
1099 case BFD_RELOC_LARCH_TLS_IE64_LO20
:
1100 case BFD_RELOC_LARCH_TLS_IE64_HI12
:
1101 case BFD_RELOC_LARCH_TLS_LD_PC_HI20
:
1102 case BFD_RELOC_LARCH_TLS_LD_HI20
:
1103 case BFD_RELOC_LARCH_TLS_GD_PC_HI20
:
1104 case BFD_RELOC_LARCH_TLS_GD_HI20
:
1105 /* Add tls lo (got_lo reloc type). */
1106 if (fixP
->fx_addsy
== NULL
)
1107 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
1108 _("Relocation against a constant"));
1109 S_SET_THREAD_LOCAL (fixP
->fx_addsy
);
1112 case BFD_RELOC_LARCH_SOP_PUSH_PCREL
:
1113 if (fixP
->fx_addsy
== NULL
)
1114 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
1115 _("Relocation against a constant"));
1117 last_reloc_is_sop_push_pcrel_1
= 1;
1118 if (S_GET_SEGMENT (fixP
->fx_addsy
) == seg
)
1119 stack_top
= (S_GET_VALUE (fixP
->fx_addsy
) + fixP
->fx_offset
1120 - (fixP
->fx_where
+ fixP
->fx_frag
->fr_address
));
1125 case BFD_RELOC_LARCH_SOP_POP_32_S_10_5
:
1126 case BFD_RELOC_LARCH_SOP_POP_32_S_10_12
:
1127 case BFD_RELOC_LARCH_SOP_POP_32_U_10_12
:
1128 case BFD_RELOC_LARCH_SOP_POP_32_S_10_16
:
1129 case BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2
:
1130 case BFD_RELOC_LARCH_SOP_POP_32_S_5_20
:
1131 case BFD_RELOC_LARCH_SOP_POP_32_U
:
1132 case BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2
:
1133 case BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2
:
1134 if (!last_reloc_is_sop_push_pcrel
)
1137 fix_reloc_insn (fixP
, (bfd_vma
)stack_top
, buf
);
1142 if (fixP
->fx_r_type
== BFD_RELOC_32
1143 && fixP
->fx_addsy
&& fixP
->fx_subsy
1144 && (sub_segment
= S_GET_SEGMENT (fixP
->fx_subsy
))
1145 && strcmp (sub_segment
->name
, ".eh_frame") == 0
1146 && S_GET_VALUE (fixP
->fx_subsy
)
1147 == fixP
->fx_frag
->fr_address
+ fixP
->fx_where
)
1149 fixP
->fx_r_type
= BFD_RELOC_LARCH_32_PCREL
;
1150 fixP
->fx_subsy
= NULL
;
1156 fixP
->fx_next
= xmemdup (fixP
, sizeof (*fixP
), sizeof (*fixP
));
1157 fixP
->fx_next
->fx_addsy
= fixP
->fx_subsy
;
1158 fixP
->fx_next
->fx_subsy
= NULL
;
1159 fixP
->fx_next
->fx_offset
= 0;
1160 fixP
->fx_subsy
= NULL
;
1162 switch (fixP
->fx_r_type
)
1165 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD64
;
1166 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB64
;
1169 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD32
;
1170 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB32
;
1176 md_number_to_chars (buf
, 0, fixP
->fx_size
);
1179 if (fixP
->fx_addsy
== NULL
)
1182 md_number_to_chars (buf
, *valP
, fixP
->fx_size
);
1189 fixP
->fx_next
= xmemdup (fixP
, sizeof (*fixP
), sizeof (*fixP
));
1190 fixP
->fx_next
->fx_addsy
= fixP
->fx_subsy
;
1191 fixP
->fx_next
->fx_subsy
= NULL
;
1192 fixP
->fx_next
->fx_offset
= 0;
1193 fixP
->fx_subsy
= NULL
;
1195 switch (fixP
->fx_r_type
)
1198 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD24
;
1199 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB24
;
1202 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD16
;
1203 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB16
;
1206 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD8
;
1207 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB8
;
1213 md_number_to_chars (buf
, 0, fixP
->fx_size
);
1215 if (fixP
->fx_next
->fx_addsy
== NULL
)
1216 fixP
->fx_next
->fx_done
= 1;
1218 if (fixP
->fx_addsy
== NULL
)
1221 md_number_to_chars (buf
, *valP
, fixP
->fx_size
);
1225 case BFD_RELOC_LARCH_B16
:
1226 case BFD_RELOC_LARCH_B21
:
1227 case BFD_RELOC_LARCH_B26
:
1228 if (fixP
->fx_addsy
== NULL
)
1230 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
1231 _ ("Relocation against a constant."));
1233 if (S_GET_SEGMENT (fixP
->fx_addsy
) == seg
1234 && !S_FORCE_RELOC (fixP
->fx_addsy
, 1))
1236 int64_t sym_addend
= S_GET_VALUE (fixP
->fx_addsy
) + fixP
->fx_offset
;
1237 int64_t pc
= fixP
->fx_where
+ fixP
->fx_frag
->fr_address
;
1238 fix_reloc_insn (fixP
, sym_addend
- pc
, buf
);
1250 loongarch_relax_frag (asection
*sec ATTRIBUTE_UNUSED
,
1251 fragS
*fragp ATTRIBUTE_UNUSED
,
1252 long stretch ATTRIBUTE_UNUSED
)
1258 md_estimate_size_before_relax (fragS
*fragp ATTRIBUTE_UNUSED
,
1259 asection
*segtype ATTRIBUTE_UNUSED
)
1265 loongarch_fix_adjustable (fixS
*fix
)
1267 /* Prevent all adjustments to global symbols. */
1268 if (S_IS_EXTERNAL (fix
->fx_addsy
)
1269 || S_IS_WEAK (fix
->fx_addsy
)
1270 || S_FORCE_RELOC (fix
->fx_addsy
, true))
1273 /* Loongarch loads extern symbols by GOT, and if there are embedded
1274 asm(".local S"), gcc just output ".local S" to assembly file.
1275 For a local symbol with GOT relocations, this adjustments will make
1276 GOT relocation's addend not equal to zero. So this adjustments is
1277 forbidden for got relocs. */
1278 if(fix
->fx_r_type
== BFD_RELOC_LARCH_GOT_PC_HI20
1279 || fix
->fx_r_type
== BFD_RELOC_LARCH_GOT_PC_LO12
1280 || fix
->fx_r_type
== BFD_RELOC_LARCH_GOT64_PC_LO20
1281 || fix
->fx_r_type
== BFD_RELOC_LARCH_GOT64_PC_HI12
1282 || fix
->fx_r_type
== BFD_RELOC_LARCH_GOT_HI20
1283 || fix
->fx_r_type
== BFD_RELOC_LARCH_GOT_LO12
1284 || fix
->fx_r_type
== BFD_RELOC_LARCH_GOT64_LO20
1285 || fix
->fx_r_type
== BFD_RELOC_LARCH_GOT64_HI12
)
1291 /* Translate internal representation of relocation info to BFD target
1294 tc_gen_reloc (asection
*section ATTRIBUTE_UNUSED
, fixS
*fixp
)
1296 arelent
*reloc
= (arelent
*) xmalloc (sizeof (arelent
));
1298 reloc
->sym_ptr_ptr
= (asymbol
**) xmalloc (sizeof (asymbol
*));
1299 *reloc
->sym_ptr_ptr
= symbol_get_bfdsym (fixp
->fx_addsy
);
1300 reloc
->address
= fixp
->fx_frag
->fr_address
+ fixp
->fx_where
;
1301 reloc
->addend
= fixp
->fx_offset
;
1303 reloc
->howto
= bfd_reloc_type_lookup (stdoutput
, fixp
->fx_r_type
);
1304 if (reloc
->howto
== NULL
)
1306 as_bad_where (fixp
->fx_file
, fixp
->fx_line
,
1307 _("cannot represent %s relocation in object file"),
1308 bfd_get_reloc_code_name (fixp
->fx_r_type
));
1315 /* Convert a machine dependent frag. */
1317 md_convert_frag (bfd
*abfd ATTRIBUTE_UNUSED
, segT asec ATTRIBUTE_UNUSED
,
1318 fragS
*fragp ATTRIBUTE_UNUSED
)
1320 /* fragp->fr_fix += 8; */
1323 /* Standard calling conventions leave the CFA at SP on entry. */
1325 loongarch_cfi_frame_initial_instructions (void)
1327 cfi_add_CFA_def_cfa_register (3 /* $sp */);
1331 tc_loongarch_parse_to_dw2regnum (expressionS
*exp
)
1333 expression_and_evaluate (exp
);
1337 md_show_usage (FILE *stream
)
1339 fprintf (stream
, _("LARCH options:\n"));
1343 /* Fill in an rs_align_code fragment. We want to fill 'andi $r0,$r0,0'. */
1345 loongarch_handle_align (fragS
*fragp
)
1347 /* char nop_opcode; */
1349 int bytes
, size
, excess
;
1352 if (fragp
->fr_type
!= rs_align_code
)
1355 struct loongarch_cl_insn nop
=
1356 { .name
= "andi", .arg_strs
= { "$r0", "$r0", "0", NULL
} };
1358 get_loongarch_opcode (&nop
);
1359 gas_assert (nop
.all_match
);
1361 p
= fragp
->fr_literal
+ fragp
->fr_fix
;
1362 opcode
= nop
.insn_bin
;
1365 bytes
= fragp
->fr_next
->fr_address
- fragp
->fr_address
- fragp
->fr_fix
;
1366 excess
= bytes
% size
;
1368 gas_assert (excess
< 4);
1369 fragp
->fr_fix
+= excess
;
1371 while (excess
-- != 0)
1374 md_number_to_chars (p
, opcode
, size
);
1375 fragp
->fr_var
= size
;
1379 loongarch_elf_final_processing (void)
1381 elf_elfheader (stdoutput
)->e_flags
= LARCH_opts
.ase_abi
;