#include "itbl-ops.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
+#include "struc-symbol.h"
#include "elf/riscv.h"
#include "opcode/riscv.h"
static const char default_arch[] = DEFAULT_ARCH;
-unsigned xlen = 0; /* width of an x-register */
+static unsigned xlen = 0; /* width of an x-register */
+static unsigned abi_xlen = 0; /* width of a pointer in the ABI */
-#define LOAD_ADDRESS_INSN (xlen == 64 ? "ld" : "lw")
+#define LOAD_ADDRESS_INSN (abi_xlen == 64 ? "ld" : "lw")
#define ADD32_INSN (xlen == 64 ? "addiw" : "addi")
static unsigned elf_flags = 0;
{
int pic; /* Generate position-independent code. */
int rvc; /* Generate RVC code. */
+ int relax; /* Emit relocs the linker is allowed to relax. */
};
static struct riscv_set_options riscv_opts =
{
0, /* pic */
0, /* rvc */
+ 1, /* relax */
};
static void
riscv_subsets = s;
}
-/* Set which ISA and extensions are available. Formally, ISA strings must
- begin with RV32 or RV64, but we allow the prefix to be omitted.
+/* Set which ISA and extensions are available. */
- FIXME: Version numbers are not supported yet. */
static void
-riscv_set_arch (const char *p)
+riscv_set_arch (const char *s)
{
- const char *all_subsets = "IMAFDC";
+ const char *all_subsets = "imafdc";
const char *extension = NULL;
- int rvc = 0;
- int i;
+ const char *p = s;
- if (strncasecmp (p, "RV32", 4) == 0)
+ if (strncmp (p, "rv32", 4) == 0)
{
xlen = 32;
p += 4;
}
- else if (strncasecmp (p, "RV64", 4) == 0)
+ else if (strncmp (p, "rv64", 4) == 0)
{
xlen = 64;
p += 4;
}
- else if (strncasecmp (p, "RV", 2) == 0)
- p += 2;
+ else
+ as_fatal ("-march=%s: ISA string must begin with rv32 or rv64", s);
- switch (TOUPPER(*p))
+ switch (*p)
{
- case 'I':
+ case 'i':
break;
- case 'G':
+ case 'g':
p++;
- /* Fall through. */
-
- case '\0':
- for (i = 0; all_subsets[i] != '\0'; i++)
+ for ( ; *all_subsets != 'c'; all_subsets++)
{
- const char subset[] = {all_subsets[i], '\0'};
+ const char subset[] = {*all_subsets, '\0'};
riscv_add_subset (subset);
}
break;
default:
- as_fatal ("`I' must be the first ISA subset name specified (got %c)",
- *p);
+ as_fatal ("-march=%s: first ISA subset must be `i' or `g'", s);
}
while (*p)
{
- if (TOUPPER(*p) == 'X')
+ if (*p == 'x')
{
char *subset = xstrdup (p), *q = subset;
*q = '\0';
if (extension)
- as_fatal ("only one eXtension is supported (found %s and %s)",
- extension, subset);
+ as_fatal ("-march=%s: only one non-standard extension is supported"
+ " (found `%s' and `%s')", s, extension, subset);
extension = subset;
riscv_add_subset (subset);
p += strlen (subset);
{
const char subset[] = {*p, 0};
riscv_add_subset (subset);
- if (TOUPPER(*p) == 'C')
- rvc = 1;
all_subsets++;
p++;
}
else
- as_fatal ("unsupported ISA subset %c", *p);
- }
-
- if (rvc)
- {
- /* Override -m[no-]rvc setting if C was explicitly listed. */
- riscv_set_rvc (TRUE);
- }
- else
- {
- /* Add RVC anyway. -m[no-]rvc toggles its availability. */
- riscv_add_subset ("C");
+ as_fatal ("-march=%s: unsupported ISA subset `%c'", s, *p);
}
}
case 'C': /* RVC */
switch (c = *p++)
{
- case 'a': used_bits |= ENCODE_RVC_J_IMM(-1U); break;
+ case 'a': used_bits |= ENCODE_RVC_J_IMM (-1U); break;
case 'c': break; /* RS1, constrained to equal sp */
case 'i': used_bits |= ENCODE_RVC_SIMM3(-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 'p': used_bits |= ENCODE_RVC_B_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 'p': used_bits |= ENCODE_RVC_B_IMM (-1U); break;
case 's': USE_BITS (OP_MASK_CRS1S, OP_SH_CRS1S); break;
case 't': USE_BITS (OP_MASK_CRS2S, OP_SH_CRS2S); break;
- case 'u': used_bits |= ENCODE_RVC_IMM(-1U); break;
- case 'v': used_bits |= ENCODE_RVC_IMM(-1U); break;
+ case 'u': used_bits |= ENCODE_RVC_IMM (-1U); break;
+ case 'v': used_bits |= ENCODE_RVC_IMM (-1U); break;
case 'w': break; /* RS1S, constrained to equal RD */
case 'x': break; /* RS2S, constrained to equal RD */
- case 'K': used_bits |= ENCODE_RVC_ADDI4SPN_IMM(-1U); break;
- case 'L': used_bits |= ENCODE_RVC_ADDI16SP_IMM(-1U); break;
- case 'M': used_bits |= ENCODE_RVC_SWSP_IMM(-1U); break;
- case 'N': used_bits |= ENCODE_RVC_SDSP_IMM(-1U); break;
+ case 'K': used_bits |= ENCODE_RVC_ADDI4SPN_IMM (-1U); break;
+ case 'L': used_bits |= ENCODE_RVC_ADDI16SP_IMM (-1U); break;
+ case 'M': used_bits |= ENCODE_RVC_SWSP_IMM (-1U); break;
+ case 'N': used_bits |= ENCODE_RVC_SDSP_IMM (-1U); break;
case 'U': break; /* RS1, constrained to equal RD */
case 'V': USE_BITS (OP_MASK_CRS2, OP_SH_CRS2); break;
- case '<': used_bits |= ENCODE_RVC_IMM(-1U); break;
- case '>': used_bits |= ENCODE_RVC_IMM(-1U); break;
+ case '<': used_bits |= ENCODE_RVC_IMM (-1U); break;
+ case '>': used_bits |= ENCODE_RVC_IMM (-1U); break;
case 'T': USE_BITS (OP_MASK_CRS2, OP_SH_CRS2); break;
case 'D': USE_BITS (OP_MASK_CRS2S, OP_SH_CRS2S); break;
default:
case 'P': USE_BITS (OP_MASK_PRED, OP_SH_PRED); break;
case 'Q': USE_BITS (OP_MASK_SUCC, OP_SH_SUCC); break;
case 'o':
- case 'j': used_bits |= ENCODE_ITYPE_IMM(-1U); break;
- case 'a': used_bits |= ENCODE_UJTYPE_IMM(-1U); break;
- case 'p': used_bits |= ENCODE_SBTYPE_IMM(-1U); break;
- case 'q': used_bits |= ENCODE_STYPE_IMM(-1U); break;
- case 'u': used_bits |= ENCODE_UTYPE_IMM(-1U); break;
+ case 'j': used_bits |= ENCODE_ITYPE_IMM (-1U); break;
+ case 'a': used_bits |= ENCODE_UJTYPE_IMM (-1U); break;
+ case 'p': used_bits |= ENCODE_SBTYPE_IMM (-1U); break;
+ case 'q': used_bits |= ENCODE_STYPE_IMM (-1U); break;
+ case 'u': used_bits |= ENCODE_UTYPE_IMM (-1U); break;
case '[': break;
case ']': break;
case '0': break;
md_begin (void)
{
int i = 0;
+ unsigned long mach = xlen == 64 ? bfd_mach_riscv64 : bfd_mach_riscv32;
- if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, 0))
+ if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
as_warn (_("Could not set architecture and machine"));
op_hash = hash_new ();
record_alignment (text_section, riscv_opts.rvc ? 1 : 2);
}
+static insn_t
+riscv_apply_const_reloc (bfd_reloc_code_real_type reloc_type, bfd_vma value)
+{
+ switch (reloc_type)
+ {
+ case BFD_RELOC_32:
+ return value;
+
+ case BFD_RELOC_RISCV_HI20:
+ return ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART (value));
+
+ case BFD_RELOC_RISCV_LO12_S:
+ return ENCODE_STYPE_IMM (value);
+
+ case BFD_RELOC_RISCV_LO12_I:
+ return ENCODE_ITYPE_IMM (value);
+
+ default:
+ abort ();
+ }
+}
+
/* Output an instruction. IP is the instruction information.
ADDRESS_EXPR is an operand of the instruction to be used with
RELOC_TYPE. */
{
reloc_howto_type *howto;
- gas_assert(address_expr);
+ gas_assert (address_expr);
if (reloc_type == BFD_RELOC_12_PCREL
|| reloc_type == BFD_RELOC_RISCV_JMP)
{
return;
}
else if (address_expr->X_op == O_constant)
+ ip->insn_opcode |= riscv_apply_const_reloc (reloc_type,
+ address_expr->X_add_number);
+ else
{
- switch (reloc_type)
- {
- case BFD_RELOC_32:
- ip->insn_opcode |= address_expr->X_add_number;
- goto append;
-
- case BFD_RELOC_RISCV_HI20:
- {
- insn_t imm = RISCV_CONST_HIGH_PART (address_expr->X_add_number);
- ip->insn_opcode |= ENCODE_UTYPE_IMM (imm);
- goto append;
- }
+ howto = bfd_reloc_type_lookup (stdoutput, reloc_type);
+ if (howto == NULL)
+ as_bad (_("Unsupported RISC-V relocation number %d"), reloc_type);
- case BFD_RELOC_RISCV_LO12_S:
- ip->insn_opcode |= ENCODE_STYPE_IMM (address_expr->X_add_number);
- goto append;
+ ip->fixp = fix_new_exp (ip->frag, ip->where,
+ bfd_get_reloc_size (howto),
+ address_expr, FALSE, reloc_type);
- case BFD_RELOC_RISCV_LO12_I:
- ip->insn_opcode |= ENCODE_ITYPE_IMM (address_expr->X_add_number);
- goto append;
-
- default:
- break;
- }
+ ip->fixp->fx_tcbit = riscv_opts.relax;
}
-
- 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, FALSE, reloc_type);
}
-append:
add_fixed_insn (ip);
install_insn (ip);
}
make_internal_label (void)
{
return (symbolS *) local_symbol_make (FAKE_LABEL_NAME, now_seg,
- (valueT) frag_now_fix(), frag_now);
+ (valueT) frag_now_fix (), frag_now);
}
/* Load an entry from the GOT. */
return;
}
- if (xlen > 32 && !IS_SEXT_32BIT_NUM(ep->X_add_number))
+ if (xlen > 32 && !IS_SEXT_32BIT_NUM (ep->X_add_number))
{
/* Reduce to a signed 32-bit constant using SLLI and ADDI. */
while (((upper.X_add_number >> shift) & 1) == 0)
shift++;
upper.X_add_number = (int64_t) upper.X_add_number >> shift;
- load_const(reg, &upper);
+ load_const (reg, &upper);
macro_build (NULL, "slli", "d,s,>", reg, reg, shift);
if (lower.X_add_number != 0)
/* Check whether the output BFD supports this relocation.
If not, issue an error and fall back on something safe. */
- if (!bfd_reloc_type_lookup (stdoutput, percent_op->reloc))
+ if (*reloc != BFD_RELOC_UNUSED
+ && !bfd_reloc_type_lookup (stdoutput, *reloc))
{
as_bad ("relocation %s isn't supported by the current ABI",
percent_op->str);
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_warn (_("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;
enum options
{
- OPTION_M32 = OPTION_MD_BASE,
- OPTION_M64,
- OPTION_MARCH,
+ OPTION_MARCH = OPTION_MD_BASE,
OPTION_PIC,
OPTION_NO_PIC,
- OPTION_MSOFT_FLOAT,
- OPTION_MHARD_FLOAT,
- OPTION_MRVC,
- OPTION_MNO_RVC,
+ OPTION_MABI,
OPTION_END_OF_ENUM
};
struct option md_longopts[] =
{
- {"m32", no_argument, NULL, OPTION_M32},
- {"m64", no_argument, NULL, OPTION_M64},
{"march", required_argument, NULL, OPTION_MARCH},
{"fPIC", no_argument, NULL, OPTION_PIC},
{"fpic", no_argument, NULL, OPTION_PIC},
{"fno-pic", no_argument, NULL, OPTION_NO_PIC},
- {"mrvc", no_argument, NULL, OPTION_MRVC},
- {"mno-rvc", no_argument, NULL, OPTION_MNO_RVC},
- {"msoft-float", no_argument, NULL, OPTION_MSOFT_FLOAT},
- {"mhard-float", no_argument, NULL, OPTION_MHARD_FLOAT},
+ {"mabi", required_argument, NULL, OPTION_MABI},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
-enum float_mode
-{
- FLOAT_MODE_DEFAULT,
- FLOAT_MODE_SOFT,
- FLOAT_MODE_HARD
+enum float_abi {
+ FLOAT_ABI_DEFAULT = -1,
+ FLOAT_ABI_SOFT,
+ FLOAT_ABI_SINGLE,
+ FLOAT_ABI_DOUBLE,
+ FLOAT_ABI_QUAD
};
-static enum float_mode float_mode = FLOAT_MODE_DEFAULT;
+static enum float_abi float_abi = FLOAT_ABI_DEFAULT;
+
+static void
+riscv_set_abi (unsigned new_xlen, enum float_abi new_float_abi)
+{
+ abi_xlen = new_xlen;
+ float_abi = new_float_abi;
+}
int
md_parse_option (int c, const char *arg)
{
switch (c)
{
- case OPTION_MRVC:
- riscv_set_rvc (TRUE);
- break;
-
- case OPTION_MNO_RVC:
- riscv_set_rvc (FALSE);
- break;
-
- case OPTION_MSOFT_FLOAT:
- float_mode = FLOAT_MODE_SOFT;
- break;
-
- case OPTION_MHARD_FLOAT:
- float_mode = FLOAT_MODE_HARD;
- break;
-
- case OPTION_M32:
- xlen = 32;
- break;
-
- case OPTION_M64:
- xlen = 64;
- break;
-
case OPTION_MARCH:
riscv_set_arch (arg);
break;
riscv_opts.pic = TRUE;
break;
+ case OPTION_MABI:
+ if (strcmp (arg, "ilp32") == 0)
+ riscv_set_abi (32, FLOAT_ABI_SOFT);
+ else if (strcmp (arg, "ilp32f") == 0)
+ riscv_set_abi (32, FLOAT_ABI_SINGLE);
+ else if (strcmp (arg, "ilp32d") == 0)
+ riscv_set_abi (32, FLOAT_ABI_DOUBLE);
+ else if (strcmp (arg, "ilp32q") == 0)
+ riscv_set_abi (32, FLOAT_ABI_QUAD);
+ else if (strcmp (arg, "lp64") == 0)
+ riscv_set_abi (64, FLOAT_ABI_SOFT);
+ else if (strcmp (arg, "lp64f") == 0)
+ riscv_set_abi (64, FLOAT_ABI_SINGLE);
+ else if (strcmp (arg, "lp64d") == 0)
+ riscv_set_abi (64, FLOAT_ABI_DOUBLE);
+ else if (strcmp (arg, "lp64q") == 0)
+ riscv_set_abi (64, FLOAT_ABI_QUAD);
+ else
+ return 0;
+ break;
+
default:
return 0;
}
void
riscv_after_parse_args (void)
{
- if (riscv_subsets == NULL)
- riscv_set_arch ("RVIMAFD");
-
if (xlen == 0)
{
if (strcmp (default_arch, "riscv32") == 0)
else
as_bad ("unknown default architecture `%s'", default_arch);
}
+
+ if (riscv_subsets == NULL)
+ riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
+
+ /* Add the RVC extension, regardless of -march, to support .option rvc. */
+ if (riscv_subset_supports ("c"))
+ riscv_set_rvc (TRUE);
+ else
+ riscv_add_subset ("c");
+
+ /* Infer ABI from ISA if not specified on command line. */
+ if (abi_xlen == 0)
+ abi_xlen = xlen;
+ else if (abi_xlen > xlen)
+ as_bad ("can't have %d-bit ABI on %d-bit ISA", abi_xlen, xlen);
+ else if (abi_xlen < xlen)
+ as_bad ("%d-bit ABI not yet supported on %d-bit ISA", abi_xlen, xlen);
+
+ if (float_abi == FLOAT_ABI_DEFAULT)
+ {
+ struct riscv_subset *subset;
+
+ /* Assume soft-float unless D extension is present. */
+ float_abi = FLOAT_ABI_SOFT;
+
+ for (subset = riscv_subsets; subset != NULL; subset = subset->next)
+ if (strcasecmp (subset->name, "D") == 0)
+ float_abi = FLOAT_ABI_DOUBLE;
+ }
+
+ /* Insert float_abi into the EF_RISCV_FLOAT_ABI field of elf_flags. */
+ elf_flags |= float_abi * (EF_RISCV_FLOAT_ABI & ~(EF_RISCV_FLOAT_ABI << 1));
}
long
void
md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
+ unsigned int subtype;
bfd_byte *buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
+ bfd_boolean relaxable = FALSE;
/* Remember value for tc_gen_reloc. */
fixP->fx_addnumber = *valP;
switch (fixP->fx_r_type)
{
- case BFD_RELOC_RISCV_TLS_GOT_HI20:
- case BFD_RELOC_RISCV_TLS_GD_HI20:
- case BFD_RELOC_RISCV_TLS_DTPREL32:
- case BFD_RELOC_RISCV_TLS_DTPREL64:
- case BFD_RELOC_RISCV_TPREL_HI20:
- case BFD_RELOC_RISCV_TPREL_LO12_I:
- case BFD_RELOC_RISCV_TPREL_LO12_S:
- case BFD_RELOC_RISCV_TPREL_ADD:
- S_SET_THREAD_LOCAL (fixP->fx_addsy);
- /* Fall through. */
-
- case BFD_RELOC_RISCV_GOT_HI20:
- case BFD_RELOC_RISCV_PCREL_HI20:
case BFD_RELOC_RISCV_HI20:
case BFD_RELOC_RISCV_LO12_I:
case BFD_RELOC_RISCV_LO12_S:
+ bfd_putl32 (riscv_apply_const_reloc (fixP->fx_r_type, *valP)
+ | bfd_getl32 (buf), buf);
+ relaxable = TRUE;
+ 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:
case BFD_RELOC_RISCV_ADD64:
+ case BFD_RELOC_RISCV_SUB6:
case BFD_RELOC_RISCV_SUB8:
case BFD_RELOC_RISCV_SUB16:
case BFD_RELOC_RISCV_SUB32:
case BFD_RELOC_RISCV_SUB64:
- gas_assert (fixP->fx_addsy != NULL);
- /* Nothing needed to do. The value comes from the reloc entry. */
+ case BFD_RELOC_RISCV_RELAX:
+ break;
+
+ case BFD_RELOC_RISCV_TPREL_HI20:
+ case BFD_RELOC_RISCV_TPREL_LO12_I:
+ case BFD_RELOC_RISCV_TPREL_LO12_S:
+ case BFD_RELOC_RISCV_TPREL_ADD:
+ relaxable = TRUE;
+ /* Fall through. */
+
+ case BFD_RELOC_RISCV_TLS_GOT_HI20:
+ case BFD_RELOC_RISCV_TLS_GD_HI20:
+ case BFD_RELOC_RISCV_TLS_DTPREL32:
+ case BFD_RELOC_RISCV_TLS_DTPREL64:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
break;
case BFD_RELOC_64:
case BFD_RELOC_32:
case BFD_RELOC_16:
case BFD_RELOC_8:
+ case BFD_RELOC_RISCV_CFA:
if (fixP->fx_addsy && fixP->fx_subsy)
{
fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB8;
break;
+ case BFD_RELOC_RISCV_CFA:
+ /* Load the byte to get the subtype. */
+ subtype = bfd_get_8 (NULL, &fixP->fx_frag->fr_literal[fixP->fx_where]);
+ switch (subtype)
+ {
+ case DW_CFA_advance_loc1:
+ fixP->fx_where++;
+ fixP->fx_next->fx_where++;
+ fixP->fx_r_type = BFD_RELOC_RISCV_SET8;
+ fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB8;
+ break;
+
+ case DW_CFA_advance_loc2:
+ fixP->fx_size = 2;
+ fixP->fx_where++;
+ fixP->fx_next->fx_size = 2;
+ fixP->fx_next->fx_where++;
+ fixP->fx_r_type = BFD_RELOC_RISCV_SET16;
+ fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB16;
+ break;
+
+ case DW_CFA_advance_loc4:
+ fixP->fx_size = 4;
+ fixP->fx_where++;
+ fixP->fx_next->fx_size = 4;
+ fixP->fx_next->fx_where++;
+ fixP->fx_r_type = BFD_RELOC_RISCV_SET32;
+ fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB32;
+ break;
+
+ default:
+ if (subtype < 0x80 && (subtype & 0x40))
+ {
+ /* DW_CFA_advance_loc */
+ fixP->fx_r_type = BFD_RELOC_RISCV_SET6;
+ fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB6;
+ }
+ else
+ as_fatal (_("internal error: bad CFA value #%d"), subtype);
+ break;
+ }
+ break;
+
default:
/* This case is unreachable. */
abort ();
}
break;
- case BFD_RELOC_RISCV_PCREL_LO12_S:
- case BFD_RELOC_RISCV_PCREL_LO12_I:
case BFD_RELOC_RISCV_CALL:
case BFD_RELOC_RISCV_CALL_PLT:
+ relaxable = TRUE;
+ break;
+
+ case BFD_RELOC_RISCV_PCREL_LO12_S:
+ case BFD_RELOC_RISCV_PCREL_LO12_I:
case BFD_RELOC_RISCV_ALIGN:
break;
if (bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type) != NULL)
as_fatal (_("internal error: bad relocation #%d"), fixP->fx_r_type);
}
+
+ /* Add an R_RISCV_RELAX reloc if the reloc is relaxable. */
+ if (relaxable && fixP->fx_tcbit && fixP->fx_addsy != NULL)
+ {
+ fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
+ fixP->fx_next->fx_addsy = fixP->fx_next->fx_subsy = NULL;
+ fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_RELAX;
+ }
}
+/* Because the value of .cfi_remember_state may changed after relaxation,
+ we insert a fix to relocate it again in link-time. */
+
+void
+riscv_pre_output_hook (void)
+{
+ const frchainS *frch;
+ const asection *s;
+
+ for (s = stdoutput->sections; s; s = s->next)
+ for (frch = seg_info (s)->frchainP; frch; frch = frch->frch_next)
+ {
+ const fragS *frag;
+
+ for (frag = frch->frch_root; frag; frag = frag->fr_next)
+ {
+ if (frag->fr_type == rs_cfa)
+ {
+ const fragS *loc4_frag;
+ expressionS exp;
+
+ symbolS *add_symbol = frag->fr_symbol->sy_value.X_add_symbol;
+ symbolS *op_symbol = frag->fr_symbol->sy_value.X_op_symbol;
+
+ exp.X_op = O_subtract;
+ exp.X_add_symbol = add_symbol;
+ exp.X_add_number = 0;
+ exp.X_op_symbol = op_symbol;
+
+ loc4_frag = (fragS *) frag->fr_opcode;
+ fix_new_exp (loc4_frag, (int) frag->fr_offset, 1, &exp, 0,
+ BFD_RELOC_RISCV_CFA);
+ }
+ }
+ }
+}
+
+
/* This structure is used to hold a stack of .option values. */
struct riscv_option_stack
riscv_opts.pic = TRUE;
else if (strcmp (name, "nopic") == 0)
riscv_opts.pic = FALSE;
- else if (strcmp (name, "soft-float") == 0)
- float_mode = FLOAT_MODE_SOFT;
- else if (strcmp (name, "hard-float") == 0)
- float_mode = FLOAT_MODE_HARD;
+ else if (strcmp (name, "relax") == 0)
+ riscv_opts.relax = TRUE;
+ else if (strcmp (name, "norelax") == 0)
+ riscv_opts.relax = FALSE;
else if (strcmp (name, "push") == 0)
{
struct riscv_option_stack *s;
goto done;
default:
- abort();
+ abort ();
}
}
void
riscv_elf_final_processing (void)
{
- enum float_mode elf_float_mode = float_mode;
-
elf_elfheader (stdoutput)->e_flags |= elf_flags;
-
- if (elf_float_mode == FLOAT_MODE_DEFAULT)
- {
- struct riscv_subset *subset;
-
- /* Assume soft-float unless D extension is present. */
- elf_float_mode = FLOAT_MODE_SOFT;
-
- for (subset = riscv_subsets; subset != NULL; subset = subset->next)
- if (strcasecmp (subset->name, "D") == 0)
- elf_float_mode = FLOAT_MODE_HARD;
- }
-
- if (elf_float_mode == FLOAT_MODE_SOFT)
- elf_elfheader (stdoutput)->e_flags |= EF_RISCV_SOFT_FLOAT;
}
/* Parse the .sleb128 and .uleb128 pseudos. Only allow constant expressions,