1 /* tc-loongarch.c -- Assemble for the LoongArch ISA 2 3 Copyright (C) 2021-2022 Free Software Foundation, Inc. 4 Contributed by Loongson Ltd. 5 6 This file is part of GAS. 7 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. 12 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. 17 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/>. */ 21 22 #include "as.h" 23 #include "dw2gencfi.h" 24 #include "loongarch-lex.h" 25 #include "elf/loongarch.h" 26 #include "opcode/loongarch.h" 27 #include "obj-elf.h" 28 #include "bfd/elfxx-loongarch.h" 29 #include <stdlib.h> 30 #include <string.h> 31 #include <stdio.h> 32 #include <assert.h> 33 34 /* All information about an instruction during assemble. */ 35 struct loongarch_cl_insn 36 { 37 /* First split string. */ 38 const char *name; 39 const char *arg_strs[MAX_ARG_NUM_PLUS_2]; 40 size_t arg_num; 41 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. */ 47 int match_now; 48 int all_match; 49 50 const struct loongarch_opcode *insn; 51 size_t insn_length; 52 53 offsetT args[MAX_ARG_NUM_PLUS_2]; 54 struct reloc_info reloc_info[MAX_RELOC_NUMBER_A_INSN]; 55 size_t reloc_num; 56 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; 62 63 /* Then we get the binary representation of insn 64 and write it in to section. */ 65 insn_t insn_bin; 66 67 /* The frag that contains the instruction. */ 68 struct frag *frag; 69 /* The offset into FRAG of the first instruction byte. */ 70 long where; 71 /* The relocs associated with the instruction, if any. */ 72 fixS *fixp[MAX_RELOC_NUMBER_A_INSN]; 73 }; 74 75 #ifndef DEFAULT_ARCH 76 #define DEFAULT_ARCH "loongarch64" 77 #endif 78 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[] = "#"; 82 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[] = "#"; 91 92 /* This array holds machine specific line separator characters. */ 93 const char line_separator_chars[] = ";"; 94 95 /* Chars that can be used to separate mant from exp in floating point nums. */ 96 const char EXP_CHARS[] = "eE"; 97 98 /* Chars that mean this number is a floating point constant. */ 99 /* As in 0f12.456. */ 100 /* or 0d1.2345e12. */ 101 const char FLT_CHARS[] = "rRsSfFdDxXpP"; 102 103 const char *md_shortopts = "O::g::G:"; 104 105 static const char default_arch[] = DEFAULT_ARCH; 106 107 enum options 108 { 109 OPTION_IGNORE = OPTION_MD_BASE, 110 111 OPTION_ABI, 112 OPTION_FLOAT_ABI, 113 114 OPTION_FLOAT_ISA, 115 116 OPTION_LA_LOCAL_WITH_ABS, 117 OPTION_LA_GLOBAL_WITH_PCREL, 118 OPTION_LA_GLOBAL_WITH_ABS, 119 120 OPTION_END_OF_ENUM, 121 }; 122 123 struct option md_longopts[] = 124 { 125 { "mabi", required_argument, NULL, OPTION_ABI }, 126 127 { "mfpu", required_argument, NULL, OPTION_FLOAT_ISA }, 128 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 }, 132 133 { NULL, no_argument, NULL, 0 } 134 }; 135 136 size_t md_longopts_size = sizeof (md_longopts); 137 138 int 139 md_parse_option (int c, const char *arg) 140 { 141 int ret = 1; 142 char lp64[256] = ""; 143 char ilp32[256] = ""; 144 unsigned char *suf = (unsigned char *)arg; 145 146 lp64['s'] = lp64['S'] = EF_LOONGARCH_ABI_LP64_SOFT_FLOAT; 147 lp64['f'] = lp64['F'] = EF_LOONGARCH_ABI_LP64_SINGLE_FLOAT; 148 lp64['d'] = lp64['D'] = EF_LOONGARCH_ABI_LP64_DOUBLE_FLOAT; 149 150 ilp32['s'] = ilp32['S'] = EF_LOONGARCH_ABI_ILP32_SOFT_FLOAT; 151 ilp32['f'] = ilp32['F'] = EF_LOONGARCH_ABI_ILP32_SINGLE_FLOAT; 152 ilp32['d'] = ilp32['D'] = EF_LOONGARCH_ABI_ILP32_DOUBLE_FLOAT; 153 154 switch (c) 155 { 156 case OPTION_ABI: 157 if (strncasecmp (arg, "lp64", 4) == 0 && lp64[suf[4]] != 0) 158 { 159 LARCH_opts.ase_ilp32 = 1; 160 LARCH_opts.ase_lp64 = 1; 161 LARCH_opts.ase_abi = lp64[suf[4]]; 162 } 163 else if (strncasecmp (arg, "ilp32", 5) == 0 && ilp32[suf[5]] != 0) 164 { 165 LARCH_opts.ase_abi = ilp32[suf[5]]; 166 LARCH_opts.ase_ilp32 = 1; 167 } 168 else 169 ret = 0; 170 break; 171 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) 178 { 179 LARCH_opts.ase_sf = 1; 180 LARCH_opts.ase_df = 1; 181 } 182 else 183 ret = 0; 184 break; 185 186 case OPTION_LA_LOCAL_WITH_ABS: 187 LARCH_opts.ase_labs = 1; 188 break; 189 190 case OPTION_LA_GLOBAL_WITH_PCREL: 191 LARCH_opts.ase_gpcr = 1; 192 break; 193 194 case OPTION_LA_GLOBAL_WITH_ABS: 195 LARCH_opts.ase_gabs = 1; 196 break; 197 198 case OPTION_IGNORE: 199 break; 200 201 default: 202 ret = 0; 203 break; 204 } 205 return ret; 206 } 207 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; 214 215 void 216 loongarch_after_parse_args () 217 { 218 /* Set default ABI/ISA LP64D. */ 219 if (!EF_LOONGARCH_IS_LP64(LARCH_opts.ase_abi) 220 && !EF_LOONGARCH_IS_ILP32(LARCH_opts.ase_abi)) 221 { 222 if (strcmp (default_arch, "loongarch64") == 0) 223 { 224 LARCH_opts.ase_abi = EF_LOONGARCH_ABI_LP64_DOUBLE_FLOAT; 225 LARCH_opts.ase_ilp32 = 1; 226 LARCH_opts.ase_lp64 = 1; 227 } 228 else if (strcmp (default_arch, "loongarch32") == 0) 229 { 230 LARCH_opts.ase_abi = EF_LOONGARCH_ABI_ILP32_DOUBLE_FLOAT; 231 LARCH_opts.ase_ilp32 = 1; 232 } 233 else 234 as_bad ("unknown default architecture `%s'", default_arch); 235 } 236 237 /* Set default ISA double-float. */ 238 if (!LARCH_opts.ase_nf 239 && !LARCH_opts.ase_sf 240 && !LARCH_opts.ase_df) 241 { 242 LARCH_opts.ase_sf = 1; 243 LARCH_opts.ase_df = 1; 244 } 245 246 size_t i; 247 248 assert(LARCH_opts.ase_ilp32); 249 250 /* Init ilp32/lp64 registers names. */ 251 if (!r_htab) 252 r_htab = str_htab_create (), str_hash_insert (r_htab, "", 0, 0); 253 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); 256 257 if (!cr_htab) 258 cr_htab = str_htab_create (), str_hash_insert (cr_htab, "", 0, 0); 259 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); 262 263 /* Init single/double float registers names. */ 264 if (LARCH_opts.ase_sf || LARCH_opts.ase_df) 265 { 266 if (!f_htab) 267 f_htab = str_htab_create (), str_hash_insert (f_htab, "", 0, 0); 268 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), 271 0); 272 273 if (!c_htab) 274 c_htab = str_htab_create (), str_hash_insert (c_htab, "", 0, 0); 275 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), 278 0); 279 280 } 281 282 /* Init lsx registers names. */ 283 if (LARCH_opts.ase_lsx) 284 { 285 if (!v_htab) 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), 289 0); 290 } 291 292 /* Init lasx registers names. */ 293 if (LARCH_opts.ase_lasx) 294 { 295 if (!x_htab) 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), 299 0); 300 } 301 302 /* Init lp64 registers alias. */ 303 if (LARCH_opts.ase_lp64) 304 { 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), 307 0); 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), 310 0); 311 } 312 313 /* Init float-lp64 registers alias */ 314 if ((LARCH_opts.ase_sf || LARCH_opts.ase_df) && LARCH_opts.ase_lp64) 315 { 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); 322 } 323 } 324 325 const char * 326 loongarch_target_format () 327 { 328 return LARCH_opts.ase_lp64 ? "elf64-loongarch" : "elf32-loongarch"; 329 } 330 331 void 332 md_begin () 333 { 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++) 338 { 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 " 344 "macro is NULL"), 345 it->name, it->format); 346 if (it->macro 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); 350 } 351 352 /* FIXME: expressionS use 'offsetT' as constant, 353 * we want this is 64-bit type. */ 354 assert (8 <= sizeof (offsetT)); 355 } 356 357 unsigned long 358 loongarch_mach (void) 359 { 360 return LARCH_opts.ase_lp64 ? bfd_mach_loongarch64 : bfd_mach_loongarch32; 361 } 362 363 static const expressionS const_0 = { .X_op = O_constant, .X_add_number = 0 }; 364 365 static const char * 366 my_getExpression (expressionS *ep, const char *str) 367 { 368 char *save_in, *ret; 369 save_in = input_line_pointer; 370 input_line_pointer = (char *) str; 371 expression (ep); 372 ret = input_line_pointer; 373 input_line_pointer = save_in; 374 return ret; 375 } 376 377 static void 378 s_loongarch_align (int arg) 379 { 380 const char *t = input_line_pointer; 381 while (!is_end_of_line[(unsigned char) *t] && *t != ',') 382 ++t; 383 if (*t == ',') 384 s_align_ptwo (arg); 385 else 386 s_align_ptwo (0); 387 } 388 389 /* Handle the .dtprelword and .dtpreldword pseudo-ops. They generate 390 a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for 391 use in DWARF debug information. */ 392 393 static void 394 s_dtprel (int bytes) 395 { 396 expressionS ex; 397 char *p; 398 399 expression (&ex); 400 401 if (ex.X_op != O_symbol) 402 { 403 as_bad (_("Unsupported use of %s"), 404 (bytes == 8 ? ".dtpreldword" : ".dtprelword")); 405 ignore_rest_of_line (); 406 } 407 408 p = frag_more (bytes); 409 md_number_to_chars (p, 0, bytes); 410 fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE, 411 (bytes == 8 412 ? BFD_RELOC_LARCH_TLS_DTPREL64 413 : BFD_RELOC_LARCH_TLS_DTPREL32)); 414 415 demand_empty_rest_of_line (); 416 } 417 418 static const pseudo_typeS loongarch_pseudo_table[] = 419 { 420 { "align", s_loongarch_align, -4 }, 421 { "dword", cons, 8 }, 422 { "word", cons, 4 }, 423 { "half", cons, 2 }, 424 { "dtprelword", s_dtprel, 4 }, 425 { "dtpreldword", s_dtprel, 8 }, 426 { NULL, NULL, 0 }, 427 }; 428 429 void 430 loongarch_pop_insert (void) 431 { 432 pop_insert (loongarch_pseudo_table); 433 } 434 435 #define INTERNAL_LABEL_SPECIAL 10 436 static unsigned long internal_label_count[INTERNAL_LABEL_SPECIAL] = { 0 }; 437 438 static const char * 439 loongarch_internal_label_name (unsigned long label, int augend) 440 { 441 static char symbol_name_build[24]; 442 unsigned long want_label; 443 char *p; 444 445 want_label = internal_label_count[label] + augend; 446 447 p = symbol_name_build; 448 #ifdef LOCAL_LABEL_PREFIX 449 *p++ = LOCAL_LABEL_PREFIX; 450 #endif 451 *p++ = 'L'; 452 for (; label; label /= 10) 453 *p++ = label % 10 + '0'; 454 /* Make sure internal label never belong to normal label namespace. */ 455 *p++ = ':'; 456 for (; want_label; want_label /= 10) 457 *p++ = want_label % 10 + '0'; 458 *p++ = '\0'; 459 return symbol_name_build; 460 } 461 462 static void 463 setup_internal_label_here (unsigned long label) 464 { 465 assert (label < INTERNAL_LABEL_SPECIAL); 466 internal_label_count[label]++; 467 colon (loongarch_internal_label_name (label, 0)); 468 } 469 470 void 471 get_internal_label (expressionS *label_expr, unsigned long label, 472 int augend /* 0 for previous, 1 for next. */) 473 { 474 assert (label < INTERNAL_LABEL_SPECIAL); 475 if (augend == 0 && internal_label_count[label] == 0) 476 as_fatal (_("internal error: we have no internal label yet")); 477 label_expr->X_op = O_symbol; 478 label_expr->X_add_symbol = 479 symbol_find_or_make (loongarch_internal_label_name (label, augend)); 480 label_expr->X_add_number = 0; 481 } 482 483 extern int loongarch_parse_expr (const char *expr, 484 struct reloc_info *reloc_stack_top, 485 size_t max_reloc_num, size_t *reloc_num, 486 offsetT *imm_if_no_reloc); 487 488 static int 489 is_internal_label (const char *c_str) 490 { 491 do 492 { 493 if (*c_str != ':') 494 break; 495 c_str++; 496 if (!('0' <= *c_str && *c_str <= '9')) 497 break; 498 while ('0' <= *c_str && *c_str <= '9') 499 c_str++; 500 if (*c_str != 'b' && *c_str != 'f') 501 break; 502 c_str++; 503 return *c_str == '\0'; 504 } 505 while (0); 506 return 0; 507 } 508 509 static int 510 is_label (const char *c_str) 511 { 512 if (is_internal_label (c_str)) 513 return 1; 514 else if ('0' <= *c_str && *c_str <= '9') 515 { 516 /* [0-9]+[bf] */ 517 while ('0' <= *c_str && *c_str <= '9') 518 c_str++; 519 return *c_str == 'b' || *c_str == 'f'; 520 } 521 else if (is_name_beginner (*c_str)) 522 { 523 /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */ 524 c_str++; 525 while (is_part_of_name (*c_str)) 526 c_str++; 527 return *c_str == '\0'; 528 } 529 else 530 return 0; 531 } 532 533 static int 534 is_label_with_addend (const char *c_str) 535 { 536 if (is_internal_label (c_str)) 537 return 1; 538 else if ('0' <= *c_str && *c_str <= '9') 539 { 540 /* [0-9]+[bf] */ 541 while ('0' <= *c_str && *c_str <= '9') 542 c_str++; 543 if (*c_str == 'b' || *c_str == 'f') 544 c_str++; 545 else 546 return 0; 547 return *c_str == '\0' 548 || ((*c_str == '-' || *c_str == '+') 549 && is_unsigned (c_str + 1)); 550 } 551 else if (is_name_beginner (*c_str)) 552 { 553 /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */ 554 c_str++; 555 while (is_part_of_name (*c_str)) 556 c_str++; 557 return *c_str == '\0' 558 || ((*c_str == '-' || *c_str == '+') 559 && is_unsigned (c_str + 1)); 560 } 561 else 562 return 0; 563 } 564 565 static int32_t 566 loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2, 567 const char *bit_field, 568 const char *arg, void *context) 569 { 570 struct loongarch_cl_insn *ip = context; 571 offsetT imm, ret = 0; 572 size_t reloc_num_we_have = MAX_RELOC_NUMBER_A_INSN - ip->reloc_num; 573 size_t reloc_num = 0; 574 575 if (!ip->match_now) 576 return 0; 577 578 switch (esc_ch1) 579 { 580 case 'l': 581 switch (esc_ch2) 582 { 583 default: 584 ip->match_now = is_label (arg); 585 if (!ip->match_now && is_label_with_addend (arg)) 586 as_fatal (_("This label shouldn't be with addend.")); 587 break; 588 case 'a': 589 ip->match_now = is_label_with_addend (arg); 590 break; 591 } 592 break; 593 case 's': 594 case 'u': 595 ip->match_now = 596 loongarch_parse_expr (arg, ip->reloc_info + ip->reloc_num, 597 reloc_num_we_have, &reloc_num, &imm) == 0; 598 599 if (!ip->match_now) 600 break; 601 602 if (esc_ch1 == 's') 603 switch (esc_ch2) 604 { 605 case 'c': 606 ip->match_now = reloc_num == 0; 607 break; 608 } 609 else 610 switch (esc_ch2) 611 { 612 case 'c': 613 ip->match_now = reloc_num == 0 && 0 <= imm; 614 break; 615 } 616 617 if (!ip->match_now) 618 break; 619 620 ret = imm; 621 if (reloc_num) 622 { 623 bfd_reloc_code_real_type reloc_type = BFD_RELOC_NONE; 624 reloc_num_we_have -= reloc_num; 625 if (reloc_num_we_have == 0) 626 as_fatal (_("expr too huge") /* Want one more reloc. */); 627 if (esc_ch1 == 'u') 628 { 629 if (strncmp (bit_field, "10:12", strlen ("10:12")) == 0) 630 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_U_10_12; 631 } 632 else if (esc_ch1 == 's') 633 { 634 if (strncmp (bit_field, "10:16<<2", strlen ("10:16<<2")) == 0) 635 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2; 636 else if (strncmp (bit_field, "0:5|10:16<<2", 637 strlen ("0:5|10:16<<2")) == 0) 638 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2; 639 else if (strncmp (bit_field, "0:10|10:16<<2", 640 strlen ("0:10|10:16<<2")) == 0) 641 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2; 642 else if (strncmp (bit_field, "10:12", strlen ("10:12")) == 0) 643 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_12; 644 else if (strncmp (bit_field, "5:20", strlen ("5:20")) == 0) 645 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_5_20; 646 else if (strncmp (bit_field, "10:16", strlen ("10:16")) == 0) 647 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_16; 648 else if (strncmp (bit_field, "10:5", strlen ("10:5")) == 0) 649 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_5; 650 } 651 if (reloc_type == BFD_RELOC_NONE) 652 as_fatal ( 653 _("not support reloc bit-field\nfmt: %c%c %s\nargs: %s"), 654 esc_ch1, esc_ch2, bit_field, arg); 655 reloc_num++; 656 ip->reloc_num += reloc_num; 657 ip->reloc_info[ip->reloc_num - 1].type = reloc_type; 658 ip->reloc_info[ip->reloc_num - 1].value = const_0; 659 } 660 break; 661 case 'r': 662 imm = (intptr_t) str_hash_find (r_htab, arg); 663 ip->match_now = 0 < imm; 664 ret = imm - 1; 665 break; 666 case 'f': 667 imm = (intptr_t) str_hash_find (f_htab, arg); 668 ip->match_now = 0 < imm; 669 ret = imm - 1; 670 break; 671 case 'c': 672 switch (esc_ch2) 673 { 674 case 'r': 675 imm = (intptr_t) str_hash_find (cr_htab, arg); 676 break; 677 default: 678 imm = (intptr_t) str_hash_find (c_htab, arg); 679 } 680 ip->match_now = 0 < imm; 681 ret = imm - 1; 682 break; 683 case 'v': 684 imm = (intptr_t) str_hash_find (v_htab, arg); 685 ip->match_now = 0 < imm; 686 ret = imm - 1; 687 break; 688 case 'x': 689 imm = (intptr_t) str_hash_find (x_htab, arg); 690 ip->match_now = 0 < imm; 691 ret = imm - 1; 692 break; 693 case '\0': 694 ip->all_match = ip->match_now; 695 ip->insn_length = 696 ip->insn->mask ? loongarch_insn_length (ip->insn->match) : 0; 697 /* FIXME: now we have no relax insn. */ 698 ip->relax_max_length = ip->insn_length; 699 break; 700 default: 701 as_fatal (_("unknown escape")); 702 } 703 704 do 705 { 706 /* Check imm overflow. */ 707 int bit_width, bits_needed_s, bits_needed_u; 708 char *t; 709 710 if (!ip->match_now) 711 break; 712 713 if (0 < reloc_num) 714 break; 715 716 bit_width = loongarch_get_bit_field_width (bit_field, &t); 717 718 if (bit_width == -1) 719 /* No specify bit width. */ 720 break; 721 722 imm = ret; 723 if (t[0] == '<' && t[1] == '<') 724 { 725 int i = strtol (t += 2, &t, 10), j; 726 for (j = i; 0 < j; j--, imm >>= 1) 727 if (imm & 1) 728 as_fatal (_("require imm low %d bit is 0."), i); 729 } 730 731 if (*t == '+') 732 imm -= strtol (t, &t, 10); 733 734 bits_needed_s = loongarch_bits_imm_needed (imm, 1); 735 bits_needed_u = loongarch_bits_imm_needed (imm, 0); 736 737 if ((esc_ch1 == 's' && bit_width < bits_needed_s) 738 || (esc_ch1 != 's' && bit_width < bits_needed_u)) 739 /* How to do after we detect overflow. */ 740 as_fatal (_("Immediate overflow.\n" 741 "format: %c%c%s\n" 742 "arg: %s"), 743 esc_ch1, esc_ch2, bit_field, arg); 744 } 745 while (0); 746 747 if (esc_ch1 != '\0') 748 { 749 ip->args[ip->arg_num] = ret; 750 ip->arg_num++; 751 } 752 return ret; 753 } 754 755 static void 756 get_loongarch_opcode (struct loongarch_cl_insn *insn) 757 { 758 const struct loongarch_opcode *it; 759 struct loongarch_ase *ase; 760 for (ase = loongarch_ASEs; ase->enabled; ase++) 761 { 762 if (!*ase->enabled || (ase->include && !*ase->include) 763 || (ase->exclude && *ase->exclude)) 764 continue; 765 766 if (!ase->name_hash_entry) 767 { 768 ase->name_hash_entry = str_htab_create (); 769 for (it = ase->opcodes; it->name; it++) 770 str_hash_insert (ase->name_hash_entry, it->name, (void *) it, 0); 771 } 772 773 if ((it = str_hash_find (ase->name_hash_entry, insn->name)) == NULL) 774 continue; 775 776 do 777 { 778 insn->insn = it; 779 insn->match_now = 1; 780 insn->all_match = 0; 781 insn->arg_num = 0; 782 insn->reloc_num = 0; 783 insn->insn_bin = (loongarch_foreach_args 784 (it->format, insn->arg_strs, 785 loongarch_args_parser_can_match_arg_helper, 786 insn)); 787 if (insn->all_match && !(it->include && !*it->include) 788 && !(it->exclude && *it->exclude)) 789 { 790 insn->insn_bin |= it->match; 791 return; 792 } 793 it++; 794 } 795 while (it->name && strcasecmp (it->name, insn->name) == 0); 796 } 797 } 798 799 static int 800 check_this_insn_before_appending (struct loongarch_cl_insn *ip) 801 { 802 int ret = 0; 803 if (strcmp (ip->name, "la.abs") == 0) 804 { 805 ip->reloc_info[ip->reloc_num].type = BFD_RELOC_LARCH_MARK_LA; 806 my_getExpression (&ip->reloc_info[ip->reloc_num].value, ip->arg_strs[1]); 807 ip->reloc_num++; 808 } 809 else if (ip->insn->mask == 0xffff8000 810 /* amswap.w rd, rk, rj */ 811 && ((ip->insn_bin & 0xfff00000) == 0x38600000 812 /* ammax_db.wu rd, rk, rj */ 813 || (ip->insn_bin & 0xffff0000) == 0x38700000 814 /* ammin_db.wu rd, rk, rj */ 815 || (ip->insn_bin & 0xffff0000) == 0x38710000)) 816 { 817 /* For AMO insn amswap.[wd], amadd.[wd], etc. */ 818 if (ip->args[0] != 0 819 && (ip->args[0] == ip->args[1] || ip->args[0] == ip->args[2])) 820 as_fatal (_("AMO insns require rd != base && rd != rt" 821 " when rd isn't $r0")); 822 } 823 else if ((ip->insn->mask == 0xffe08000 824 /* bstrins.w rd, rj, msbw, lsbw */ 825 && (ip->insn_bin & 0xffe00000) == 0x00600000) 826 || (ip->insn->mask == 0xffc00000 827 /* bstrins.d rd, rj, msbd, lsbd */ 828 && (ip->insn_bin & 0xff800000) == 0x00800000)) 829 { 830 /* For bstr(ins|pick).[wd]. */ 831 if (ip->args[2] < ip->args[3]) 832 as_fatal (_("bstr(ins|pick).[wd] require msbd >= lsbd")); 833 } 834 else if (ip->insn->mask != 0 && (ip->insn_bin & 0xfe0003c0) == 0x04000000 835 /* csrxchg rd, rj, csr_num */ 836 && (strcmp ("csrxchg", ip->name) == 0)) 837 as_fatal (_("csrxchg require rj != $r0 && rj != $r1")); 838 839 return ret; 840 } 841 842 static void 843 install_insn (const struct loongarch_cl_insn *insn) 844 { 845 char *f = insn->frag->fr_literal + insn->where; 846 if (0 < insn->insn_length) 847 md_number_to_chars (f, insn->insn_bin, insn->insn_length); 848 } 849 850 static void 851 move_insn (struct loongarch_cl_insn *insn, fragS *frag, long where) 852 { 853 size_t i; 854 insn->frag = frag; 855 insn->where = where; 856 for (i = 0; i < insn->reloc_num; i++) 857 { 858 insn->fixp[i]->fx_frag = frag; 859 insn->fixp[i]->fx_where = where; 860 } 861 install_insn (insn); 862 } 863 864 /* Add INSN to the end of the output. */ 865 static void 866 append_fixed_insn (struct loongarch_cl_insn *insn) 867 { 868 char *f = frag_more (insn->insn_length); 869 move_insn (insn, frag_now, f - frag_now->fr_literal); 870 } 871 872 static void 873 append_fixp_and_insn (struct loongarch_cl_insn *ip) 874 { 875 reloc_howto_type *howto; 876 bfd_reloc_code_real_type reloc_type; 877 struct reloc_info *reloc_info = ip->reloc_info; 878 size_t i; 879 880 dwarf2_emit_insn (0); 881 882 for (i = 0; i < ip->reloc_num; i++) 883 { 884 reloc_type = reloc_info[i].type; 885 howto = bfd_reloc_type_lookup (stdoutput, reloc_type); 886 if (howto == NULL) 887 as_fatal (_("no HOWTO loong relocation number %d"), reloc_type); 888 889 ip->fixp[i] = 890 fix_new_exp (ip->frag, ip->where, bfd_get_reloc_size (howto), 891 &reloc_info[i].value, FALSE, reloc_type); 892 } 893 894 if (ip->insn_length < ip->relax_max_length) 895 as_fatal (_("Internal error: not support relax now")); 896 else 897 append_fixed_insn (ip); 898 } 899 900 /* Ask helper for returning a malloced c_str or NULL. */ 901 static char * 902 assember_macro_helper (const char *const args[], void *context_ptr) 903 { 904 struct loongarch_cl_insn *insn = context_ptr; 905 char *ret = NULL; 906 if ( strcmp (insn->name, "li.w") == 0 || strcmp (insn->name, "li.d") == 0) 907 { 908 char args_buf[50], insns_buf[200]; 909 const char *arg_strs[6]; 910 uint32_t hi32, lo32; 911 912 /* We pay attention to sign extend beacause it is chance of reduce insn. 913 The exception is 12-bit and hi-12-bit unsigned, 914 we need a 'ori' or a 'lu52i.d' accordingly. */ 915 char all0_bit_vec, sign_bit_vec, allf_bit_vec, paritial_is_sext_of_prev; 916 917 lo32 = insn->args[1] & 0xffffffff; 918 hi32 = insn->args[1] >> 32; 919 920 if (strcmp (insn->name, "li.w") == 0) 921 { 922 if (hi32 != 0 && hi32 != 0xffffffff) 923 as_fatal (_("li overflow: hi32:0x%x lo32:0x%x"), hi32, lo32); 924 hi32 = lo32 & 0x80000000 ? 0xffffffff : 0; 925 } 926 927 if (strcmp (insn->name, "li.d") == 0 && !LARCH_opts.ase_lp64) 928 as_fatal (_("we can't li.d on 32bit-arch")); 929 930 snprintf (args_buf, sizeof (args_buf), "0x%x,0x%x,0x%x,0x%x,%s", 931 (hi32 >> 20) & 0xfff, hi32 & 0xfffff, (lo32 >> 12) & 0xfffff, 932 lo32 & 0xfff, args[0]); 933 loongarch_split_args_by_comma (args_buf, arg_strs); 934 935 all0_bit_vec = 936 ((((hi32 & 0xfff00000) == 0) << 3) | (((hi32 & 0x000fffff) == 0) << 2) 937 | (((lo32 & 0xfffff000) == 0) << 1) | ((lo32 & 0x00000fff) == 0)); 938 sign_bit_vec = 939 ((((hi32 & 0x80000000) != 0) << 3) | (((hi32 & 0x00080000) != 0) << 2) 940 | (((lo32 & 0x80000000) != 0) << 1) | ((lo32 & 0x00000800) != 0)); 941 allf_bit_vec = 942 ((((hi32 & 0xfff00000) == 0xfff00000) << 3) 943 | (((hi32 & 0x000fffff) == 0x000fffff) << 2) 944 | (((lo32 & 0xfffff000) == 0xfffff000) << 1) 945 | ((lo32 & 0x00000fff) == 0x00000fff)); 946 paritial_is_sext_of_prev = 947 (all0_bit_vec ^ allf_bit_vec) & (all0_bit_vec ^ (sign_bit_vec << 1)); 948 949 static const char *const li_32bit[] = 950 { 951 "lu12i.w %5,%3&0x80000?%3-0x100000:%3;ori %5,%5,%4;", 952 "lu12i.w %5,%3&0x80000?%3-0x100000:%3;", 953 "addi.w %5,$r0,%4&0x800?%4-0x1000:%4;", 954 "or %5,$r0,$r0;", 955 }; 956 static const char *const li_hi_32bit[] = 957 { 958 "lu32i.d %5,%2&0x80000?%2-0x100000:%2;" 959 "lu52i.d %5,%5,%1&0x800?%1-0x1000:%1;", 960 "lu52i.d %5,%5,%1&0x800?%1-0x1000:%1;", 961 "lu32i.d %5,%2&0x80000?%2-0x100000:%2;", 962 "", 963 }; 964 do 965 { 966 insns_buf[0] = '\0'; 967 if (paritial_is_sext_of_prev == 0x7) 968 { 969 strcat (insns_buf, "lu52i.d %5,$r0,%1&0x800?%1-0x1000:%1;"); 970 break; 971 } 972 if ((all0_bit_vec & 0x3) == 0x2) 973 strcat (insns_buf, "ori %5,$r0,%4;"); 974 else 975 strcat (insns_buf, li_32bit[paritial_is_sext_of_prev & 0x3]); 976 strcat (insns_buf, li_hi_32bit[paritial_is_sext_of_prev >> 2]); 977 } 978 while (0); 979 980 ret = loongarch_expand_macro (insns_buf, arg_strs, NULL, NULL, 981 sizeof (args_buf)); 982 } 983 return ret; 984 } 985 986 /* Accept instructions separated by ';' 987 * assuming 'not starting with space and not ending with space' or pass in 988 * empty c_str. */ 989 static void 990 loongarch_assemble_INSNs (char *str) 991 { 992 char *rest; 993 size_t len_str = strlen(str); 994 995 for (rest = str; *rest != ';' && *rest != '\0'; rest++); 996 if (*rest == ';') 997 *rest++ = '\0'; 998 999 if (*str == ':') 1000 { 1001 str++; 1002 setup_internal_label_here (strtol (str, &str, 10)); 1003 str++; 1004 } 1005 1006 do 1007 { 1008 if (*str == '\0') 1009 break; 1010 1011 struct loongarch_cl_insn the_one = { 0 }; 1012 the_one.name = str; 1013 1014 for (; *str && *str != ' '; str++) 1015 ; 1016 if (*str == ' ') 1017 *str++ = '\0'; 1018 1019 loongarch_split_args_by_comma (str, the_one.arg_strs); 1020 get_loongarch_opcode (&the_one); 1021 1022 if (!the_one.all_match) 1023 { 1024 char *ss = loongarch_cat_splited_strs (the_one.arg_strs); 1025 as_bad (_("no match insn: %s\t%s"), the_one.name, ss ? ss : ""); 1026 free(ss); 1027 return; 1028 } 1029 1030 if (check_this_insn_before_appending (&the_one) != 0) 1031 break; 1032 1033 append_fixp_and_insn (&the_one); 1034 if (the_one.insn_length == 0 && the_one.insn->macro) 1035 { 1036 char *c_str = loongarch_expand_macro (the_one.insn->macro, 1037 the_one.arg_strs, 1038 assember_macro_helper, 1039 &the_one, len_str); 1040 loongarch_assemble_INSNs (c_str); 1041 free (c_str); 1042 } 1043 } 1044 while (0); 1045 1046 if (*rest != '\0') 1047 loongarch_assemble_INSNs (rest); 1048 } 1049 1050 void 1051 md_assemble (char *str) 1052 { 1053 loongarch_assemble_INSNs (str); 1054 } 1055 1056 const char * 1057 md_atof (int type, char *litP, int *sizeP) 1058 { 1059 return ieee_md_atof (type, litP, sizeP, FALSE); 1060 } 1061 1062 void 1063 md_number_to_chars (char *buf, valueT val, int n) 1064 { 1065 number_to_chars_littleendian (buf, val, n); 1066 } 1067 1068 /* The location from which a PC relative jump should be calculated, 1069 given a PC relative reloc. */ 1070 long 1071 md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED) 1072 { 1073 return 0; 1074 } 1075 1076 static void fix_reloc_insn (fixS *fixP, bfd_vma reloc_val, char *buf) 1077 { 1078 reloc_howto_type *howto; 1079 insn_t insn; 1080 howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); 1081 1082 insn = bfd_getl32 (buf); 1083 1084 if (!loongarch_adjust_reloc_bitsfield(howto, &reloc_val)) 1085 as_warn_where (fixP->fx_file, fixP->fx_line, "Reloc overflow"); 1086 1087 insn = (insn & (insn_t)howto->src_mask) 1088 | ((insn & (~(insn_t)howto->dst_mask)) | reloc_val); 1089 1090 bfd_putl32 (insn, buf); 1091 } 1092 1093 void 1094 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) 1095 { 1096 static int64_t stack_top; 1097 static int last_reloc_is_sop_push_pcrel_1 = 0; 1098 int last_reloc_is_sop_push_pcrel = last_reloc_is_sop_push_pcrel_1; 1099 last_reloc_is_sop_push_pcrel_1 = 0; 1100 1101 char *buf = fixP->fx_frag->fr_literal + fixP->fx_where; 1102 switch (fixP->fx_r_type) 1103 { 1104 case BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL: 1105 case BFD_RELOC_LARCH_SOP_PUSH_TLS_GD: 1106 case BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT: 1107 case BFD_RELOC_LARCH_SOP_PUSH_PCREL: 1108 case BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL: 1109 if (fixP->fx_addsy == NULL) 1110 as_bad_where (fixP->fx_file, fixP->fx_line, 1111 _("Relocation against a constant")); 1112 1113 if (fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL 1114 || fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_GD 1115 || fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT) 1116 S_SET_THREAD_LOCAL (fixP->fx_addsy); 1117 1118 if (fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_PCREL) 1119 { 1120 last_reloc_is_sop_push_pcrel_1 = 1; 1121 if (S_GET_SEGMENT (fixP->fx_addsy) == seg) 1122 stack_top = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset 1123 - (fixP->fx_where + fixP->fx_frag->fr_address)); 1124 else 1125 stack_top = 0; 1126 } 1127 break; 1128 1129 case BFD_RELOC_LARCH_SOP_POP_32_S_10_5: 1130 case BFD_RELOC_LARCH_SOP_POP_32_S_10_12: 1131 case BFD_RELOC_LARCH_SOP_POP_32_U_10_12: 1132 case BFD_RELOC_LARCH_SOP_POP_32_S_10_16: 1133 case BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2: 1134 case BFD_RELOC_LARCH_SOP_POP_32_S_5_20: 1135 case BFD_RELOC_LARCH_SOP_POP_32_U: 1136 case BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2: 1137 case BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2: 1138 if (!last_reloc_is_sop_push_pcrel) 1139 break; 1140 1141 fix_reloc_insn (fixP, (bfd_vma)stack_top, buf); 1142 break; 1143 1144 case BFD_RELOC_64: 1145 case BFD_RELOC_32: 1146 if (fixP->fx_subsy) 1147 { 1148 case BFD_RELOC_24: 1149 case BFD_RELOC_16: 1150 case BFD_RELOC_8: 1151 fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP)); 1152 fixP->fx_next->fx_addsy = fixP->fx_subsy; 1153 fixP->fx_next->fx_subsy = NULL; 1154 fixP->fx_next->fx_offset = 0; 1155 fixP->fx_subsy = NULL; 1156 1157 switch (fixP->fx_r_type) 1158 { 1159 case BFD_RELOC_64: 1160 fixP->fx_r_type = BFD_RELOC_LARCH_ADD64; 1161 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB64; 1162 break; 1163 case BFD_RELOC_32: 1164 fixP->fx_r_type = BFD_RELOC_LARCH_ADD32; 1165 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB32; 1166 break; 1167 case BFD_RELOC_24: 1168 fixP->fx_r_type = BFD_RELOC_LARCH_ADD24; 1169 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB24; 1170 break; 1171 case BFD_RELOC_16: 1172 fixP->fx_r_type = BFD_RELOC_LARCH_ADD16; 1173 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB16; 1174 break; 1175 case BFD_RELOC_8: 1176 fixP->fx_r_type = BFD_RELOC_LARCH_ADD8; 1177 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB8; 1178 break; 1179 default: 1180 break; 1181 } 1182 md_number_to_chars (buf, 0, fixP->fx_size); 1183 if (fixP->fx_next->fx_addsy == NULL) 1184 fixP->fx_next->fx_done = 1; 1185 } 1186 if (fixP->fx_addsy == NULL) 1187 { 1188 fixP->fx_done = 1; 1189 md_number_to_chars (buf, *valP, fixP->fx_size); 1190 } 1191 break; 1192 1193 default: 1194 break; 1195 } 1196 } 1197 1198 int 1199 loongarch_relax_frag (asection *sec ATTRIBUTE_UNUSED, 1200 fragS *fragp ATTRIBUTE_UNUSED, 1201 long stretch ATTRIBUTE_UNUSED) 1202 { 1203 return 0; 1204 } 1205 1206 int 1207 md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, 1208 asection *segtype ATTRIBUTE_UNUSED) 1209 { 1210 return 0; 1211 } 1212 1213 /* Translate internal representation of relocation info to BFD target 1214 format. */ 1215 arelent * 1216 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) 1217 { 1218 arelent *reloc = (arelent *) xmalloc (sizeof (arelent)); 1219 1220 reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); 1221 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); 1222 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; 1223 reloc->addend = fixp->fx_offset; 1224 1225 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); 1226 if (reloc->howto == NULL) 1227 { 1228 as_bad_where (fixp->fx_file, fixp->fx_line, 1229 _("cannot represent %s relocation in object file"), 1230 bfd_get_reloc_code_name (fixp->fx_r_type)); 1231 return NULL; 1232 } 1233 1234 return reloc; 1235 } 1236 1237 /* Convert a machine dependent frag. */ 1238 void 1239 md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec ATTRIBUTE_UNUSED, 1240 fragS *fragp ATTRIBUTE_UNUSED) 1241 { 1242 /* fragp->fr_fix += 8; */ 1243 } 1244 1245 /* Standard calling conventions leave the CFA at SP on entry. */ 1246 void 1247 loongarch_cfi_frame_initial_instructions (void) 1248 { 1249 cfi_add_CFA_def_cfa_register (3 /* $sp */); 1250 } 1251 1252 int 1253 loongarch_dwarf2_addr_size (void) 1254 { 1255 return LARCH_opts.ase_lp64 ? 8 : 4; 1256 } 1257 1258 void 1259 tc_loongarch_parse_to_dw2regnum (expressionS *exp) 1260 { 1261 expression_and_evaluate (exp); 1262 } 1263 1264 void 1265 md_show_usage (FILE *stream) 1266 { 1267 fprintf (stream, _("LARCH options:\n")); 1268 /* FIXME */ 1269 } 1270 1271 /* Fill in an rs_align_code fragment. We want to fill 'andi $r0,$r0,0'. */ 1272 void 1273 loongarch_handle_align (fragS *fragp) 1274 { 1275 /* char nop_opcode; */ 1276 char *p; 1277 int bytes, size, excess; 1278 valueT opcode; 1279 1280 if (fragp->fr_type != rs_align_code) 1281 return; 1282 1283 struct loongarch_cl_insn nop = 1284 { .name = "andi", .arg_strs = { "$r0", "$r0", "0", NULL } }; 1285 1286 get_loongarch_opcode (&nop); 1287 gas_assert (nop.all_match); 1288 1289 p = fragp->fr_literal + fragp->fr_fix; 1290 opcode = nop.insn_bin; 1291 size = 4; 1292 1293 bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; 1294 excess = bytes % size; 1295 1296 gas_assert (excess < 4); 1297 fragp->fr_fix += excess; 1298 1299 while (excess-- != 0) 1300 *p++ = 0; 1301 1302 md_number_to_chars (p, opcode, size); 1303 fragp->fr_var = size; 1304 } 1305 1306 void 1307 loongarch_elf_final_processing (void) 1308 { 1309 elf_elfheader (stdoutput)->e_flags = LARCH_opts.ase_abi; 1310 } 1311