/* Altera Nios II assembler.
- Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Copyright (C) 2012-2020 Free Software Foundation, Inc.
Contributed by Nigel Gray (ngray@altera.com).
Contributed by Mentor Graphics, Inc.
#include "elf/nios2.h"
#include "tc-nios2.h"
#include "bfd.h"
-#include "libbfd.h"
#include "dwarf2dbg.h"
#include "subsegs.h"
#include "safe-ctype.h"
} relax_optionT;
/* Struct contains all assembler options set with .set. */
-struct
+static struct
{
/* .set noat -> noat = 1 allows assembly code to use at without warning
and macro expansions generate a warning.
static int nios2_auto_align_on = 1;
/* The last seen label in the current section. This is used to auto-align
- labels preceeding instructions. */
+ labels preceding instructions. */
static symbolS *nios2_last_label;
/* If we saw a 16-bit CDX instruction, we can align on 2-byte boundaries
of type TYPE, and store the appropriate bytes in *LITP. The number
of LITTLENUMS emitted is stored in *SIZEP. An error message is
returned, or NULL on OK. */
-char *
+const char *
md_atof (int type, char *litP, int *sizeP)
{
int prec;
#define CDX_CBRANCH_SUBTYPE(N) (CDXBRANCH | CBRANCH | (N))
#define SUBTYPE_ADDIS(SUBTYPE) ((SUBTYPE) & 0xffff)
-/* For the -relax-section mode, unconditional branches require 2 extra i
- nstructions besides the addis, conditional branches require 3. */
+/* For the -relax-section mode, unconditional branches require 2 extra
+ instructions besides the addis, conditional branches require 3. */
#define UBRANCH_ADDIS_TO_SIZE(N) (((N) + 2) * 4)
#define CBRANCH_ADDIS_TO_SIZE(N) (((N) + 3) * 4)
if ((fixup & 0x80000000) > 0)
{
/* Check for negative overflow. */
- if ((signed) fixup < ((signed) ~0 << (howto->bitsize-1)))
+ if ((signed) fixup < (signed) (~0U << (howto->bitsize - 1)))
return TRUE;
}
else
nios2_diagnose_overflow (fixup, howto, fixP, value);
/* Apply the right shift. */
- fixup = ((signed)fixup) >> howto->rightshift;
+ fixup = (offsetT) fixup >> howto->rightshift;
/* Truncate the fixup to right size. */
switch (fixP->fx_r_type)
fixup = fixup & 0xFFFF;
break;
case BFD_RELOC_NIOS2_HIADJ16:
- fixup = ((((fixup >> 16) & 0xFFFF) + ((fixup >> 15) & 0x01))
- & 0xFFFF);
+ fixup = ((fixup + 0x8000) >> 16) & 0xFFFF;
break;
default:
{
- int n = sizeof (fixup) * 8 - howto->bitsize;
- fixup = (fixup << n) >> n;
+ fixup &= ((valueT) 1 << howto->bitsize) - 1;
break;
}
}
nios2_insn_reloc_new (bfd_reloc_code_real_type reloc_type, unsigned int pcrel)
{
nios2_insn_relocS *retval;
- retval = (nios2_insn_relocS *) malloc (sizeof (nios2_insn_relocS));
+ retval = XNEW (nios2_insn_relocS);
if (retval == NULL)
{
as_bad (_("can't create relocation"));
mask = (reglist & 0x00ffc000) >> 14;
if (reglist & (1 << 28))
mask |= 1 << 10;
- if (reglist & (1 << 31))
+ if (reglist & (1u << 31))
mask |= 1 << 11;
}
insn->insn_code |= SET_IW_F1X4L17_REGMASK (mask);
{
char *tmp = parsed_args[ndx];
- parsed_args[ndx]
- = (char *) malloc (strlen (parsed_args[ndx]) + strlen (modifier) + 1);
- strcpy (parsed_args[ndx], tmp);
- strcat (parsed_args[ndx], modifier);
+ parsed_args[ndx] = concat (tmp, modifier, (char *) NULL);
}
/* Modify parsed_args[ndx] by negating that argument. */
{
char *tmp = parsed_args[ndx];
- parsed_args[ndx]
- = (char *) malloc (strlen ("~(") + strlen (parsed_args[ndx]) +
- strlen (")+1") + 1);
-
- strcpy (parsed_args[ndx], "~(");
- strcat (parsed_args[ndx], tmp);
- strcat (parsed_args[ndx], ")+1");
+ parsed_args[ndx] = concat ("~(", tmp, ")+1", (char *) NULL);
}
/* The function nios2_swap_args swaps the pointers at indices index_1 and
static void
nios2_free_arg (char **parsed_args, int num ATTRIBUTE_UNUSED, int start)
{
- if (parsed_args[start])
- {
- free (parsed_args[start]);
- parsed_args[start] = NULL;
- }
+ free (parsed_args[start]);
+ parsed_args[start] = NULL;
}
/* This function swaps the pseudo-op for a real op. */
nios2_translate_pseudo_insn (nios2_insn_infoS *insn)
{
+ const struct nios2_opcode *op = insn->insn_nios2_opcode;
nios2_ps_insn_infoS *ps_insn;
+ unsigned int tokidx, ntok;
- /* Find which real insn the pseudo-op transates to and
+ /* Find which real insn the pseudo-op translates to and
switch the insn_info ptr to point to it. */
- ps_insn = nios2_ps_lookup (insn->insn_nios2_opcode->name);
+ ps_insn = nios2_ps_lookup (op->name);
if (ps_insn != NULL)
{
insn->insn_nios2_opcode = nios2_opcode_lookup (ps_insn->insn);
insn->insn_tokens[0] = insn->insn_nios2_opcode->name;
+
+ /* Make sure there are enough arguments. */
+ ntok = ((op->pinfo & NIOS2_INSN_OPTARG)
+ ? op->num_args - 1 : op->num_args);
+ for (tokidx = 1; tokidx <= ntok; tokidx++)
+ if (insn->insn_tokens[tokidx] == NULL)
+ {
+ as_bad ("missing argument");
+ return NULL;
+ }
+
/* Modify the args so they work with the real insn. */
ps_insn->arg_modifer_func ((char **) insn->insn_tokens,
ps_insn->arg_modifier, ps_insn->num,
and puts it in the current frag. */
char *f = frag_more (8);
nios2_insn_relocS *reloc = insn->insn_reloc;
- unsigned long reg, code;
+ unsigned long reg, code = 0;
const struct nios2_opcode *op = insn->insn_nios2_opcode;
/* If the reloc is NULL, there was an error assembling the movia. */
/* The following functions are called by machine-independent parts of
the assembler. */
int
-md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
+md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
{
switch (c)
{
unsigned long saved_pinfo = 0;
nios2_insn_infoS thisinsn;
nios2_insn_infoS *insn = &thisinsn;
+ bfd_boolean ps_error = FALSE;
/* Make sure we are aligned on an appropriate boundary. */
if (nios2_current_align < nios2_min_align)
with its real equivalent, and then continue. */
if ((insn->insn_nios2_opcode->pinfo & NIOS2_INSN_MACRO)
== NIOS2_INSN_MACRO)
- ps_insn = nios2_translate_pseudo_insn (insn);
-
- /* Assemble the parsed arguments into the instruction word. */
- nios2_assemble_args (insn);
-
- /* Handle relaxation and other transformations. */
- if (nios2_as_options.relax != relax_none
- && !nios2_as_options.noat
- && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_UBRANCH)
- output_ubranch (insn);
- else if (nios2_as_options.relax != relax_none
- && !nios2_as_options.noat
- && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CBRANCH)
- output_cbranch (insn);
- else if (nios2_as_options.relax == relax_all
- && !nios2_as_options.noat
- && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CALL
- && insn->insn_reloc
- && ((insn->insn_reloc->reloc_type
- == BFD_RELOC_NIOS2_CALL26)
- || (insn->insn_reloc->reloc_type
- == BFD_RELOC_NIOS2_CALL26_NOAT)))
- output_call (insn);
- else if (saved_pinfo == NIOS2_INSN_MACRO_MOVIA)
- output_movia (insn);
- else
- output_insn (insn);
- if (ps_insn)
- nios2_cleanup_pseudo_insn (insn, ps_insn);
+ {
+ ps_insn = nios2_translate_pseudo_insn (insn);
+ if (!ps_insn)
+ ps_error = TRUE;
+ }
+
+ /* If we found invalid pseudo-instruction syntax, the error's already
+ been diagnosed in nios2_translate_pseudo_insn, so skip
+ remaining processing. */
+ if (!ps_error)
+ {
+ /* Assemble the parsed arguments into the instruction word. */
+ nios2_assemble_args (insn);
+
+ /* Handle relaxation and other transformations. */
+ if (nios2_as_options.relax != relax_none
+ && !nios2_as_options.noat
+ && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_UBRANCH)
+ output_ubranch (insn);
+ else if (nios2_as_options.relax != relax_none
+ && !nios2_as_options.noat
+ && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CBRANCH)
+ output_cbranch (insn);
+ else if (nios2_as_options.relax == relax_all
+ && !nios2_as_options.noat
+ && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CALL
+ && insn->insn_reloc
+ && ((insn->insn_reloc->reloc_type
+ == BFD_RELOC_NIOS2_CALL26)
+ || (insn->insn_reloc->reloc_type
+ == BFD_RELOC_NIOS2_CALL26_NOAT)))
+ output_call (insn);
+ else if (saved_pinfo == NIOS2_INSN_MACRO_MOVIA)
+ output_movia (insn);
+ else
+ output_insn (insn);
+ if (ps_insn)
+ nios2_cleanup_pseudo_insn (insn, ps_insn);
+ }
}
else
/* Unrecognised instruction - error. */
arelent *
tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
{
- arelent *reloc = (arelent *) xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ arelent *reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
/* Called just before the assembler exits. */
void
-md_end ()
+md_end (void)
{
/* FIXME - not yet implemented */
}
/* Map 's' to SHF_NIOS2_GPREL. */
/* This is from the Alpha code tc-alpha.c. */
int
-nios2_elf_section_letter (int letter, char **ptr_msg)
+nios2_elf_section_letter (int letter, const char **ptr_msg)
{
if (letter == 's')
return SHF_NIOS2_GPREL;
return flags;
}
-/* Implement TC_PARSE_CONS_EXPRESSION to handle %tls_ldo(...) */
+/* Implement TC_PARSE_CONS_EXPRESSION to handle %tls_ldo(...) and
+ %gotoff(...). */
bfd_reloc_code_real_type
nios2_cons (expressionS *exp, int size)
{
- bfd_reloc_code_real_type nios2_tls_ldo_reloc = BFD_RELOC_NONE;
+ bfd_reloc_code_real_type explicit_reloc = BFD_RELOC_NONE;
+ const char *reloc_name = NULL;
SKIP_WHITESPACE ();
if (input_line_pointer[0] == '%')
{
if (strprefix (input_line_pointer + 1, "tls_ldo"))
{
+ reloc_name = "%tls_ldo";
if (size != 4)
as_bad (_("Illegal operands: %%tls_ldo in %d-byte data field"),
size);
else
{
input_line_pointer += 8;
- nios2_tls_ldo_reloc = BFD_RELOC_NIOS2_TLS_DTPREL;
+ explicit_reloc = BFD_RELOC_NIOS2_TLS_DTPREL;
+ }
+ }
+ else if (strprefix (input_line_pointer + 1, "gotoff"))
+ {
+ reloc_name = "%gotoff";
+ if (size != 4)
+ as_bad (_("Illegal operands: %%gotoff in %d-byte data field"),
+ size);
+ else
+ {
+ input_line_pointer += 7;
+ explicit_reloc = BFD_RELOC_NIOS2_GOTOFF;
}
}
- if (nios2_tls_ldo_reloc != BFD_RELOC_NONE)
+
+ if (explicit_reloc != BFD_RELOC_NONE)
{
SKIP_WHITESPACE ();
if (input_line_pointer[0] != '(')
- as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()"));
+ as_bad (_("Illegal operands: %s requires arguments in ()"),
+ reloc_name);
else
{
int c;
}
if (c != ')')
- as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()"));
+ as_bad (_("Illegal operands: %s requires arguments in ()"),
+ reloc_name);
else
{
*end = '\0';
expression (exp);
*end = c;
if (input_line_pointer != end)
- as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()"));
+ as_bad (_("Illegal operands: %s requires arguments in ()"),
+ reloc_name);
else
{
input_line_pointer++;
SKIP_WHITESPACE ();
c = *input_line_pointer;
if (! is_end_of_line[c] && c != ',')
- as_bad (_("Illegal operands: garbage after %%tls_ldo()"));
+ as_bad (_("Illegal operands: garbage after %s()"),
+ reloc_name);
}
}
}
}
}
- if (nios2_tls_ldo_reloc == BFD_RELOC_NONE)
+ if (explicit_reloc == BFD_RELOC_NONE)
expression (exp);
- return nios2_tls_ldo_reloc;
+ return explicit_reloc;
}
/* Implement HANDLE_ALIGN. */