aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-riscv.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config/tc-riscv.c')
-rw-r--r--gas/config/tc-riscv.c144
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