/* tc-arc.c -- Assembler for the ARC
- Copyright (C) 1994-2017 Free Software Foundation, Inc.
+ Copyright (C) 1994-2020 Free Software Foundation, Inc.
Contributor: Claudiu Zissulescu <claziss@synopsys.com>
#include "as.h"
#include "subsegs.h"
-#include "struc-symbol.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
#include "safe-ctype.h"
#include "opcode/arc.h"
+#include "opcode/arc-attrs.h"
#include "elf/arc.h"
#include "../opcodes/arc-ext.h"
#define LP_INSN(x) ((MAJOR_OPCODE (x) == 0x4) \
&& (SUB_OPCODE (x) == 0x28))
-/* Equal to MAX_PRECISION in atof-ieee.c. */
-#define MAX_LITTLENUMS 6
-
#ifndef TARGET_WITH_CPU
#define TARGET_WITH_CPU "arc700"
#endif /* TARGET_WITH_CPU */
+#define ARC_GET_FLAG(s) (*symbol_get_tc (s))
+#define ARC_SET_FLAG(s,v) (*symbol_get_tc (s) |= (v))
+#define streq(a, b) (strcmp (a, b) == 0)
+
/* Enum used to enumerate the relaxable ins operands. */
enum rlx_operand_type
{
#define is_spfp_p(op) (((sc) == SPX))
#define is_dpfp_p(op) (((sc) == DPX))
#define is_fpuda_p(op) (((sc) == DPA))
-#define is_br_jmp_insn_p(op) (((op)->insn_class == BRANCH \
- || (op)->insn_class == JUMP))
+#define is_br_jmp_insn_p(op) (((op)->insn_class == BRANCH \
+ || (op)->insn_class == JUMP \
+ || (op)->insn_class == BRCC \
+ || (op)->insn_class == BBIT0 \
+ || (op)->insn_class == BBIT1 \
+ || (op)->insn_class == BI \
+ || (op)->insn_class == EI \
+ || (op)->insn_class == ENTER \
+ || (op)->insn_class == JLI \
+ || (op)->insn_class == LOOP \
+ || (op)->insn_class == LEAVE \
+ ))
#define is_kernel_insn_p(op) (((op)->insn_class == KERNEL))
#define is_nps400_p(op) (((sc) == NPS400))
static void arc_extra_reloc (int);
static void arc_extinsn (int);
static void arc_extcorereg (int);
+static void arc_attribute (int);
const pseudo_typeS md_pseudo_table[] =
{
{ "lcommon", arc_lcomm, 0 },
{ "cpu", arc_option, 0 },
+ { "arc_attribute", arc_attribute, 0 },
{ "extinstruction", arc_extinsn, 0 },
{ "extcoreregister", arc_extcorereg, EXT_CORE_REGISTER },
{ "extauxregister", arc_extcorereg, EXT_AUX_REGISTER },
#define ARC_CPU_TYPE_AV2HS(NAME,EXTRA) \
{ #NAME, ARC_OPCODE_ARCv2HS, bfd_mach_arc_arcv2, \
EF_ARC_CPU_ARCV2HS, EXTRA}
+#define ARC_CPU_TYPE_NONE \
+ { 0, 0, 0, 0, 0 }
/* A table of CPU names and opcode sets. */
static const struct cpu_type
}
cpu_types[] =
{
- ARC_CPU_TYPE_A7xx (arc700, 0x00),
- ARC_CPU_TYPE_A7xx (nps400, ARC_NPS400),
-
- ARC_CPU_TYPE_AV2EM (arcem, 0x00),
- ARC_CPU_TYPE_AV2EM (em, 0x00),
- ARC_CPU_TYPE_AV2EM (em4, ARC_CD),
- ARC_CPU_TYPE_AV2EM (em4_dmips, ARC_CD),
- ARC_CPU_TYPE_AV2EM (em4_fpus, ARC_CD),
- ARC_CPU_TYPE_AV2EM (em4_fpuda, ARC_CD | ARC_FPUDA),
- ARC_CPU_TYPE_AV2EM (quarkse_em, ARC_CD | ARC_SPFP | ARC_DPFP),
-
- ARC_CPU_TYPE_AV2HS (archs, ARC_CD),
- ARC_CPU_TYPE_AV2HS (hs, ARC_CD),
- ARC_CPU_TYPE_AV2HS (hs34, ARC_CD),
- ARC_CPU_TYPE_AV2HS (hs38, ARC_CD),
- ARC_CPU_TYPE_AV2HS (hs38_linux, ARC_CD),
-
- ARC_CPU_TYPE_A6xx (arc600, 0x00),
- ARC_CPU_TYPE_A6xx (arc600_norm, 0x00),
- ARC_CPU_TYPE_A6xx (arc600_mul64, 0x00),
- ARC_CPU_TYPE_A6xx (arc600_mul32x16, 0x00),
- ARC_CPU_TYPE_A6xx (arc601, 0x00),
- ARC_CPU_TYPE_A6xx (arc601_norm, 0x00),
- ARC_CPU_TYPE_A6xx (arc601_mul64, 0x00),
- ARC_CPU_TYPE_A6xx (arc601_mul32x16, 0x00),
- { 0, 0, 0, 0, 0 }
+ #include "elf/arc-cpu.def"
};
/* Information about the cpu/variant we're assembling for. */
-static struct cpu_type selected_cpu = { 0, 0, 0, 0, 0 };
+static struct cpu_type selected_cpu = { 0, 0, 0, E_ARC_OSABI_CURRENT, 0 };
-/* A table with options. */
-static const struct feature_type
-{
- unsigned feature;
- unsigned cpus;
- const char *name;
-}
- feature_list[] =
-{
- { ARC_CD, ARC_OPCODE_ARCV2, "code-density" },
- { ARC_NPS400, ARC_OPCODE_ARC700, "nps400" },
- { ARC_SPFP, ARC_OPCODE_ARCFPX, "single-precision FPX" },
- { ARC_DPFP, ARC_OPCODE_ARCFPX, "double-precision FPX" },
- { ARC_FPUDA, ARC_OPCODE_ARCv2EM, "double assist FP" }
-};
+/* TRUE if current assembly code uses RF16 only registers. */
+static bfd_boolean rf16_only = TRUE;
+
+/* MPY option. */
+static unsigned mpy_option = 0;
+
+/* Use PIC. */
+static unsigned pic_option = 0;
+
+/* Use small data. */
+static unsigned sda_option = 0;
+
+/* Use TLS. */
+static unsigned tls_option = 0;
/* Command line given features. */
static unsigned cl_features = 0;
const unsigned arc_num_relaxable_ins = ARRAY_SIZE (arc_relaxable_insns);
-/* Flags to set in the elf header. */
-static const flagword arc_initial_eflag = 0x00;
-
/* Pre-defined "_GLOBAL_OFFSET_TABLE_". */
symbolS * GOT_symbol = 0;
/* Set to TRUE when we assemble instructions. */
static bfd_boolean assembling_insn = FALSE;
+/* List with attributes set explicitly. */
+static bfd_boolean attributes_set_explicitly[NUM_KNOWN_OBJ_ATTRIBUTES];
+
/* Functions implementation. */
/* Return a pointer to ARC_OPCODE_HASH_ENTRY that identifies all
md_number_to_chars (buf, val, n);
break;
case 6:
- md_number_to_chars (buf, (val & 0xffff00000000) >> 32, 2);
+ md_number_to_chars (buf, (val & 0xffff00000000ull) >> 32, 2);
md_number_to_chars_midend (buf + 2, (val & 0xffffffff), 4);
break;
case 4:
md_number_to_chars (buf + 2, (val & 0xffff), 2);
break;
case 8:
- md_number_to_chars_midend (buf, (val & 0xffffffff00000000) >> 32, 4);
+ md_number_to_chars_midend (buf, (val & 0xffffffff00000000ull) >> 32, 4);
md_number_to_chars_midend (buf + 4, (val & 0xffffffff), 4);
break;
default:
if (!selected_cpu.features
|| !selected_cpu.name)
return;
- for (i = 0; (i < ARRAY_SIZE (feature_list)); i++)
- {
- if ((selected_cpu.features & feature_list[i].feature)
- && !(selected_cpu.flags & feature_list[i].cpus))
- {
- as_bad (_("invalid %s option for %s cpu"), feature_list[i].name,
- selected_cpu.name);
- }
- }
+
+ for (i = 0; i < ARRAY_SIZE (feature_list); i++)
+ if ((selected_cpu.features & feature_list[i].feature)
+ && !(selected_cpu.flags & feature_list[i].cpus))
+ as_bad (_("invalid %s option for %s cpu"), feature_list[i].name,
+ selected_cpu.name);
+
+ for (i = 0; i < ARRAY_SIZE (conflict_list); i++)
+ if ((selected_cpu.features & conflict_list[i]) == conflict_list[i])
+ as_bad(_("conflicting ISA extension attributes."));
}
/* Select an appropriate entry from CPU_TYPES based on ARG and initialise
static void
arc_select_cpu (const char *arg, enum mach_selection_type sel)
{
- int cpu_flags = 0;
int i;
+ static struct cpu_type old_cpu = { 0, 0, 0, E_ARC_OSABI_CURRENT, 0 };
/* We should only set a default if we've not made a selection from some
other source. */
}
return;
}
-
/* Initialise static global data about selected machine type. */
selected_cpu.flags = cpu_types[i].flags;
selected_cpu.name = cpu_types[i].name;
selected_cpu.features = cpu_types[i].features | cl_features;
selected_cpu.mach = cpu_types[i].mach;
- cpu_flags = cpu_types[i].eflags;
+ selected_cpu.eflags = ((selected_cpu.eflags & ~EF_ARC_MACH_MSK)
+ | cpu_types[i].eflags);
break;
}
}
/* Check if set features are compatible with the chosen CPU. */
arc_check_feature ();
- gas_assert (cpu_flags != 0);
- selected_cpu.eflags = (arc_initial_eflag & ~EF_ARC_MACH_MSK) | cpu_flags;
+
+ /* If we change the CPU, we need to re-init the bfd. */
+ if (mach_selection_mode != MACH_SELECTION_NONE
+ && (old_cpu.mach != selected_cpu.mach))
+ {
+ bfd_find_target (arc_target_format, stdoutput);
+ if (! bfd_set_arch_mach (stdoutput, bfd_arch_arc, selected_cpu.mach))
+ as_warn (_("Could not set architecture and machine"));
+ }
+
mach_selection_mode = sel;
+ old_cpu = selected_cpu;
}
/* Here ends all the ARCompact extension instruction assembling
arc_select_cpu (cpu_name, MACH_SELECTION_FROM_CPU_DIRECTIVE);
- if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, selected_cpu.mach))
- as_fatal (_("could not set architecture and machine"));
-
- /* Set elf header flags. */
- bfd_set_private_flags (stdoutput, selected_cpu.eflags);
-
restore_line_pointer (c);
demand_empty_rest_of_line ();
}
fflush (stderr);
}
+/* Helper for parsing an argument, used for sorting out the relocation
+ type. */
+
+static void
+parse_reloc_symbol (expressionS *resultP)
+{
+ char *reloc_name, c, *sym_name;
+ size_t len;
+ int i;
+ const struct arc_reloc_op_tag *r;
+ expressionS right;
+ symbolS *base;
+
+ /* A relocation operand has the following form
+ @identifier@relocation_type. The identifier is already in
+ tok! */
+ if (resultP->X_op != O_symbol)
+ {
+ as_bad (_("No valid label relocation operand"));
+ resultP->X_op = O_illegal;
+ return;
+ }
+
+ /* Parse @relocation_type. */
+ input_line_pointer++;
+ c = get_symbol_name (&reloc_name);
+ len = input_line_pointer - reloc_name;
+ if (len == 0)
+ {
+ as_bad (_("No relocation operand"));
+ resultP->X_op = O_illegal;
+ return;
+ }
+
+ /* Go through known relocation and try to find a match. */
+ r = &arc_reloc_op[0];
+ for (i = arc_num_reloc_op - 1; i >= 0; i--, r++)
+ if (len == r->length
+ && memcmp (reloc_name, r->name, len) == 0)
+ break;
+ if (i < 0)
+ {
+ as_bad (_("Unknown relocation operand: @%s"), reloc_name);
+ resultP->X_op = O_illegal;
+ return;
+ }
+
+ *input_line_pointer = c;
+ SKIP_WHITESPACE_AFTER_NAME ();
+ /* Extra check for TLS: base. */
+ if (*input_line_pointer == '@')
+ {
+ if (resultP->X_op_symbol != NULL
+ || resultP->X_op != O_symbol)
+ {
+ as_bad (_("Unable to parse TLS base: %s"),
+ input_line_pointer);
+ resultP->X_op = O_illegal;
+ return;
+ }
+ input_line_pointer++;
+ c = get_symbol_name (&sym_name);
+ base = symbol_find_or_make (sym_name);
+ resultP->X_op = O_subtract;
+ resultP->X_op_symbol = base;
+ restore_line_pointer (c);
+ right.X_add_number = 0;
+ }
+
+ if ((*input_line_pointer != '+')
+ && (*input_line_pointer != '-'))
+ right.X_add_number = 0;
+ else
+ {
+ /* Parse the constant of a complex relocation expression
+ like @identifier@reloc +/- const. */
+ if (! r->complex_expr)
+ {
+ as_bad (_("@%s is not a complex relocation."), r->name);
+ resultP->X_op = O_illegal;
+ return;
+ }
+ expression (&right);
+ if (right.X_op != O_constant)
+ {
+ as_bad (_("Bad expression: @%s + %s."),
+ r->name, input_line_pointer);
+ resultP->X_op = O_illegal;
+ return;
+ }
+ }
+
+ resultP->X_md = r->op;
+ resultP->X_add_number = right.X_add_number;
+}
+
/* Parse the arguments to an opcode. */
static int
bfd_boolean saw_arg = FALSE;
int brk_lvl = 0;
int num_args = 0;
- int i;
- size_t len;
- const struct arc_reloc_op_tag *r;
- expressionS tmpE;
- char *reloc_name, c;
memset (tok, 0, sizeof (*tok) * ntok);
goto err;
/* Parse @label. */
+ input_line_pointer++;
tok->X_op = O_symbol;
tok->X_md = O_absent;
expression (tok);
- if (*input_line_pointer != '@')
- goto normalsymbol; /* This is not a relocation. */
-
- relocationsym:
-
- /* A relocation operand has the following form
- @identifier@relocation_type. The identifier is already
- in tok! */
- if (tok->X_op != O_symbol)
- {
- as_bad (_("No valid label relocation operand"));
- goto err;
- }
-
- /* Parse @relocation_type. */
- input_line_pointer++;
- c = get_symbol_name (&reloc_name);
- len = input_line_pointer - reloc_name;
- if (len == 0)
- {
- as_bad (_("No relocation operand"));
- goto err;
- }
- /* Go through known relocation and try to find a match. */
- r = &arc_reloc_op[0];
- for (i = arc_num_reloc_op - 1; i >= 0; i--, r++)
- if (len == r->length
- && memcmp (reloc_name, r->name, len) == 0)
- break;
- if (i < 0)
- {
- as_bad (_("Unknown relocation operand: @%s"), reloc_name);
- goto err;
- }
-
- *input_line_pointer = c;
- SKIP_WHITESPACE_AFTER_NAME ();
- /* Extra check for TLS: base. */
if (*input_line_pointer == '@')
- {
- symbolS *base;
- if (tok->X_op_symbol != NULL
- || tok->X_op != O_symbol)
- {
- as_bad (_("Unable to parse TLS base: %s"),
- input_line_pointer);
- goto err;
- }
- input_line_pointer++;
- char *sym_name;
- c = get_symbol_name (&sym_name);
- base = symbol_find_or_make (sym_name);
- tok->X_op = O_subtract;
- tok->X_op_symbol = base;
- restore_line_pointer (c);
- tmpE.X_add_number = 0;
- }
- if ((*input_line_pointer != '+')
- && (*input_line_pointer != '-'))
- {
- tmpE.X_add_number = 0;
- }
- else
- {
- /* Parse the constant of a complex relocation expression
- like @identifier@reloc +/- const. */
- if (! r->complex_expr)
- {
- as_bad (_("@%s is not a complex relocation."), r->name);
- goto err;
- }
- expression (&tmpE);
- if (tmpE.X_op != O_constant)
- {
- as_bad (_("Bad expression: @%s + %s."),
- r->name, input_line_pointer);
- goto err;
- }
- }
-
- tok->X_md = r->op;
- tok->X_add_number = tmpE.X_add_number;
+ parse_reloc_symbol (tok);
debug_exp (tok);
+ if (tok->X_op == O_illegal
+ || tok->X_op == O_absent
+ || num_args == ntok)
+ goto err;
+
saw_comma = FALSE;
saw_arg = TRUE;
tok++;
identifier@relocation_type, if it is the case parse the
relocation type as well. */
if (*input_line_pointer == '@')
- goto relocationsym;
+ parse_reloc_symbol (tok);
- normalsymbol:
debug_exp (tok);
if (tok->X_op == O_illegal
static bfd_boolean
check_cpu_feature (insn_subclass_t sc)
{
- if (is_code_density_p (sc) && !(selected_cpu.features & ARC_CD))
+ if (is_code_density_p (sc) && !(selected_cpu.features & CD))
return FALSE;
- if (is_spfp_p (sc) && !(selected_cpu.features & ARC_SPFP))
+ if (is_spfp_p (sc) && !(selected_cpu.features & SPX))
return FALSE;
- if (is_dpfp_p (sc) && !(selected_cpu.features & ARC_DPFP))
+ if (is_dpfp_p (sc) && !(selected_cpu.features & DPX))
return FALSE;
- if (is_fpuda_p (sc) && !(selected_cpu.features & ARC_FPUDA))
+ if (is_fpuda_p (sc) && !(selected_cpu.features & DPA))
return FALSE;
- if (is_nps400_p (sc) && !(selected_cpu.features & ARC_NPS400))
+ if (is_nps400_p (sc) && !(selected_cpu.features & NPS400))
return FALSE;
return TRUE;
case O_symbol:
{
const char *p;
+ char *tmpp, *pp;
const struct arc_aux_reg *auxr;
if (opcode->insn_class != AUXREG)
goto de_fault;
p = S_GET_NAME (tok[tokidx].X_add_symbol);
- auxr = hash_find (arc_aux_hash, p);
+ /* For compatibility reasons, an aux register can
+ be spelled with upper or lower case
+ letters. */
+ tmpp = strdup (p);
+ for (pp = tmpp; *pp; ++pp) *pp = TOLOWER (*pp);
+
+ auxr = hash_find (arc_aux_hash, tmpp);
if (auxr)
{
/* We modify the token array here, safe in the
tok[tokidx].X_add_number = auxr->address;
ARC_SET_FLAG (tok[tokidx].X_add_symbol, ARC_FLAG_AUX);
}
+ free (tmpp);
if (tok[tokidx].X_op != O_constant)
goto de_fault;
return entry;
}
-/* Given an opcode name, pre-tokenized set of arguments and the
+/* Autodetect cpu attribute list. */
+
+static void
+autodetect_attributes (const struct arc_opcode *opcode,
+ const expressionS *tok,
+ int ntok)
+{
+ unsigned i;
+ struct mpy_type
+ {
+ unsigned feature;
+ unsigned encoding;
+ } mpy_list[] = {{ MPY1E, 1 }, { MPY6E, 6 }, { MPY7E, 7 }, { MPY8E, 8 },
+ { MPY9E, 9 }};
+
+ for (i = 0; i < ARRAY_SIZE (feature_list); i++)
+ if (opcode->subclass == feature_list[i].feature)
+ selected_cpu.features |= feature_list[i].feature;
+
+ for (i = 0; i < ARRAY_SIZE (mpy_list); i++)
+ if (opcode->subclass == mpy_list[i].feature)
+ mpy_option = mpy_list[i].encoding;
+
+ for (i = 0; i < (unsigned) ntok; i++)
+ {
+ switch (tok[i].X_md)
+ {
+ case O_gotoff:
+ case O_gotpc:
+ case O_plt:
+ pic_option = 2;
+ break;
+ case O_sda:
+ sda_option = 2;
+ break;
+ case O_tlsgd:
+ case O_tlsie:
+ case O_tpoff9:
+ case O_tpoff:
+ case O_dtpoff9:
+ case O_dtpoff:
+ tls_option = 1;
+ break;
+ default:
+ break;
+ }
+
+ switch (tok[i].X_op)
+ {
+ case O_register:
+ if ((tok[i].X_add_number >= 4 && tok[i].X_add_number <= 9)
+ || (tok[i].X_add_number >= 16 && tok[i].X_add_number <= 25))
+ rf16_only = FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/* Given an opcode name, pre-tockenized set of argumenst and the
opcode flags, take it all the way through emission. */
static void
{
struct arc_insn insn;
+ autodetect_attributes (opcode, tok, ntok);
assemble_insn (opcode, tok, ntok, pflags, nflgs, &insn);
emit_insn (&insn);
return;
md_section_align (segT segment,
valueT size)
{
- int align = bfd_get_section_alignment (stdoutput, segment);
+ int align = bfd_section_alignment (segment);
return ((size + (1 << align) - 1) & (-((valueT) 1 << align)));
}
break;
default:
if ((int) fixP->fx_r_type < 0)
- as_fatal (_("PC relative relocation not allowed for (internal) type %d"),
- fixP->fx_r_type);
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("PC relative relocation not allowed for (internal)"
+ " type %d"),
+ fixP->fx_r_type);
break;
}
}
int size, fix;
struct arc_relax_type *relax_arg = &fragP->tc_frag_data;
- fix = (fragP->fr_fix < 0 ? 0 : fragP->fr_fix);
+ fix = fragP->fr_fix;
dest = fragP->fr_literal + fix;
table_entry = TC_GENERIC_RELAX_TABLE + fragP->fr_subtype;
GOTPC reference to _GLOBAL_OFFSET_TABLE_. */
if (((*name == '_')
&& (*(name+1) == 'G')
- && (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0))
- || ((*name == '_')
- && (*(name+1) == 'D')
- && (strcmp (name, DYNAMIC_STRUCT_NAME) == 0)))
+ && (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)))
{
if (!GOT_symbol)
{
/* Called for any expression that can not be recognized. When the
function is called, `input_line_pointer' will point to the start of
- the expression. */
+ the expression. We use it when we have complex operations like
+ @label1 - @label2. */
void
-md_operand (expressionS *expressionP ATTRIBUTE_UNUSED)
+md_operand (expressionS *expressionP)
{
char *p = input_line_pointer;
if (*p == '@')
{
input_line_pointer++;
expressionP->X_op = O_symbol;
+ expressionP->X_md = O_absent;
expression (expressionP);
}
}
if (!assembling_insn)
return FALSE;
- if (e->X_op == O_symbol)
+ if (e->X_op == O_symbol
+ && e->X_md == O_absent)
return FALSE;
sym = hash_find (arc_reg_hash, name);
break;
case OPTION_CD:
- selected_cpu.features |= ARC_CD;
- cl_features |= ARC_CD;
+ selected_cpu.features |= CD;
+ cl_features |= CD;
arc_check_feature ();
break;
break;
case OPTION_NPS400:
- selected_cpu.features |= ARC_NPS400;
- cl_features |= ARC_NPS400;
+ selected_cpu.features |= NPS400;
+ cl_features |= NPS400;
arc_check_feature ();
break;
case OPTION_SPFP:
- selected_cpu.features |= ARC_SPFP;
- cl_features |= ARC_SPFP;
+ selected_cpu.features |= SPX;
+ cl_features |= SPX;
arc_check_feature ();
break;
case OPTION_DPFP:
- selected_cpu.features |= ARC_DPFP;
- cl_features |= ARC_DPFP;
+ selected_cpu.features |= DPX;
+ cl_features |= DPX;
arc_check_feature ();
break;
case OPTION_FPUDA:
- selected_cpu.features |= ARC_FPUDA;
- cl_features |= ARC_FPUDA;
+ selected_cpu.features |= DPA;
+ cl_features |= DPA;
arc_check_feature ();
break;
{
case O_plt:
if (opcode->insn_class == JUMP)
- as_bad_where (frag_now->fr_file, frag_now->fr_line,
- _("Unable to use @plt relocation for insn %s"),
- opcode->name);
+ as_bad (_("Unable to use @plt relocation for insn %s"),
+ opcode->name);
needGOTSymbol = TRUE;
reloc = find_reloc ("plt", opcode->name,
pflags, nflg,
reloc = ARC_RELOC_TABLE (t->X_md)->reloc;
if (arc_opcode_len (opcode) == 2
|| opcode->insn_class == JUMP)
- as_bad_where (frag_now->fr_file, frag_now->fr_line,
- _("Unable to use @pcl relocation for insn %s"),
- opcode->name);
+ as_bad (_("Unable to use @pcl relocation for insn %s"),
+ opcode->name);
}
else
{
/* Check if the current instruction is legally used. */
if (arc_last_insns[1].has_delay_slot
&& is_br_jmp_insn_p (arc_last_insns[0].opcode))
- as_bad_where (frag_now->fr_file, frag_now->fr_line,
- _("A jump/branch instruction in delay slot."));
+ as_bad (_("Insn %s has a jump/branch instruction %s in its delay slot."),
+ arc_last_insns[1].opcode->name,
+ arc_last_insns[0].opcode->name);
+ if (arc_last_insns[1].has_delay_slot
+ && arc_last_insns[0].has_limm)
+ as_bad (_("Insn %s has an instruction %s with limm in its delay slot."),
+ arc_last_insns[1].opcode->name,
+ arc_last_insns[0].opcode->name);
}
void
if (*r_type_p == BFD_RELOC_32
&& exp->X_op == O_subtract
&& exp->X_op_symbol != NULL
- && exp->X_op_symbol->bsym->section == now_seg)
+ && S_GET_SEGMENT (exp->X_op_symbol) == now_seg)
*r_type_p = BFD_RELOC_ARC_32_PCREL;
}
insn_name = xstrdup (p);
restore_line_pointer (c);
+ /* Convert to lower case. */
+ for (p = insn_name; *p; ++p)
+ *p = TOLOWER (*p);
+
/* 2nd: get major opcode. */
if (*input_line_pointer != ',')
{
if (!arcext_section)
{
arcext_section = subseg_new (".arcextmap", 0);
- bfd_set_section_flags (stdoutput, arcext_section,
- SEC_READONLY | SEC_HAS_CONTENTS);
+ bfd_set_section_flags (arcext_section, SEC_READONLY | SEC_HAS_CONTENTS);
}
else
subseg_set (arcext_section, 0);
create_extcore_section (&ereg, opertype);
}
+/* Parse a .arc_attribute directive. */
+
+static void
+arc_attribute (int ignored ATTRIBUTE_UNUSED)
+{
+ int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
+
+ if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
+ attributes_set_explicitly[tag] = TRUE;
+}
+
+/* Set an attribute if it has not already been set by the user. */
+
+static void
+arc_set_attribute_int (int tag, int value)
+{
+ if (tag < 1
+ || tag >= NUM_KNOWN_OBJ_ATTRIBUTES
+ || !attributes_set_explicitly[tag])
+ bfd_elf_add_proc_attr_int (stdoutput, tag, value);
+}
+
+static void
+arc_set_attribute_string (int tag, const char *value)
+{
+ if (tag < 1
+ || tag >= NUM_KNOWN_OBJ_ATTRIBUTES
+ || !attributes_set_explicitly[tag])
+ bfd_elf_add_proc_attr_string (stdoutput, tag, value);
+}
+
+/* Allocate and concatenate two strings. s1 can be NULL but not
+ s2. s1 pointer is freed at end of this procedure. */
+
+static char *
+arc_stralloc (char * s1, const char * s2)
+{
+ char * p;
+ int len = 0;
+
+ if (s1)
+ len = strlen (s1) + 1;
+
+ /* Only s1 can be null. */
+ gas_assert (s2);
+ len += strlen (s2) + 1;
+
+ p = (char *) xmalloc (len);
+ if (p == NULL)
+ as_fatal (_("Virtual memory exhausted"));
+
+ if (s1)
+ {
+ strcpy (p, s1);
+ strcat (p, ",");
+ strcat (p, s2);
+ free (s1);
+ }
+ else
+ strcpy (p, s2);
+
+ return p;
+}
+
+/* Set the public ARC object attributes. */
+
+static void
+arc_set_public_attributes (void)
+{
+ int base = 0;
+ char *s = NULL;
+ unsigned int i;
+
+ /* Tag_ARC_CPU_name. */
+ arc_set_attribute_string (Tag_ARC_CPU_name, selected_cpu.name);
+
+ /* Tag_ARC_CPU_base. */
+ switch (selected_cpu.eflags & EF_ARC_MACH_MSK)
+ {
+ case E_ARC_MACH_ARC600:
+ case E_ARC_MACH_ARC601:
+ base = TAG_CPU_ARC6xx;
+ break;
+ case E_ARC_MACH_ARC700:
+ base = TAG_CPU_ARC7xx;
+ break;
+ case EF_ARC_CPU_ARCV2EM:
+ base = TAG_CPU_ARCEM;
+ break;
+ case EF_ARC_CPU_ARCV2HS:
+ base = TAG_CPU_ARCHS;
+ break;
+ default:
+ base = 0;
+ break;
+ }
+ if (attributes_set_explicitly[Tag_ARC_CPU_base]
+ && (base != bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC,
+ Tag_ARC_CPU_base)))
+ as_warn (_("Overwrite explicitly set Tag_ARC_CPU_base"));
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_ARC_CPU_base, base);
+
+ /* Tag_ARC_ABI_osver. */
+ if (attributes_set_explicitly[Tag_ARC_ABI_osver])
+ {
+ int val = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC,
+ Tag_ARC_ABI_osver);
+
+ selected_cpu.eflags = ((selected_cpu.eflags & ~EF_ARC_OSABI_MSK)
+ | (val & 0x0f << 8));
+ }
+ else
+ {
+ arc_set_attribute_int (Tag_ARC_ABI_osver, E_ARC_OSABI_CURRENT >> 8);
+ }
+
+ /* Tag_ARC_ISA_config. */
+ arc_check_feature();
+
+ for (i = 0; i < ARRAY_SIZE (feature_list); i++)
+ if (selected_cpu.features & feature_list[i].feature)
+ s = arc_stralloc (s, feature_list[i].attr);
+
+ if (s)
+ arc_set_attribute_string (Tag_ARC_ISA_config, s);
+
+ /* Tag_ARC_ISA_mpy_option. */
+ arc_set_attribute_int (Tag_ARC_ISA_mpy_option, mpy_option);
+
+ /* Tag_ARC_ABI_pic. */
+ arc_set_attribute_int (Tag_ARC_ABI_pic, pic_option);
+
+ /* Tag_ARC_ABI_sda. */
+ arc_set_attribute_int (Tag_ARC_ABI_sda, sda_option);
+
+ /* Tag_ARC_ABI_tls. */
+ arc_set_attribute_int (Tag_ARC_ABI_tls, tls_option);
+
+ /* Tag_ARC_ATR_version. */
+ arc_set_attribute_int (Tag_ARC_ATR_version, 1);
+
+ /* Tag_ARC_ABI_rf16. */
+ if (attributes_set_explicitly[Tag_ARC_ABI_rf16]
+ && bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC,
+ Tag_ARC_ABI_rf16)
+ && !rf16_only)
+ {
+ as_warn (_("Overwrite explicitly set Tag_ARC_ABI_rf16 to full "
+ "register file"));
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_ARC_ABI_rf16, 0);
+ }
+}
+
+/* Add the default contents for the .ARC.attributes section. */
+
+void
+arc_md_end (void)
+{
+ arc_set_public_attributes ();
+
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, selected_cpu.mach))
+ as_fatal (_("could not set architecture and machine"));
+
+ bfd_set_private_flags (stdoutput, selected_cpu.eflags);
+}
+
+void arc_copy_symbol_attributes (symbolS *dest, symbolS *src)
+{
+ ARC_GET_FLAG (dest) = ARC_GET_FLAG (src);
+}
+
+int arc_convert_symbolic_attribute (const char *name)
+{
+ static const struct
+ {
+ const char * name;
+ const int tag;
+ }
+ attribute_table[] =
+ {
+#define T(tag) {#tag, tag}
+ T (Tag_ARC_PCS_config),
+ T (Tag_ARC_CPU_base),
+ T (Tag_ARC_CPU_variation),
+ T (Tag_ARC_CPU_name),
+ T (Tag_ARC_ABI_rf16),
+ T (Tag_ARC_ABI_osver),
+ T (Tag_ARC_ABI_sda),
+ T (Tag_ARC_ABI_pic),
+ T (Tag_ARC_ABI_tls),
+ T (Tag_ARC_ABI_enumsize),
+ T (Tag_ARC_ABI_exceptions),
+ T (Tag_ARC_ABI_double_size),
+ T (Tag_ARC_ISA_config),
+ T (Tag_ARC_ISA_apex),
+ T (Tag_ARC_ISA_mpy_option),
+ T (Tag_ARC_ATR_version)
+#undef T
+ };
+ unsigned int i;
+
+ if (name == NULL)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE (attribute_table); i++)
+ if (streq (name, attribute_table[i].name))
+ return attribute_table[i].tag;
+
+ return -1;
+}
+
/* Local variables:
eval: (c-set-style "gnu")
indent-tabs-mode: t