diff options
Diffstat (limited to 'gas/config/tc-riscv.c')
-rw-r--r-- | gas/config/tc-riscv.c | 144 |
1 files changed, 92 insertions, 52 deletions
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index e008370..4fc980a 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -162,6 +162,7 @@ struct riscv_ip_error static const char default_arch[] = DEFAULT_ARCH; static const char *default_arch_with_ext = DEFAULT_RISCV_ARCH_WITH_EXT; +static const char *file_arch_str = NULL; static enum riscv_spec_class default_isa_spec = ISA_SPEC_CLASS_NONE; static enum riscv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE; @@ -305,15 +306,17 @@ static riscv_parse_subset_t riscv_rps_as = true, /* check_unknown_prefixed_ext. */ }; -/* Update the architecture string in the subset_list. */ +/* Update file/function-level architecture string according to the + subset_list. */ static void -riscv_reset_subsets_list_arch_str (void) +riscv_set_arch_str (const char **arch_str_p) { riscv_subset_list_t *subsets = riscv_rps_as.subset_list; - if (subsets->arch_str != NULL) - free ((void *) subsets->arch_str); - subsets->arch_str = riscv_arch_str (xlen, subsets); + const char *arch_str = *arch_str_p; + if (arch_str != NULL) + free ((void *) arch_str); + *arch_str_p = riscv_arch_str (xlen, subsets); } /* This structure is used to hold a stack of .option values. */ @@ -347,7 +350,8 @@ riscv_set_arch (const char *s) } riscv_release_subset_list (riscv_rps_as.subset_list); riscv_parse_subset (&riscv_rps_as, s); - riscv_reset_subsets_list_arch_str (); + riscv_set_arch_str (&file_arch_str); + riscv_set_arch_str (&riscv_rps_as.subset_list->arch_str); riscv_set_rvc (false); if (riscv_subset_supports (&riscv_rps_as, "c") @@ -1688,6 +1692,12 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length) case '3': used_bits |= ENCODE_CV_IS3_UIMM5 (-1U); break; + case '6': + used_bits |= ENCODE_CV_BITMANIP_UIMM5(-1U); + break; + case '7': + used_bits |= ENCODE_CV_BITMANIP_UIMM2(-1U); + break; default: goto unknown_validate_operand; } @@ -1784,6 +1794,7 @@ init_opcode_hash (const struct riscv_opcode *opcodes, help us resolve the corresponding low-part relocation later. */ typedef struct { + const asection *sec; bfd_vma address; symbolS *symbol; bfd_vma target; @@ -1798,7 +1809,13 @@ static hashval_t riscv_pcrel_fixup_hash (const void *entry) { const riscv_pcrel_hi_fixup *e = entry; - return (hashval_t) (e->address); + + /* the pcrel_hi with same address may reside in different segments, + to ensure uniqueness, the segment ID needs to be included in the + hash key calculation. + Temporarily using the prime number 499 as a multiplier, but it + might not be large enough. */ + return e->address + 499 * e->sec->id; } /* Compare the keys between two entries fo the pcrel_hi hash table. */ @@ -1807,16 +1824,17 @@ static int riscv_pcrel_fixup_eq (const void *entry1, const void *entry2) { const riscv_pcrel_hi_fixup *e1 = entry1, *e2 = entry2; - return e1->address == e2->address; + return e1->sec->id == e2->sec->id + && e1->address == e2->address; } /* Record the pcrel_hi relocation. */ static bool -riscv_record_pcrel_fixup (htab_t p, bfd_vma address, symbolS *symbol, - bfd_vma target) +riscv_record_pcrel_fixup (htab_t p, const asection *sec, bfd_vma address, + symbolS *symbol, bfd_vma target) { - riscv_pcrel_hi_fixup entry = {address, symbol, target}; + riscv_pcrel_hi_fixup entry = {sec, address, symbol, target}; riscv_pcrel_hi_fixup **slot = (riscv_pcrel_hi_fixup **) htab_find_slot (p, &entry, INSERT); if (slot == NULL) @@ -3988,6 +4006,26 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, ip->insn_opcode |= ENCODE_CV_IS2_UIMM5 (imm_expr->X_add_number); continue; + case '6': + my_getExpression (imm_expr, asarg); + check_absolute_expr (ip, imm_expr, FALSE); + asarg = expr_parse_end; + if (imm_expr->X_add_number < 0 + || imm_expr->X_add_number > 31) + break; + ip->insn_opcode + |= ENCODE_CV_BITMANIP_UIMM5 (imm_expr->X_add_number); + continue; + case '7': + my_getExpression (imm_expr, asarg); + check_absolute_expr (ip, imm_expr, FALSE); + asarg = expr_parse_end; + if (imm_expr->X_add_number < 0 + || imm_expr->X_add_number > 3) + break; + ip->insn_opcode + |= ENCODE_CV_BITMANIP_UIMM2 (imm_expr->X_add_number); + continue; default: goto unknown_riscv_ip_operand; } @@ -4426,7 +4464,7 @@ md_pcrel_from (fixS *fixP) /* Apply a fixup to the object file. */ void -md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) +md_apply_fix (fixS *fixP, valueT *valP, segT seg) { unsigned int subtype; bfd_byte *buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where); @@ -4677,6 +4715,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) /* Record PCREL_HI20. */ if (!riscv_record_pcrel_fixup (riscv_pcrel_hi_fixup_hash, + (const asection *) seg, md_pcrel_from (fixP), fixP->fx_addsy, target)) @@ -4698,7 +4737,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) and set fx_done for -mno-relax. */ { bfd_vma location_pcrel_hi = S_GET_VALUE (fixP->fx_addsy) + *valP; - riscv_pcrel_hi_fixup search = {location_pcrel_hi, 0, 0}; + riscv_pcrel_hi_fixup search = + {(const asection *) seg, location_pcrel_hi, 0, 0}; riscv_pcrel_hi_fixup *entry = htab_find (riscv_pcrel_hi_fixup_hash, &search); if (entry && entry->symbol @@ -4707,7 +4747,10 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { bfd_vma target = entry->target; bfd_vma value = target - entry->address; - bfd_putl32 (bfd_getl32 (buf) | ENCODE_ITYPE_IMM (value), buf); + if (fixP->fx_r_type == BFD_RELOC_RISCV_PCREL_LO12_S) + bfd_putl32 (bfd_getl32 (buf) | ENCODE_STYPE_IMM (value), buf); + else + bfd_putl32 (bfd_getl32 (buf) | ENCODE_ITYPE_IMM (value), buf); /* Relaxations should never be enabled by `.option relax'. */ if (!riscv_opts.relax) fixP->fx_done = 1; @@ -4798,13 +4841,13 @@ s_riscv_option (int x ATTRIBUTE_UNUSED) if (strcmp (name, "rvc") == 0) { riscv_update_subset (&riscv_rps_as, "+c"); - riscv_reset_subsets_list_arch_str (); + riscv_set_arch_str (&riscv_rps_as.subset_list->arch_str); riscv_set_rvc (true); } else if (strcmp (name, "norvc") == 0) { riscv_update_subset (&riscv_rps_as, "-c"); - riscv_reset_subsets_list_arch_str (); + riscv_set_arch_str (&riscv_rps_as.subset_list->arch_str); riscv_set_rvc (false); } else if (strcmp (name, "pic") == 0) @@ -4825,7 +4868,7 @@ s_riscv_option (int x ATTRIBUTE_UNUSED) if (ISSPACE (*name) && *name != '\0') name++; riscv_update_subset (&riscv_rps_as, name); - riscv_reset_subsets_list_arch_str (); + riscv_set_arch_str (&riscv_rps_as.subset_list->arch_str); riscv_set_rvc (false); if (riscv_subset_supports (&riscv_rps_as, "c") @@ -4980,40 +5023,37 @@ riscv_handle_align (fragS *fragP) switch (fragP->fr_type) { case rs_align_code: - /* When relaxing, riscv_frag_align_code handles code alignment. */ - if (!riscv_opts.relax) - { - bfd_signed_vma bytes = (fragP->fr_next->fr_address - - fragP->fr_address - fragP->fr_fix); - /* We have 4 byte uncompressed nops. */ - bfd_signed_vma size = 4; - bfd_signed_vma excess = bytes % size; - bfd_boolean odd_padding = (excess % 2 == 1); - char *p = fragP->fr_literal + fragP->fr_fix; - - if (bytes <= 0) - break; + { + bfd_signed_vma bytes = (fragP->fr_next->fr_address + - fragP->fr_address - fragP->fr_fix); + /* We have 4 byte uncompressed nops. */ + bfd_signed_vma size = 4; + bfd_signed_vma excess = bytes % size; + char *p = fragP->fr_literal + fragP->fr_fix; + + if (bytes <= 0) + break; - /* Insert zeros or compressed nops to get 4 byte alignment. */ - if (excess) - { - if (odd_padding) - riscv_add_odd_padding_symbol (fragP); - riscv_make_nops (p, excess); - fragP->fr_fix += excess; - p += excess; - } + /* Insert zeros or compressed nops to get 4 byte alignment. */ + if (excess) + { + if (excess % 2) + riscv_add_odd_padding_symbol (fragP); + riscv_make_nops (p, excess); + fragP->fr_fix += excess; + p += excess; + } - /* The frag will be changed to `rs_fill` later. The function - `write_contents` will try to fill the remaining spaces - according to the patterns we give. In this case, we give - a 4 byte uncompressed nop as the pattern, and set the size - of the pattern into `fr_var`. The nop will be output to the - file `fr_offset` times. However, `fr_offset` could be zero - if we don't need to pad the boundary finally. */ - riscv_make_nops (p, size); - fragP->fr_var = size; - } + /* The frag will be changed to `rs_fill` later. The function + `write_contents` will try to fill the remaining spaces + according to the patterns we give. In this case, we give + a 4 byte uncompressed nop as the pattern, and set the size + of the pattern into `fr_var`. The nop will be output to the + file `fr_offset` times. However, `fr_offset` could be zero + if we don't need to pad the boundary finally. */ + riscv_make_nops (p, size); + fragP->fr_var = size; + } break; default: @@ -5350,7 +5390,7 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED) static void riscv_write_out_attrs (void) { - const char *arch_str, *priv_str, *p; + const char *priv_str, *p; /* versions[0]: major version. versions[1]: minor version. versions[2]: revision version. */ @@ -5358,10 +5398,10 @@ riscv_write_out_attrs (void) unsigned int i; /* Re-write architecture elf attribute. */ - arch_str = riscv_rps_as.subset_list->arch_str; - if (!bfd_elf_add_proc_attr_string (stdoutput, Tag_RISCV_arch, arch_str)) + if (!bfd_elf_add_proc_attr_string (stdoutput, Tag_RISCV_arch, file_arch_str)) as_fatal (_("error adding attribute: %s"), bfd_errmsg (bfd_get_error ())); + free ((void *) file_arch_str); /* For the file without any instruction, we don't set the default_priv_spec according to the privileged elf attributes since the md_assemble isn't |