#include <stdio.h>
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "symcat.h"
#include "opcodes/m32r-desc.h"
#include "opcodes/m32r-opc.h"
#include "cgen.h"
#include "elf/m32r.h"
typedef struct sym_link
{
struct sym_link *next;
symbolS *symbol;
} sym_linkS;
static sym_linkS *debug_sym_link = (sym_linkS *) 0;
typedef struct
{
const CGEN_INSN *insn;
const CGEN_INSN *orig_insn;
CGEN_FIELDS fields;
#if CGEN_INT_INSN_P
CGEN_INSN_INT buffer[1];
#define INSN_VALUE(buf) (*(buf))
#else
unsigned char buffer[CGEN_MAX_INSN_SIZE];
#define INSN_VALUE(buf) (buf)
#endif
char *addr;
fragS *frag;
int num_fixups;
fixS *fixups[GAS_CGEN_MAX_FIXUPS];
int indices[MAX_OPERAND_INSTANCES];
sym_linkS *debug_sym_link;
}
m32r_insn;
static m32r_insn prev_insn;
static int seen_relaxable_p = 0;
int pic_code;
static int m32r_relax;
static int warn_unmatched_high = 0;
static int enable_m32rx = 0;
static int enable_special = 0;
static int enable_special_m32r = 1;
static int enable_special_float = 0;
static int warn_explicit_parallel_conflicts = 1;
static int ignore_parallel_conflicts = 0;
static int use_parallel = 1;
static int optimize;
static int m32r_flags = 0;
static segT sbss_section;
static asection scom_section;
static asymbol scom_symbol;
const char comment_chars[] = ";";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = "!";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
struct m32r_hi_fixup
{
struct m32r_hi_fixup *next;
fixS *fixp;
segT seg;
};
static struct m32r_hi_fixup *m32r_hi_fixup_list;
struct {
enum bfd_architecture bfd_mach;
int mach_flags;
} mach_table[] =
{
{ bfd_mach_m32r, (1<<MACH_M32R) },
{ bfd_mach_m32rx, (1<<MACH_M32RX) },
{ bfd_mach_m32r2, (1<<MACH_M32R2) }
};
static void allow_m32rx (int);
static void
allow_m32rx (int on)
{
enable_m32rx = on;
if (stdoutput != NULL)
bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach_table[on].bfd_mach);
if (gas_cgen_cpu_desc != NULL)
gas_cgen_cpu_desc->machs = mach_table[on].mach_flags;
}
#define M32R_SHORTOPTS "O::K:"
const char *md_shortopts = M32R_SHORTOPTS;
struct option md_longopts[] =
{
#define OPTION_M32R (OPTION_MD_BASE)
#define OPTION_M32RX (OPTION_M32R + 1)
#define OPTION_M32R2 (OPTION_M32RX + 1)
#define OPTION_BIG (OPTION_M32R2 + 1)
#define OPTION_LITTLE (OPTION_BIG + 1)
#define OPTION_PARALLEL (OPTION_LITTLE + 1)
#define OPTION_NO_PARALLEL (OPTION_PARALLEL + 1)
#define OPTION_WARN_PARALLEL (OPTION_NO_PARALLEL + 1)
#define OPTION_NO_WARN_PARALLEL (OPTION_WARN_PARALLEL + 1)
#define OPTION_IGNORE_PARALLEL (OPTION_NO_WARN_PARALLEL + 1)
#define OPTION_NO_IGNORE_PARALLEL (OPTION_IGNORE_PARALLEL + 1)
#define OPTION_SPECIAL (OPTION_NO_IGNORE_PARALLEL + 1)
#define OPTION_SPECIAL_M32R (OPTION_SPECIAL + 1)
#define OPTION_NO_SPECIAL_M32R (OPTION_SPECIAL_M32R + 1)
#define OPTION_SPECIAL_FLOAT (OPTION_NO_SPECIAL_M32R + 1)
#define OPTION_WARN_UNMATCHED (OPTION_SPECIAL_FLOAT + 1)
#define OPTION_NO_WARN_UNMATCHED (OPTION_WARN_UNMATCHED + 1)
{"m32r", no_argument, NULL, OPTION_M32R},
{"m32rx", no_argument, NULL, OPTION_M32RX},
{"m32r2", no_argument, NULL, OPTION_M32R2},
{"big", no_argument, NULL, OPTION_BIG},
{"little", no_argument, NULL, OPTION_LITTLE},
{"EB", no_argument, NULL, OPTION_BIG},
{"EL", no_argument, NULL, OPTION_LITTLE},
{"parallel", no_argument, NULL, OPTION_PARALLEL},
{"no-parallel", no_argument, NULL, OPTION_NO_PARALLEL},
{"warn-explicit-parallel-conflicts", no_argument, NULL, OPTION_WARN_PARALLEL},
{"Wp", no_argument, NULL, OPTION_WARN_PARALLEL},
{"no-warn-explicit-parallel-conflicts", no_argument, NULL, OPTION_NO_WARN_PARALLEL},
{"Wnp", no_argument, NULL, OPTION_NO_WARN_PARALLEL},
{"ignore-parallel-conflicts", no_argument, NULL, OPTION_IGNORE_PARALLEL},
{"Ip", no_argument, NULL, OPTION_IGNORE_PARALLEL},
{"no-ignore-parallel-conflicts", no_argument, NULL, OPTION_NO_IGNORE_PARALLEL},
{"nIp", no_argument, NULL, OPTION_NO_IGNORE_PARALLEL},
{"hidden", no_argument, NULL, OPTION_SPECIAL},
{"bitinst", no_argument, NULL, OPTION_SPECIAL_M32R},
{"no-bitinst", no_argument, NULL, OPTION_NO_SPECIAL_M32R},
{"float", no_argument, NULL, OPTION_SPECIAL_FLOAT},
{"warn-unmatched-high", no_argument, NULL, OPTION_WARN_UNMATCHED},
{"Wuh", no_argument, NULL, OPTION_WARN_UNMATCHED},
{"no-warn-unmatched-high", no_argument, NULL, OPTION_NO_WARN_UNMATCHED},
{"Wnuh", no_argument, NULL, OPTION_NO_WARN_UNMATCHED},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
static void little (int);
static int parallel (void);
static void
little (int on)
{
target_big_endian = ! on;
}
static int
parallel (void)
{
if (! enable_m32rx)
return 0;
if (use_parallel == 1)
return 1;
return 0;
}
int
md_parse_option (c, arg)
int c;
char *arg ATTRIBUTE_UNUSED;
{
switch (c)
{
case 'O':
optimize = 1;
use_parallel = 1;
break;
case OPTION_M32R:
allow_m32rx (0);
break;
case OPTION_M32RX:
allow_m32rx (1);
break;
case OPTION_M32R2:
allow_m32rx (2);
enable_special = 1;
enable_special_m32r = 1;
break;
case OPTION_BIG:
target_big_endian = 1;
break;
case OPTION_LITTLE:
target_big_endian = 0;
break;
case OPTION_PARALLEL:
use_parallel = 1;
break;
case OPTION_NO_PARALLEL:
use_parallel = 0;
break;
case OPTION_WARN_PARALLEL:
warn_explicit_parallel_conflicts = 1;
break;
case OPTION_NO_WARN_PARALLEL:
warn_explicit_parallel_conflicts = 0;
break;
case OPTION_IGNORE_PARALLEL:
ignore_parallel_conflicts = 1;
break;
case OPTION_NO_IGNORE_PARALLEL:
ignore_parallel_conflicts = 0;
break;
case OPTION_SPECIAL:
if (enable_m32rx)
enable_special = 1;
else
{
as_bad (_("Unrecognised option: -hidden"));
return 0;
}
break;
case OPTION_SPECIAL_M32R:
enable_special_m32r = 1;
break;
case OPTION_NO_SPECIAL_M32R:
enable_special_m32r = 0;
break;
case OPTION_SPECIAL_FLOAT:
enable_special_float = 1;
break;
case OPTION_WARN_UNMATCHED:
warn_unmatched_high = 1;
break;
case OPTION_NO_WARN_UNMATCHED:
warn_unmatched_high = 0;
break;
case 'K':
if (strcmp (arg, "PIC") != 0)
as_warn (_("Unrecognized option following -K"));
else
pic_code = 1;
break;
default:
return 0;
}
return 1;
}
void
md_show_usage (stream)
FILE *stream;
{
fprintf (stream, _(" M32R specific command line options:\n"));
fprintf (stream, _("\
-m32r disable support for the m32rx instruction set\n"));
fprintf (stream, _("\
-m32rx support the extended m32rx instruction set\n"));
fprintf (stream, _("\
-m32r2 support the extended m32r2 instruction set\n"));
fprintf (stream, _("\
-EL,-little produce little endian code and data\n"));
fprintf (stream, _("\
-EB,-big produce big endian code and data\n"));
fprintf (stream, _("\
-parallel try to combine instructions in parallel\n"));
fprintf (stream, _("\
-no-parallel disable -parallel\n"));
fprintf (stream, _("\
-no-bitinst disallow the M32R2's extended bit-field instructions\n"));
fprintf (stream, _("\
-O try to optimize code. Implies -parallel\n"));
fprintf (stream, _("\
-warn-explicit-parallel-conflicts warn when parallel instructions\n"));
fprintf (stream, _("\
might violate contraints\n"));
fprintf (stream, _("\
-no-warn-explicit-parallel-conflicts do not warn when parallel\n"));
fprintf (stream, _("\
instructions might violate contraints\n"));
fprintf (stream, _("\
-Wp synonym for -warn-explicit-parallel-conflicts\n"));
fprintf (stream, _("\
-Wnp synonym for -no-warn-explicit-parallel-conflicts\n"));
fprintf (stream, _("\
-ignore-parallel-conflicts do not check parallel instructions\n"));
fprintf (stream, _("\
fo contraint violations\n"));
fprintf (stream, _("\
-no-ignore-parallel-conflicts check parallel instructions for\n"));
fprintf (stream, _("\
contraint violations\n"));
fprintf (stream, _("\
-Ip synonym for -ignore-parallel-conflicts\n"));
fprintf (stream, _("\
-nIp synonym for -no-ignore-parallel-conflicts\n"));
fprintf (stream, _("\
-warn-unmatched-high warn when an (s)high reloc has no matching low reloc\n"));
fprintf (stream, _("\
-no-warn-unmatched-high do not warn about missing low relocs\n"));
fprintf (stream, _("\
-Wuh synonym for -warn-unmatched-high\n"));
fprintf (stream, _("\
-Wnuh synonym for -no-warn-unmatched-high\n"));
fprintf (stream, _("\
-KPIC generate PIC\n"));
}
static void fill_insn PARAMS ((int));
static void m32r_scomm PARAMS ((int));
static void debug_sym PARAMS ((int));
static void expand_debug_syms PARAMS ((sym_linkS *, int));
static subsegT prev_subseg;
static segT prev_seg;
const pseudo_typeS md_pseudo_table[] =
{
{ "word", cons, 4 },
{ "fillinsn", fill_insn, 0 },
{ "scomm", m32r_scomm, 0 },
{ "debugsym", debug_sym, 0 },
{ "m32r", allow_m32rx, 0 },
{ "m32rx", allow_m32rx, 1 },
{ "m32r2", allow_m32rx, 2 },
{ "little", little, 1 },
{ "big", little, 0 },
{ NULL, NULL, 0 }
};
#define GOT_NAME "_GLOBAL_OFFSET_TABLE_"
symbolS * GOT_symbol;
static inline int
m32r_PIC_related_p (symbolS *sym)
{
expressionS *exp;
if (! sym)
return 0;
if (sym == GOT_symbol)
return 1;
exp = symbol_get_value_expression (sym);
return (exp->X_op == O_PIC_reloc
|| exp->X_md == BFD_RELOC_M32R_26_PLTREL
|| m32r_PIC_related_p (exp->X_add_symbol)
|| m32r_PIC_related_p (exp->X_op_symbol));
}
static inline int
m32r_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
{
expressionS *exp = main_exp;
if (exp->X_op == O_add && m32r_PIC_related_p (exp->X_op_symbol))
return 1;
if (exp->X_op == O_symbol && exp->X_add_symbol)
{
if (exp->X_add_symbol == GOT_symbol)
{
*r_type_p = BFD_RELOC_M32R_GOTPC24;
return 0;
}
}
else if (exp->X_op == O_add)
{
exp = symbol_get_value_expression (exp->X_add_symbol);
if (! exp)
return 0;
}
if (exp->X_op == O_PIC_reloc || exp->X_md != BFD_RELOC_UNUSED)
{
*r_type_p = exp->X_md;
if (exp == main_exp)
exp->X_op = O_symbol;
else
{
main_exp->X_add_symbol = exp->X_add_symbol;
main_exp->X_add_number += exp->X_add_number;
}
}
else
return (m32r_PIC_related_p (exp->X_add_symbol)
|| m32r_PIC_related_p (exp->X_op_symbol));
return 0;
}
#define NOP_INSN 0x7000
#define PAR_NOP_INSN 0xf000
void
m32r_handle_align (fragp)
fragS *fragp;
{
static const unsigned char nop_pattern[] = { 0xf0, 0x00 };
static const unsigned char multi_nop_pattern[] = { 0x70, 0x00, 0xf0, 0x00 };
int bytes, fix;
char *p;
if (fragp->fr_type != rs_align_code)
return;
bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
p = fragp->fr_literal + fragp->fr_fix;
fix = 0;
if (bytes & 1)
{
fix = 1;
*p++ = 0;
bytes--;
}
if (bytes & 2)
{
memcpy (p, nop_pattern, 2);
p += 2;
bytes -= 2;
fix += 2;
}
memcpy (p, multi_nop_pattern, 4);
fragp->fr_fix += fix;
fragp->fr_var = 4;
}
static void
fill_insn (ignore)
int ignore ATTRIBUTE_UNUSED;
{
frag_align_code (2, 0);
prev_insn.insn = NULL;
seen_relaxable_p = 0;
}
static void
debug_sym (ignore)
int ignore ATTRIBUTE_UNUSED;
{
register char *name;
register char delim;
register char *end_name;
register symbolS *symbolP;
register sym_linkS *link;
name = input_line_pointer;
delim = get_symbol_end ();
end_name = input_line_pointer;
if ((symbolP = symbol_find (name)) == NULL
&& (symbolP = md_undefined_symbol (name)) == NULL)
{
symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
}
symbol_table_insert (symbolP);
if (S_IS_DEFINED (symbolP) && (S_GET_SEGMENT (symbolP) != reg_section
|| S_IS_EXTERNAL (symbolP)
|| S_IS_WEAK (symbolP)))
as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
else
{
link = (sym_linkS *) xmalloc (sizeof (sym_linkS));
link->symbol = symbolP;
link->next = debug_sym_link;
debug_sym_link = link;
symbol_get_obj (symbolP)->local = 1;
}
*end_name = delim;
demand_empty_rest_of_line ();
}
static void
expand_debug_syms (syms, align)
sym_linkS *syms;
int align;
{
char *save_input_line = input_line_pointer;
sym_linkS *next_syms;
if (!syms)
return;
(void) frag_align_code (align, 0);
for (; syms != (sym_linkS *) 0; syms = next_syms)
{
symbolS *symbolP = syms->symbol;
next_syms = syms->next;
input_line_pointer = ".\n";
pseudo_set (symbolP);
free ((char *) syms);
}
input_line_pointer = save_input_line;
}
void
m32r_flush_pending_output()
{
if (debug_sym_link)
{
expand_debug_syms (debug_sym_link, 1);
debug_sym_link = (sym_linkS *) 0;
}
}
int
m32r_fill_insn (done)
int done;
{
if (prev_seg != NULL)
{
segT seg = now_seg;
subsegT subseg = now_subseg;
subseg_set (prev_seg, prev_subseg);
fill_insn (0);
subseg_set (seg, subseg);
}
if (done && debug_sym_link)
{
expand_debug_syms (debug_sym_link, 1);
debug_sym_link = (sym_linkS *) 0;
}
return 1;
}
const char *
m32r_target_format ()
{
#ifdef TE_LINUX
if (target_big_endian)
return "elf32-m32r-linux";
else
return "elf32-m32rle-linux";
#else
if (target_big_endian)
return "elf32-m32r";
else
return "elf32-m32rle";
#endif
}
void
md_begin ()
{
flagword applicable;
segT seg;
subsegT subseg;
gas_cgen_cpu_desc = m32r_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
CGEN_CPU_OPEN_ENDIAN,
(target_big_endian ?
CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE),
CGEN_CPU_OPEN_END);
m32r_cgen_init_asm (gas_cgen_cpu_desc);
m32r_cgen_init_opinst_table (gas_cgen_cpu_desc);
cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
seg = now_seg;
subseg = now_subseg;
sbss_section = subseg_new (".sbss", 0);
applicable = bfd_applicable_section_flags (stdoutput);
bfd_set_section_flags (stdoutput, sbss_section, applicable & SEC_ALLOC);
subseg_set (seg, subseg);
scom_section = bfd_com_section;
scom_section.name = ".scommon";
scom_section.output_section = &scom_section;
scom_section.symbol = &scom_symbol;
scom_section.symbol_ptr_ptr = &scom_section.symbol;
scom_symbol = *bfd_com_section.symbol;
scom_symbol.name = ".scommon";
scom_symbol.section = &scom_section;
allow_m32rx (enable_m32rx);
gas_cgen_initialize_saved_fixups_array ();
}
#define OPERAND_IS_COND_BIT(operand, indices, index) \
((operand)->hw_type == HW_H_COND \
|| ((operand)->hw_type == HW_H_PSW) \
|| ((operand)->hw_type == HW_H_CR \
&& (indices [index] == 0 || indices [index] == 1)))
static int first_writes_to_seconds_operands
PARAMS ((m32r_insn *, m32r_insn *, const int));
static int
first_writes_to_seconds_operands (a, b, check_outputs)
m32r_insn *a;
m32r_insn *b;
const int check_outputs;
{
const CGEN_OPINST *a_operands = CGEN_INSN_OPERANDS (a->insn);
const CGEN_OPINST *b_ops = CGEN_INSN_OPERANDS (b->insn);
int a_index;
if (ignore_parallel_conflicts)
return 0;
if (a_operands == NULL || b_ops == NULL)
return 0;
for (a_index = 0;
a_operands->type != CGEN_OPINST_END;
a_index ++, a_operands ++)
{
if (a_operands->type == CGEN_OPINST_OUTPUT)
{
int b_index;
const CGEN_OPINST *b_operands = b_ops;
if (OPERAND_IS_COND_BIT (a_operands, a->indices, a_index))
{
for (b_index = 0;
b_operands->type != CGEN_OPINST_END;
b_index++, b_operands++)
{
if ((b_operands->type
== (check_outputs
? CGEN_OPINST_OUTPUT
: CGEN_OPINST_INPUT))
&& OPERAND_IS_COND_BIT (b_operands, b->indices, b_index))
return 1;
}
}
else
{
for (b_index = 0;
b_operands->type != CGEN_OPINST_END;
b_index++, b_operands++)
{
if ((b_operands->type
== (check_outputs
? CGEN_OPINST_OUTPUT
: CGEN_OPINST_INPUT))
&& (b_operands->hw_type == a_operands->hw_type)
&& (a->indices[a_index] == b->indices[b_index]))
return 1;
}
}
}
}
return 0;
}
static int writes_to_pc PARAMS ((m32r_insn *));
static int
writes_to_pc (a)
m32r_insn *a;
{
if (CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_UNCOND_CTI)
|| CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_COND_CTI))
return 1;
return 0;
}
static const char *can_make_parallel PARAMS ((m32r_insn *, m32r_insn *));
static const char *
can_make_parallel (a, b)
m32r_insn *a;
m32r_insn *b;
{
PIPE_ATTR a_pipe;
PIPE_ATTR b_pipe;
if (CGEN_FIELDS_BITSIZE (&a->fields) != 16
|| CGEN_FIELDS_BITSIZE (&b->fields) != 16)
abort ();
if (first_writes_to_seconds_operands (a, b, TRUE))
return _("instructions write to the same destination register.");
a_pipe = CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_PIPE);
b_pipe = CGEN_INSN_ATTR_VALUE (b->insn, CGEN_INSN_PIPE);
if (a_pipe == PIPE_NONE
|| b_pipe == PIPE_NONE)
return _("Instructions do not use parallel execution pipelines.");
if (a_pipe == PIPE_S
|| b_pipe == PIPE_O
|| (b_pipe == PIPE_O_OS && (enable_m32rx != 2)))
return _("Instructions share the same execution pipeline");
return NULL;
}
static void make_parallel PARAMS ((CGEN_INSN_BYTES_PTR));
static void
make_parallel (buffer)
CGEN_INSN_BYTES_PTR buffer;
{
#if CGEN_INT_INSN_P
*buffer |= 0x8000;
#else
buffer[CGEN_CPU_ENDIAN (gas_cgen_cpu_desc) == CGEN_ENDIAN_BIG ? 0 : 1]
|= 0x80;
#endif
}
static void target_make_parallel PARAMS ((char *));
static void
target_make_parallel (buffer)
char *buffer;
{
buffer[CGEN_CPU_ENDIAN (gas_cgen_cpu_desc) == CGEN_ENDIAN_BIG ? 0 : 1]
|= 0x80;
}
static void assemble_two_insns PARAMS ((char *, char *, int));
static void
assemble_two_insns (str, str2, parallel_p)
char *str;
char *str2;
int parallel_p;
{
char *str3;
m32r_insn first;
m32r_insn second;
char *errmsg;
char save_str2 = *str2;
*str2 = 0;
fill_insn (0);
first.debug_sym_link = debug_sym_link;
debug_sym_link = (sym_linkS *) 0;
if (! (first.insn = m32r_cgen_assemble_insn
(gas_cgen_cpu_desc, str, & first.fields, first.buffer, & errmsg)))
{
as_bad (errmsg);
return;
}
if (CGEN_FIELDS_BITSIZE (&first.fields) != 16)
{
as_bad (_("not a 16 bit instruction '%s'"), str);
return;
}
#ifdef E_M32R2_ARCH
else if ((enable_m32rx == 1)
&& ((CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
& (1 << MACH_M32R2))
&& !((CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
& (1 << MACH_M32RX)))))
{
as_bad (_("instruction '%s' is for the M32R2 only"), str);
return;
}
else if ((! enable_special
&& CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL))
|| (! enable_special_m32r
&& CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL_M32R)))
#else
else if (! enable_special
&& CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL))
#endif
{
as_bad (_("unknown instruction '%s'"), str);
return;
}
else if (! enable_m32rx
&& (CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
== (1 << MACH_M32RX)))
{
as_bad (_("instruction '%s' is for the M32RX only"), str);
return;
}
if (parallel_p
&& CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_PIPE) == PIPE_NONE)
{
as_bad (_("instruction '%s' cannot be executed in parallel."), str);
return;
}
*str2 = save_str2;
str3 = str;
str = str2 + 2;
str2 = str3;
{
char *s2 = str;
while (ISSPACE (*s2++))
continue;
--s2;
while (ISALNUM (*s2))
{
*s2 = TOLOWER (*s2);
s2++;
}
}
gas_cgen_save_fixups (0);
first.orig_insn = first.insn;
{
CGEN_FIELDS tmp_fields;
first.insn = cgen_lookup_get_insn_operands
(gas_cgen_cpu_desc, NULL, INSN_VALUE (first.buffer), NULL, 16,
first.indices, &tmp_fields);
}
if (first.insn == NULL)
as_fatal (_("internal error: lookup/get operands failed"));
second.debug_sym_link = NULL;
if (! (second.insn = m32r_cgen_assemble_insn
(gas_cgen_cpu_desc, str, & second.fields, second.buffer, & errmsg)))
{
as_bad (errmsg);
return;
}
if (CGEN_FIELDS_BITSIZE (&second.fields) != 16)
{
as_bad (_("not a 16 bit instruction '%s'"), str);
return;
}
#ifdef E_M32R2_ARCH
else if ((enable_m32rx == 1)
&& ((CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
& (1 << MACH_M32R2))
&& !((CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH)
& (1 << MACH_M32RX)))))
{
as_bad (_("instruction '%s' is for the M32R2 only"), str);
return;
}
else if ((! enable_special
&& CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL))
|| (! enable_special_m32r
&& CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL_M32R)))
#else
else if (! enable_special
&& CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL))
#endif
{
as_bad (_("unknown instruction '%s'"), str);
return;
}
else if (! enable_m32rx
&& CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
{
as_bad (_("instruction '%s' is for the M32RX only"), str);
return;
}
if (parallel_p
&& CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_PIPE) == PIPE_NONE)
{
as_bad (_("instruction '%s' cannot be executed in parallel."), str);
return;
}
if (parallel_p && ! enable_m32rx)
{
if (CGEN_INSN_NUM (first.insn) != M32R_INSN_NOP
&& CGEN_INSN_NUM (second.insn) != M32R_INSN_NOP)
{
as_bad (_("'%s': only the NOP instruction can be issued in parallel on the m32r"), str2);
return;
}
}
second.orig_insn = second.insn;
{
CGEN_FIELDS tmp_fields;
second.insn = cgen_lookup_get_insn_operands
(gas_cgen_cpu_desc, NULL, INSN_VALUE (second.buffer), NULL, 16,
second.indices, &tmp_fields);
}
if (second.insn == NULL)
as_fatal (_("internal error: lookup/get operands failed"));
if (parallel_p && warn_explicit_parallel_conflicts)
{
if (first_writes_to_seconds_operands (&first, &second, FALSE))
as_warn (_("%s: output of 1st instruction is the same as an input to 2nd instruction - is this intentional ?"), str2);
if (first_writes_to_seconds_operands (&second, &first, FALSE))
as_warn (_("%s: output of 2nd instruction is the same as an input to 1st instruction - is this intentional ?"), str2);
}
if (!parallel_p
|| (errmsg = (char *) can_make_parallel (&first, &second)) == NULL)
{
gas_cgen_swap_fixups (0);
expand_debug_syms (first.debug_sym_link, 1);
gas_cgen_finish_insn (first.orig_insn, first.buffer,
CGEN_FIELDS_BITSIZE (&first.fields), 0, NULL);
if (parallel_p)
make_parallel (second.buffer);
gas_cgen_restore_fixups (0);
expand_debug_syms (second.debug_sym_link, 1);
gas_cgen_finish_insn (second.orig_insn, second.buffer,
CGEN_FIELDS_BITSIZE (&second.fields), 0, NULL);
}
else if (can_make_parallel (&second, &first) == NULL)
{
expand_debug_syms (second.debug_sym_link, 1);
gas_cgen_finish_insn (second.orig_insn, second.buffer,
CGEN_FIELDS_BITSIZE (&second.fields), 0, NULL);
make_parallel (first.buffer);
gas_cgen_restore_fixups (0);
expand_debug_syms (first.debug_sym_link, 1);
gas_cgen_finish_insn (first.orig_insn, first.buffer,
CGEN_FIELDS_BITSIZE (&first.fields), 0, NULL);
}
else
{
as_bad ("'%s': %s", str2, errmsg);
return;
}
if (CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL)
|| CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL))
m32r_flags |= E_M32R_HAS_HIDDEN_INST;
if (CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL_M32R)
|| CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL_M32R))
m32r_flags |= E_M32R_HAS_BIT_INST;
if (CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL_FLOAT)
|| CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL_FLOAT))
m32r_flags |= E_M32R_HAS_FLOAT_INST;
prev_seg = now_seg;
prev_subseg = now_subseg;
}
void
md_assemble (str)
char *str;
{
m32r_insn insn;
char *errmsg;
char *str2 = NULL;
gas_cgen_init_parse ();
if ((str2 = strstr (str, "||")) != NULL)
{
assemble_two_insns (str, str2, 1);
m32r_flags |= E_M32R_HAS_PARALLEL;
return;
}
if ((str2 = strstr (str, "->")) != NULL)
{
assemble_two_insns (str, str2, 0);
return;
}
insn.debug_sym_link = debug_sym_link;
debug_sym_link = (sym_linkS *) 0;
insn.insn = m32r_cgen_assemble_insn
(gas_cgen_cpu_desc, str, &insn.fields, insn.buffer, & errmsg);
if (!insn.insn)
{
as_bad (errmsg);
return;
}
#ifdef E_M32R2_ARCH
if ((enable_m32rx == 1)
&& ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MACH)
& (1 << MACH_M32R2))
&& !((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MACH)
& (1 << MACH_M32RX)))))
{
as_bad (_("instruction '%s' is for the M32R2 only"), str);
return;
}
else if ((! enable_special
&& CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SPECIAL))
|| (! enable_special_m32r
&& CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SPECIAL_M32R)))
#else
if (! enable_special
&& CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SPECIAL))
#endif
{
as_bad (_("unknown instruction '%s'"), str);
return;
}
else if (! enable_m32rx
&& CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
{
as_bad (_("instruction '%s' is for the M32RX only"), str);
return;
}
if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SPECIAL))
m32r_flags |= E_M32R_HAS_HIDDEN_INST;
if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SPECIAL_M32R))
m32r_flags |= E_M32R_HAS_BIT_INST;
if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SPECIAL_FLOAT))
m32r_flags |= E_M32R_HAS_FLOAT_INST;
if (CGEN_INSN_BITSIZE (insn.insn) == 32)
{
if (prev_insn.insn || seen_relaxable_p)
{
fill_insn (0);
}
expand_debug_syms (insn.debug_sym_link, 2);
gas_cgen_finish_insn (insn.insn, insn.buffer,
CGEN_FIELDS_BITSIZE (&insn.fields), 1, NULL);
}
else
{
int on_32bit_boundary_p;
int swap = FALSE;
if (CGEN_INSN_BITSIZE (insn.insn) != 16)
abort ();
insn.orig_insn = insn.insn;
if (prev_insn.insn && seen_relaxable_p && optimize)
fill_insn (0);
if (enable_m32rx)
{
{
CGEN_FIELDS tmp_fields;
insn.insn = cgen_lookup_get_insn_operands
(gas_cgen_cpu_desc, NULL, INSN_VALUE (insn.buffer), NULL,
16, insn.indices, &tmp_fields);
}
if (insn.insn == NULL)
as_fatal (_("internal error: lookup/get operands failed"));
}
on_32bit_boundary_p = prev_insn.insn == NULL;
if (parallel() && on_32bit_boundary_p)
{
frag_wane (frag_now);
frag_new (0);
}
if (! on_32bit_boundary_p
&& parallel ()
&& CGEN_INSN_ATTR_VALUE (insn.orig_insn, CGEN_INSN_RELAXABLE) == 0
&& ! writes_to_pc (&prev_insn)
&& ! first_writes_to_seconds_operands (&prev_insn, &insn, FALSE))
{
if (can_make_parallel (&prev_insn, &insn) == NULL)
make_parallel (insn.buffer);
else if (can_make_parallel (&insn, &prev_insn) == NULL)
swap = TRUE;
}
expand_debug_syms (insn.debug_sym_link, 1);
{
int i;
finished_insnS fi;
frag_grow (4);
gas_cgen_finish_insn (insn.orig_insn, insn.buffer,
CGEN_FIELDS_BITSIZE (&insn.fields),
1 , &fi);
insn.addr = fi.addr;
insn.frag = fi.frag;
insn.num_fixups = fi.num_fixups;
for (i = 0; i < fi.num_fixups; ++i)
insn.fixups[i] = fi.fixups[i];
}
if (swap)
{
int i, tmp;
#define SWAP_BYTES(a,b) tmp = a; a = b; b = tmp
SWAP_BYTES (prev_insn.addr[0], insn.addr[0]);
SWAP_BYTES (prev_insn.addr[1], insn.addr[1]);
target_make_parallel (insn.addr);
if (prev_insn.frag->fr_opcode == prev_insn.addr)
prev_insn.frag->fr_opcode = insn.addr;
else if (insn.frag->fr_opcode == insn.addr)
insn.frag->fr_opcode = prev_insn.addr;
if (prev_insn.frag != insn.frag)
{
for (i = 0; i < prev_insn.num_fixups; ++i)
prev_insn.fixups[i]->fx_frag = insn.frag;
for (i = 0; i < insn.num_fixups; ++i)
insn.fixups[i]->fx_frag = prev_insn.frag;
}
else
{
for (i = 0; i < prev_insn.num_fixups; ++i)
prev_insn.fixups[i]->fx_where += 2;
for (i = 0; i < insn.num_fixups; ++i)
insn.fixups[i]->fx_where -= 2;
}
}
if (on_32bit_boundary_p)
prev_insn = insn;
else
prev_insn.insn = NULL;
if (on_32bit_boundary_p
&& CGEN_INSN_ATTR_VALUE (insn.orig_insn, CGEN_INSN_FILL_SLOT) != 0)
fill_insn (0);
if (CGEN_INSN_ATTR_VALUE (insn.orig_insn, CGEN_INSN_RELAXABLE) != 0)
seen_relaxable_p = 1;
}
prev_seg = now_seg;
prev_subseg = now_subseg;
}
void
md_operand (expressionP)
expressionS *expressionP;
{
if (*input_line_pointer == '#')
{
input_line_pointer++;
expression (expressionP);
}
}
valueT
md_section_align (segment, size)
segT segment;
valueT size;
{
int align = bfd_get_section_alignment (stdoutput, segment);
return ((size + (1 << align) - 1) & (-1 << align));
}
symbolS *
md_undefined_symbol (name)
char *name ATTRIBUTE_UNUSED;
{
return 0;
}
static void
m32r_scomm (ignore)
int ignore ATTRIBUTE_UNUSED;
{
register char *name;
register char c;
register char *p;
offsetT size;
register symbolS *symbolP;
offsetT align;
int align2;
name = input_line_pointer;
c = get_symbol_end ();
p = input_line_pointer;
*p = c;
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
as_bad (_("Expected comma after symbol-name: rest of line ignored."));
ignore_rest_of_line ();
return;
}
input_line_pointer++;
if ((size = get_absolute_expression ()) < 0)
{
as_warn (_(".SCOMMon length (%ld.) <0! Ignored."), (long) size);
ignore_rest_of_line ();
return;
}
if (*input_line_pointer != ',')
align = 8;
else
{
++input_line_pointer;
align = get_absolute_expression ();
if (align <= 0)
{
as_warn (_("ignoring bad alignment"));
align = 8;
}
}
if (align)
{
for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2)
continue;
if (align != 1)
{
as_bad (_("Common alignment not a power of 2"));
ignore_rest_of_line ();
return;
}
}
else
align2 = 0;
*p = 0;
symbolP = symbol_find_or_make (name);
*p = c;
if (S_IS_DEFINED (symbolP))
{
as_bad (_("Ignoring attempt to re-define symbol `%s'."),
S_GET_NAME (symbolP));
ignore_rest_of_line ();
return;
}
if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size)
{
as_bad (_("Length of .scomm \"%s\" is already %ld. Not changed to %ld."),
S_GET_NAME (symbolP),
(long) S_GET_VALUE (symbolP),
(long) size);
ignore_rest_of_line ();
return;
}
if (symbol_get_obj (symbolP)->local)
{
segT old_sec = now_seg;
int old_subsec = now_subseg;
char *pfrag;
record_alignment (sbss_section, align2);
subseg_set (sbss_section, 0);
if (align2)
frag_align (align2, 0, 0);
if (S_GET_SEGMENT (symbolP) == sbss_section)
symbol_get_frag (symbolP)->fr_symbol = 0;
symbol_set_frag (symbolP, frag_now);
pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
(char *) 0);
*pfrag = 0;
S_SET_SIZE (symbolP, size);
S_SET_SEGMENT (symbolP, sbss_section);
S_CLEAR_EXTERNAL (symbolP);
subseg_set (old_sec, old_subsec);
}
else
{
S_SET_VALUE (symbolP, (valueT) size);
S_SET_ALIGN (symbolP, align2);
S_SET_EXTERNAL (symbolP);
S_SET_SEGMENT (symbolP, &scom_section);
}
demand_empty_rest_of_line ();
}
const relax_typeS md_relax_table[] =
{
{1, 1, 0, 0},
{511 - 2 - 2, -512 - 2 + 2, 0, 2 },
{0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
{0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
};
long
m32r_relax_frag (segment, fragP, stretch)
segT segment;
fragS *fragP;
long stretch;
{
long address = fragP->fr_address + fragP->fr_fix - 2;
long growth = 0;
if (fragP->fr_subtype == 2)
{
if ((address & 3) != 0)
{
fragP->fr_subtype = 3;
growth = 2;
}
}
else if (fragP->fr_subtype == 3)
{
if ((address & 3) == 0)
{
fragP->fr_subtype = 2;
growth = -2;
}
}
else
{
growth = relax_frag (segment, fragP, stretch);
if (fragP->fr_subtype == 2 && (address & 3) != 0)
{
fragP->fr_subtype = 3;
growth += 2;
}
}
return growth;
}
int
md_estimate_size_before_relax (fragP, segment)
fragS *fragP;
segT segment;
{
if (S_GET_SEGMENT (fragP->fr_symbol) != segment
|| S_IS_EXTERNAL (fragP->fr_symbol)
|| S_IS_WEAK (fragP->fr_symbol))
{
fragP->fr_subtype = 2;
{
const CGEN_INSN *insn;
int i;
for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
{
if ((strcmp (CGEN_INSN_MNEMONIC (insn),
CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
== 0)
&& CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
break;
}
if (i == 4)
abort ();
fragP->fr_cgen.insn = insn;
return 2;
}
}
return md_relax_table[fragP->fr_subtype].rlx_length;
}
void
md_convert_frag (abfd, sec, fragP)
bfd *abfd ATTRIBUTE_UNUSED;
segT sec;
fragS *fragP;
{
char *opcode;
char *displacement;
int target_address;
int opcode_address;
int extension;
int addend;
opcode = fragP->fr_opcode;
opcode_address = fragP->fr_address + fragP->fr_fix - 2;
switch (fragP->fr_subtype)
{
case 1:
extension = 0;
displacement = &opcode[1];
break;
case 2:
opcode[0] |= 0x80;
extension = 2;
displacement = &opcode[1];
break;
case 3:
opcode[2] = opcode[0] | 0x80;
md_number_to_chars (opcode, PAR_NOP_INSN, 2);
opcode_address += 2;
extension = 4;
displacement = &opcode[3];
break;
default:
abort ();
}
if (S_GET_SEGMENT (fragP->fr_symbol) != sec
|| S_IS_EXTERNAL (fragP->fr_symbol)
|| S_IS_WEAK (fragP->fr_symbol))
{
if (fragP->fr_offset & 3)
as_warn (_("Addend to unresolved symbol not on word boundary."));
#ifdef USE_M32R_OLD_RELOC
addend = fragP->fr_offset >> 2;
#else
addend = 0;
#endif
}
else
{
target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
addend = (target_address - (opcode_address & -4)) >> 2;
}
if (S_GET_SEGMENT (fragP->fr_symbol) != sec
|| S_IS_EXTERNAL (fragP->fr_symbol)
|| S_IS_WEAK (fragP->fr_symbol))
{
fixS *fixP;
assert (fragP->fr_subtype != 1);
assert (fragP->fr_cgen.insn != 0);
fixP = gas_cgen_record_fixup (fragP,
fragP->fr_fix + extension - 4,
fragP->fr_cgen.insn,
4 ,
cgen_operand_lookup_by_num (gas_cgen_cpu_desc,
M32R_OPERAND_DISP24),
fragP->fr_cgen.opinfo,
fragP->fr_symbol, fragP->fr_offset);
if (fragP->fr_cgen.opinfo)
fixP->fx_r_type = fragP->fr_cgen.opinfo;
}
#define SIZE_FROM_RELAX_STATE(n) ((n) == 1 ? 1 : 3)
md_number_to_chars (displacement, (valueT) addend,
SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
fragP->fr_fix += extension;
}
long
md_pcrel_from_section (fixP, sec)
fixS *fixP;
segT sec;
{
if (fixP->fx_addsy != (symbolS *) NULL
&& (! S_IS_DEFINED (fixP->fx_addsy)
|| S_GET_SEGMENT (fixP->fx_addsy) != sec
|| S_IS_EXTERNAL (fixP->fx_addsy)
|| S_IS_WEAK (fixP->fx_addsy)))
{
if (S_GET_SEGMENT (fixP->fx_addsy) != sec
&& S_IS_DEFINED (fixP->fx_addsy)
&& ! S_IS_EXTERNAL (fixP->fx_addsy)
&& ! S_IS_WEAK (fixP->fx_addsy))
return fixP->fx_offset;
return 0;
}
return (fixP->fx_frag->fr_address + fixP->fx_where) & -4L;
}
bfd_reloc_code_real_type
md_cgen_lookup_reloc (insn, operand, fixP)
const CGEN_INSN *insn ATTRIBUTE_UNUSED;
const CGEN_OPERAND *operand;
fixS *fixP;
{
switch (operand->type)
{
case M32R_OPERAND_DISP8: return BFD_RELOC_M32R_10_PCREL;
case M32R_OPERAND_DISP16: return BFD_RELOC_M32R_18_PCREL;
case M32R_OPERAND_DISP24: return BFD_RELOC_M32R_26_PCREL;
case M32R_OPERAND_UIMM24: return BFD_RELOC_M32R_24;
case M32R_OPERAND_HI16:
case M32R_OPERAND_SLO16:
case M32R_OPERAND_ULO16:
if (fixP->fx_cgen.opinfo != 0)
return fixP->fx_cgen.opinfo;
break;
default:
break;
}
return BFD_RELOC_NONE;
}
static void m32r_record_hi16 PARAMS ((int, fixS *, segT));
static void
m32r_record_hi16 (reloc_type, fixP, seg)
int reloc_type;
fixS *fixP;
segT seg ATTRIBUTE_UNUSED;
{
struct m32r_hi_fixup *hi_fixup;
assert (reloc_type == BFD_RELOC_M32R_HI16_SLO
|| reloc_type == BFD_RELOC_M32R_HI16_ULO);
hi_fixup = ((struct m32r_hi_fixup *)
xmalloc (sizeof (struct m32r_hi_fixup)));
hi_fixup->fixp = fixP;
hi_fixup->seg = now_seg;
hi_fixup->next = m32r_hi_fixup_list;
m32r_hi_fixup_list = hi_fixup;
}
fixS *
m32r_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;
bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED;
if (m32r_check_fixup (exp, &r_type))
as_bad (_("Invalid PIC expression."));
fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
operand, opinfo, exp);
switch (operand->type)
{
case M32R_OPERAND_HI16:
if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_SLO
|| fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO)
m32r_record_hi16 (fixP->fx_cgen.opinfo, fixP, now_seg);
break;
default:
break;
}
switch (r_type)
{
case BFD_RELOC_UNUSED:
default:
return fixP;
case BFD_RELOC_M32R_GOTPC24:
if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_SLO)
r_type = BFD_RELOC_M32R_GOTPC_HI_SLO;
else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO)
r_type = BFD_RELOC_M32R_GOTPC_HI_ULO;
else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_LO16)
r_type = BFD_RELOC_M32R_GOTPC_LO;
break;
case BFD_RELOC_M32R_GOT24:
if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_SLO)
r_type = BFD_RELOC_M32R_GOT16_HI_SLO;
else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO)
r_type = BFD_RELOC_M32R_GOT16_HI_ULO;
else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_LO16)
r_type = BFD_RELOC_M32R_GOT16_LO;
break;
case BFD_RELOC_M32R_GOTOFF:
if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_SLO)
r_type = BFD_RELOC_M32R_GOTOFF_HI_SLO;
else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO)
r_type = BFD_RELOC_M32R_GOTOFF_HI_ULO;
else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_LO16)
r_type = BFD_RELOC_M32R_GOTOFF_LO;
break;
case BFD_RELOC_M32R_26_PLTREL:
as_bad (_("Invalid PIC expression."));
break;
}
fixP->fx_r_type = r_type;
return fixP;
}
#define FX_OPINFO_R_TYPE(f) ((f)->fx_cgen.opinfo)
void
m32r_frob_file ()
{
struct m32r_hi_fixup *l;
for (l = m32r_hi_fixup_list; l != NULL; l = l->next)
{
segment_info_type *seginfo;
int pass;
assert (FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_M32R_HI16_SLO
|| FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_M32R_HI16_ULO);
if (l->fixp->fx_next != NULL
&& FX_OPINFO_R_TYPE (l->fixp->fx_next) == BFD_RELOC_M32R_LO16
&& l->fixp->fx_addsy == l->fixp->fx_next->fx_addsy
&& l->fixp->fx_offset == l->fixp->fx_next->fx_offset)
continue;
seginfo = seg_info (l->seg);
for (pass = 0; pass < 2; pass++)
{
fixS *f;
fixS *prev;
prev = NULL;
for (f = seginfo->fix_root; f != NULL; f = f->fx_next)
{
if (FX_OPINFO_R_TYPE (f) == BFD_RELOC_M32R_LO16
&& f->fx_addsy == l->fixp->fx_addsy
&& f->fx_offset == l->fixp->fx_offset
&& (pass == 1
|| prev == NULL
|| (FX_OPINFO_R_TYPE (prev) != BFD_RELOC_M32R_HI16_SLO
&& FX_OPINFO_R_TYPE (prev) != BFD_RELOC_M32R_HI16_ULO)
|| prev->fx_addsy != f->fx_addsy
|| prev->fx_offset != f->fx_offset))
{
fixS **pf;
for (pf = &seginfo->fix_root;
*pf != l->fixp;
pf = & (*pf)->fx_next)
assert (*pf != NULL);
*pf = l->fixp->fx_next;
l->fixp->fx_next = f;
if (prev == NULL)
seginfo->fix_root = l->fixp;
else
prev->fx_next = l->fixp;
break;
}
prev = f;
}
if (f != NULL)
break;
if (pass == 1
&& warn_unmatched_high)
as_warn_where (l->fixp->fx_file, l->fixp->fx_line,
_("Unmatched high/shigh reloc"));
}
}
}
int
m32r_force_relocation (fix)
fixS *fix;
{
if (generic_force_reloc (fix))
return 1;
if (! m32r_relax)
return 0;
return fix->fx_pcrel;
}
void
md_number_to_chars (buf, val, n)
char *buf;
valueT val;
int n;
{
if (target_big_endian)
number_to_chars_bigendian (buf, val, n);
else
number_to_chars_littleendian (buf, val, n);
}
#define MAX_LITTLENUMS 6
char *
md_atof (type, litP, sizeP)
char type;
char *litP;
int *sizeP;
{
int i;
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
char *t;
switch (type)
{
case 'f':
case 'F':
case 's':
case 'S':
prec = 2;
break;
case 'd':
case 'D':
case 'r':
case 'R':
prec = 4;
break;
default:
*sizeP = 0;
return _("Bad call to md_atof()");
}
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
*sizeP = prec * sizeof (LITTLENUM_TYPE);
if (target_big_endian)
{
for (i = 0; i < prec; i++)
{
md_number_to_chars (litP, (valueT) words[i],
sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
}
else
{
for (i = prec - 1; i >= 0; i--)
{
md_number_to_chars (litP, (valueT) words[i],
sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
}
return 0;
}
void
m32r_elf_section_change_hook ()
{
if (prev_insn.insn || seen_relaxable_p)
(void) m32r_fill_insn (0);
}
bfd_boolean
m32r_fix_adjustable (fixP)
fixS *fixP;
{
bfd_reloc_code_real_type reloc_type;
if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
{
const CGEN_INSN *insn = NULL;
int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
const CGEN_OPERAND *operand =
cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
}
else
reloc_type = fixP->fx_r_type;
if (fixP->fx_addsy == NULL)
return 1;
if (S_IS_EXTERN (fixP->fx_addsy))
return 0;
if (S_IS_WEAK (fixP->fx_addsy))
return 0;
if (pic_code
&& (reloc_type == BFD_RELOC_M32R_24
|| reloc_type == BFD_RELOC_M32R_26_PCREL
|| reloc_type == BFD_RELOC_M32R_HI16_SLO
|| reloc_type == BFD_RELOC_M32R_HI16_ULO
|| reloc_type == BFD_RELOC_M32R_LO16))
return 0;
if (reloc_type == BFD_RELOC_M32R_GOT24
|| reloc_type == BFD_RELOC_M32R_26_PLTREL
|| reloc_type == BFD_RELOC_M32R_GOTPC_HI_SLO
|| reloc_type == BFD_RELOC_M32R_GOTPC_HI_ULO
|| reloc_type == BFD_RELOC_M32R_GOTPC_LO
|| reloc_type == BFD_RELOC_M32R_GOT16_HI_SLO
|| reloc_type == BFD_RELOC_M32R_GOT16_HI_ULO
|| reloc_type == BFD_RELOC_M32R_GOT16_LO)
return 0;
if (reloc_type == BFD_RELOC_VTABLE_INHERIT
|| reloc_type == BFD_RELOC_VTABLE_ENTRY)
return 0;
return 1;
}
void
m32r_elf_final_processing (void)
{
if (use_parallel)
m32r_flags |= E_M32R_HAS_PARALLEL;
elf_elfheader (stdoutput)->e_flags |= m32r_flags;
}
arelent *
tc_gen_reloc (section, fixP)
asection * section;
fixS * fixP;
{
arelent * reloc;
bfd_reloc_code_real_type code;
reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
code = fixP->fx_r_type;
if (pic_code)
{
#ifdef DEBUG_PIC
printf("%s",bfd_get_reloc_code_name(code));
#endif
switch (code)
{
case BFD_RELOC_M32R_26_PCREL:
code = BFD_RELOC_M32R_26_PLTREL;
break;
case BFD_RELOC_M32R_24:
if (fixP->fx_addsy != NULL
&& strcmp (S_GET_NAME (fixP->fx_addsy), GOT_NAME) == 0)
code = BFD_RELOC_M32R_GOTPC24;
else
code = BFD_RELOC_M32R_GOT24;
break;
case BFD_RELOC_M32R_HI16_ULO:
if (fixP->fx_addsy != NULL
&& strcmp (S_GET_NAME (fixP->fx_addsy), GOT_NAME) == 0)
code = BFD_RELOC_M32R_GOTPC_HI_ULO;
else
code = BFD_RELOC_M32R_GOT16_HI_ULO;
break;
case BFD_RELOC_M32R_HI16_SLO:
if (fixP->fx_addsy != NULL
&& strcmp (S_GET_NAME (fixP->fx_addsy), GOT_NAME) == 0)
code = BFD_RELOC_M32R_GOTPC_HI_SLO;
else
code = BFD_RELOC_M32R_GOT16_HI_SLO;
break;
case BFD_RELOC_M32R_LO16:
if (fixP->fx_addsy != NULL
&& strcmp (S_GET_NAME (fixP->fx_addsy), GOT_NAME) == 0)
code = BFD_RELOC_M32R_GOTPC_LO;
else
code = BFD_RELOC_M32R_GOT16_LO;
break;
default:
break;
}
#ifdef DEBUG_PIC
printf(" => %s",bfd_get_reloc_code_name(code));
#endif
}
reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
#ifdef DEBUG_PIC
printf(" => %s\n",reloc->howto->name);
#endif
if (reloc->howto == (reloc_howto_type *) NULL)
{
as_bad_where (fixP->fx_file, fixP->fx_line,
_("internal error: can't export reloc type %d (`%s')"),
fixP->fx_r_type, bfd_get_reloc_code_name (code));
return NULL;
}
if ( fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
reloc->addend = fixP->fx_offset;
else if ((!pic_code
&& code != BFD_RELOC_M32R_26_PLTREL)
&& fixP->fx_pcrel
&& fixP->fx_addsy != NULL
&& (S_GET_SEGMENT(fixP->fx_addsy) != section)
&& S_IS_DEFINED (fixP->fx_addsy)
&& ! S_IS_EXTERNAL(fixP->fx_addsy)
&& ! S_IS_WEAK(fixP->fx_addsy))
reloc->addend = fixP->fx_offset;
else
reloc->addend = fixP->fx_addnumber;
return reloc;
}
inline static char *
m32r_end_of_match (char *cont, char *what)
{
int len = strlen (what);
if (strncasecmp (cont, what, strlen (what)) == 0
&& ! is_part_of_name (cont[len]))
return cont + len;
return NULL;
}
int
m32r_parse_name (char const *name, expressionS *exprP, char *nextcharP)
{
char *next = input_line_pointer;
char *next_end;
int reloc_type;
operatorT op_type;
segT segment;
exprP->X_op_symbol = NULL;
exprP->X_md = BFD_RELOC_UNUSED;
if (strcmp (name, GOT_NAME) == 0)
{
if (! GOT_symbol)
GOT_symbol = symbol_find_or_make (name);
exprP->X_add_symbol = GOT_symbol;
no_suffix:
segment = S_GET_SEGMENT (exprP->X_add_symbol);
if (segment == absolute_section)
{
exprP->X_op = O_constant;
exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
exprP->X_add_symbol = NULL;
}
else if (segment == reg_section)
{
exprP->X_op = O_register;
exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
exprP->X_add_symbol = NULL;
}
else
{
exprP->X_op = O_symbol;
exprP->X_add_number = 0;
}
return 1;
}
exprP->X_add_symbol = symbol_find_or_make (name);
if (*nextcharP != '@')
goto no_suffix;
else if ((next_end = m32r_end_of_match (next + 1, "GOTOFF")))
{
reloc_type = BFD_RELOC_M32R_GOTOFF;
op_type = O_PIC_reloc;
}
else if ((next_end = m32r_end_of_match (next + 1, "GOT")))
{
reloc_type = BFD_RELOC_M32R_GOT24;
op_type = O_PIC_reloc;
}
else if ((next_end = m32r_end_of_match (next + 1, "PLT")))
{
reloc_type = BFD_RELOC_M32R_26_PLTREL;
op_type = O_PIC_reloc;
}
else
goto no_suffix;
*input_line_pointer = *nextcharP;
input_line_pointer = next_end;
*nextcharP = *input_line_pointer;
*input_line_pointer = '\0';
exprP->X_op = op_type;
exprP->X_add_number = 0;
exprP->X_md = reloc_type;
return 1;
}
int
m32r_cgen_parse_fix_exp(int opinfo, expressionS *exp)
{
if (exp->X_op == O_PIC_reloc
&& exp->X_md == BFD_RELOC_M32R_26_PLTREL)
{
exp->X_op = O_symbol;
opinfo = exp->X_md;
}
return opinfo;
}