#include <stdio.h>
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "opcode/mn10300.h"
#include "dwarf2dbg.h"
struct reg_name
{
const char *name;
int value;
};
const char comment_chars[] = "#";
const char line_comment_chars[] = ";#";
const char line_separator_chars[] = ";";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
const relax_typeS md_relax_table[] =
{
{0x7f, -0x80, 2, 1},
{0x7fff + 2, -0x8000 + 2, 5, 2},
{0x7fffffff, -0x80000000, 7, 0},
{0x7f, -0x80, 3, 4},
{0x7fff + 3, -0x8000 + 3, 6, 5},
{0x7fffffff, -0x80000000, 8, 0},
{0x7fff, -0x8000, 5, 7},
{0x7fffffff, -0x80000000, 7, 0},
{0x7fff, -0x8000, 4, 9},
{0x7fffffff, -0x80000000, 6, 0},
{0x7f, -0x80, 2, 11},
{0x7fff, -0x8000, 3, 12},
{0x7fffffff, -0x80000000, 5, 0},
{0x7f, -0x80, 3, 14},
{0x7fff + 3, -0x8000 + 3, 6, 15},
{0x7fffffff, -0x80000000, 8, 0},
};
static void mn10300_insert_operand PARAMS ((unsigned long *, unsigned long *,
const struct mn10300_operand *,
offsetT, char *, unsigned,
unsigned));
static unsigned long check_operand PARAMS ((unsigned long,
const struct mn10300_operand *,
offsetT));
static int reg_name_search PARAMS ((const struct reg_name *, int, const char *));
static bfd_boolean data_register_name PARAMS ((expressionS *expressionP));
static bfd_boolean address_register_name PARAMS ((expressionS *expressionP));
static bfd_boolean other_register_name PARAMS ((expressionS *expressionP));
static bfd_boolean r_register_name PARAMS ((expressionS *expressionP));
static bfd_boolean xr_register_name PARAMS ((expressionS *expressionP));
static void set_arch_mach PARAMS ((int));
int linkrelax = 1;
static int current_machine;
#define MAX_INSN_FIXUPS (5)
struct mn10300_fixup
{
expressionS exp;
int opindex;
bfd_reloc_code_real_type reloc;
};
struct mn10300_fixup fixups[MAX_INSN_FIXUPS];
static int fc;
int mn10300_reg_operands[MN10300_MAX_OPERANDS];
const char *md_shortopts = "";
struct option md_longopts[] = {
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
const pseudo_typeS md_pseudo_table[] =
{
{ "am30", set_arch_mach, AM30 },
{ "am33", set_arch_mach, AM33 },
{ "am33_2", (void (*) PARAMS ((int))) set_arch_mach, AM33_2 },
{ "mn10300", set_arch_mach, MN103 },
{NULL, 0, 0}
};
#define HAVE_AM33_2 (current_machine == AM33_2)
#define HAVE_AM33 (current_machine == AM33 || HAVE_AM33_2)
#define HAVE_AM30 (current_machine == AM30)
static struct hash_control *mn10300_hash;
static const struct reg_name data_registers[] =
{
{ "d0", 0 },
{ "d1", 1 },
{ "d2", 2 },
{ "d3", 3 },
};
#define DATA_REG_NAME_CNT \
(sizeof (data_registers) / sizeof (struct reg_name))
static const struct reg_name address_registers[] =
{
{ "a0", 0 },
{ "a1", 1 },
{ "a2", 2 },
{ "a3", 3 },
};
#define ADDRESS_REG_NAME_CNT \
(sizeof (address_registers) / sizeof (struct reg_name))
static const struct reg_name r_registers[] =
{
{ "a0", 8 },
{ "a1", 9 },
{ "a2", 10 },
{ "a3", 11 },
{ "d0", 12 },
{ "d1", 13 },
{ "d2", 14 },
{ "d3", 15 },
{ "e0", 0 },
{ "e1", 1 },
{ "e10", 10 },
{ "e11", 11 },
{ "e12", 12 },
{ "e13", 13 },
{ "e14", 14 },
{ "e15", 15 },
{ "e2", 2 },
{ "e3", 3 },
{ "e4", 4 },
{ "e5", 5 },
{ "e6", 6 },
{ "e7", 7 },
{ "e8", 8 },
{ "e9", 9 },
{ "r0", 0 },
{ "r1", 1 },
{ "r10", 10 },
{ "r11", 11 },
{ "r12", 12 },
{ "r13", 13 },
{ "r14", 14 },
{ "r15", 15 },
{ "r2", 2 },
{ "r3", 3 },
{ "r4", 4 },
{ "r5", 5 },
{ "r6", 6 },
{ "r7", 7 },
{ "r8", 8 },
{ "r9", 9 },
};
#define R_REG_NAME_CNT \
(sizeof (r_registers) / sizeof (struct reg_name))
static const struct reg_name xr_registers[] =
{
{ "mcrh", 2 },
{ "mcrl", 3 },
{ "mcvf", 4 },
{ "mdrq", 1 },
{ "sp", 0 },
{ "xr0", 0 },
{ "xr1", 1 },
{ "xr10", 10 },
{ "xr11", 11 },
{ "xr12", 12 },
{ "xr13", 13 },
{ "xr14", 14 },
{ "xr15", 15 },
{ "xr2", 2 },
{ "xr3", 3 },
{ "xr4", 4 },
{ "xr5", 5 },
{ "xr6", 6 },
{ "xr7", 7 },
{ "xr8", 8 },
{ "xr9", 9 },
};
#define XR_REG_NAME_CNT \
(sizeof (xr_registers) / sizeof (struct reg_name))
static const struct reg_name other_registers[] =
{
{ "epsw", AM33 },
{ "mdr", 0 },
{ "pc", AM33 },
{ "psw", 0 },
{ "sp", 0 },
};
#define OTHER_REG_NAME_CNT \
(sizeof (other_registers) / sizeof (struct reg_name))
static const struct reg_name float_registers[] =
{
{ "fs0", 0 },
{ "fs1", 1 },
{ "fs10", 10 },
{ "fs11", 11 },
{ "fs12", 12 },
{ "fs13", 13 },
{ "fs14", 14 },
{ "fs15", 15 },
{ "fs16", 16 },
{ "fs17", 17 },
{ "fs18", 18 },
{ "fs19", 19 },
{ "fs2", 2 },
{ "fs20", 20 },
{ "fs21", 21 },
{ "fs22", 22 },
{ "fs23", 23 },
{ "fs24", 24 },
{ "fs25", 25 },
{ "fs26", 26 },
{ "fs27", 27 },
{ "fs28", 28 },
{ "fs29", 29 },
{ "fs3", 3 },
{ "fs30", 30 },
{ "fs31", 31 },
{ "fs4", 4 },
{ "fs5", 5 },
{ "fs6", 6 },
{ "fs7", 7 },
{ "fs8", 8 },
{ "fs9", 9 },
};
#define FLOAT_REG_NAME_CNT \
(sizeof (float_registers) / sizeof (struct reg_name))
static const struct reg_name double_registers[] =
{
{ "fd0", 0 },
{ "fd10", 10 },
{ "fd12", 12 },
{ "fd14", 14 },
{ "fd16", 16 },
{ "fd18", 18 },
{ "fd2", 2 },
{ "fd20", 20 },
{ "fd22", 22 },
{ "fd24", 24 },
{ "fd26", 26 },
{ "fd28", 28 },
{ "fd30", 30 },
{ "fd4", 4 },
{ "fd6", 6 },
{ "fd8", 8 },
};
#define DOUBLE_REG_NAME_CNT \
(sizeof (double_registers) / sizeof (struct reg_name))
static int
reg_name_search (regs, regcount, name)
const struct reg_name *regs;
int regcount;
const char *name;
{
int middle, low, high;
int cmp;
low = 0;
high = regcount - 1;
do
{
middle = (low + high) / 2;
cmp = strcasecmp (name, regs[middle].name);
if (cmp < 0)
high = middle - 1;
else if (cmp > 0)
low = middle + 1;
else
return regs[middle].value;
}
while (low <= high);
return -1;
}
static bfd_boolean
r_register_name (expressionP)
expressionS *expressionP;
{
int reg_number;
char *name;
char *start;
char c;
start = name = input_line_pointer;
c = get_symbol_end ();
reg_number = reg_name_search (r_registers, R_REG_NAME_CNT, name);
*input_line_pointer = c;
if (reg_number >= 0)
{
expressionP->X_op = O_register;
expressionP->X_add_number = reg_number;
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
return TRUE;
}
input_line_pointer = start;
return FALSE;
}
static bfd_boolean
xr_register_name (expressionP)
expressionS *expressionP;
{
int reg_number;
char *name;
char *start;
char c;
start = name = input_line_pointer;
c = get_symbol_end ();
reg_number = reg_name_search (xr_registers, XR_REG_NAME_CNT, name);
*input_line_pointer = c;
if (reg_number >= 0)
{
expressionP->X_op = O_register;
expressionP->X_add_number = reg_number;
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
return TRUE;
}
input_line_pointer = start;
return FALSE;
}
static bfd_boolean
data_register_name (expressionP)
expressionS *expressionP;
{
int reg_number;
char *name;
char *start;
char c;
start = name = input_line_pointer;
c = get_symbol_end ();
reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name);
*input_line_pointer = c;
if (reg_number >= 0)
{
expressionP->X_op = O_register;
expressionP->X_add_number = reg_number;
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
return TRUE;
}
input_line_pointer = start;
return FALSE;
}
static bfd_boolean
address_register_name (expressionP)
expressionS *expressionP;
{
int reg_number;
char *name;
char *start;
char c;
start = name = input_line_pointer;
c = get_symbol_end ();
reg_number = reg_name_search (address_registers, ADDRESS_REG_NAME_CNT, name);
*input_line_pointer = c;
if (reg_number >= 0)
{
expressionP->X_op = O_register;
expressionP->X_add_number = reg_number;
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
return TRUE;
}
input_line_pointer = start;
return FALSE;
}
static bfd_boolean
other_register_name (expressionP)
expressionS *expressionP;
{
int reg_number;
char *name;
char *start;
char c;
start = name = input_line_pointer;
c = get_symbol_end ();
reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name);
*input_line_pointer = c;
if (reg_number == 0
|| (reg_number == AM33 && HAVE_AM33))
{
expressionP->X_op = O_register;
expressionP->X_add_number = 0;
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
return TRUE;
}
input_line_pointer = start;
return FALSE;
}
static bfd_boolean double_register_name PARAMS ((expressionS *));
static bfd_boolean float_register_name PARAMS ((expressionS *));
static bfd_boolean
float_register_name (expressionP)
expressionS *expressionP;
{
int reg_number;
char *name;
char *start;
char c;
start = name = input_line_pointer;
c = get_symbol_end ();
reg_number = reg_name_search (float_registers, FLOAT_REG_NAME_CNT, name);
* input_line_pointer = c;
if (reg_number >= 0)
{
expressionP->X_op = O_register;
expressionP->X_add_number = reg_number;
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
return TRUE;
}
input_line_pointer = start;
return FALSE;
}
static bfd_boolean
double_register_name (expressionP)
expressionS *expressionP;
{
int reg_number;
char *name;
char *start;
char c;
start = name = input_line_pointer;
c = get_symbol_end ();
reg_number = reg_name_search (double_registers, DOUBLE_REG_NAME_CNT, name);
* input_line_pointer = c;
if (reg_number >= 0)
{
expressionP->X_op = O_register;
expressionP->X_add_number = reg_number;
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
return TRUE;
}
input_line_pointer = start;
return FALSE;
}
void
md_show_usage (stream)
FILE *stream;
{
fprintf (stream, _("MN10300 options:\n\
none yet\n"));
}
int
md_parse_option (c, arg)
int c ATTRIBUTE_UNUSED;
char *arg ATTRIBUTE_UNUSED;
{
return 0;
}
symbolS *
md_undefined_symbol (name)
char *name ATTRIBUTE_UNUSED;
{
return 0;
}
char *
md_atof (type, litp, sizep)
int type;
char *litp;
int *sizep;
{
int prec;
LITTLENUM_TYPE words[4];
char *t;
int i;
switch (type)
{
case 'f':
prec = 2;
break;
case 'd':
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 * 2;
for (i = prec - 1; i >= 0; i--)
{
md_number_to_chars (litp, (valueT) words[i], 2);
litp += 2;
}
return NULL;
}
void
md_convert_frag (abfd, sec, fragP)
bfd *abfd ATTRIBUTE_UNUSED;
asection *sec;
fragS *fragP;
{
static unsigned long label_count = 0;
char buf[40];
subseg_change (sec, 0);
if (fragP->fr_subtype == 0)
{
fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 2;
}
else if (fragP->fr_subtype == 1)
{
int offset = fragP->fr_fix;
int opcode = fragP->fr_literal[offset] & 0xff;
switch (opcode)
{
case 0xc8:
opcode = 0xc9;
break;
case 0xc9:
opcode = 0xc8;
break;
case 0xc0:
opcode = 0xc2;
break;
case 0xc2:
opcode = 0xc0;
break;
case 0xc3:
opcode = 0xc1;
break;
case 0xc1:
opcode = 0xc3;
break;
case 0xc4:
opcode = 0xc6;
break;
case 0xc6:
opcode = 0xc4;
break;
case 0xc7:
opcode = 0xc5;
break;
case 0xc5:
opcode = 0xc7;
break;
default:
abort ();
}
fragP->fr_literal[offset] = opcode;
sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
fix_new (fragP, fragP->fr_fix + 1, 1,
symbol_new (buf, sec, 0, fragP->fr_next),
fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
fragP->fr_literal[offset + 2] = 0xcc;
fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 5;
}
else if (fragP->fr_subtype == 2)
{
int offset = fragP->fr_fix;
int opcode = fragP->fr_literal[offset] & 0xff;
switch (opcode)
{
case 0xc8:
opcode = 0xc9;
break;
case 0xc9:
opcode = 0xc8;
break;
case 0xc0:
opcode = 0xc2;
break;
case 0xc2:
opcode = 0xc0;
break;
case 0xc3:
opcode = 0xc1;
break;
case 0xc1:
opcode = 0xc3;
break;
case 0xc4:
opcode = 0xc6;
break;
case 0xc6:
opcode = 0xc4;
break;
case 0xc7:
opcode = 0xc5;
break;
case 0xc5:
opcode = 0xc7;
break;
default:
abort ();
}
fragP->fr_literal[offset] = opcode;
sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
fix_new (fragP, fragP->fr_fix + 1, 1,
symbol_new (buf, sec, 0, fragP->fr_next),
fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
fragP->fr_literal[offset + 2] = 0xdc;
fix_new (fragP, fragP->fr_fix + 3, 4, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 7;
}
else if (fragP->fr_subtype == 3)
{
fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 3;
}
else if (fragP->fr_subtype == 4)
{
int offset = fragP->fr_fix;
int opcode = fragP->fr_literal[offset + 1] & 0xff;
switch (opcode)
{
case 0xe8:
opcode = 0xe9;
break;
case 0xe9:
opcode = 0xe8;
break;
case 0xea:
opcode = 0xeb;
break;
case 0xeb:
opcode = 0xea;
break;
default:
abort ();
}
fragP->fr_literal[offset + 1] = opcode;
sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
fix_new (fragP, fragP->fr_fix + 2, 1,
symbol_new (buf, sec, 0, fragP->fr_next),
fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
fragP->fr_literal[offset + 3] = 0xcc;
fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 6;
}
else if (fragP->fr_subtype == 5)
{
int offset = fragP->fr_fix;
int opcode = fragP->fr_literal[offset + 1] & 0xff;
switch (opcode)
{
case 0xe8:
opcode = 0xe9;
break;
case 0xea:
opcode = 0xeb;
break;
case 0xeb:
opcode = 0xea;
break;
default:
abort ();
}
fragP->fr_literal[offset + 1] = opcode;
sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
fix_new (fragP, fragP->fr_fix + 2, 1,
symbol_new (buf, sec, 0, fragP->fr_next),
fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
fragP->fr_literal[offset + 3] = 0xdc;
fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 8;
}
else if (fragP->fr_subtype == 6)
{
int offset = fragP->fr_fix;
fragP->fr_literal[offset] = 0xcd;
fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 5;
}
else if (fragP->fr_subtype == 7)
{
int offset = fragP->fr_fix;
fragP->fr_literal[offset] = 0xdd;
fragP->fr_literal[offset + 5] = fragP->fr_literal[offset + 3];
fragP->fr_literal[offset + 6] = fragP->fr_literal[offset + 4];
fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 7;
}
else if (fragP->fr_subtype == 8)
{
int offset = fragP->fr_fix;
fragP->fr_literal[offset] = 0xfa;
fragP->fr_literal[offset + 1] = 0xff;
fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
fragP->fr_offset + 2, 1, BFD_RELOC_16_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 4;
}
else if (fragP->fr_subtype == 9)
{
int offset = fragP->fr_fix;
fragP->fr_literal[offset] = 0xfc;
fragP->fr_literal[offset + 1] = 0xff;
fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
fragP->fr_offset + 2, 1, BFD_RELOC_32_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 6;
}
else if (fragP->fr_subtype == 10)
{
fragP->fr_literal[fragP->fr_fix] = 0xca;
fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 2;
}
else if (fragP->fr_subtype == 11)
{
int offset = fragP->fr_fix;
fragP->fr_literal[offset] = 0xcc;
fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 3;
}
else if (fragP->fr_subtype == 12)
{
int offset = fragP->fr_fix;
fragP->fr_literal[offset] = 0xdc;
fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 5;
}
else if (fragP->fr_subtype == 13)
{
fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 3;
}
else if (fragP->fr_subtype == 14)
{
int offset = fragP->fr_fix;
int opcode = fragP->fr_literal[offset + 1] & 0xff;
switch (opcode)
{
case 0xd0:
opcode = 0xd1;
break;
case 0xd1:
opcode = 0xd0;
break;
case 0xd2:
opcode = 0xdc;
break;
case 0xd3:
opcode = 0xdb;
break;
case 0xd4:
opcode = 0xda;
break;
case 0xd5:
opcode = 0xd9;
break;
case 0xd6:
opcode = 0xd8;
break;
case 0xd7:
opcode = 0xdd;
break;
case 0xd8:
opcode = 0xd6;
break;
case 0xd9:
opcode = 0xd5;
break;
case 0xda:
opcode = 0xd4;
break;
case 0xdb:
opcode = 0xd3;
break;
case 0xdc:
opcode = 0xd2;
break;
case 0xdd:
opcode = 0xd7;
break;
default:
abort ();
}
fragP->fr_literal[offset + 1] = opcode;
sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
fix_new (fragP, fragP->fr_fix + 2, 1,
symbol_new (buf, sec, 0, fragP->fr_next),
fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
fragP->fr_literal[offset + 3] = 0xcc;
fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 6;
}
else if (fragP->fr_subtype == 15)
{
int offset = fragP->fr_fix;
int opcode = fragP->fr_literal[offset + 1] & 0xff;
switch (opcode)
{
case 0xd0:
opcode = 0xd1;
break;
case 0xd1:
opcode = 0xd0;
break;
case 0xd2:
opcode = 0xdc;
break;
case 0xd3:
opcode = 0xdb;
break;
case 0xd4:
opcode = 0xda;
break;
case 0xd5:
opcode = 0xd9;
break;
case 0xd6:
opcode = 0xd8;
break;
case 0xd7:
opcode = 0xdd;
break;
case 0xd8:
opcode = 0xd6;
break;
case 0xd9:
opcode = 0xd5;
break;
case 0xda:
opcode = 0xd4;
break;
case 0xdb:
opcode = 0xd3;
break;
case 0xdc:
opcode = 0xd2;
break;
case 0xdd:
opcode = 0xd7;
break;
default:
abort ();
}
fragP->fr_literal[offset + 1] = opcode;
sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
fix_new (fragP, fragP->fr_fix + 2, 1,
symbol_new (buf, sec, 0, fragP->fr_next),
fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
fragP->fr_literal[offset + 3] = 0xdc;
fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
fragP->fr_var = 0;
fragP->fr_fix += 8;
}
else
abort ();
}
valueT
md_section_align (seg, addr)
asection *seg;
valueT addr;
{
int align = bfd_get_section_alignment (stdoutput, seg);
return ((addr + (1 << align) - 1) & (-1 << align));
}
void
md_begin ()
{
char *prev_name = "";
register const struct mn10300_opcode *op;
mn10300_hash = hash_new ();
op = mn10300_opcodes;
while (op->name)
{
if (strcmp (prev_name, op->name))
{
prev_name = (char *) op->name;
hash_insert (mn10300_hash, op->name, (char *) op);
}
op++;
}
#ifdef TE_LINUX
if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, AM33_2))
as_warn (_("could not set architecture and machine"));
current_machine = AM33_2;
#else
if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, MN103))
as_warn (_("could not set architecture and machine"));
current_machine = MN103;
#endif
}
static symbolS *GOT_symbol;
static inline int mn10300_check_fixup PARAMS ((struct mn10300_fixup *));
static inline int mn10300_PIC_related_p PARAMS ((symbolS *));
static inline int
mn10300_PIC_related_p (sym)
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
|| mn10300_PIC_related_p (exp->X_add_symbol)
|| mn10300_PIC_related_p (exp->X_op_symbol));
}
static inline int
mn10300_check_fixup (fixup)
struct mn10300_fixup *fixup;
{
expressionS *exp = &fixup->exp;
repeat:
switch (exp->X_op)
{
case O_add:
case O_subtract:
if (exp != &fixup->exp || mn10300_PIC_related_p (exp->X_op_symbol))
return 1;
if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol)
fixup->reloc = BFD_RELOC_32_GOT_PCREL;
exp = symbol_get_value_expression (exp->X_add_symbol);
goto repeat;
case O_symbol:
if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol)
fixup->reloc = BFD_RELOC_32_GOT_PCREL;
break;
case O_PIC_reloc:
fixup->reloc = exp->X_md;
exp->X_op = O_symbol;
if (fixup->reloc == BFD_RELOC_32_PLT_PCREL
&& fixup->opindex >= 0
&& (mn10300_operands[fixup->opindex].flags
& MN10300_OPERAND_RELAX))
return 1;
break;
default:
return (mn10300_PIC_related_p (exp->X_add_symbol)
|| mn10300_PIC_related_p (exp->X_op_symbol));
}
return 0;
}
void
mn10300_cons_fix_new (frag, off, size, exp)
fragS *frag;
int off, size;
expressionS *exp;
{
struct mn10300_fixup fixup;
fixup.opindex = -1;
fixup.exp = *exp;
fixup.reloc = BFD_RELOC_UNUSED;
mn10300_check_fixup (&fixup);
if (fixup.reloc == BFD_RELOC_MN10300_GOT32)
switch (size)
{
case 2:
fixup.reloc = BFD_RELOC_MN10300_GOT16;
break;
case 3:
fixup.reloc = BFD_RELOC_MN10300_GOT24;
break;
case 4:
break;
default:
goto error;
}
else if (fixup.reloc == BFD_RELOC_UNUSED)
switch (size)
{
case 1:
fixup.reloc = BFD_RELOC_8;
break;
case 2:
fixup.reloc = BFD_RELOC_16;
break;
case 3:
fixup.reloc = BFD_RELOC_24;
break;
case 4:
fixup.reloc = BFD_RELOC_32;
break;
default:
goto error;
}
else if (size != 4)
{
error:
as_bad (_("unsupported BFD relocation size %u"), size);
fixup.reloc = BFD_RELOC_UNUSED;
}
fix_new_exp (frag, off, size, &fixup.exp, 0, fixup.reloc);
}
void
md_assemble (str)
char *str;
{
char *s;
struct mn10300_opcode *opcode;
struct mn10300_opcode *next_opcode;
const unsigned char *opindex_ptr;
int next_opindex, relaxable;
unsigned long insn, extension, size = 0;
char *f;
int i;
int match;
for (s = str; *s != '\0' && !ISSPACE (*s); s++)
;
if (*s != '\0')
*s++ = '\0';
opcode = (struct mn10300_opcode *) hash_find (mn10300_hash, str);
if (opcode == NULL)
{
as_bad (_("Unrecognized opcode: `%s'"), str);
return;
}
str = s;
while (ISSPACE (*str))
++str;
input_line_pointer = str;
for (;;)
{
const char *errmsg;
int op_idx;
char *hold;
int extra_shift = 0;
errmsg = _("Invalid opcode/operands");
memset (mn10300_reg_operands, -1, sizeof (mn10300_reg_operands));
relaxable = 0;
fc = 0;
match = 0;
next_opindex = 0;
insn = opcode->opcode;
extension = 0;
if (opcode->machine
&& !(opcode->machine == AM33_2 && HAVE_AM33_2)
&& !(opcode->machine == AM33 && HAVE_AM33)
&& !(opcode->machine == AM30 && HAVE_AM30))
goto error;
for (op_idx = 1, opindex_ptr = opcode->operands;
*opindex_ptr != 0;
opindex_ptr++, op_idx++)
{
const struct mn10300_operand *operand;
expressionS ex;
if (next_opindex == 0)
{
operand = &mn10300_operands[*opindex_ptr];
}
else
{
operand = &mn10300_operands[next_opindex];
next_opindex = 0;
}
while (*str == ' ' || *str == ',')
++str;
if (operand->flags & MN10300_OPERAND_RELAX)
relaxable = 1;
hold = input_line_pointer;
input_line_pointer = str;
if (operand->flags & MN10300_OPERAND_PAREN)
{
if (*input_line_pointer != ')' && *input_line_pointer != '(')
{
input_line_pointer = hold;
str = hold;
goto error;
}
input_line_pointer++;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_DREG)
{
if (!data_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
}
else if (operand->flags & MN10300_OPERAND_AREG)
{
if (!address_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
}
else if (operand->flags & MN10300_OPERAND_SP)
{
char *start = input_line_pointer;
char c = get_symbol_end ();
if (strcasecmp (start, "sp") != 0)
{
*input_line_pointer = c;
input_line_pointer = hold;
str = hold;
goto error;
}
*input_line_pointer = c;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_RREG)
{
if (!r_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
}
else if (operand->flags & MN10300_OPERAND_XRREG)
{
if (!xr_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
}
else if (operand->flags & MN10300_OPERAND_FSREG)
{
if (!float_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
}
else if (operand->flags & MN10300_OPERAND_FDREG)
{
if (!double_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
}
else if (operand->flags & MN10300_OPERAND_FPCR)
{
char *start = input_line_pointer;
char c = get_symbol_end ();
if (strcasecmp (start, "fpcr") != 0)
{
*input_line_pointer = c;
input_line_pointer = hold;
str = hold;
goto error;
}
*input_line_pointer = c;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_USP)
{
char *start = input_line_pointer;
char c = get_symbol_end ();
if (strcasecmp (start, "usp") != 0)
{
*input_line_pointer = c;
input_line_pointer = hold;
str = hold;
goto error;
}
*input_line_pointer = c;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_SSP)
{
char *start = input_line_pointer;
char c = get_symbol_end ();
if (strcasecmp (start, "ssp") != 0)
{
*input_line_pointer = c;
input_line_pointer = hold;
str = hold;
goto error;
}
*input_line_pointer = c;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_MSP)
{
char *start = input_line_pointer;
char c = get_symbol_end ();
if (strcasecmp (start, "msp") != 0)
{
*input_line_pointer = c;
input_line_pointer = hold;
str = hold;
goto error;
}
*input_line_pointer = c;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_PC)
{
char *start = input_line_pointer;
char c = get_symbol_end ();
if (strcasecmp (start, "pc") != 0)
{
*input_line_pointer = c;
input_line_pointer = hold;
str = hold;
goto error;
}
*input_line_pointer = c;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_EPSW)
{
char *start = input_line_pointer;
char c = get_symbol_end ();
if (strcasecmp (start, "epsw") != 0)
{
*input_line_pointer = c;
input_line_pointer = hold;
str = hold;
goto error;
}
*input_line_pointer = c;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_PLUS)
{
if (*input_line_pointer != '+')
{
input_line_pointer = hold;
str = hold;
goto error;
}
input_line_pointer++;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_PSW)
{
char *start = input_line_pointer;
char c = get_symbol_end ();
if (strcasecmp (start, "psw") != 0)
{
*input_line_pointer = c;
input_line_pointer = hold;
str = hold;
goto error;
}
*input_line_pointer = c;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_MDR)
{
char *start = input_line_pointer;
char c = get_symbol_end ();
if (strcasecmp (start, "mdr") != 0)
{
*input_line_pointer = c;
input_line_pointer = hold;
str = hold;
goto error;
}
*input_line_pointer = c;
goto keep_going;
}
else if (operand->flags & MN10300_OPERAND_REG_LIST)
{
unsigned int value = 0;
if (*input_line_pointer != '[')
{
input_line_pointer = hold;
str = hold;
goto error;
}
input_line_pointer++;
while (*input_line_pointer != ']')
{
char *start;
char c;
if (*input_line_pointer == ',')
input_line_pointer++;
start = input_line_pointer;
c = get_symbol_end ();
if (strcasecmp (start, "d2") == 0)
{
value |= 0x80;
*input_line_pointer = c;
}
else if (strcasecmp (start, "d3") == 0)
{
value |= 0x40;
*input_line_pointer = c;
}
else if (strcasecmp (start, "a2") == 0)
{
value |= 0x20;
*input_line_pointer = c;
}
else if (strcasecmp (start, "a3") == 0)
{
value |= 0x10;
*input_line_pointer = c;
}
else if (strcasecmp (start, "other") == 0)
{
value |= 0x08;
*input_line_pointer = c;
}
else if (HAVE_AM33
&& strcasecmp (start, "exreg0") == 0)
{
value |= 0x04;
*input_line_pointer = c;
}
else if (HAVE_AM33
&& strcasecmp (start, "exreg1") == 0)
{
value |= 0x02;
*input_line_pointer = c;
}
else if (HAVE_AM33
&& strcasecmp (start, "exother") == 0)
{
value |= 0x01;
*input_line_pointer = c;
}
else if (HAVE_AM33
&& strcasecmp (start, "all") == 0)
{
value |= 0xff;
*input_line_pointer = c;
}
else
{
input_line_pointer = hold;
str = hold;
goto error;
}
}
input_line_pointer++;
mn10300_insert_operand (&insn, &extension, operand,
value, (char *) NULL, 0, 0);
goto keep_going;
}
else if (data_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
else if (address_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
else if (other_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
else if (HAVE_AM33 && r_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
else if (HAVE_AM33 && xr_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
else if (HAVE_AM33_2 && float_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
else if (HAVE_AM33_2 && double_register_name (&ex))
{
input_line_pointer = hold;
str = hold;
goto error;
}
else if (*str == ')' || *str == '(')
{
input_line_pointer = hold;
str = hold;
goto error;
}
else
{
expression (&ex);
}
switch (ex.X_op)
{
case O_illegal:
errmsg = _("illegal operand");
goto error;
case O_absent:
errmsg = _("missing operand");
goto error;
case O_register:
{
int mask;
mask = MN10300_OPERAND_DREG | MN10300_OPERAND_AREG;
if (HAVE_AM33)
mask |= MN10300_OPERAND_RREG | MN10300_OPERAND_XRREG;
if (HAVE_AM33_2)
mask |= MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG;
if ((operand->flags & mask) == 0)
{
input_line_pointer = hold;
str = hold;
goto error;
}
if (opcode->format == FMT_D1 || opcode->format == FMT_S1)
extra_shift = 8;
else if (opcode->format == FMT_D2
|| opcode->format == FMT_D4
|| opcode->format == FMT_S2
|| opcode->format == FMT_S4
|| opcode->format == FMT_S6
|| opcode->format == FMT_D5)
extra_shift = 16;
else if (opcode->format == FMT_D7)
extra_shift = 8;
else if (opcode->format == FMT_D8 || opcode->format == FMT_D9)
extra_shift = 8;
else
extra_shift = 0;
mn10300_insert_operand (&insn, &extension, operand,
ex.X_add_number, (char *) NULL,
0, extra_shift);
mn10300_reg_operands[op_idx - 1] = ex.X_add_number;
break;
}
case O_constant:
if (operand->flags
& (MN10300_OPERAND_PROMOTE | MN10300_OPERAND_RELAX)
&& !check_operand (insn, operand, ex.X_add_number))
{
input_line_pointer = hold;
str = hold;
goto error;
}
mn10300_insert_operand (&insn, &extension, operand,
ex.X_add_number, (char *) NULL,
0, 0);
break;
default:
if (operand->flags & MN10300_OPERAND_PROMOTE)
{
input_line_pointer = hold;
str = hold;
goto error;
}
if (fc >= MAX_INSN_FIXUPS)
as_fatal (_("too many fixups"));
fixups[fc].exp = ex;
fixups[fc].opindex = *opindex_ptr;
fixups[fc].reloc = BFD_RELOC_UNUSED;
if (mn10300_check_fixup (& fixups[fc]))
goto error;
++fc;
break;
}
keep_going:
str = input_line_pointer;
input_line_pointer = hold;
while (*str == ' ' || *str == ',')
++str;
}
if (*str != ',')
match = 1;
if (opcode->no_match_operands)
{
int i;
for (i = 0; i < MN10300_MAX_OPERANDS; i++)
{
if ((1 << i) & opcode->no_match_operands)
{
int j;
for (j = i + 1; j < MN10300_MAX_OPERANDS; j++)
{
if (((1 << j) & opcode->no_match_operands)
&& mn10300_reg_operands[i] == mn10300_reg_operands[j])
{
errmsg = _("Invalid register specification.");
match = 0;
goto error;
}
}
}
}
}
error:
if (match == 0)
{
next_opcode = opcode + 1;
if (!strcmp (next_opcode->name, opcode->name))
{
opcode = next_opcode;
continue;
}
as_bad ("%s", errmsg);
return;
}
break;
}
while (ISSPACE (*str))
++str;
if (*str != '\0')
as_bad (_("junk at end of line: `%s'"), str);
input_line_pointer = str;
if (opcode->format == FMT_S0)
size = 1;
if (opcode->format == FMT_S1 || opcode->format == FMT_D0)
size = 2;
if (opcode->format == FMT_S2 || opcode->format == FMT_D1)
size = 3;
if (opcode->format == FMT_D6)
size = 3;
if (opcode->format == FMT_D7 || opcode->format == FMT_D10)
size = 4;
if (opcode->format == FMT_D8)
size = 6;
if (opcode->format == FMT_D9)
size = 7;
if (opcode->format == FMT_S4)
size = 5;
if (opcode->format == FMT_S6 || opcode->format == FMT_D5)
size = 7;
if (opcode->format == FMT_D2)
size = 4;
if (opcode->format == FMT_D3)
size = 5;
if (opcode->format == FMT_D4)
size = 6;
if (relaxable && fc > 0)
{
int type;
f = frag_more (0);
dwarf2_emit_insn (0);
if (size == 2)
{
if (opcode->opcode == 0xca00)
type = 10;
else
type = 0;
}
else if (size == 5)
type = 6;
else if (size == 4)
type = 8;
else if (size == 3 && opcode->opcode == 0xcc0000)
type = 10;
else if (size == 3 && (opcode->opcode & 0xfff000) == 0xf8d000)
type = 13;
else
type = 3;
f = frag_var (rs_machine_dependent, 8, 8 - size, type,
fixups[0].exp.X_add_symbol,
fixups[0].exp.X_add_number,
(char *)fixups[0].opindex);
number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
if (size > 8)
{
number_to_chars_bigendian (f + 4, extension, 4);
number_to_chars_bigendian (f + 8, 0, size - 8);
}
else if (size > 4)
number_to_chars_bigendian (f + 4, extension, size - 4);
}
else
{
f = frag_more (size);
if (opcode->format == FMT_S0
|| opcode->format == FMT_S1
|| opcode->format == FMT_D0
|| opcode->format == FMT_D6
|| opcode->format == FMT_D7
|| opcode->format == FMT_D10
|| opcode->format == FMT_D1)
{
number_to_chars_bigendian (f, insn, size);
}
else if (opcode->format == FMT_S2
&& opcode->opcode != 0xdf0000
&& opcode->opcode != 0xde0000)
{
number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
}
else if (opcode->format == FMT_S2)
{
number_to_chars_bigendian (f, insn, 3);
}
else if (opcode->format == FMT_S4
&& opcode->opcode != 0xdc000000)
{
unsigned long temp = (insn >> 8) & 0xffff;
number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
number_to_chars_littleendian (f + 1, temp, 2);
number_to_chars_bigendian (f + 3, insn & 0xff, 1);
number_to_chars_bigendian (f + 4, extension & 0xff, 1);
}
else if (opcode->format == FMT_S4)
{
unsigned long temp = ((insn & 0xffffff) << 8) | (extension & 0xff);
number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
number_to_chars_littleendian (f + 1, temp, 4);
}
else if (opcode->format == FMT_S6)
{
unsigned long temp = ((insn & 0xffffff) << 8)
| ((extension >> 16) & 0xff);
number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
number_to_chars_littleendian (f + 1, temp, 4);
number_to_chars_bigendian (f + 5, (extension >> 8) & 0xff, 1);
number_to_chars_bigendian (f + 6, extension & 0xff, 1);
}
else if (opcode->format == FMT_D2
&& opcode->opcode != 0xfaf80000
&& opcode->opcode != 0xfaf00000
&& opcode->opcode != 0xfaf40000)
{
number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
}
else if (opcode->format == FMT_D2)
{
number_to_chars_bigendian (f, insn, 4);
}
else if (opcode->format == FMT_D3)
{
number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
number_to_chars_bigendian (f + 4, extension & 0xff, 1);
}
else if (opcode->format == FMT_D4)
{
unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
number_to_chars_littleendian (f + 2, temp, 4);
}
else if (opcode->format == FMT_D5)
{
unsigned long temp = (((insn & 0xffff) << 16)
| ((extension >> 8) & 0xffff));
number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
number_to_chars_littleendian (f + 2, temp, 4);
number_to_chars_bigendian (f + 6, extension & 0xff, 1);
}
else if (opcode->format == FMT_D8)
{
unsigned long temp = ((insn & 0xff) << 16) | (extension & 0xffff);
number_to_chars_bigendian (f, (insn >> 8) & 0xffffff, 3);
number_to_chars_bigendian (f + 3, (temp & 0xff), 1);
number_to_chars_littleendian (f + 4, temp >> 8, 2);
}
else if (opcode->format == FMT_D9)
{
unsigned long temp = ((insn & 0xff) << 24) | (extension & 0xffffff);
number_to_chars_bigendian (f, (insn >> 8) & 0xffffff, 3);
number_to_chars_littleendian (f + 3, temp, 4);
}
for (i = 0; i < fc; i++)
{
const struct mn10300_operand *operand;
operand = &mn10300_operands[fixups[i].opindex];
if (fixups[i].reloc != BFD_RELOC_UNUSED
&& fixups[i].reloc != BFD_RELOC_32_GOT_PCREL
&& fixups[i].reloc != BFD_RELOC_32_GOTOFF
&& fixups[i].reloc != BFD_RELOC_32_PLT_PCREL
&& fixups[i].reloc != BFD_RELOC_MN10300_GOT32)
{
reloc_howto_type *reloc_howto;
int size;
int offset;
fixS *fixP;
reloc_howto = bfd_reloc_type_lookup (stdoutput,
fixups[i].reloc);
if (!reloc_howto)
abort ();
size = bfd_get_reloc_size (reloc_howto);
if (size < 1 || size > 4)
abort ();
offset = 4 - size;
fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
size, &fixups[i].exp,
reloc_howto->pc_relative,
fixups[i].reloc);
}
else
{
int reloc, pcrel, reloc_size, offset;
fixS *fixP;
reloc = BFD_RELOC_NONE;
if (fixups[i].reloc != BFD_RELOC_UNUSED)
reloc = fixups[i].reloc;
if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
reloc_size = 32;
else if ((operand->flags & MN10300_OPERAND_24BIT) != 0)
reloc_size = 24;
else
reloc_size = operand->bits;
pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
if (reloc != BFD_RELOC_NONE)
pcrel = bfd_reloc_type_lookup (stdoutput, reloc)->pc_relative;
offset = size - (reloc_size + operand->shift) / 8;
if (reloc != BFD_RELOC_NONE)
;
else if (pcrel)
{
if (reloc_size == 32)
reloc = BFD_RELOC_32_PCREL;
else if (reloc_size == 16)
reloc = BFD_RELOC_16_PCREL;
else if (reloc_size == 8)
reloc = BFD_RELOC_8_PCREL;
else
abort ();
}
else
{
if (reloc_size == 32)
reloc = BFD_RELOC_32;
else if (reloc_size == 16)
reloc = BFD_RELOC_16;
else if (reloc_size == 8)
reloc = BFD_RELOC_8;
else
abort ();
}
reloc_size = reloc_size / 8;
if (reloc_size == 8)
reloc_size = 0;
else if (reloc_size == 16)
reloc_size = 1;
else if (reloc_size == 32)
reloc_size = 2;
fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
reloc_size, &fixups[i].exp, pcrel,
((bfd_reloc_code_real_type) reloc));
if (pcrel)
fixP->fx_offset += offset;
}
}
dwarf2_emit_insn (size);
}
}
arelent *
tc_gen_reloc (seg, fixp)
asection *seg 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,
_("reloc %d not supported by object file format"),
(int) fixp->fx_r_type);
return NULL;
}
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
if (fixp->fx_subsy
&& S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
{
fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy);
fixp->fx_subsy = 0;
}
if (fixp->fx_addsy && fixp->fx_subsy)
{
reloc->sym_ptr_ptr = NULL;
if (S_GET_SEGMENT (fixp->fx_subsy) == seg)
{
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->addend = (reloc->address - S_GET_VALUE (fixp->fx_subsy)
+ fixp->fx_offset);
switch (fixp->fx_r_type)
{
case BFD_RELOC_8:
reloc->howto = bfd_reloc_type_lookup (stdoutput,
BFD_RELOC_8_PCREL);
return reloc;
case BFD_RELOC_16:
reloc->howto = bfd_reloc_type_lookup (stdoutput,
BFD_RELOC_16_PCREL);
return reloc;
case BFD_RELOC_24:
reloc->howto = bfd_reloc_type_lookup (stdoutput,
BFD_RELOC_24_PCREL);
return reloc;
case BFD_RELOC_32:
reloc->howto = bfd_reloc_type_lookup (stdoutput,
BFD_RELOC_32_PCREL);
return reloc;
default:
break;
}
}
if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
|| S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
"Difference of symbols in different sections is not supported");
}
else
{
char *fixpos = fixp->fx_where + fixp->fx_frag->fr_literal;
reloc->addend = (S_GET_VALUE (fixp->fx_addsy)
- S_GET_VALUE (fixp->fx_subsy) + fixp->fx_offset);
switch (fixp->fx_r_type)
{
case BFD_RELOC_8:
md_number_to_chars (fixpos, reloc->addend, 1);
break;
case BFD_RELOC_16:
md_number_to_chars (fixpos, reloc->addend, 2);
break;
case BFD_RELOC_24:
md_number_to_chars (fixpos, reloc->addend, 3);
break;
case BFD_RELOC_32:
md_number_to_chars (fixpos, reloc->addend, 4);
break;
default:
reloc->sym_ptr_ptr = (asymbol **) &bfd_abs_symbol;
return reloc;
}
}
if (reloc->sym_ptr_ptr)
free (reloc->sym_ptr_ptr);
free (reloc);
return NULL;
}
else
{
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->addend = fixp->fx_offset;
}
return reloc;
}
int
md_estimate_size_before_relax (fragp, seg)
fragS *fragp;
asection *seg;
{
if (fragp->fr_subtype == 6
&& (!S_IS_DEFINED (fragp->fr_symbol)
|| seg != S_GET_SEGMENT (fragp->fr_symbol)))
fragp->fr_subtype = 7;
else if (fragp->fr_subtype == 8
&& (!S_IS_DEFINED (fragp->fr_symbol)
|| seg != S_GET_SEGMENT (fragp->fr_symbol)))
fragp->fr_subtype = 9;
else if (fragp->fr_subtype == 10
&& (!S_IS_DEFINED (fragp->fr_symbol)
|| seg != S_GET_SEGMENT (fragp->fr_symbol)))
fragp->fr_subtype = 12;
if (fragp->fr_subtype == 13)
return 3;
if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
abort ();
return md_relax_table[fragp->fr_subtype].rlx_length;
}
long
md_pcrel_from (fixp)
fixS *fixp;
{
if (fixp->fx_addsy != (symbolS *) NULL && !S_IS_DEFINED (fixp->fx_addsy))
{
return 0;
}
return fixp->fx_frag->fr_address + fixp->fx_where;
}
void
md_apply_fix3 (fixP, valP, seg)
fixS * fixP;
valueT * valP;
segT seg;
{
char * fixpos = fixP->fx_where + fixP->fx_frag->fr_literal;
int size = 0;
int value = (int) * valP;
assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
if (seg->flags & SEC_ALLOC)
abort ();
if (fixP->fx_addsy != (symbolS *) NULL && ! fixP->fx_pcrel)
value = fixP->fx_offset;
if (fixP->fx_addsy != NULL
&& (! S_IS_DEFINED (fixP->fx_addsy)
|| (S_GET_SEGMENT (fixP->fx_addsy) != seg)))
{
fixP->fx_done = 0;
return;
}
switch (fixP->fx_r_type)
{
case BFD_RELOC_8:
case BFD_RELOC_8_PCREL:
size = 1;
break;
case BFD_RELOC_16:
case BFD_RELOC_16_PCREL:
size = 2;
break;
case BFD_RELOC_32:
case BFD_RELOC_32_PCREL:
size = 4;
break;
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
fixP->fx_done = 0;
return;
case BFD_RELOC_NONE:
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
_("Bad relocation fixup type (%d)"), fixP->fx_r_type);
}
md_number_to_chars (fixpos, value, size);
if (fixP->fx_addsy == NULL)
fixP->fx_done = 1;
}
bfd_boolean
mn10300_fix_adjustable (fixp)
struct fix *fixp;
{
if (! TC_RELOC_RTSYM_LOC_FIXUP (fixp))
return 0;
if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 0;
if (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_CODE)
return 0;
if (! (S_GET_SEGMENT(fixp->fx_addsy)->flags & SEC_MERGE))
return 0;
if (strncmp (S_GET_SEGMENT (fixp->fx_addsy)->name, ".debug", 6) == 0)
return 0;
return 1;
}
static void
mn10300_insert_operand (insnp, extensionp, operand, val, file, line, shift)
unsigned long *insnp;
unsigned long *extensionp;
const struct mn10300_operand *operand;
offsetT val;
char *file;
unsigned int line;
unsigned int shift;
{
if (operand->bits != 32
&& (operand->flags & MN10300_OPERAND_SPLIT) == 0)
{
long min, max;
offsetT test;
int bits;
bits = operand->bits;
if (operand->flags & MN10300_OPERAND_24BIT)
bits = 24;
if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
{
max = (1 << (bits - 1)) - 1;
min = - (1 << (bits - 1));
}
else
{
max = (1 << bits) - 1;
min = 0;
}
test = val;
if (test < (offsetT) min || test > (offsetT) max)
as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
}
if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
{
*insnp |= (val >> (32 - operand->bits)) & ((1 << operand->bits) - 1);
*extensionp |= ((val & ((1 << (32 - operand->bits)) - 1))
<< operand->shift);
}
else if ((operand->flags & MN10300_OPERAND_24BIT) != 0)
{
*insnp |= (val >> (24 - operand->bits)) & ((1 << operand->bits) - 1);
*extensionp |= ((val & ((1 << (24 - operand->bits)) - 1))
<< operand->shift);
}
else if ((operand->flags & (MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG)))
{
unsigned long mask_low, mask_high;
int shl_low, shr_high, shl_high;
switch (operand->bits)
{
case 5:
if (operand->shift >= 0)
{
shl_low = operand->shift;
shl_high = 8 + (8 & shl_low) + (shl_low & 4) / 4;
}
else
{
shl_low = -operand->shift;
shl_high = shl_low / 4;
}
mask_low = 0x0f;
mask_high = 0x10;
shr_high = 4;
break;
case 3:
shl_low = -operand->shift;
shl_high = 0;
mask_low = 0x03;
mask_high = 0x04;
shr_high = 2;
break;
default:
abort ();
}
*insnp |= ((((val & mask_high) >> shr_high) << shl_high)
| ((val & mask_low) << shl_low));
}
else if ((operand->flags & MN10300_OPERAND_EXTENDED) == 0)
{
*insnp |= (((long) val & ((1 << operand->bits) - 1))
<< (operand->shift + shift));
if ((operand->flags & MN10300_OPERAND_REPEATED) != 0)
*insnp |= (((long) val & ((1 << operand->bits) - 1))
<< (operand->shift + shift + operand->bits));
}
else
{
*extensionp |= (((long) val & ((1 << operand->bits) - 1))
<< (operand->shift + shift));
if ((operand->flags & MN10300_OPERAND_REPEATED) != 0)
*extensionp |= (((long) val & ((1 << operand->bits) - 1))
<< (operand->shift + shift + operand->bits));
}
}
static unsigned long
check_operand (insn, operand, val)
unsigned long insn ATTRIBUTE_UNUSED;
const struct mn10300_operand *operand;
offsetT val;
{
if (operand->bits != 32
&& (operand->flags & MN10300_OPERAND_SPLIT) == 0)
{
long min, max;
offsetT test;
int bits;
bits = operand->bits;
if (operand->flags & MN10300_OPERAND_24BIT)
bits = 24;
if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
{
max = (1 << (bits - 1)) - 1;
min = - (1 << (bits - 1));
}
else
{
max = (1 << bits) - 1;
min = 0;
}
test = val;
if (test < (offsetT) min || test > (offsetT) max)
return 0;
else
return 1;
}
return 1;
}
static void
set_arch_mach (mach)
int mach;
{
if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, mach))
as_warn (_("could not set architecture and machine"));
current_machine = mach;
}
static inline char * mn10300_end_of_match PARAMS ((char *, char *));
static inline char *
mn10300_end_of_match (cont, what)
char *cont, *what;
{
int len = strlen (what);
if (strncmp (cont, what, strlen (what)) == 0
&& ! is_part_of_name (cont[len]))
return cont + len;
return NULL;
}
int
mn10300_parse_name (name, exprP, nextcharP)
char const *name;
expressionS *exprP;
char *nextcharP;
{
char *next = input_line_pointer;
char *next_end;
int reloc_type;
segT segment;
exprP->X_op_symbol = NULL;
if (strcmp (name, GLOBAL_OFFSET_TABLE_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 = mn10300_end_of_match (next + 1, "GOTOFF")))
reloc_type = BFD_RELOC_32_GOTOFF;
else if ((next_end = mn10300_end_of_match (next + 1, "GOT")))
reloc_type = BFD_RELOC_MN10300_GOT32;
else if ((next_end = mn10300_end_of_match (next + 1, "PLT")))
reloc_type = BFD_RELOC_32_PLT_PCREL;
else
goto no_suffix;
*input_line_pointer = *nextcharP;
input_line_pointer = next_end;
*nextcharP = *input_line_pointer;
*input_line_pointer = '\0';
exprP->X_op = O_PIC_reloc;
exprP->X_add_number = 0;
exprP->X_md = reloc_type;
return 1;
}