/* GAS interface for targets using CGEN: Cpu tools GENerator.
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006, 2007, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1996-2020 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
along with GAS; see the file COPYING. If not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
-#include <setjmp.h>
#include "as.h"
+#include <setjmp.h>
#include "symcat.h"
#include "cgen-desc.h"
#include "subsegs.h"
#include "dwarf2dbg.h"
#include "symbols.h"
-#include "struc-symbol.h"
#ifdef OBJ_COMPLEX_RELC
static expressionS * make_right_shifted_expr
const unsigned long, const unsigned long, const unsigned long, \
const unsigned long);
-static char * weak_operand_overflow_check
+static const char * weak_operand_overflow_check
(const expressionS *, const CGEN_OPERAND *);
static void queue_fixup_recursively
??? Not currently used. */
void
-cgen_asm_record_register (name, number)
- char *name;
- int number;
+cgen_asm_record_register (char *name, int number)
{
/* Use symbol_create here instead of symbol_new so we don't try to
output registers into the object file's symbol table. */
symbol_table_insert (symbol_create (name, reg_section,
- number, &zero_address_frag));
+ &zero_address_frag, number));
}
/* We need to keep a list of fixups. We can't simply generate them as
??? May wish to make this static and delete calls in md_assemble. */
void
-gas_cgen_init_parse ()
+gas_cgen_init_parse (void)
{
num_fixups = 0;
}
/* Queue a fixup. */
static void
-queue_fixup (opindex, opinfo, expP)
- int opindex;
- int opinfo;
- expressionS * expP;
+queue_fixup (int opindex, int opinfo, expressionS *expP)
{
/* We need to generate a fixup for this expression. */
if (num_fixups >= GAS_CGEN_MAX_FIXUPS)
static struct saved_fixups stored_fixups[MAX_SAVED_FIXUP_CHAINS];
void
-gas_cgen_initialize_saved_fixups_array ()
+gas_cgen_initialize_saved_fixups_array (void)
{
int i = 0;
}
void
-gas_cgen_save_fixups (i)
- int i;
+gas_cgen_save_fixups (int i)
{
if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
{
}
void
-gas_cgen_restore_fixups (i)
- int i;
+gas_cgen_restore_fixups (int i)
{
if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
{
}
void
-gas_cgen_swap_fixups (i)
- int i;
+gas_cgen_swap_fixups (int i)
{
if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
{
operand type. We pick a BFD reloc type in md_apply_fix. */
fixS *
-gas_cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset)
- fragS * frag;
- int where;
- const CGEN_INSN * insn;
- int length;
- const CGEN_OPERAND * operand;
- int opinfo;
- symbolS * symbol;
- offsetT offset;
+gas_cgen_record_fixup (fragS *frag, int where, const CGEN_INSN *insn,
+ int length, const CGEN_OPERAND *operand, int opinfo,
+ symbolS *symbol, offsetT offset)
{
fixS *fixP;
operand type. We pick a BFD reloc type in md_apply_fix. */
fixS *
-gas_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
- fragS * frag;
- int where;
- const CGEN_INSN * insn;
- int length;
- const CGEN_OPERAND * operand;
- int opinfo;
- expressionS * exp;
+gas_cgen_record_fixup_exp (fragS *frag, int where, const CGEN_INSN *insn,
+ int length, const CGEN_OPERAND *operand, int opinfo,
+ expressionS *exp)
{
fixS *fixP;
The resulting value is stored in VALUEP. */
const char *
-gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP)
-
-#ifdef OBJ_COMPLEX_RELC
- CGEN_CPU_DESC cd;
-#else
- CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
-#endif
- enum cgen_parse_operand_type want;
- const char **strP;
- int opindex;
- int opinfo;
- enum cgen_parse_operand_result *resultP;
- bfd_vma *valueP;
+gas_cgen_parse_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
+ enum cgen_parse_operand_type want, const char **strP,
+ int opindex, int opinfo,
+ enum cgen_parse_operand_result *resultP,
+ bfd_vma *valueP)
{
#ifdef __STDC__
/* These are volatile to survive the setjmp. */
if (! errmsg)
{
+ asymbol *bsym;
+
/* Fragment the expression as necessary, and queue a reloc. */
memset (& dummy_fixup, 0, sizeof (fixS));
if (exp.X_op == O_symbol
&& reloc_type == BFD_RELOC_RELC
- && exp.X_add_symbol->sy_value.X_op == O_constant
- && (!exp.X_add_symbol->bsym
- || (exp.X_add_symbol->bsym->section != expr_section
- && exp.X_add_symbol->bsym->section != absolute_section
- && exp.X_add_symbol->bsym->section != undefined_section)))
+ && symbol_constant_p (exp.X_add_symbol)
+ && (!symbol_symbolS (exp.X_add_symbol)
+ || (bsym = symbol_get_bfdsym (exp.X_add_symbol)) == NULL
+ || (bsym->section != expr_section
+ && bsym->section != absolute_section
+ && bsym->section != undefined_section)))
{
/* Local labels will have been (eagerly) turned into constants
by now, due to the inappropriately deep insight of the
prematurely dives into the symbol evaluator, and in this
case it gets a bad answer, so we manually create the
expression symbol we want here. */
- stmp = symbol_create (FAKE_LABEL_NAME, expr_section, 0,
- & zero_address_frag);
+ stmp = symbol_create (FAKE_LABEL_NAME, expr_section,
+ &zero_address_frag, 0);
symbol_set_value_expression (stmp, & exp);
}
else
if (operand && (operand->hw_type == HW_H_SINT))
signed_p = 1;
- if (stmp->bsym && (stmp->bsym->section == expr_section))
+ if (symbol_symbolS (stmp)
+ && (bsym = symbol_get_bfdsym (stmp)) != NULL
+ && bsym->section == expr_section
+ && ! S_IS_LOCAL (stmp))
{
if (signed_p)
- stmp->bsym->flags |= BSF_SRELC;
+ bsym->flags |= BSF_SRELC;
else
- stmp->bsym->flags |= BSF_RELC;
+ bsym->flags |= BSF_RELC;
}
/* Now package it all up for the fixup emitter. */
??? This could be done differently by adding code to `expression'. */
void
-gas_cgen_md_operand (expressionP)
- expressionS *expressionP ATTRIBUTE_UNUSED;
+gas_cgen_md_operand (expressionS *expressionP ATTRIBUTE_UNUSED)
{
/* Don't longjmp if we're not called from within cgen_parse_operand(). */
if (expr_jmp_buf_p)
The "result" is stored in RESULT if non-NULL. */
void
-gas_cgen_finish_insn (insn, buf, length, relax_p, result)
- const CGEN_INSN *insn;
- CGEN_INSN_BYTES_PTR buf;
- unsigned int length;
- int relax_p;
- finished_insnS *result;
+gas_cgen_finish_insn (const CGEN_INSN *insn, CGEN_INSN_BYTES_PTR buf,
+ unsigned int length, int relax_p, finished_insnS *result)
{
int i;
int relax_operand;
/* If we're recording insns as numbers (rather than a string of bytes),
target byte order handling is deferred until now. */
#if CGEN_INT_INSN_P
- cgen_put_insn_value (gas_cgen_cpu_desc, (unsigned char *) f, length, *buf);
+ cgen_put_insn_value (gas_cgen_cpu_desc, (unsigned char *) f, length, *buf,
+ gas_cgen_cpu_desc->insn_endian);
#else
memcpy (f, buf, byte_len);
#endif
overflow, so signal it by returning an error string. Any other case is
ambiguous, so we assume it's OK and return NULL. */
-static char *
+static const char *
weak_operand_overflow_check (const expressionS * exp,
const CGEN_OPERAND * operand)
{
const unsigned long len = operand->length;
unsigned long mask;
- unsigned long opmask = (((1L << (len - 1)) - 1) << 1) | 1;
+ unsigned long opmask = len == 0 ? 0 : (1UL << (len - 1) << 1) - 1;
if (!exp)
return NULL;
mask = exp->X_add_number;
if (exp->X_add_symbol
- && exp->X_add_symbol->sy_value.X_op == O_constant)
- mask |= exp->X_add_symbol->sy_value.X_add_number;
+ && symbol_constant_p (exp->X_add_symbol))
+ mask |= *symbol_X_add_number (exp->X_add_symbol);
if (exp->X_op_symbol
- && exp->X_op_symbol->sy_value.X_op == O_constant)
- mask |= exp->X_op_symbol->sy_value.X_add_number;
+ && symbol_constant_p (exp->X_op_symbol))
+ mask |= *symbol_X_add_number (exp->X_op_symbol);
/* Want to know if mask covers more bits than opmask.
this is the same as asking if mask has any bits not in opmask,
{
symbolS * stmp = 0;
expressionS * new_exp;
+ asymbol *bsym;
stmp = expr_build_binary (O_right_shift,
make_expr_symbol (exp),
expr_build_uconstant (amount));
+ bsym = symbol_get_bfdsym (stmp);
if (signed_p)
- stmp->bsym->flags |= BSF_SRELC;
+ bsym->flags |= BSF_SRELC;
else
- stmp->bsym->flags |= BSF_RELC;
+ bsym->flags |= BSF_RELC;
/* Then wrap that in a "symbol expr" for good measure. */
- new_exp = xmalloc (sizeof (expressionS));
+ new_exp = XNEW (expressionS);
memset (new_exp, 0, sizeof (expressionS));
new_exp->X_op = O_symbol;
new_exp->X_op_symbol = 0;
should handle them all. */
void
-gas_cgen_md_apply_fix (fixP, valP, seg)
- fixS * fixP;
- valueT * valP;
- segT seg ATTRIBUTE_UNUSED;
+gas_cgen_md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
valueT value = * valP;
const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex);
const char *errmsg;
bfd_reloc_code_real_type reloc_type;
- CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
const CGEN_INSN *insn = fixP->fx_cgen.insn;
+#ifdef OBJ_COMPLEX_RELC
int start;
int length;
int signed_p = 0;
values will be signed relocs, but it's possible. */
if (operand && (operand->hw_type == HW_H_SINT))
signed_p = 1;
+#endif
/* If the reloc has been fully resolved finish the operand here. */
/* FIXME: This duplicates the capabilities of code in BFD. */
finish the job. Testing for pcrel is a temporary hack. */
|| fixP->fx_pcrel)
{
+ CGEN_FIELDS *fields = xmalloc (CGEN_CPU_SIZEOF_FIELDS (cd));
+
CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn));
CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value);
{
CGEN_INSN_INT insn_value =
cgen_get_insn_value (cd, (unsigned char *) where,
- CGEN_INSN_BITSIZE (insn));
+ CGEN_INSN_BITSIZE (insn),
+ cd->insn_endian);
/* ??? 0 is passed for `pc'. */
errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
&insn_value, (bfd_vma) 0);
cgen_put_insn_value (cd, (unsigned char *) where,
- CGEN_INSN_BITSIZE (insn), insn_value);
+ CGEN_INSN_BITSIZE (insn), insn_value,
+ cd->insn_endian);
}
#else
/* ??? 0 is passed for `pc'. */
#endif
if (errmsg)
as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg);
+
+ free (fields);
}
if (fixP->fx_done)
fixP->fx_addnumber = value;
}
+bfd_reloc_code_real_type
+gas_cgen_pcrel_r_type (bfd_reloc_code_real_type r)
+{
+ switch (r)
+ {
+ case BFD_RELOC_8: r = BFD_RELOC_8_PCREL; break;
+ case BFD_RELOC_16: r = BFD_RELOC_16_PCREL; break;
+ case BFD_RELOC_24: r = BFD_RELOC_24_PCREL; break;
+ case BFD_RELOC_32: r = BFD_RELOC_32_PCREL; break;
+ case BFD_RELOC_64: r = BFD_RELOC_64_PCREL; break;
+ default:
+ break;
+ }
+ return r;
+}
+
/* Translate internal representation of relocation info to BFD target format.
FIXME: To what extent can we get all relevant targets to use this? */
arelent *
-gas_cgen_tc_gen_reloc (section, fixP)
- asection * section ATTRIBUTE_UNUSED;
- fixS * fixP;
+gas_cgen_tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
{
+ bfd_reloc_code_real_type r_type = fixP->fx_r_type;
arelent *reloc;
- reloc = (arelent *) xmalloc (sizeof (arelent));
- reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+ reloc = XNEW (arelent);
+
+#ifdef GAS_CGEN_PCREL_R_TYPE
+ if (fixP->fx_pcrel)
+ r_type = GAS_CGEN_PCREL_R_TYPE (r_type);
+#endif
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, r_type);
+
if (reloc->howto == (reloc_howto_type *) NULL)
{
as_bad_where (fixP->fx_file, fixP->fx_line,
gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
/* Use fx_offset for these cases. */
Called after gas_cgen_cpu_desc has been created. */
void
-gas_cgen_begin ()
+gas_cgen_begin (void)
{
if (flag_signed_overflow_ok)
cgen_set_signed_overflow_ok (gas_cgen_cpu_desc);