#include <setjmp.h>
#include "ansidecl.h"
#include "libiberty.h"
#include "bfd.h"
#include "symcat.h"
#include "cgen-desc.h"
#include "as.h"
#include "subsegs.h"
#include "cgen.h"
#include "dwarf2dbg.h"
static void queue_fixup (int, int, expressionS *);
CGEN_CPU_DESC gas_cgen_cpu_desc;
void
cgen_asm_record_register (name, number)
char *name;
int number;
{
symbol_table_insert (symbol_create (name, reg_section,
number, &zero_address_frag));
}
struct fixup
{
int opindex;
int opinfo;
expressionS exp;
};
static struct fixup fixups[GAS_CGEN_MAX_FIXUPS];
static int num_fixups;
void
gas_cgen_init_parse ()
{
num_fixups = 0;
}
static void
queue_fixup (opindex, opinfo, expP)
int opindex;
int opinfo;
expressionS * expP;
{
if (num_fixups >= GAS_CGEN_MAX_FIXUPS)
as_fatal (_("too many fixups"));
fixups[num_fixups].exp = *expP;
fixups[num_fixups].opindex = opindex;
fixups[num_fixups].opinfo = opinfo;
++ num_fixups;
}
struct saved_fixups
{
struct fixup fixup_chain[GAS_CGEN_MAX_FIXUPS];
int num_fixups_in_chain;
};
static struct saved_fixups stored_fixups[MAX_SAVED_FIXUP_CHAINS];
void
gas_cgen_initialize_saved_fixups_array ()
{
int i = 0;
while (i < MAX_SAVED_FIXUP_CHAINS)
stored_fixups[i++].num_fixups_in_chain = 0;
}
void
gas_cgen_save_fixups (i)
int i;
{
if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
{
as_fatal ("index into stored_fixups[] out of bounds");
return;
}
stored_fixups[i].num_fixups_in_chain = num_fixups;
memcpy (stored_fixups[i].fixup_chain, fixups,
sizeof (fixups[0]) * num_fixups);
num_fixups = 0;
}
void
gas_cgen_restore_fixups (i)
int i;
{
if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
{
as_fatal ("index into stored_fixups[] out of bounds");
return;
}
num_fixups = stored_fixups[i].num_fixups_in_chain;
memcpy (fixups, stored_fixups[i].fixup_chain,
(sizeof (stored_fixups[i].fixup_chain[0])) * num_fixups);
stored_fixups[i].num_fixups_in_chain = 0;
}
void
gas_cgen_swap_fixups (i)
int i;
{
if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS)
{
as_fatal ("index into stored_fixups[] out of bounds");
return;
}
if (num_fixups == 0)
gas_cgen_restore_fixups (i);
else if (stored_fixups[i].num_fixups_in_chain == 0)
gas_cgen_save_fixups (i);
else
{
int tmp;
struct fixup tmp_fixup;
tmp = stored_fixups[i].num_fixups_in_chain;
stored_fixups[i].num_fixups_in_chain = num_fixups;
num_fixups = tmp;
for (tmp = GAS_CGEN_MAX_FIXUPS; tmp--;)
{
tmp_fixup = stored_fixups[i].fixup_chain [tmp];
stored_fixups[i].fixup_chain[tmp] = fixups [tmp];
fixups [tmp] = tmp_fixup;
}
}
}
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;
{
fixS *fixP;
fixP = fix_new (frag, where, length / 8, symbol, offset,
CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR),
(bfd_reloc_code_real_type)
((int) BFD_RELOC_UNUSED
+ (int) operand->type));
fixP->fx_cgen.insn = insn;
fixP->fx_cgen.opinfo = opinfo;
return fixP;
}
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;
{
fixS *fixP;
fixP = fix_new_exp (frag, where, length / 8, exp,
CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR),
(bfd_reloc_code_real_type)
((int) BFD_RELOC_UNUSED
+ (int) operand->type));
fixP->fx_cgen.insn = insn;
fixP->fx_cgen.opinfo = opinfo;
return fixP;
}
static jmp_buf expr_jmp_buf;
static int expr_jmp_buf_p;
const char *
gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP)
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__
char * volatile hold;
enum cgen_parse_operand_result * volatile resultP_1;
#else
static char *hold;
static enum cgen_parse_operand_result *resultP_1;
#endif
const char *errmsg;
expressionS exp;
if (want == CGEN_PARSE_OPERAND_INIT)
{
gas_cgen_init_parse ();
return NULL;
}
resultP_1 = resultP;
hold = input_line_pointer;
input_line_pointer = (char *) *strP;
if (setjmp (expr_jmp_buf) != 0)
{
expr_jmp_buf_p = 0;
input_line_pointer = (char *) hold;
*resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR;
return _("illegal operand");
}
expr_jmp_buf_p = 1;
expression (&exp);
expr_jmp_buf_p = 0;
errmsg = NULL;
*strP = input_line_pointer;
input_line_pointer = hold;
#ifdef TC_CGEN_PARSE_FIX_EXP
opinfo = TC_CGEN_PARSE_FIX_EXP (opinfo, & exp);
#endif
switch (exp.X_op)
{
case O_illegal:
errmsg = _("illegal operand");
*resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
break;
case O_absent:
errmsg = _("missing operand");
*resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
break;
case O_constant:
*valueP = exp.X_add_number;
*resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER;
break;
case O_register:
*valueP = exp.X_add_number;
*resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER;
break;
default:
queue_fixup (opindex, opinfo, &exp);
*valueP = 0;
*resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED;
break;
}
return errmsg;
}
void
gas_cgen_md_operand (expressionP)
expressionS *expressionP ATTRIBUTE_UNUSED;
{
if (expr_jmp_buf_p)
longjmp (expr_jmp_buf, 1);
}
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;
{
int i;
int relax_operand;
char *f;
unsigned int byte_len = length / 8;
if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
abort ();
relax_operand = -1;
if (relax_p && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXABLE))
{
for (i = 0; i < num_fixups; ++i)
{
if (CGEN_OPERAND_ATTR_VALUE (cgen_operand_lookup_by_num (gas_cgen_cpu_desc, fixups[i].opindex),
CGEN_OPERAND_RELAX))
{
relax_operand = i;
break;
}
}
}
if (relax_operand != -1)
{
int max_len;
fragS *old_frag;
expressionS *exp;
symbolS *sym;
offsetT off;
#ifdef TC_CGEN_MAX_RELAX
max_len = TC_CGEN_MAX_RELAX (insn, byte_len);
#else
max_len = CGEN_MAX_INSN_SIZE;
#endif
frag_grow (max_len);
f = frag_more (byte_len);
old_frag = frag_now;
exp = &fixups[relax_operand].exp;
sym = exp->X_add_symbol;
off = exp->X_add_number;
if (exp->X_op != O_constant && exp->X_op != O_symbol)
{
sym = make_expr_symbol (exp);
off = 0;
}
frag_var (rs_machine_dependent,
max_len - byte_len ,
0 ,
1 ,
sym,
off,
f);
old_frag->fr_cgen.insn = insn;
old_frag->fr_cgen.opindex = fixups[relax_operand].opindex;
old_frag->fr_cgen.opinfo = fixups[relax_operand].opinfo;
if (result)
result->frag = old_frag;
}
else
{
f = frag_more (byte_len);
if (result)
result->frag = frag_now;
}
#if CGEN_INT_INSN_P
cgen_put_insn_value (gas_cgen_cpu_desc, f, length, *buf);
#else
memcpy (f, buf, byte_len);
#endif
dwarf2_emit_insn (byte_len);
for (i = 0; i < num_fixups; ++i)
{
fixS *fixP;
const CGEN_OPERAND *operand =
cgen_operand_lookup_by_num (gas_cgen_cpu_desc, fixups[i].opindex);
if (relax_p
&& CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXABLE)
&& CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_RELAX))
continue;
#ifndef md_cgen_record_fixup_exp
#define md_cgen_record_fixup_exp gas_cgen_record_fixup_exp
#endif
fixP = md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal,
insn, length, operand,
fixups[i].opinfo,
&fixups[i].exp);
if (result)
result->fixups[i] = fixP;
}
if (result)
{
result->num_fixups = num_fixups;
result->addr = f;
}
}
void
gas_cgen_md_apply_fix3 (fixP, valP, seg)
fixS * fixP;
valueT * valP;
segT seg ATTRIBUTE_UNUSED;
{
char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
valueT value = * valP;
CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
if (fixP->fx_addsy == (symbolS *) NULL)
fixP->fx_done = 1;
if (fixP->fx_subsy != (symbolS *) NULL)
as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
{
int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
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;
if (fixP->fx_done
|| fixP->fx_pcrel)
{
CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn));
CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value);
#if CGEN_INT_INSN_P
{
CGEN_INSN_INT insn_value =
cgen_get_insn_value (cd, where, CGEN_INSN_BITSIZE (insn));
errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
&insn_value, (bfd_vma) 0);
cgen_put_insn_value (cd, where, CGEN_INSN_BITSIZE (insn),
insn_value);
}
#else
errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields, where,
(bfd_vma) 0);
#endif
if (errmsg)
as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg);
}
if (fixP->fx_done)
return;
reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
if (reloc_type != BFD_RELOC_NONE)
fixP->fx_r_type = reloc_type;
else
{
as_bad_where (fixP->fx_file, fixP->fx_line,
_("unresolved expression that must be resolved"));
fixP->fx_done = 1;
return;
}
}
else if (fixP->fx_done)
{
switch (fixP->fx_r_type)
{
case BFD_RELOC_8:
md_number_to_chars (where, value, 1);
break;
case BFD_RELOC_16:
md_number_to_chars (where, value, 2);
break;
case BFD_RELOC_32:
md_number_to_chars (where, value, 4);
break;
case BFD_RELOC_64:
md_number_to_chars (where, value, 8);
break;
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
_("internal error: can't install fix for reloc type %d (`%s')"),
fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
break;
}
}
fixP->fx_addnumber = value;
}
arelent *
gas_cgen_tc_gen_reloc (section, fixP)
asection * section ATTRIBUTE_UNUSED;
fixS * fixP;
{
arelent *reloc;
reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
if (reloc->howto == (reloc_howto_type *) NULL)
{
as_bad_where (fixP->fx_file, fixP->fx_line,
_("relocation is not supported"));
return NULL;
}
assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
reloc->addend = fixP->fx_offset;
else
reloc->addend = fixP->fx_addnumber;
reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
return reloc;
}
void
gas_cgen_begin ()
{
if (flag_signed_overflow_ok)
cgen_set_signed_overflow_ok (gas_cgen_cpu_desc);
else
cgen_clear_signed_overflow_ok (gas_cgen_cpu_desc);
}