/* Altera Nios II assembler.
- Copyright (C) 2012-2015 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.
do not generate warnings. */
bfd_boolean noat;
- /* .set nobreak -> nobreak = 1 allows assembly code to use ba,bt without
+ /* .set nobreak -> nobreak = 1 allows assembly code to use ba,bt without
warning.
.set break -> nobreak = 0, assembly code using ba,bt warns. */
bfd_boolean nobreak;
/* Constant bits masked into insn_code for self-check mode. */
unsigned long constant_bits;
-
+
/* Pointer to the relevant bit of the opcode table. */
const struct nios2_opcode *insn_nios2_opcode;
/* After parsing ptrs to the tokens in the instruction fill this array
} nios2_ps_insn_infoS;
/* Opcode hash table. */
-static struct hash_control *nios2_opcode_hash = NULL;
+static htab_t nios2_opcode_hash = NULL;
#define nios2_opcode_lookup(NAME) \
- ((struct nios2_opcode *) hash_find (nios2_opcode_hash, (NAME)))
+ ((struct nios2_opcode *) str_hash_find (nios2_opcode_hash, (NAME)))
/* Register hash table. */
-static struct hash_control *nios2_reg_hash = NULL;
+static htab_t nios2_reg_hash = NULL;
#define nios2_reg_lookup(NAME) \
- ((struct nios2_reg *) hash_find (nios2_reg_hash, (NAME)))
+ ((struct nios2_reg *) str_hash_find (nios2_reg_hash, (NAME)))
/* Pseudo-op hash table. */
-static struct hash_control *nios2_ps_hash = NULL;
+static htab_t nios2_ps_hash = NULL;
#define nios2_ps_lookup(NAME) \
- ((nios2_ps_insn_infoS *) hash_find (nios2_ps_hash, (NAME)))
+ ((nios2_ps_insn_infoS *) str_hash_find (nios2_ps_hash, (NAME)))
/* The known current alignment of the current section. */
static int nios2_current_align;
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;
static void
s_nios2_set (int equiv)
{
- char *directive = input_line_pointer;
- char delim = get_symbol_end ();
+ char *save = input_line_pointer;
+ char *directive;
+ char delim = get_symbol_name (&directive);
char *endline = input_line_pointer;
- *endline = delim;
+
+ (void) restore_line_pointer (delim);
/* We only want to handle ".set XXX" if the
user has tried ".set XXX, YYY" they are not
trying a directive. This prevents
us from polluting the name space. */
SKIP_WHITESPACE ();
- if (is_end_of_line[(unsigned char) *input_line_pointer])
+ if (is_end_of_line[(unsigned char) *input_line_pointer])
{
bfd_boolean done = TRUE;
*endline = 0;
-
+
if (!strcmp (directive, "noat"))
nios2_as_options.noat = TRUE;
else if (!strcmp (directive, "at"))
nios2_as_options.relax = relax_all;
else
done = FALSE;
-
+
if (done)
{
*endline = delim;
}
/* If we fall through to here, either we have ".set XXX, YYY"
- or we have ".set XXX" where XXX is unknown or we have
+ or we have ".set XXX" where XXX is unknown or we have
a syntax error. */
- input_line_pointer = directive;
- *endline = delim;
+ input_line_pointer = save;
s_set (equiv);
}
Nios II PC-relative branch instructions only support 16-bit offsets.
And, there's no good way to add a 32-bit constant to the PC without
using two registers.
-
+
To deal with this, for the pc-relative relaxation mode we convert
br label
into a series of 16-bit adds, like:
16-bit CDX branch instructions are relaxed first into equivalent
32-bit branches and then the above transformations are applied
- if necessary.
+ if necessary.
*/
#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)
md_number_to_chars (buffer, op, 4);
fragp->fr_fix += 4;
buffer += 4;
-
+
/* We need to know whether the offset is positive or negative. */
target += S_GET_VALUE (symbolp);
offset = target - fragp->fr_address - fragp->fr_fix;
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
= ((fixP->fx_frag->fr_address + fixP->fx_where) & 0xf0000000);
range_max = range_min + 0x0fffffff;
address = fixup | range_min;
-
+
as_bad_where (fixP->fx_file, fixP->fx_line,
_("call target address 0x%08x out of range 0x%08x to 0x%08x"),
address, range_min, range_max);
if (fixP->fx_r_type == BFD_RELOC_64)
{
/* We may reach here due to .8byte directives, but we never output
- BFD_RELOC_64; it must be resolved. */
+ BFD_RELOC_64; it must be resolved. */
if (fixP->fx_addsy != NULL)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("cannot create 64-bit relocation"));
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"));
/* The various nios2_assemble_* functions call this
function to generate an expression from a string representing an expression.
It then tries to evaluate the expression, and if it can, returns its value.
- If not, it creates a new nios2_insn_relocS and stores the expression and
+ If not, it creates a new nios2_insn_relocS and stores the expression and
reloc_type for future use. */
static unsigned long
nios2_assemble_expression (const char *exprstr,
{
reloc_type = nios2_special_reloc[i].reloc_type;
exprstr += strlen (nios2_special_reloc[i].string) + 1;
-
+
/* %lo and %hiadj have different meanings for PC-relative
expressions. */
if (pcrel)
if (reloc_type == BFD_RELOC_NIOS2_HIADJ16)
reloc_type = BFD_RELOC_NIOS2_PCREL_HA;
}
-
+
break;
}
/* Control register index. */
-static void
+static void
nios2_assemble_arg_c (const char *token, nios2_insn_infoS *insn)
{
struct nios2_reg *reg = nios2_parse_reg (token, REG_CONTROL);
}
/* Destination register. */
-static void
+static void
nios2_assemble_arg_d (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* Source register 1. */
-static void
+static void
nios2_assemble_arg_s (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* Source register 2. */
-static void
+static void
nios2_assemble_arg_t (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* Destination register w/3-bit encoding. */
-static void
+static void
nios2_assemble_arg_D (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
int reg = nios2_assemble_reg3 (token);
-
+
switch (op->format)
{
case iw_T1I7_type:
}
/* Source register w/3-bit encoding. */
-static void
+static void
nios2_assemble_arg_S (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
int reg = nios2_assemble_reg3 (token);
-
+
switch (op->format)
{
case iw_T1I7_type:
}
/* Source register 2 w/3-bit encoding. */
-static void
+static void
nios2_assemble_arg_T (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
int reg = nios2_assemble_reg3 (token);
-
+
switch (op->format)
{
case iw_T2I4_type:
}
/* 16-bit signed immediate. */
-static void
+static void
nios2_assemble_arg_i (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 12-bit signed immediate. */
-static void
+static void
nios2_assemble_arg_I (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 16-bit unsigned immediate. */
-static void
+static void
nios2_assemble_arg_u (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 7-bit unsigned immediate with 2-bit shift. */
-static void
+static void
nios2_assemble_arg_U (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 5-bit unsigned immediate with 2-bit shift. */
-static void
+static void
nios2_assemble_arg_V (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 4-bit unsigned immediate with 2-bit shift. */
-static void
+static void
nios2_assemble_arg_W (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
insn->constant_bits |= SET_IW_T2I4_IMM4 (val >> 2);
break;
case iw_L5I4X1_type:
- /* This argument is optional for push.n/pop.n, and defaults to
+ /* This argument is optional for push.n/pop.n, and defaults to
zero if unspecified. */
if (token == NULL)
return;
}
/* 4-bit unsigned immediate with 1-bit shift. */
-static void
+static void
nios2_assemble_arg_X (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 4-bit unsigned immediate without shift. */
-static void
+static void
nios2_assemble_arg_Y (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
/* 16-bit signed immediate address offset. */
-static void
+static void
nios2_assemble_arg_o (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 10-bit signed address offset with 1-bit shift. */
-static void
+static void
nios2_assemble_arg_O (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 7-bit signed address offset with 1-bit shift. */
-static void
+static void
nios2_assemble_arg_P (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 5-bit unsigned immediate. */
-static void
+static void
nios2_assemble_arg_j (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* Second 5-bit unsigned immediate field. */
-static void
+static void
nios2_assemble_arg_k (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 8-bit unsigned immediate. */
-static void
+static void
nios2_assemble_arg_l (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 26-bit unsigned immediate. */
-static void
+static void
nios2_assemble_arg_m (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 6-bit unsigned immediate with no shifting. */
-static void
+static void
nios2_assemble_arg_M (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* 6-bit unsigned immediate with 2-bit shift. */
-static void
+static void
nios2_assemble_arg_N (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
/* Encoded enumeration for addi.n/subi.n. */
-static void
+static void
nios2_assemble_arg_e (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* Encoded enumeration for slli.n/srli.n. */
-static void
+static void
nios2_assemble_arg_f (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* Encoded enumeration for andi.n. */
-static void
+static void
nios2_assemble_arg_g (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* Encoded enumeration for movi.n. */
-static void
+static void
nios2_assemble_arg_h (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
}
/* Encoded REGMASK for ldwm/stwm or push.n/pop.n. */
-static void
+static void
nios2_assemble_arg_R (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
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);
insn->insn_code |= SET_IW_L5I4X1_CS (1);
}
break;
-
+
default:
bad_opcode (op);
}
}
/* Base register for ldwm/stwm. */
-static void
+static void
nios2_assemble_arg_B (const char *token, nios2_insn_infoS *insn)
{
const struct nios2_opcode *op = insn->insn_nios2_opcode;
switch (op->format)
{
case iw_F1X4L17_type:
- /* For ldwm, check to see if the base register is already inside the
+ /* For ldwm, check to see if the base register is already inside the
register list. */
if (op->match == MATCH_R2_LDWM
&& (nios2_reglist_mask & (1 << reg->index)))
case 'c':
nios2_assemble_arg_c (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'd':
nios2_assemble_arg_d (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 's':
nios2_assemble_arg_s (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 't':
nios2_assemble_arg_t (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'D':
nios2_assemble_arg_D (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'S':
nios2_assemble_arg_S (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'T':
nios2_assemble_arg_T (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'i':
nios2_assemble_arg_i (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'I':
nios2_assemble_arg_I (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'u':
nios2_assemble_arg_u (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'U':
nios2_assemble_arg_U (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'V':
nios2_assemble_arg_V (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'W':
nios2_assemble_arg_W (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'X':
nios2_assemble_arg_X (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'Y':
nios2_assemble_arg_Y (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'o':
nios2_assemble_arg_o (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'O':
nios2_assemble_arg_O (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'P':
nios2_assemble_arg_P (insn->insn_tokens[tokidx++], insn);
break;
case 'j':
nios2_assemble_arg_j (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'k':
nios2_assemble_arg_k (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'l':
nios2_assemble_arg_l (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'm':
nios2_assemble_arg_m (insn->insn_tokens[tokidx++], insn);
break;
case 'e':
nios2_assemble_arg_e (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'f':
nios2_assemble_arg_f (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'g':
nios2_assemble_arg_g (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'h':
nios2_assemble_arg_h (insn->insn_tokens[tokidx++], insn);
break;
-
+
case 'R':
nios2_assemble_arg_R (insn->insn_tokens[tokidx++], insn);
break;
break;
}
- /* Perform argument checking. */
+ /* Perform argument checking. */
nios2_check_assembly (insn->insn_code | insn->constant_bits,
insn->insn_tokens[tokidx]);
}
nios2_consume_arg (char *argstr, const char *parsestr)
{
char *temp;
-
+
switch (*parsestr)
{
case 'c':
case 'h':
case 'M':
case 'N':
-
+
/* We can't have %hi, %lo or %hiadj here. */
if (*argstr == '%')
as_bad (_("badly formed expression near %s"), argstr);
p = argstr;
i = 0;
bfd_boolean terminate = FALSE;
-
+
/* This rest of this function is it too fragile and it mostly works,
therefore special case this one. */
if (*parsestr == 0 && argstr != 0)
parsed_args[0] = NULL;
return;
}
-
+
while (p != NULL && !terminate && i < NIOS2_MAX_INSN_TOKENS)
{
parsed_args[i] = nios2_consume_arg (p, parsestr);
{
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
parsed_args[i + 1] = NULL;
}
-/* This function inserts the string insert num times in the array
+/* This function inserts the string insert num times in the array
parsed_args, starting at the index start. */
static void
nios2_insert_arg (char **parsed_args, const char *insert, int num,
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,
output_insn (nios2_insn_infoS *insn)
{
char *f;
- nios2_insn_relocS *reloc;
+ nios2_insn_relocS *reloc;
f = frag_more (insn->insn_nios2_opcode->size);
/* This allocates enough space for the instruction
and puts it in the current frag. */
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)
{
md_begin (void)
{
int i;
- const char *inserted;
switch (nios2_architecture)
{
break;
}
- /* Create and fill a hashtable for the Nios II opcodes, registers and
+ /* Create and fill a hashtable for the Nios II opcodes, registers and
arguments. */
- nios2_opcode_hash = hash_new ();
- nios2_reg_hash = hash_new ();
- nios2_ps_hash = hash_new ();
+ nios2_opcode_hash = str_htab_create ();
+ nios2_reg_hash = str_htab_create ();
+ nios2_ps_hash = str_htab_create ();
for (i = 0; i < nios2_num_opcodes; ++i)
- {
- inserted
- = hash_insert (nios2_opcode_hash, nios2_opcodes[i].name,
- (PTR) & nios2_opcodes[i]);
- if (inserted != NULL)
- {
- fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
- nios2_opcodes[i].name, inserted);
- /* Probably a memory allocation problem? Give up now. */
- as_fatal (_("Broken assembler. No assembly attempted."));
- }
- }
+ str_hash_insert (nios2_opcode_hash, nios2_opcodes[i].name,
+ (PTR) & nios2_opcodes[i]);
for (i = 0; i < nios2_num_regs; ++i)
- {
- inserted
- = hash_insert (nios2_reg_hash, nios2_regs[i].name,
- (PTR) & nios2_regs[i]);
- if (inserted != NULL)
- {
- fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
- nios2_regs[i].name, inserted);
- /* Probably a memory allocation problem? Give up now. */
- as_fatal (_("Broken assembler. No assembly attempted."));
- }
-
- }
+ str_hash_insert (nios2_reg_hash, nios2_regs[i].name,
+ (PTR) & nios2_regs[i]);
for (i = 0; i < nios2_num_ps_insn_info_structs; ++i)
- {
- inserted
- = hash_insert (nios2_ps_hash, nios2_ps_insn_info_structs[i].pseudo_insn,
- (PTR) & nios2_ps_insn_info_structs[i]);
- if (inserted != NULL)
- {
- fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
- nios2_ps_insn_info_structs[i].pseudo_insn, inserted);
- /* Probably a memory allocation problem? Give up now. */
- as_fatal (_("Broken assembler. No assembly attempted."));
- }
- }
+ str_hash_insert (nios2_ps_hash, nios2_ps_insn_info_structs[i].pseudo_insn,
+ (PTR) & nios2_ps_insn_info_structs[i]);
/* Assembler option defaults. */
nios2_as_options.noat = FALSE;
void
md_assemble (char *op_str)
{
- char *argstr;
+ char *argstr;
char *op_strdup = NULL;
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)
nios2_parse_args (insn, argstr, insn->insn_nios2_opcode->args_test,
(char **) &insn->insn_tokens[1]);
- /* We need to preserve the MOVIA macro as this is clobbered by
+ /* We need to preserve the MOVIA macro as this is clobbered by
translate_pseudo_insn. */
if (insn->insn_nios2_opcode->pinfo == NIOS2_INSN_MACRO_MOVIA)
saved_pinfo = NIOS2_INSN_MACRO_MOVIA;
- /* If the instruction is an pseudo-instruction, we want to replace it
+ /* If the instruction is an pseudo-instruction, we want to replace it
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 */
}
as_bad ("GOT already in the symbol table");
GOT_symbol = symbol_new (name, undefined_section,
- (valueT) 0, &zero_address_frag);
+ &zero_address_frag, 0);
}
return GOT_symbol;
/* 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. */