X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-riscv.c;h=a4e01b6c798a7195fd26704b0c11acd4088c83af;hb=21a186f28061ea51e422ae47d062793ceac2180f;hp=2830ba1e53e83a54f052b417ea864af8f6f37fe7;hpb=fecb9c46659c576e9e2c790eff2a25df8203a97f;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 2830ba1e53..a4e01b6c79 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -126,7 +126,7 @@ riscv_clear_subsets (void) while (riscv_subsets != NULL) { struct riscv_subset *next = riscv_subsets->next; - free (riscv_subsets->name); + free ((void *) riscv_subsets->name); free (riscv_subsets); riscv_subsets = next; } @@ -147,8 +147,8 @@ riscv_add_subset (const char *subset) static void riscv_set_arch (const char *s) { - const char *all_subsets = "imafdc"; - const char *extension = NULL; + const char *all_subsets = "imafdqc"; + char *extension = NULL; const char *p = s; riscv_clear_subsets(); @@ -173,7 +173,7 @@ riscv_set_arch (const char *s) case 'g': p++; - for ( ; *all_subsets != 'c'; all_subsets++) + for ( ; *all_subsets != 'q'; all_subsets++) { const char subset[] = {*all_subsets, '\0'}; riscv_add_subset (subset); @@ -188,7 +188,8 @@ riscv_set_arch (const char *s) { if (*p == 'x') { - char *subset = xstrdup (p), *q = subset; + char *subset = xstrdup (p); + char *q = subset; while (*++q != '\0' && *q != '_') ; @@ -200,7 +201,6 @@ riscv_set_arch (const char *s) extension = subset; riscv_add_subset (subset); p += strlen (subset); - free (subset); } else if (*p == '_') p++; @@ -211,15 +211,11 @@ riscv_set_arch (const char *s) all_subsets++; p++; } - else if (*p == 'q') - { - const char subset[] = {*p, 0}; - riscv_add_subset (subset); - p++; - } else as_fatal ("-march=%s: unsupported ISA subset `%c'", s, *p); } + + free (extension); } /* Handle of the OPCODE hash table. */ @@ -647,6 +643,7 @@ md_begin (void) hash_reg_names (RCLASS_FPR, riscv_fpr_names_abi, NFPR); #define DECLARE_CSR(name, num) hash_reg_name (RCLASS_CSR, #name, num); +#define DECLARE_CSR_ALIAS(name, num) DECLARE_CSR(name, num); #include "opcode/riscv-opc.h" #undef DECLARE_CSR @@ -719,6 +716,21 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr, add_fixed_insn (ip); install_insn (ip); + + /* We need to start a new frag after any instruction that can be + optimized away or compressed by the linker during relaxation, to prevent + the assembler from computing static offsets across such an instruction. + This is necessary to get correct EH info. */ + if (reloc_type == BFD_RELOC_RISCV_CALL + || reloc_type == BFD_RELOC_RISCV_CALL_PLT + || reloc_type == BFD_RELOC_RISCV_HI20 + || reloc_type == BFD_RELOC_RISCV_PCREL_HI20 + || reloc_type == BFD_RELOC_RISCV_TPREL_HI20 + || reloc_type == BFD_RELOC_RISCV_TPREL_ADD) + { + frag_wane (frag_now); + frag_new (0); + } } /* Build an instruction created by a macro expansion. This is passed @@ -1173,6 +1185,25 @@ my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc, return reloc_index; } +/* Detect and handle implicitly zero load-store offsets. For example, + "lw t0, (t1)" is shorthand for "lw t0, 0(t1)". Return TRUE iff such + an implicit offset was detected. */ + +static bfd_boolean +riscv_handle_implicit_zero_offset (expressionS *expr, const char *s) +{ + /* Check whether there is only a single bracketed expression left. + If so, it must be the base register and the constant must be zero. */ + if (*s == '(' && strchr (s + 1, '(') == 0) + { + expr->X_op = O_constant; + expr->X_add_number = 0; + return TRUE; + } + + return FALSE; +} + /* This routine assembles an instruction into its binary format. As a side effect, it sets the global variable imm_reloc to the type of relocation to do if one of the operands is an address expression. */ @@ -1313,6 +1344,8 @@ rvc_imm_done: ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number); goto rvc_imm_done; case 'k': + if (riscv_handle_implicit_zero_offset (imm_expr, s)) + continue; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_LW_IMM (imm_expr->X_add_number)) @@ -1320,6 +1353,8 @@ rvc_imm_done: ip->insn_opcode |= ENCODE_RVC_LW_IMM (imm_expr->X_add_number); goto rvc_imm_done; case 'l': + if (riscv_handle_implicit_zero_offset (imm_expr, s)) + continue; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_LD_IMM (imm_expr->X_add_number)) @@ -1327,6 +1362,8 @@ rvc_imm_done: ip->insn_opcode |= ENCODE_RVC_LD_IMM (imm_expr->X_add_number); goto rvc_imm_done; case 'm': + if (riscv_handle_implicit_zero_offset (imm_expr, s)) + continue; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_LWSP_IMM (imm_expr->X_add_number)) @@ -1335,6 +1372,8 @@ rvc_imm_done: ENCODE_RVC_LWSP_IMM (imm_expr->X_add_number); goto rvc_imm_done; case 'n': + if (riscv_handle_implicit_zero_offset (imm_expr, s)) + continue; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_LDSP_IMM (imm_expr->X_add_number)) @@ -1345,6 +1384,9 @@ rvc_imm_done: case 'o': if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant + /* C.addiw, c.li, and c.andi allow zero immediate. + C.addi allows zero immediate as hint. Otherwise this + is same as 'j'. */ || !VALID_RVC_IMM (imm_expr->X_add_number)) break; ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number); @@ -1368,6 +1410,8 @@ rvc_imm_done: ENCODE_RVC_ADDI16SP_IMM (imm_expr->X_add_number); goto rvc_imm_done; case 'M': + if (riscv_handle_implicit_zero_offset (imm_expr, s)) + continue; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_SWSP_IMM (imm_expr->X_add_number)) @@ -1376,6 +1420,8 @@ rvc_imm_done: ENCODE_RVC_SWSP_IMM (imm_expr->X_add_number); goto rvc_imm_done; case 'N': + if (riscv_handle_implicit_zero_offset (imm_expr, s)) + continue; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_SDSP_IMM (imm_expr->X_add_number)) @@ -1445,8 +1491,8 @@ rvc_lui: my_getExpression (imm_expr, s); check_absolute_expr (ip, imm_expr); if ((unsigned long) imm_expr->X_add_number > 31) - as_warn (_("Improper shift amount (%lu)"), - (unsigned long) imm_expr->X_add_number); + as_bad (_("Improper shift amount (%lu)"), + (unsigned long) imm_expr->X_add_number); INSERT_OPERAND (SHAMTW, *ip, imm_expr->X_add_number); imm_expr->X_op = O_absent; s = expr_end; @@ -1456,8 +1502,8 @@ rvc_lui: my_getExpression (imm_expr, s); check_absolute_expr (ip, imm_expr); if ((unsigned long) imm_expr->X_add_number >= xlen) - as_warn (_("Improper shift amount (%lu)"), - (unsigned long) imm_expr->X_add_number); + as_bad (_("Improper shift amount (%lu)"), + (unsigned long) imm_expr->X_add_number); INSERT_OPERAND (SHAMT, *ip, imm_expr->X_add_number); imm_expr->X_op = O_absent; s = expr_end; @@ -1467,8 +1513,8 @@ rvc_lui: my_getExpression (imm_expr, s); check_absolute_expr (ip, imm_expr); if ((unsigned long) imm_expr->X_add_number > 31) - as_warn (_("Improper CSRxI immediate (%lu)"), - (unsigned long) imm_expr->X_add_number); + as_bad (_("Improper CSRxI immediate (%lu)"), + (unsigned long) imm_expr->X_add_number); INSERT_OPERAND (RS1, *ip, imm_expr->X_add_number); imm_expr->X_op = O_absent; s = expr_end; @@ -1482,8 +1528,8 @@ rvc_lui: my_getExpression (imm_expr, s); check_absolute_expr (ip, imm_expr); if ((unsigned long) imm_expr->X_add_number > 0xfff) - as_warn (_("Improper CSR address (%lu)"), - (unsigned long) imm_expr->X_add_number); + as_bad (_("Improper CSR address (%lu)"), + (unsigned long) imm_expr->X_add_number); INSERT_OPERAND (CSR, *ip, imm_expr->X_add_number); imm_expr->X_op = O_absent; s = expr_end; @@ -1606,12 +1652,7 @@ rvc_lui: p = percent_op_rtype; *imm_reloc = BFD_RELOC_UNUSED; load_store: - /* Check whether there is only a single bracketed expression - left. If so, it must be the base register and the - constant must be zero. */ - imm_expr->X_op = O_constant; - imm_expr->X_add_number = 0; - if (*s == '(' && strchr (s + 1, '(') == 0) + if (riscv_handle_implicit_zero_offset (imm_expr, s)) continue; alu_op: /* If this value won't fit into a 16 bit offset, then go @@ -1871,6 +1912,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) bfd_byte *buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where); bfd_boolean relaxable = FALSE; offsetT loc; + segT sub_segment; /* Remember value for tc_gen_reloc. */ fixP->fx_addnumber = *valP; @@ -1888,7 +1930,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) break; case BFD_RELOC_RISCV_GOT_HI20: - case BFD_RELOC_RISCV_PCREL_HI20: case BFD_RELOC_RISCV_ADD8: case BFD_RELOC_RISCV_ADD16: case BFD_RELOC_RISCV_ADD32: @@ -1919,8 +1960,25 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) _("TLS relocation against a constant")); break; - case BFD_RELOC_64: case BFD_RELOC_32: + /* Use pc-relative relocation for FDE initial location. + The symbol address in .eh_frame may be adjusted in + _bfd_elf_discard_section_eh_frame, and the content of + .eh_frame will be adjusted in _bfd_elf_write_section_eh_frame. + Therefore, we cannot insert a relocation whose addend symbol is + in .eh_frame. Othrewise, the value may be adjusted twice.*/ + if (fixP->fx_addsy && fixP->fx_subsy + && (sub_segment = S_GET_SEGMENT (fixP->fx_subsy)) + && strcmp (sub_segment->name, ".eh_frame") == 0 + && S_GET_VALUE (fixP->fx_subsy) + == fixP->fx_frag->fr_address + fixP->fx_where) + { + fixP->fx_r_type = BFD_RELOC_RISCV_32_PCREL; + fixP->fx_subsy = NULL; + break; + } + /* Fall through. */ + case BFD_RELOC_64: case BFD_RELOC_16: case BFD_RELOC_8: case BFD_RELOC_RISCV_CFA: @@ -2064,8 +2122,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) relaxable = TRUE; break; + case BFD_RELOC_RISCV_PCREL_HI20: case BFD_RELOC_RISCV_PCREL_LO12_S: case BFD_RELOC_RISCV_PCREL_LO12_I: + relaxable = riscv_opts.relax; + break; + case BFD_RELOC_RISCV_ALIGN: break; @@ -2260,30 +2322,29 @@ bfd_boolean riscv_frag_align_code (int n) { bfd_vma bytes = (bfd_vma) 1 << n; - bfd_vma min_text_alignment_order = riscv_opts.rvc ? 1 : 2; - bfd_vma min_text_alignment = (bfd_vma) 1 << min_text_alignment_order; + bfd_vma insn_alignment = riscv_opts.rvc ? 2 : 4; + bfd_vma worst_case_bytes = bytes - insn_alignment; + char *nops; + expressionS ex; - /* First, get back to minimal alignment. */ - frag_align_code (min_text_alignment_order, 0); + /* If we are moving to a smaller alignment than the instruction size, then no + alignment is required. */ + if (bytes <= insn_alignment) + return TRUE; + + nops = frag_more (worst_case_bytes); /* When not relaxing, riscv_handle_align handles code alignment. */ if (!riscv_opts.relax) return FALSE; - if (bytes > min_text_alignment) - { - bfd_vma worst_case_bytes = bytes - min_text_alignment; - char *nops = frag_more (worst_case_bytes); - expressionS ex; - - ex.X_op = O_constant; - ex.X_add_number = worst_case_bytes; + ex.X_op = O_constant; + ex.X_add_number = worst_case_bytes; - riscv_make_nops (nops, worst_case_bytes); + riscv_make_nops (nops, worst_case_bytes); - fix_new_exp (frag_now, nops - frag_now->fr_literal, 0, - &ex, FALSE, BFD_RELOC_RISCV_ALIGN); - } + fix_new_exp (frag_now, nops - frag_now->fr_literal, 0, + &ex, FALSE, BFD_RELOC_RISCV_ALIGN); return TRUE; }