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.c312
1 files changed, 215 insertions, 97 deletions
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 8485ad4..df60c20 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -93,6 +93,7 @@ enum riscv_csr_class
CSR_CLASS_SSAIA_AND_H_32, /* Ssaia with H, rv32 only */
CSR_CLASS_SSAIA_OR_SSCSRIND, /* Ssaia/Smcsrind */
CSR_CLASS_SSAIA_OR_SSCSRIND_AND_H, /* Ssaia/Smcsrind with H */
+ CSR_CLASS_SSCCFG, /* Ssccfg */
CSR_CLASS_SSCSRIND, /* Sscsrind */
CSR_CLASS_SSCSRIND_AND_H, /* Sscsrind with H */
CSR_CLASS_SSSTATEEN, /* S[ms]stateen only */
@@ -331,6 +332,7 @@ struct riscv_option_stack
struct riscv_option_stack *next;
struct riscv_set_options options;
riscv_subset_list_t *subset_list;
+ unsigned xlen;
};
static struct riscv_option_stack *riscv_opts_stack = NULL;
@@ -536,7 +538,7 @@ make_mapping_symbol (enum riscv_seg_mstate state,
{
/* Store current $x+arch into tc_segment_info. */
seg_info (now_seg)->tc_segment_info_data.arch_map_symbol = symbol;
- xfree ((void *) buff);
+ xfree (buff);
}
/* If .fill or other data filling directive generates zero sized data,
@@ -932,7 +934,7 @@ opcode_name_lookup (char **s)
save_c = *e;
*e = '\0';
- o = (struct opcode_name_t *) str_hash_find (opcode_names_hash, *s);
+ o = str_hash_find (opcode_names_hash, *s);
/* Advance to next token if one was recognized. */
if (o)
@@ -960,15 +962,15 @@ static htab_t reg_names_hash = NULL;
static htab_t csr_extra_hash = NULL;
#define ENCODE_REG_HASH(cls, n) \
- ((void *)(uintptr_t)((n) * RCLASS_MAX + (cls) + 1))
-#define DECODE_REG_CLASS(hash) (((uintptr_t)(hash) - 1) % RCLASS_MAX)
-#define DECODE_REG_NUM(hash) (((uintptr_t)(hash) - 1) / RCLASS_MAX)
+ ((n) * RCLASS_MAX + (cls) + 1)
+#define DECODE_REG_CLASS(hash) (((hash) - 1) % RCLASS_MAX)
+#define DECODE_REG_NUM(hash) (((hash) - 1) / RCLASS_MAX)
static void
hash_reg_name (enum reg_class class, const char *name, unsigned n)
{
- void *hash = ENCODE_REG_HASH (class, n);
- if (str_hash_insert (reg_names_hash, name, hash, 0) != NULL)
+ uintptr_t hash = ENCODE_REG_HASH (class, n);
+ if (str_hash_insert_int (reg_names_hash, name, hash, 0) != NULL)
as_fatal (_("internal: duplicate %s"), name);
}
@@ -994,7 +996,7 @@ riscv_init_csr_hash (const char *name,
bool need_enrty = true;
pre_entry = NULL;
- entry = (struct riscv_csr_extra *) str_hash_find (csr_extra_hash, name);
+ entry = str_hash_find (csr_extra_hash, name);
while (need_enrty && entry != NULL)
{
if (entry->csr_class == class
@@ -1118,6 +1120,9 @@ riscv_csr_address (const char *csr_name,
is_h_required = (csr_class == CSR_CLASS_SSAIA_OR_SSCSRIND_AND_H);
extension = "ssaia or sscsrind";
break;
+ case CSR_CLASS_SSCCFG:
+ extension = "ssccfg";
+ break;
case CSR_CLASS_SSCSRIND:
case CSR_CLASS_SSCSRIND_AND_H:
is_h_required = (csr_class == CSR_CLASS_SSCSRIND_AND_H);
@@ -1206,8 +1211,7 @@ riscv_csr_address (const char *csr_name,
static unsigned int
reg_csr_lookup_internal (const char *s)
{
- struct riscv_csr_extra *r =
- (struct riscv_csr_extra *) str_hash_find (csr_extra_hash, s);
+ struct riscv_csr_extra *r = str_hash_find (csr_extra_hash, s);
if (r == NULL)
return -1U;
@@ -1218,13 +1222,13 @@ reg_csr_lookup_internal (const char *s)
static unsigned int
reg_lookup_internal (const char *s, enum reg_class class)
{
- void *r;
+ uintptr_t r;
if (class == RCLASS_CSR)
return reg_csr_lookup_internal (s);
- r = str_hash_find (reg_names_hash, s);
- if (r == NULL || DECODE_REG_CLASS (r) != class)
+ r = str_hash_find_int (reg_names_hash, s);
+ if (r == (uintptr_t) -1 || DECODE_REG_CLASS (r) != class)
return -1;
if (riscv_subset_supports (&riscv_rps_as, "e")
@@ -1752,6 +1756,21 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
goto unknown_validate_operand;
}
break;
+ case 'm': /* Vendor-specific (MIPS) operands. */
+ switch (*++oparg)
+ {
+ case '@': USE_BITS (OP_MASK_MIPS_HINT, OP_SH_MIPS_HINT);
+ break;
+ case '#': USE_BITS (OP_MASK_MIPS_IMM9, OP_SH_MIPS_IMM9);
+ break;
+ case '$': used_bits |= ENCODE_MIPS_LDP_IMM (-1U); break;
+ case '%': used_bits |= ENCODE_MIPS_LWP_IMM (-1U); break;
+ case '^': used_bits |= ENCODE_MIPS_SDP_IMM (-1U); break;
+ case '&': used_bits |= ENCODE_MIPS_SWP_IMM (-1U); break;
+ default:
+ goto unknown_validate_operand;
+ }
+ break;
default:
goto unknown_validate_operand;
}
@@ -1867,15 +1886,13 @@ riscv_record_pcrel_fixup (htab_t p, const asection *sec, bfd_vma address,
symbolS *symbol, bfd_vma 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);
+ void **slot = htab_find_slot (p, &entry, INSERT);
if (slot == NULL)
return false;
- *slot = (riscv_pcrel_hi_fixup *) xmalloc (sizeof (riscv_pcrel_hi_fixup));
- if (*slot == NULL)
- return false;
- **slot = entry;
+ riscv_pcrel_hi_fixup *pent = xmalloc (sizeof (*pent));
+ *slot = pent;
+ *pent = entry;
return true;
}
@@ -2029,7 +2046,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
va_start (args, fmt);
r = BFD_RELOC_UNUSED;
- mo = (struct riscv_opcode *) str_hash_find (op_hash, name);
+ mo = str_hash_find (op_hash, name);
gas_assert (mo);
/* Find a non-RVC variant of the instruction. append_insn will compress
@@ -2501,13 +2518,16 @@ parse_relocation (char **str, bfd_reloc_code_real_type *reloc,
}
static void
-my_getExpression (expressionS *ep, char *str)
+my_getExpression (expressionS *ep, char *str, bool defer)
{
char *save_in;
save_in = input_line_pointer;
input_line_pointer = str;
- expression (ep);
+ if (defer)
+ deferred_expression (ep);
+ else
+ expression (ep);
expr_parse_end = input_line_pointer;
input_line_pointer = save_in;
}
@@ -2526,6 +2546,7 @@ my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
size_t reloc_index;
unsigned crux_depth, str_depth;
bool orig_probing = probing_insn_operands;
+ bool force_reloc = false;
char *crux;
/* Search for the start of the main expression.
@@ -2565,7 +2586,10 @@ my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
if (str_depth || reloc_index)
probing_insn_operands = false;
- my_getExpression (ep, crux);
+ if (*reloc == BFD_RELOC_RISCV_GOT_HI20)
+ force_reloc = true;
+
+ my_getExpression (ep, crux, force_reloc);
str = expr_parse_end;
probing_insn_operands = orig_probing;
@@ -2657,7 +2681,7 @@ my_getVsetvliExpression (expressionS *ep, char *str)
}
else
{
- my_getExpression (ep, str);
+ my_getExpression (ep, str, false/* defer */);
str = expr_parse_end;
}
}
@@ -2710,7 +2734,7 @@ my_getThVsetvliExpression (expressionS *ep, char *str)
}
else
{
- my_getExpression (ep, str);
+ my_getExpression (ep, str, false/* defer */);
str = expr_parse_end;
}
}
@@ -2834,6 +2858,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
error.missing_ext = NULL;
/* Indicate we are assembling instruction with CSR. */
bool insn_with_csr = false;
+ bool force_reloc = false;
/* Parse the name of the instruction. Terminate the string if whitespace
is found so that str_hash_find only sees the name part of the string. */
@@ -2845,7 +2870,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
break;
}
- insn = (struct riscv_opcode *) str_hash_find (hash, str);
+ insn = str_hash_find (hash, str);
probing_insn_operands = true;
@@ -3336,7 +3361,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
continue;
case 'i': /* vector arith signed immediate */
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
if (imm_expr->X_add_number > 15
|| imm_expr->X_add_number < -16)
@@ -3348,7 +3373,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
continue;
case 'j': /* vector arith unsigned immediate */
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
if (imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 32)
@@ -3360,7 +3385,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
continue;
case 'k': /* vector arith signed immediate, minus 1 */
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
if (imm_expr->X_add_number > 16
|| imm_expr->X_add_number < -15)
@@ -3372,7 +3397,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
continue;
case 'l': /* 6-bit vector arith unsigned immediate */
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
if (imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 64)
@@ -3436,7 +3461,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
break;
case '<': /* Shift amount, 0 - 31. */
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, false);
if ((unsigned long) imm_expr->X_add_number > 31)
as_bad (_("improper shift amount (%"PRIu64")"),
@@ -3447,7 +3472,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
continue;
case '>': /* Shift amount, 0 - (XLEN-1). */
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, false);
if ((unsigned long) imm_expr->X_add_number >= xlen)
as_bad (_("improper shift amount (%"PRIu64")"),
@@ -3458,7 +3483,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
continue;
case 'Z': /* CSRRxI immediate. */
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, false);
if ((unsigned long) imm_expr->X_add_number > 31)
as_bad (_("improper CSRxI immediate (%"PRIu64")"),
@@ -3475,7 +3500,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
INSERT_OPERAND (CSR, *ip, regno);
else
{
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, true);
if ((unsigned long) imm_expr->X_add_number > 0xfff)
as_bad (_("improper CSR address (%"PRIu64")"),
@@ -3574,7 +3599,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
break;
case 'I':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
if (imm_expr->X_op != O_big
&& imm_expr->X_op != O_constant)
break;
@@ -3583,7 +3608,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
continue;
case 'A':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
normalize_constant_expr (imm_expr);
/* The 'A' format specifier must be a symbol. */
if (imm_expr->X_op != O_symbol)
@@ -3593,7 +3618,10 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
continue;
case 'B':
- my_getExpression (imm_expr, asarg);
+ if (ip->insn_mo->mask == M_LGA
+ || (riscv_opts.pic && ip->insn_mo->mask == M_LA))
+ force_reloc = true;
+ my_getExpression (imm_expr, asarg, force_reloc);
normalize_constant_expr (imm_expr);
/* The 'B' format specifier must be a symbol or a constant. */
if (imm_expr->X_op != O_symbol && imm_expr->X_op != O_constant)
@@ -3645,7 +3673,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
case 'p': /* PC-relative offset. */
branch:
*imm_reloc = BFD_RELOC_12_PCREL;
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
asarg = expr_parse_end;
continue;
@@ -3668,13 +3696,13 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
case 'a': /* 20-bit PC-relative offset. */
jump:
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
asarg = expr_parse_end;
*imm_reloc = BFD_RELOC_RISCV_JMP;
continue;
case 'c':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
asarg = expr_parse_end;
if (strcmp (asarg, "@plt") == 0)
asarg += 4;
@@ -3775,7 +3803,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
break;
case 'y': /* bs immediate */
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
if ((unsigned long)imm_expr->X_add_number > 3)
as_bad(_("Improper bs immediate (%lu)"),
@@ -3786,7 +3814,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
continue;
case 'Y': /* rnum immediate */
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
if ((unsigned long)imm_expr->X_add_number > 10)
as_bad(_("Improper rnum immediate (%lu)"),
@@ -3816,7 +3844,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
pseudo S-type but lower 5-bits zero. */
if (riscv_handle_implicit_zero_offset (imm_expr, asarg))
continue;
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, false);
if (((unsigned) (imm_expr->X_add_number) & 0x1fU)
|| imm_expr->X_add_number >= RISCV_IMM_REACH / 2
@@ -4008,7 +4036,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
s = strtol (oparg + 1, (char **)&oparg, 10);
oparg--;
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, false);
if (!sign)
{
@@ -4036,7 +4064,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
switch (*++oparg)
{
case '2':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
asarg = expr_parse_end;
if (imm_expr->X_add_number<0
@@ -4046,7 +4074,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
|= ENCODE_CV_IS2_UIMM5 (imm_expr->X_add_number);
continue;
case '3':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
asarg = expr_parse_end;
if (imm_expr->X_add_number < 0
@@ -4056,7 +4084,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
|= ENCODE_CV_IS3_UIMM5 (imm_expr->X_add_number);
continue;
case '4':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
asarg = expr_parse_end;
if (imm_expr->X_add_number < -16
@@ -4066,7 +4094,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
|= ENCODE_CV_IS2_UIMM5 (imm_expr->X_add_number);
continue;
case '5':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
asarg = expr_parse_end;
if (imm_expr->X_add_number < -32
@@ -4076,7 +4104,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
|= ENCODE_CV_SIMD_IMM6 (imm_expr->X_add_number);
continue;
case '6':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
asarg = expr_parse_end;
if (imm_expr->X_add_number < 0
@@ -4086,7 +4114,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
|= ENCODE_CV_BITMANIP_UIMM5 (imm_expr->X_add_number);
continue;
case '7':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
asarg = expr_parse_end;
if (imm_expr->X_add_number < 0
@@ -4096,7 +4124,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
|= ENCODE_CV_BITMANIP_UIMM2 (imm_expr->X_add_number);
continue;
case '8':
- my_getExpression (imm_expr, asarg);
+ my_getExpression (imm_expr, asarg, force_reloc);
check_absolute_expr (ip, imm_expr, FALSE);
asarg = expr_parse_end;
++oparg;
@@ -4173,6 +4201,92 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
#undef ENCODE_UIMM_BIT_FIELD
break;
+ case 'm': /* Vendor-specific (MIPS) operands. */
+ switch (*++oparg)
+ {
+ case '@': /* hint 0 - 31. */
+ my_getExpression (imm_expr, asarg, force_reloc);
+ check_absolute_expr (ip, imm_expr, FALSE);
+ if ((unsigned long)imm_expr->X_add_number > 31)
+ as_bad(_("Improper hint amount (%lu)"),
+ (unsigned long)imm_expr->X_add_number);
+ INSERT_OPERAND(MIPS_HINT, *ip, imm_expr->X_add_number);
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+
+ case '#': /* immediate 0 - 511. */
+ my_getExpression (imm_expr, asarg, force_reloc);
+ check_absolute_expr (ip, imm_expr, FALSE);
+ if ((unsigned long)imm_expr->X_add_number > 511)
+ as_bad(_("Improper immediate amount (%lu)"),
+ (unsigned long)imm_expr->X_add_number);
+ INSERT_OPERAND(MIPS_IMM9, *ip, imm_expr->X_add_number);
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+
+ case '$': /* LDP offset 0 to (1<<7)-8. */
+ my_getExpression (imm_expr, asarg, force_reloc);
+ check_absolute_expr (ip, imm_expr, FALSE);
+ if ((unsigned long)imm_expr->X_add_number >= (1 << 7)
+ || ((unsigned long)imm_expr->X_add_number & 0x7) != 0)
+ as_bad(_("Improper LDP offset amount (%lu)"),
+ (unsigned long)imm_expr->X_add_number);
+ INSERT_OPERAND(MIPS_LDP_OFFSET, *ip,
+ (imm_expr->X_add_number >> 3));
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+
+ case '%': /* LWP offset 0 to (1<<7)-4. */
+ my_getExpression (imm_expr, asarg, force_reloc);
+ check_absolute_expr (ip, imm_expr, FALSE);
+ if ((unsigned long)imm_expr->X_add_number >= (1 << 7)
+ || ((unsigned long)imm_expr->X_add_number & 0x3) != 0)
+ as_bad(_("Improper LWP offset amount (%lu)"),
+ (unsigned long)imm_expr->X_add_number);
+ INSERT_OPERAND(MIPS_LWP_OFFSET, *ip,
+ (imm_expr->X_add_number >> 2));
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+
+ case '^': /* SDP offset 0 to (1<<7)-8. */
+ my_getExpression (imm_expr, asarg, force_reloc);
+ check_absolute_expr (ip, imm_expr, FALSE);
+ if ((unsigned long)imm_expr->X_add_number >= (1 << 7)
+ || ((unsigned long)imm_expr->X_add_number & 0x7) != 0)
+ as_bad(_("Improper SDP offset amount (%lu)"),
+ (unsigned long)imm_expr->X_add_number);
+ INSERT_OPERAND(MIPS_SDP_OFFSET10, *ip,
+ (imm_expr->X_add_number >> 3));
+ INSERT_OPERAND(MIPS_SDP_OFFSET25, *ip,
+ (imm_expr->X_add_number >> 5));
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+
+ case '&': /* SWP offset 0 to (1<<7)-4. */
+ my_getExpression (imm_expr, asarg, force_reloc);
+ check_absolute_expr (ip, imm_expr, FALSE);
+ if ((unsigned long)imm_expr->X_add_number >= (1 << 7)
+ || ((unsigned long)imm_expr->X_add_number & 0x3) != 0)
+ as_bad(_("Improper SWP offset amount (%lu)"),
+ (unsigned long)imm_expr->X_add_number);
+ INSERT_OPERAND(MIPS_SWP_OFFSET9, *ip,
+ (imm_expr->X_add_number >> 2));
+ INSERT_OPERAND(MIPS_SWP_OFFSET25, *ip,
+ (imm_expr->X_add_number >> 5));
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+
+ default:
+ goto unknown_riscv_ip_operand;
+ }
+ break;
+
default:
goto unknown_riscv_ip_operand;
}
@@ -4219,12 +4333,12 @@ riscv_ip_hardcode (char *str,
switch (imm_expr->X_op)
{
case O_constant:
- values[num++] = (insn_t) imm_expr->X_add_number;
+ values[num++] = imm_expr->X_add_number;
break;
case O_big:
/* Extract lower 32-bits of a big number.
Assume that generic_bignum_to_int32 work on such number. */
- values[num++] = (insn_t) generic_bignum_to_int32 ();
+ values[num++] = generic_bignum_to_int32 ();
break;
default:
/* The first value isn't constant, so it should be
@@ -4510,10 +4624,10 @@ bool riscv_parse_name (const char *name, struct expressionS *ep,
if (!probing_insn_operands)
return false;
- gas_assert (mode == expr_normal);
+ gas_assert (mode == expr_normal || expr_defer_p (mode));
regno = reg_lookup_internal (name, RCLASS_GPR);
- if (regno == (unsigned int)-1)
+ if (regno == -1u)
return false;
if (symbol_find (name) != NULL)
@@ -4747,7 +4861,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
bfd_vma delta = target - md_pcrel_from (fixP);
bfd_putl32 (bfd_getl32 (buf) | ENCODE_JTYPE_IMM (delta), buf);
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
- fixP->fx_done = 1;
+ {
+ if (!VALID_JTYPE_IMM (delta))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("invalid J-type offset (%+lld)"),
+ (long long) delta);
+ fixP->fx_done = 1;
+ }
}
break;
@@ -4759,7 +4879,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
bfd_vma delta = target - md_pcrel_from (fixP);
bfd_putl32 (bfd_getl32 (buf) | ENCODE_BTYPE_IMM (delta), buf);
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
- fixP->fx_done = 1;
+ {
+ if (!VALID_BTYPE_IMM (delta))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("invalid B-type offset (%+lld)"),
+ (long long) delta);
+ fixP->fx_done = 1;
+ }
}
break;
@@ -4771,7 +4897,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
bfd_vma delta = target - md_pcrel_from (fixP);
bfd_putl16 (bfd_getl16 (buf) | ENCODE_CBTYPE_IMM (delta), buf);
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
- fixP->fx_done = 1;
+ {
+ if (!VALID_CBTYPE_IMM (delta))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("invalid CB-type offset (%+lld)"),
+ (long long) delta);
+ fixP->fx_done = 1;
+ }
}
break;
@@ -4783,7 +4915,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
bfd_vma delta = target - md_pcrel_from (fixP);
bfd_putl16 (bfd_getl16 (buf) | ENCODE_CJTYPE_IMM (delta), buf);
if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
- fixP->fx_done = 1;
+ {
+ if (!VALID_CJTYPE_IMM (delta))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("invalid CJ-type offset (%+lld)"),
+ (long long) delta);
+ fixP->fx_done = 1;
+ }
}
break;
@@ -4808,7 +4946,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
/* Record PCREL_HI20. */
if (!riscv_record_pcrel_fixup (riscv_pcrel_hi_fixup_hash,
- (const asection *) seg,
+ seg,
md_pcrel_from (fixP),
fixP->fx_addsy,
target))
@@ -4818,7 +4956,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
| ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)),
buf);
if (!riscv_opts.relax)
- fixP->fx_done = 1;
+ {
+ if (xlen > 32
+ && !VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("invalid pcrel_hi offset (%+lld)"),
+ (long long) value);
+ fixP->fx_done = 1;
+ }
}
relaxable = true;
break;
@@ -4830,8 +4975,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
and set fx_done for -mno-relax. */
{
bfd_vma location_pcrel_hi = S_GET_VALUE (fixP->fx_addsy) + *valP;
- riscv_pcrel_hi_fixup search =
- {(const asection *) seg, location_pcrel_hi, 0, 0};
+ riscv_pcrel_hi_fixup search = {seg, location_pcrel_hi, 0, 0};
riscv_pcrel_hi_fixup *entry = htab_find (riscv_pcrel_hi_fixup_hash,
&search);
if (entry && entry->symbol
@@ -4844,7 +4988,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
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'. */
+ /* Relaxations should never be enabled by `.option relax'.
+ The offset is checked by corresponding %pcrel_hi entry. */
if (!riscv_opts.relax)
fixP->fx_done = 1;
}
@@ -4939,7 +5084,7 @@ s_riscv_option (int x ATTRIBUTE_UNUSED)
}
else if (strcmp (name, "norvc") == 0)
{
- riscv_update_subset (&riscv_rps_as, "-c");
+ riscv_update_subset_norvc (&riscv_rps_as);
riscv_arch_str (xlen, riscv_rps_as.subset_list, true/* update */);
riscv_set_rvc (false);
}
@@ -4977,6 +5122,7 @@ s_riscv_option (int x ATTRIBUTE_UNUSED)
s->next = riscv_opts_stack;
s->options = riscv_opts;
s->subset_list = riscv_rps_as.subset_list;
+ s->xlen = xlen;
riscv_opts_stack = s;
riscv_rps_as.subset_list = riscv_copy_subset_list (s->subset_list);
}
@@ -4993,6 +5139,7 @@ s_riscv_option (int x ATTRIBUTE_UNUSED)
riscv_opts_stack = s->next;
riscv_opts = s->options;
riscv_rps_as.subset_list = s->subset_list;
+ xlen = s->xlen;
riscv_release_subset_list (release_subsets);
free (s);
}
@@ -5367,7 +5514,7 @@ RISC-V options:\n\
-fno-pic don't generate position-independent code (default)\n\
-march=ISA set the RISC-V architecture\n\
-misa-spec=ISAspec set the RISC-V ISA spec (2.2, 20190608, 20191213)\n\
- -mpriv-spec=PRIVspec set the RISC-V privilege spec (1.10, 1.11, 1.12)\n\
+ -mpriv-spec=PRIVspec set the RISC-V privilege spec (1.10, 1.11, 1.12, 1.13)\n\
-mabi=ABI set the RISC-V ABI\n\
-mrelax enable relax (default)\n\
-mno-relax disable relax\n\
@@ -5616,7 +5763,7 @@ riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
exp_dup->X_add_number = 0; /* Set addend of SUB_ULEB128 to zero. */
fix_new_exp (fragP, fragP->fr_fix, 0,
exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
- free ((void *) exp_dup);
+ free (exp_dup);
}
}
@@ -5643,7 +5790,7 @@ riscv_md_end (void)
void
riscv_adjust_symtab (void)
{
- bfd_map_over_sections (stdoutput, riscv_check_mapping_symbols, (char *) 0);
+ bfd_map_over_sections (stdoutput, riscv_check_mapping_symbols, NULL);
elf_adjust_symtab ();
}
@@ -5752,35 +5899,6 @@ s_variant_cc (int ignored ATTRIBUTE_UNUSED)
elfsym->internal_elf_sym.st_other |= STO_RISCV_VARIANT_CC;
}
-/* Same as elf_copy_symbol_attributes, but without copying st_other.
- This is needed so RISC-V specific st_other values can be independently
- specified for an IFUNC resolver (that is called by the dynamic linker)
- and the symbol it resolves (aliased to the resolver). In particular,
- if a function symbol has special st_other value set via directives,
- then attaching an IFUNC resolver to that symbol should not override
- the st_other setting. Requiring the directive on the IFUNC resolver
- symbol would be unexpected and problematic in C code, where the two
- symbols appear as two independent function declarations. */
-
-void
-riscv_elf_copy_symbol_attributes (symbolS *dest, symbolS *src)
-{
- struct elf_obj_sy *srcelf = symbol_get_obj (src);
- struct elf_obj_sy *destelf = symbol_get_obj (dest);
- /* If size is unset, copy size from src. Because we don't track whether
- .size has been used, we can't differentiate .size dest, 0 from the case
- where dest's size is unset. */
- if (!destelf->size && S_GET_SIZE (dest) == 0)
- {
- if (srcelf->size)
- {
- destelf->size = XNEW (expressionS);
- *destelf->size = *srcelf->size;
- }
- S_SET_SIZE (dest, S_GET_SIZE (src));
- }
-}
-
/* RISC-V pseudo-ops table. */
static const pseudo_typeS riscv_pseudo_table[] =
{