diff options
author | Andrew Waterman <waterman@cs.berkeley.edu> | 2015-03-30 18:14:33 -0700 |
---|---|---|
committer | Andrew Waterman <waterman@cs.berkeley.edu> | 2015-03-31 12:13:35 -0700 |
commit | 0a401fc3ed8e16e233196a22070f5faf9c178e7b (patch) | |
tree | 75f879adb1227aaab284522da6a09d32357cbb54 /binutils | |
parent | 6285c24a785d664beaf5b45ffb1121c70af7d0ee (diff) | |
download | riscv-gnu-toolchain-0a401fc3ed8e16e233196a22070f5faf9c178e7b.zip riscv-gnu-toolchain-0a401fc3ed8e16e233196a22070f5faf9c178e7b.tar.gz riscv-gnu-toolchain-0a401fc3ed8e16e233196a22070f5faf9c178e7b.tar.bz2 |
binutils: produce RVC branches/jumps
Diffstat (limited to 'binutils')
-rw-r--r-- | binutils/bfd/elfnn-riscv.c | 18 | ||||
-rw-r--r-- | binutils/bfd/elfxx-riscv.c | 35 | ||||
-rw-r--r-- | binutils/gas/config/tc-riscv.c | 244 | ||||
-rw-r--r-- | binutils/include/elf/riscv.h | 2 | ||||
-rw-r--r-- | binutils/include/opcode/riscv.h | 22 | ||||
-rw-r--r-- | binutils/opcodes/riscv-dis.c | 11 | ||||
-rw-r--r-- | binutils/opcodes/riscv-opc.c | 16 |
7 files changed, 250 insertions, 98 deletions
diff --git a/binutils/bfd/elfnn-riscv.c b/binutils/bfd/elfnn-riscv.c index 74f6e0b..53a9235 100644 --- a/binutils/bfd/elfnn-riscv.c +++ b/binutils/bfd/elfnn-riscv.c @@ -577,6 +577,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_RISCV_CALL: case R_RISCV_JAL: case R_RISCV_BRANCH: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: case R_RISCV_PCREL_HI20: /* In shared libs, these relocs are known to bind locally. */ if (info->shared) @@ -816,6 +818,8 @@ riscv_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_RISCV_BRANCH: case R_RISCV_CALL: case R_RISCV_JAL: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: if (info->shared) break; /* Fall through. */ @@ -1506,6 +1510,18 @@ perform_relocation (const reloc_howto_type *howto, value = ENCODE_SBTYPE_IMM (value); break; + case R_RISCV_RVC_BRANCH: + if (!VALID_RVC_B_IMM (value)) + return bfd_reloc_overflow; + value = ENCODE_RVC_B_IMM (value); + break; + + case R_RISCV_RVC_JUMP: + if (!VALID_RVC_J_IMM (value)) + return bfd_reloc_overflow; + value = ENCODE_RVC_J_IMM (value); + break; + case R_RISCV_32: case R_RISCV_64: case R_RISCV_ADD8: @@ -1776,6 +1792,7 @@ riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, continue; case R_RISCV_BRANCH: + case R_RISCV_RVC_BRANCH: case R_RISCV_HI20: /* These require no special handling beyond perform_relocation. */ break; @@ -1884,6 +1901,7 @@ riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_RISCV_CALL_PLT: case R_RISCV_CALL: case R_RISCV_JAL: + case R_RISCV_RVC_JUMP: if (info->shared && h != NULL && h->plt.offset != MINUS_ONE) { /* Refer to the PLT entry. */ diff --git a/binutils/bfd/elfxx-riscv.c b/binutils/bfd/elfxx-riscv.c index e30f3c1..32738a9 100644 --- a/binutils/bfd/elfxx-riscv.c +++ b/binutils/bfd/elfxx-riscv.c @@ -639,6 +639,39 @@ static reloc_howto_type howto_table[] = 0, /* src_mask */ 0, /* dst_mask */ TRUE), /* pcrel_offset */ + + /* 8-bit PC-relative branch offset. */ + HOWTO (R_RISCV_RVC_BRANCH, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_RVC_BRANCH", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + ENCODE_RVC_B_IMM(-1U), /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* 11-bit PC-relative jump offset. */ + HOWTO (R_RISCV_RVC_JUMP, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + /* This needs complex overflow + detection, because the upper 36 + bits must match the PC + 4. */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_RVC_JUMP", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + ENCODE_RVC_J_IMM(-1U), /* dst_mask */ + TRUE), /* pcrel_offset */ }; /* A mapping from BFD reloc types to RISC-V ELF reloc types. */ @@ -686,6 +719,8 @@ static const struct elf_reloc_map riscv_reloc_map[] = { BFD_RELOC_RISCV_TLS_GOT_HI20, R_RISCV_TLS_GOT_HI20 }, { BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 }, { BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN }, + { BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH }, + { BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP }, }; /* Given a BFD reloc type, return a howto structure. */ diff --git a/binutils/gas/config/tc-riscv.c b/binutils/gas/config/tc-riscv.c index 7f9b518..ddc6c73 100644 --- a/binutils/gas/config/tc-riscv.c +++ b/binutils/gas/config/tc-riscv.c @@ -162,14 +162,15 @@ riscv_set_arch (const char* arg) if (*arg && *arg != 'I') as_fatal("`I' must be the first ISA subset name specified (got %c)", *arg); - for (p = arg; *p; p++) + for (p = arg; *p; ) { if (*p == 'X') { - char *subset = xstrdup(p + 1), *q = subset; + char *subset = xstrdup(p), *q = subset; - while (ISLOWER(*q)) + do q++; + while (ISLOWER(*q)); *q = 0; riscv_add_subset (subset); @@ -182,6 +183,7 @@ riscv_set_arch (const char* arg) riscv_add_subset (subset); if (*p == 'C') rvc = 1; + p++; } else as_fatal("unsupported ISA subset %c", *p); @@ -229,14 +231,16 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP"; static char *insn_error; -#define RELAX_BRANCH_ENCODE(uncond, toofar) \ +#define RELAX_BRANCH_ENCODE(uncond, rvc, length) \ ((relax_substateT) \ (0xc0000000 \ - | ((toofar) ? 1 : 0) \ - | ((uncond) ? 2 : 0))) + | ((uncond) ? 1 : 0) \ + | ((rvc) ? 2 : 0) \ + | ((length) << 2))) #define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000) -#define RELAX_BRANCH_TOOFAR(i) (((i) & 1) != 0) -#define RELAX_BRANCH_UNCOND(i) (((i) & 2) != 0) +#define RELAX_BRANCH_LENGTH(i) (((i) >> 2) & 0xF) +#define RELAX_BRANCH_RVC(i) (((i) & 2) != 0) +#define RELAX_BRANCH_UNCOND(i) (((i) & 1) != 0) /* Is the given value a sign-extended 32-bit value? */ #define IS_SEXT_32BIT_NUM(x) \ @@ -359,37 +363,41 @@ add_relaxed_insn (struct riscv_cl_insn *insn, int max_chars, int var, subtype, symbol, offset, NULL); } -/* Compute the length of a branch sequence, and adjust the - RELAX_BRANCH_TOOFAR bit accordingly. If FRAGP is NULL, the - worst-case length is computed. */ +/* Compute the length of a branch sequence, and adjust the stored length + accordingly. If FRAGP is NULL, the worst-case length is returned. */ + static int relaxed_branch_length (fragS *fragp, asection *sec, int update) { - bfd_boolean toofar = TRUE; + int jump, rvc, length = 8; - if (fragp) - { - bfd_boolean uncond = RELAX_BRANCH_UNCOND (fragp->fr_subtype); + if (!fragp) + return length; - if (S_IS_DEFINED (fragp->fr_symbol) - && sec == S_GET_SEGMENT (fragp->fr_symbol)) - { - offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset; - bfd_vma range; - val -= fragp->fr_address + fragp->fr_fix; + jump = RELAX_BRANCH_UNCOND (fragp->fr_subtype); + rvc = RELAX_BRANCH_RVC (fragp->fr_subtype); + length = RELAX_BRANCH_LENGTH (fragp->fr_subtype); - if (uncond) - range = RISCV_JUMP_REACH; - else - range = RISCV_BRANCH_REACH; - toofar = (bfd_vma)(val + range/2) >= range; - } + /* Assume jumps are in range; the linker will catch any that aren't. */ + length = jump ? 4 : 8; - if (update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype)) - fragp->fr_subtype = RELAX_BRANCH_ENCODE (uncond, toofar); + if (S_IS_DEFINED (fragp->fr_symbol) + && sec == S_GET_SEGMENT (fragp->fr_symbol)) + { + offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset; + bfd_vma rvc_range = jump ? RVC_JUMP_REACH : RVC_BRANCH_REACH; + val -= fragp->fr_address + fragp->fr_fix; + + if (rvc && (bfd_vma)(val + rvc_range/2) < rvc_range) + length = 2; + else if ((bfd_vma)(val + RISCV_BRANCH_REACH/2) < RISCV_BRANCH_REACH) + length = 4; } - return toofar ? 8 : 4; + if (update) + fragp->fr_subtype = RELAX_BRANCH_ENCODE (jump, rvc, length); + + return length; } struct regname { @@ -545,12 +553,16 @@ validate_riscv_insn (const struct riscv_opcode *opc) case 'S': USE_BITS (OP_MASK_CRS1, OP_SH_CRS1); break; case 'c': break; /* RS1, constrained to equal sp */ case 'U': break; /* RS2, constrained to equal RD */ + case '>': used_bits |= ENCODE_RVC_IMM(-1U); break; case 'j': used_bits |= ENCODE_RVC_IMM(-1U); break; case 'k': used_bits |= ENCODE_RVC_LW_IMM(-1U); break; case 'l': used_bits |= ENCODE_RVC_LD_IMM(-1U); break; case 'm': used_bits |= ENCODE_RVC_LWSP_IMM(-1U); break; case 'n': used_bits |= ENCODE_RVC_LDSP_IMM(-1U); break; case 'u': used_bits |= ENCODE_RVC_IMM(-1U); break; + case 'v': used_bits |= ENCODE_RVC_IMM(-1U); break; + case 'a': used_bits |= ENCODE_RVC_J_IMM(-1U); break; + case 'p': used_bits |= ENCODE_RVC_B_IMM(-1U); break; default: as_bad (_("internal: bad RISC-V opcode (unknown operand type `C%c'): %s %s"), c, opc->name, opc->args); @@ -709,10 +721,14 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr, } reloc_type = BFD_RELOC_UNUSED; } - else if (reloc_type == BFD_RELOC_12_PCREL) + else if (reloc_type == BFD_RELOC_12_PCREL + || reloc_type == BFD_RELOC_RISCV_JMP) { - add_relaxed_insn (ip, relaxed_branch_length (NULL, NULL, 0), 4, - RELAX_BRANCH_ENCODE (0, 0), + int j = reloc_type == BFD_RELOC_RISCV_JMP; + int best_case = riscv_insn_length (ip->insn_opcode); + int worst_case = relaxed_branch_length (NULL, NULL, 0); + add_relaxed_insn (ip, worst_case, best_case, + RELAX_BRANCH_ENCODE (j, best_case == 2, worst_case), address_expr->X_add_symbol, address_expr->X_add_number); return; @@ -724,14 +740,10 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr, howto = bfd_reloc_type_lookup (stdoutput, reloc_type); if (howto == NULL) as_bad (_("Unsupported RISC-V relocation number %d"), reloc_type); - + ip->fixp = fix_new_exp (ip->frag, ip->where, bfd_get_reloc_size (howto), - address_expr, - reloc_type == BFD_RELOC_12_PCREL || - reloc_type == BFD_RELOC_RISCV_CALL || - reloc_type == BFD_RELOC_RISCV_JMP, - reloc_type); + address_expr, FALSE, reloc_type); /* These relocations can have an addend that won't fit in 4 octets for 64bit assembly. */ @@ -1285,6 +1297,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, imm_expr->X_op = O_absent; *imm_reloc = BFD_RELOC_UNUSED; + p = percent_op_itype; for (args = insn->args;; ++args) { @@ -1444,70 +1457,78 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, || regno != X_SP) break; continue; - case 'j': - p = percent_op_itype; + case '>': if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant - || !VALID_RVC_IMM (imm_expr->X_add_number)) + || !VALID_RVC_IMM (imm_expr->X_add_number - 32)) break; + ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number); +rvc_imm_done: s = expr_end; imm_expr->X_op = O_absent; - ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number); continue; + case 'j': + if (my_getSmallExpression (imm_expr, imm_reloc, s, p) + || imm_expr->X_op != O_constant + || !VALID_RVC_IMM (imm_expr->X_add_number)) + break; + ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number); + goto rvc_imm_done; case 'k': - p = percent_op_itype; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_LW_IMM (imm_expr->X_add_number)) break; - s = expr_end; - imm_expr->X_op = O_absent; ip->insn_opcode |= ENCODE_RVC_LW_IMM (imm_expr->X_add_number); - continue; + goto rvc_imm_done; case 'l': - p = percent_op_itype; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_LD_IMM (imm_expr->X_add_number)) break; - s = expr_end; - imm_expr->X_op = O_absent; ip->insn_opcode |= ENCODE_RVC_LD_IMM (imm_expr->X_add_number); - continue; + goto rvc_imm_done; case 'm': - p = percent_op_itype; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_LWSP_IMM (imm_expr->X_add_number)) break; - s = expr_end; - imm_expr->X_op = O_absent; ip->insn_opcode |= ENCODE_RVC_LWSP_IMM (imm_expr->X_add_number); - continue; + goto rvc_imm_done; case 'n': - p = percent_op_itype; if (my_getSmallExpression (imm_expr, imm_reloc, s, p) || imm_expr->X_op != O_constant || !VALID_RVC_LDSP_IMM (imm_expr->X_add_number)) break; - s = expr_end; - imm_expr->X_op = O_absent; ip->insn_opcode |= ENCODE_RVC_LDSP_IMM (imm_expr->X_add_number); - continue; + goto rvc_imm_done; case 'u': p = percent_op_utype; - if (my_getSmallExpression (imm_expr, imm_reloc, s, p) - || imm_expr->X_op != O_constant + if (my_getSmallExpression (imm_expr, imm_reloc, s, p)) + break; +rvc_lui: + if (imm_expr->X_op != O_constant || imm_expr->X_add_number < 0 || imm_expr->X_add_number >= RISCV_BIGIMM_REACH || (imm_expr->X_add_number >= RISCV_RVC_IMM_REACH/2 && imm_expr->X_add_number < RISCV_BIGIMM_REACH - RISCV_RVC_IMM_REACH/2)) break; - s = expr_end; - imm_expr->X_op = O_absent; ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number); - continue; + goto rvc_imm_done; + case 'v': + if (my_getSmallExpression (imm_expr, imm_reloc, s, p) + || (imm_expr->X_add_number & (RISCV_IMM_REACH-1)) + || (int32_t)imm_expr->X_add_number + != imm_expr->X_add_number) + break; + imm_expr->X_add_number + = (uint32_t)imm_expr->X_add_number >> RISCV_IMM_BITS; + goto rvc_lui; + case 'p': + goto branch; + case 'a': + goto jump; default: as_bad (_("bad RVC field specifier 'C%c'\n"), *args); } @@ -1716,6 +1737,7 @@ alu_op: continue; case 'p': /* pc relative offset */ +branch: *imm_reloc = BFD_RELOC_12_PCREL; my_getExpression (imm_expr, s); s = expr_end; @@ -1737,6 +1759,7 @@ alu_op: continue; case 'a': /* 26 bit address */ +jump: my_getExpression (imm_expr, s); s = expr_end; *imm_reloc = BFD_RELOC_RISCV_JMP; @@ -1779,9 +1802,6 @@ md_assemble (char *str) expressionS imm_expr; bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED; - imm_expr.X_op = O_absent; - imm_reloc = BFD_RELOC_UNUSED; - riscv_ip (str, &insn, &imm_expr, &imm_reloc); if (insn_error) @@ -1994,6 +2014,24 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) } break; + case BFD_RELOC_RISCV_RVC_BRANCH: + if (fixP->fx_addsy) + { + /* Fill in a tentative value to improve objdump readability. */ + bfd_vma delta = ENCODE_RVC_B_IMM (S_GET_VALUE (fixP->fx_addsy) + *valP); + bfd_putl16 (bfd_getl16 (buf) | delta, buf); + } + break; + + case BFD_RELOC_RISCV_RVC_JUMP: + if (fixP->fx_addsy) + { + /* Fill in a tentative value to improve objdump readability. */ + bfd_vma delta = ENCODE_RVC_J_IMM (S_GET_VALUE (fixP->fx_addsy) + *valP); + bfd_putl16 (bfd_getl16 (buf) | delta, buf); + } + break; + case BFD_RELOC_RISCV_PCREL_LO12_S: case BFD_RELOC_RISCV_PCREL_LO12_I: case BFD_RELOC_RISCV_CALL: @@ -2137,7 +2175,7 @@ s_align (int x ATTRIBUTE_UNUSED) ex.X_add_number = worst_case_nop_bytes; fix_new_exp (frag_now, nops - frag_now->fr_literal, 0, - &ex, TRUE, BFD_RELOC_RISCV_ALIGN); + &ex, FALSE, BFD_RELOC_RISCV_ALIGN); } else if (alignment) frag_align (alignment, fill_value, 0); @@ -2164,13 +2202,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - - if (fixp->fx_pcrel) - /* At this point, fx_addnumber is "symbol offset - pcrel address". - Relocations want only the symbol offset. */ - reloc->addend = fixp->fx_addnumber + reloc->address; - else - reloc->addend = fixp->fx_addnumber; + reloc->addend = fixp->fx_addnumber; reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == NULL) @@ -2205,15 +2237,16 @@ riscv_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED) return 0; } -/* Convert a machine dependent frag. */ +/* Expand far branches to multi-instruction sequences. */ static void md_convert_frag_branch (fragS *fragp) { bfd_byte *buf; - insn_t insn; expressionS exp; fixS *fixp; + insn_t insn; + int rs1, reloc; buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix; @@ -2221,10 +2254,45 @@ md_convert_frag_branch (fragS *fragp) exp.X_add_symbol = fragp->fr_symbol; exp.X_add_number = fragp->fr_offset; - if (RELAX_BRANCH_TOOFAR (fragp->fr_subtype)) + gas_assert (fragp->fr_var == RELAX_BRANCH_LENGTH (fragp->fr_subtype)); + + if (RELAX_BRANCH_RVC (fragp->fr_subtype)) + { + switch (RELAX_BRANCH_LENGTH (fragp->fr_subtype)) + { + case 8: + case 4: + /* Expand the RVC branch into a RISC-V one. */ + insn = bfd_getl16 (buf); + rs1 = 8 + ((insn >> OP_SH_CRS1S) & OP_MASK_CRS1S); + if ((insn & MASK_C_J) == MATCH_C_J) + insn = MATCH_JAL; + else if ((insn & MASK_C_BEQZ) == MATCH_C_BEQZ) + insn = MATCH_BEQ | (rs1 << OP_SH_RS1); + else if ((insn & MASK_C_BNEZ) == MATCH_C_BNEZ) + insn = MATCH_BNE | (rs1 << OP_SH_RS1); + else + abort (); + bfd_putl32 (insn, buf); + break; + + case 2: + /* Just keep the RVC branch. */ + reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype) + ? BFD_RELOC_RISCV_RVC_JUMP : BFD_RELOC_RISCV_RVC_BRANCH; + fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, + 2, &exp, FALSE, reloc); + buf += 2; + goto done; + + default: + abort(); + } + } + + switch (RELAX_BRANCH_LENGTH (fragp->fr_subtype)) { - gas_assert (fragp->fr_var == 8); - /* We could relax JAL to AUIPC/JALR, but we don't do this yet. */ + case 8: gas_assert (!RELAX_BRANCH_UNCOND (fragp->fr_subtype)); /* Invert the branch condition. Branch over the jump. */ @@ -2239,17 +2307,23 @@ md_convert_frag_branch (fragS *fragp) 4, &exp, FALSE, BFD_RELOC_RISCV_JMP); md_number_to_chars ((char *) buf, MATCH_JAL, 4); buf += 4; - } - else - { + break; + + case 4: + reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype) + ? BFD_RELOC_RISCV_JMP : BFD_RELOC_12_PCREL; fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, - 4, &exp, FALSE, BFD_RELOC_12_PCREL); + 4, &exp, FALSE, reloc); buf += 4; + break; + + default: + abort (); } +done: fixp->fx_file = fragp->fr_file; fixp->fx_line = fragp->fr_line; - fixp->fx_pcrel = 1; gas_assert (buf == (bfd_byte *)fragp->fr_literal + fragp->fr_fix + fragp->fr_var); diff --git a/binutils/include/elf/riscv.h b/binutils/include/elf/riscv.h index 20ffd1d..a1e9bb6 100644 --- a/binutils/include/elf/riscv.h +++ b/binutils/include/elf/riscv.h @@ -74,6 +74,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type) RELOC_NUMBER (R_RISCV_GNU_VTINHERIT, 41) RELOC_NUMBER (R_RISCV_GNU_VTENTRY, 42) RELOC_NUMBER (R_RISCV_ALIGN, 43) + RELOC_NUMBER (R_RISCV_RVC_BRANCH, 44) + RELOC_NUMBER (R_RISCV_RVC_JUMP, 45) END_RELOC_NUMBERS (R_RISCV_max) /* Processor specific flags for the ELF header e_flags field. */ diff --git a/binutils/include/opcode/riscv.h b/binutils/include/opcode/riscv.h index 061345a..b212231 100644 --- a/binutils/include/opcode/riscv.h +++ b/binutils/include/opcode/riscv.h @@ -64,15 +64,11 @@ static const char* const riscv_pred_succ[16] = { "i", "iw", "ir", "irw", "io", "iow", "ior", "iorw", }; -#define RVC_JUMP_BITS 10 -#define RVC_JUMP_ALIGN_BITS 1 -#define RVC_JUMP_ALIGN (1 << RVC_JUMP_ALIGN_BITS) -#define RVC_JUMP_REACH ((1ULL<<RVC_JUMP_BITS)*RVC_JUMP_ALIGN) +#define RVC_JUMP_BITS 11 +#define RVC_JUMP_REACH ((1ULL<<RVC_JUMP_BITS)*RISCV_JUMP_ALIGN) -#define RVC_BRANCH_BITS 5 -#define RVC_BRANCH_ALIGN_BITS RVC_JUMP_ALIGN_BITS -#define RVC_BRANCH_ALIGN (1 << RVC_BRANCH_ALIGN_BITS) -#define RVC_BRANCH_REACH ((1ULL<<RVC_BRANCH_BITS)*RVC_BRANCH_ALIGN) +#define RVC_BRANCH_BITS 8 +#define RVC_BRANCH_REACH ((1ULL<<RVC_BRANCH_BITS)*RISCV_BRANCH_ALIGN) #define RV_X(x, s, n) (((x) >> (s)) & ((1<<(n))-1)) #define RV_IMM_SIGN(x) (-(((x) >> 31) & 1)) @@ -97,6 +93,10 @@ static const char* const riscv_pred_succ[16] = { ((RV_X(x, 4, 3) << 2) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 2) << 6)) #define EXTRACT_RVC_LDSP_IMM(x) \ ((RV_X(x, 5, 2) << 3) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 3) << 6)) +#define EXTRACT_RVC_B_IMM(x) \ + ((RV_X(x, 7, 1) << 1) | (RV_X(x, 11, 1) << 2) | (RV_X(x, 5, 2) << 3) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 10, 1) << 6) | (RV_X(x, 8, 1) << 7) | (-RV_X(x, 9, 1) << 8)) +#define EXTRACT_RVC_J_IMM(x) \ + ((RV_X(x, 7, 1) << 1) | (RV_X(x, 11, 1) << 2) | (RV_X(x, 5, 2) << 3) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 10, 1) << 6) | (RV_X(x, 8, 2) << 7) | (RV_X(x, 2, 2) << 9) | (-RV_X(x, 4, 1) << 11)) #define ENCODE_ITYPE_IMM(x) \ (RV_X(x, 0, 12) << 20) @@ -118,6 +118,10 @@ static const char* const riscv_pred_succ[16] = { ((RV_X(x, 2, 3) << 4) | (RV_X(x, 5, 1) << 12) | (RV_X(x, 6, 2) << 2)) #define ENCODE_RVC_LDSP_IMM(x) \ ((RV_X(x, 3, 2) << 5) | (RV_X(x, 5, 1) << 12) | (RV_X(x, 6, 3) << 2)) +#define ENCODE_RVC_B_IMM(x) \ + ((RV_X(x, 1, 1) << 7) | (RV_X(x, 2, 1) << 11) | (RV_X(x, 3, 2) << 5) | (RV_X(x, 5, 1) << 12) | (RV_X(x, 6, 1) << 10) | (RV_X(x, 7, 2) << 8)) +#define ENCODE_RVC_J_IMM(x) \ + ((RV_X(x, 1, 1) << 7) | (RV_X(x, 2, 1) << 11) | (RV_X(x, 3, 2) << 5) | (RV_X(x, 5, 1) << 12) | (RV_X(x, 6, 1) << 10) | (RV_X(x, 7, 2) << 8) | (RV_X(x, 9, 3) << 2)) #define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x)) #define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x)) @@ -129,6 +133,8 @@ static const char* const riscv_pred_succ[16] = { #define VALID_RVC_LD_IMM(x) (EXTRACT_RVC_LD_IMM(ENCODE_RVC_LD_IMM(x)) == (x)) #define VALID_RVC_LWSP_IMM(x) (EXTRACT_RVC_LWSP_IMM(ENCODE_RVC_LWSP_IMM(x)) == (x)) #define VALID_RVC_LDSP_IMM(x) (EXTRACT_RVC_LDSP_IMM(ENCODE_RVC_LDSP_IMM(x)) == (x)) +#define VALID_RVC_B_IMM(x) (EXTRACT_RVC_B_IMM(ENCODE_RVC_B_IMM(x)) == (x)) +#define VALID_RVC_J_IMM(x) (EXTRACT_RVC_J_IMM(ENCODE_RVC_J_IMM(x)) == (x)) #define RISCV_RTYPE(insn, rd, rs1, rs2) \ ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2)) diff --git a/binutils/opcodes/riscv-dis.c b/binutils/opcodes/riscv-dis.c index a31ca26..1c84058 100644 --- a/binutils/opcodes/riscv-dis.c +++ b/binutils/opcodes/riscv-dis.c @@ -250,10 +250,21 @@ print_insn_args (const char *d, insn_t l, bfd_vma pc, disassemble_info *info) case 'n': print (info->stream, "%d", (int)EXTRACT_RVC_LDSP_IMM (l)); break; + case 'p': + info->target = EXTRACT_RVC_B_IMM (l) + pc; + (*info->print_address_func) (info->target, info); + break; + case 'a': + info->target = EXTRACT_RVC_J_IMM (l) + pc; + (*info->print_address_func) (info->target, info); + break; case 'u': print (info->stream, "0x%x", (int)(EXTRACT_RVC_IMM (l) & (RISCV_BIGIMM_REACH-1))); break; + case '>': + print (info->stream, "0x%x", (int)EXTRACT_RVC_IMM (l) & 0x3f); + break; } break; diff --git a/binutils/opcodes/riscv-opc.c b/binutils/opcodes/riscv-opc.c index a71f07b..52c501a 100644 --- a/binutils/opcodes/riscv-opc.c +++ b/binutils/opcodes/riscv-opc.c @@ -94,6 +94,7 @@ const char * const riscv_vec_fpr_names[32] = #define MASK_RS1 (OP_MASK_RS1 << OP_SH_RS1) #define MASK_RS2 (OP_MASK_RS2 << OP_SH_RS2) #define MASK_RD (OP_MASK_RD << OP_SH_RD) +#define MASK_CRS1 (OP_MASK_CRS1 << OP_SH_CRS1) #define MASK_IMM ENCODE_ITYPE_IMM(-1U) #define MASK_UIMM ENCODE_UTYPE_IMM(-1U) #define MASK_RM (OP_MASK_RM << OP_SH_RM) @@ -127,8 +128,11 @@ const struct riscv_opcode riscv_builtin_opcodes[] = {"unimp", "I", "", MATCH_CSRRW | (CSR_CYCLE << OP_SH_CSR), 0xffffffffU, match_opcode, 0 }, /* csrw cycle, x0 */ {"sbreak", "C", "", MATCH_C_LI | ENCODE_RVC_IMM(-32U), MASK_C_LI | MASK_RD | ENCODE_RVC_IMM(-1U), match_opcode, 0 }, {"sbreak", "I", "", MATCH_SBREAK, MASK_SBREAK, match_opcode, 0 }, -{"nop", "C", "", MATCH_C_MV, MASK_C_MV | MASK_RD | (OP_MASK_CRS1 << OP_SH_CRS1), match_opcode, 0 }, +{"nop", "C", "", MATCH_C_MV, MASK_C_MV | MASK_RD | MASK_CRS1, match_opcode, 0 }, {"nop", "I", "", MATCH_ADDI, MASK_ADDI | MASK_RD | MASK_RS1 | MASK_IMM, match_opcode, INSN_ALIAS }, +{"lui", "C", "d,Cu", MATCH_C_LUI, MASK_C_LUI, match_opcode, 0 }, +{"lui", "I", "d,u", MATCH_LUI, MASK_LUI, match_opcode, WR_xd }, +{"li", "C", "d,Cv", MATCH_C_LUI, MASK_C_LUI, match_opcode, INSN_ALIAS }, {"li", "C", "d,Cj", MATCH_C_LI, MASK_C_LI, match_opcode, 0 }, {"li", "I", "d,j", MATCH_ADDI, MASK_ADDI | MASK_RS1, match_opcode, INSN_ALIAS|WR_xd }, /* addi */ {"li", "I", "d,I", 0, (int) M_LI, match_never, INSN_MACRO }, @@ -138,6 +142,7 @@ const struct riscv_opcode riscv_builtin_opcodes[] = {"andi", "I", "d,s,j", MATCH_ANDI, MASK_ANDI, match_opcode, WR_xd|RD_xs1 }, {"and", "I", "d,s,t", MATCH_AND, MASK_AND, match_opcode, WR_xd|RD_xs1|RD_xs2 }, {"and", "I", "d,s,j", MATCH_ANDI, MASK_ANDI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 }, +{"beqz", "C", "Cs,Cp", MATCH_C_BEQZ, MASK_C_BEQZ, match_opcode, 0 }, {"beqz", "I", "s,p", MATCH_BEQ, MASK_BEQ | MASK_RS2, match_opcode, INSN_ALIAS|RD_xs1 }, {"beq", "I", "s,t,p", MATCH_BEQ, MASK_BEQ, match_opcode, RD_xs1|RD_xs2 }, {"blez", "I", "t,p", MATCH_BGE, MASK_BGE | MASK_RS1, match_opcode, INSN_ALIAS|RD_xs2 }, @@ -152,6 +157,7 @@ const struct riscv_opcode riscv_builtin_opcodes[] = {"bltu", "I", "s,t,p", MATCH_BLTU, MASK_BLTU, match_opcode, RD_xs1|RD_xs2 }, {"bgt", "I", "t,s,p", MATCH_BLT, MASK_BLT, match_opcode, INSN_ALIAS|RD_xs1|RD_xs2 }, {"bgtu", "I", "t,s,p", MATCH_BLTU, MASK_BLTU, match_opcode, INSN_ALIAS|RD_xs1|RD_xs2 }, +{"bnez", "C", "Cs,Cp", MATCH_C_BNEZ, MASK_C_BNEZ, match_opcode, 0 }, {"bnez", "I", "s,p", MATCH_BNE, MASK_BNE | MASK_RS2, match_opcode, INSN_ALIAS|RD_xs1 }, {"bne", "I", "s,t,p", MATCH_BNE, MASK_BNE, match_opcode, RD_xs1|RD_xs2 }, {"addi", "C", "d,CU,Cj", MATCH_C_ADDI, MASK_C_ADDI, match_opcode, 0 }, @@ -169,7 +175,7 @@ const struct riscv_opcode riscv_builtin_opcodes[] = {"la.tls.gd", "I", "d,A", 0, (int) M_LA_TLS_GD, match_never, INSN_MACRO }, {"la.tls.ie", "I", "d,A", 0, (int) M_LA_TLS_IE, match_never, INSN_MACRO }, {"neg", "I", "d,t", MATCH_SUB, MASK_SUB | MASK_RS1, match_opcode, INSN_ALIAS|WR_xd|RD_xs2 }, /* sub 0 */ -{"slli", "C", "d,CU,Cj", MATCH_C_SLLI, MASK_C_SLLI, match_opcode, 0 }, +{"slli", "C", "d,CU,C>", MATCH_C_SLLI, MASK_C_SLLI, match_opcode, 0 }, {"slli", "I", "d,s,>", MATCH_SLLI, MASK_SLLI, match_opcode, WR_xd|RD_xs1 }, {"sll", "C", "d,CU,Cj", MATCH_C_SLLI, MASK_C_SLLI, match_opcode, 0 }, {"sll", "I", "d,s,t", MATCH_SLL, MASK_SLL, match_opcode, WR_xd|RD_xs1|RD_xs2 }, @@ -181,14 +187,16 @@ const struct riscv_opcode riscv_builtin_opcodes[] = {"sra", "I", "d,s,t", MATCH_SRA, MASK_SRA, match_opcode, WR_xd|RD_xs1|RD_xs2 }, {"sra", "I", "d,s,>", MATCH_SRAI, MASK_SRAI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 }, {"sub", "I", "d,s,t", MATCH_SUB, MASK_SUB, match_opcode, WR_xd|RD_xs1|RD_xs2 }, +{"ret", "C", "", MATCH_C_JALR | (X_RA << OP_SH_CRS1), MASK_C_JALR | MASK_RD | MASK_CRS1, match_opcode, INSN_ALIAS }, {"ret", "I", "", MATCH_JALR | (X_RA << OP_SH_RS1), MASK_JALR | MASK_RD | MASK_RS1 | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 }, +{"j", "C", "Ca", MATCH_C_J, MASK_C_J, match_opcode, 0 }, {"j", "I", "a", MATCH_JAL, MASK_JAL | MASK_RD, match_opcode, INSN_ALIAS }, {"jal", "I", "a", MATCH_JAL | (X_RA << OP_SH_RD), MASK_JAL | MASK_RD, match_opcode, INSN_ALIAS|WR_xd }, {"jal", "I", "d,a", MATCH_JAL, MASK_JAL, match_opcode, WR_xd }, {"call", "I", "c", (X_T0 << OP_SH_RS1) | (X_RA << OP_SH_RD), (int) M_CALL, match_never, INSN_MACRO }, {"tail", "I", "c", (X_T0 << OP_SH_RS1), (int) M_CALL, match_never, INSN_MACRO }, {"jump", "I", "c,s", 0, (int) M_CALL, match_never, INSN_MACRO }, -{"jr", "C", "CS", MATCH_C_JALR, MASK_C_JALR | MASK_RD, match_opcode, 0 }, +{"jr", "C", "CS", MATCH_C_JALR, MASK_C_JALR | MASK_RD, match_opcode, INSN_ALIAS }, {"jr", "I", "s", MATCH_JALR, MASK_JALR | MASK_RD | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 }, {"jr", "I", "s,j", MATCH_JALR, MASK_JALR | MASK_RD, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 }, {"jalr", "C", "CS", MATCH_C_JALR | (X_RA << OP_SH_RD), MASK_C_JALR | MASK_RD, match_opcode, 0 }, @@ -209,8 +217,6 @@ const struct riscv_opcode riscv_builtin_opcodes[] = {"lw", "C", "Cd,Ck(Cs)", MATCH_C_LW, MASK_C_LW, match_opcode, WR_xd|RD_xs1 }, {"lw", "I", "d,o(s)", MATCH_LW, MASK_LW, match_opcode, WR_xd|RD_xs1 }, {"lw", "I", "d,A", 0, (int) M_LW, match_never, INSN_MACRO }, -{"lui", "C", "d,Cu", MATCH_C_LUI, MASK_C_LUI, match_opcode, 0 }, -{"lui", "I", "d,u", MATCH_LUI, MASK_LUI, match_opcode, WR_xd }, {"not", "I", "d,s", MATCH_XORI | MASK_IMM, MASK_XORI | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 }, {"ori", "I", "d,s,j", MATCH_ORI, MASK_ORI, match_opcode, WR_xd|RD_xs1 }, {"or", "I", "d,s,t", MATCH_OR, MASK_OR, match_opcode, WR_xd|RD_xs1|RD_xs2 }, |