-/* tc-sh.c -- Assemble code for the Hitachi Super-H
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
- Free Software Foundation, Inc.
+/* tc-sh.c -- Assemble code for the Renesas / SuperH SH
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#endif
#include "dwarf2dbg.h"
+#include "dw2gencfi.h"
typedef struct
{
const char line_separator_chars[] = ";";
const char line_comment_chars[] = "!#";
-static void s_uses PARAMS ((int));
-
-static void sh_count_relocs PARAMS ((bfd *, segT, PTR));
-static void sh_frob_section PARAMS ((bfd *, segT, PTR));
-
-static void s_uacons PARAMS ((int));
-static sh_opcode_info *find_cooked_opcode PARAMS ((char **));
-static unsigned int assemble_ppi PARAMS ((char *, sh_opcode_info *));
-static void little PARAMS ((int));
-static void big PARAMS ((int));
-static int parse_reg PARAMS ((char *, int *, int *));
-static char *parse_exp PARAMS ((char *, sh_operand_info *));
-static char *parse_at PARAMS ((char *, sh_operand_info *));
-static void get_operand PARAMS ((char **, sh_operand_info *));
-static char *get_operands
- PARAMS ((sh_opcode_info *, char *, sh_operand_info *));
-static sh_opcode_info *get_specific
- PARAMS ((sh_opcode_info *, sh_operand_info *));
-static void insert PARAMS ((char *, int, int, sh_operand_info *));
-static void build_relax PARAMS ((sh_opcode_info *, sh_operand_info *));
-static char *insert_loop_bounds PARAMS ((char *, sh_operand_info *));
-static unsigned int build_Mytes
- PARAMS ((sh_opcode_info *, sh_operand_info *));
-static boolean sh_local_pcrel PARAMS ((fixS *fix));
+static void s_uses (int);
+static void s_uacons (int);
#ifdef OBJ_ELF
-static void sh_elf_cons PARAMS ((int));
-
-inline static int sh_PIC_related_p PARAMS ((symbolS *));
-static int sh_check_fixup PARAMS ((expressionS *, bfd_reloc_code_real_type *));
-inline static char *sh_end_of_match PARAMS ((char *, char *));
+static void sh_elf_cons (int);
symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
#endif
static void
-big (ignore)
- int ignore ATTRIBUTE_UNUSED;
+big (int ignore ATTRIBUTE_UNUSED)
{
if (! target_big_endian)
as_bad (_("directive .big encountered when option -big required"));
}
static void
-little (ignore)
- int ignore ATTRIBUTE_UNUSED;
+little (int ignore ATTRIBUTE_UNUSED)
{
if (target_big_endian)
as_bad (_("directive .little encountered when option -little required"));
{"2byte", s_uacons, 2},
{"4byte", s_uacons, 4},
{"8byte", s_uacons, 8},
-#ifdef BFD_ASSEMBLER
- {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
- {"loc", dwarf2_directive_loc, 0 },
-#endif
#ifdef HAVE_SH64
{"mode", s_sh64_mode, 0 },
int sh_small;
-/* Whether -dsp was seen. */
+/* Flag to generate relocations against symbol values for local symbols. */
-static int sh_dsp;
+static int dont_adjust_reloc_32;
+
+/* preset architecture set, if given; zero otherwise. */
+
+static unsigned int preset_target_arch;
/* The bit mask of architectures that could
- accomodate the insns seen so far. */
-static int valid_arch;
+ accommodate the insns seen so far. */
+static unsigned int valid_arch;
const char EXP_CHARS[] = "eE";
#define ENCODE_RELAX(what,length) (((what) << 4) + (length))
#define GET_WHAT(x) ((x>>4))
-/* These are the three types of relaxable instrction. */
+/* These are the three types of relaxable instruction. */
/* These are the types of relaxable instructions; except for END which is
a marker. */
#define COND_JUMP 1
/* Determinet whether the symbol needs any kind of PIC relocation. */
inline static int
-sh_PIC_related_p (sym)
- symbolS *sym;
+sh_PIC_related_p (symbolS *sym)
{
expressionS *exp;
expression, that may be rearranged. */
static int
-sh_check_fixup (main_exp, r_type_p)
- expressionS *main_exp;
- bfd_reloc_code_real_type *r_type_p;
+sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
{
expressionS *exp = main_exp;
/* Add expression EXP of SIZE bytes to offset OFF of fragment FRAG. */
void
-sh_cons_fix_new (frag, off, size, exp)
- fragS *frag;
- int off, size;
- expressionS *exp;
+sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
{
bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED;
suffixes such as @GOT, @GOTOFF and @PLT, that generate
machine-specific relocation types. So we must define it here. */
/* Clobbers input_line_pointer, checks end-of-line. */
+/* NBYTES 1=.byte, 2=.word, 4=.long */
static void
-sh_elf_cons (nbytes)
- register int nbytes; /* 1=.byte, 2=.word, 4=.long */
+sh_elf_cons (register int nbytes)
{
expressionS exp;
#ifdef HAVE_SH64
/* Update existing range to include a previous insn, if there was one. */
- sh64_update_contents_mark (true);
+ sh64_update_contents_mark (TRUE);
/* We need to make sure the contents type is set to data. */
sh64_flag_output ();
return;
}
+#ifdef md_cons_align
+ md_cons_align (nbytes);
+#endif
+
do
{
expression (&exp);
set up all the tables, etc that the MD part of the assembler needs. */
void
-md_begin ()
+md_begin (void)
{
const sh_opcode_info *opcode;
char *prev_name = "";
- int target_arch;
+ unsigned int target_arch;
- target_arch = arch_sh1_up & ~(sh_dsp ? arch_sh3e_up : arch_sh_dsp_up);
+ target_arch
+ = preset_target_arch ? preset_target_arch : arch_sh_up & ~arch_sh_has_dsp;
valid_arch = target_arch;
#ifdef HAVE_SH64
{
if (strcmp (prev_name, opcode->name) != 0)
{
- if (! (opcode->arch & target_arch))
+ if (!SH_MERGE_ARCH_SET_VALID (opcode->arch, target_arch))
continue;
prev_name = opcode->name;
hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
/* Try to parse a reg name. Return the number of chars consumed. */
static int
-parse_reg (src, mode, reg)
- char *src;
- int *mode;
- int *reg;
+parse_reg (char *src, int *mode, int *reg)
{
char l0 = TOLOWER (src[0]);
char l1 = l0 ? TOLOWER (src[1]) : 0;
return 3;
}
+ if (l0 == 't' && l1 == 'b' && TOLOWER (src[2]) == 'r'
+ && ! IDENT_CHAR ((unsigned char) src[3]))
+ {
+ *mode = A_TBR;
+ return 3;
+ }
if (l0 == 'm' && l1 == 'a' && TOLOWER (src[2]) == 'c'
&& ! IDENT_CHAR ((unsigned char) src[4]))
{
}
static char *
-parse_exp (s, op)
- char *s;
- sh_operand_info *op;
+parse_exp (char *s, sh_operand_info *op)
{
char *save;
char *new;
*/
static char *
-parse_at (src, op)
- char *src;
- sh_operand_info *op;
+parse_at (char *src, sh_operand_info *op)
{
int len;
int mode;
src++;
- if (src[0] == '-')
+ if (src[0] == '@')
+ {
+ src = parse_at (src, op);
+ if (op->type == A_DISP_TBR)
+ op->type = A_DISP2_TBR;
+ else
+ as_bad (_("illegal double indirection"));
+ }
+ else if (src[0] == '-')
{
/* Must be predecrement. */
src++;
{
op->type = A_DISP_GBR;
}
+ else if (mode == A_TBR)
+ {
+ op->type = A_DISP_TBR;
+ }
else if (mode == A_PC)
{
/* We want @(expr, pc) to uniformly address . + expr,
no matter if expr is a constant, or a more complex
expression, e.g. sym-. or sym1-sym2.
However, we also used to accept @(sym,pc)
- as adressing sym, i.e. meaning the same as plain sym.
+ as addressing sym, i.e. meaning the same as plain sym.
Some existing code does use the @(sym,pc) syntax, so
we give it the old semantics for now, but warn about
its use, so that users have some time to fix their code.
|| (l0 == 'i' && (l1 == 'x' || l1 == 's')))
{
src += 2;
- op->type = A_PMOD_N;
+ op->type = AX_PMOD_N;
}
else if ( (l0 == 'r' && l1 == '9')
|| (l0 == 'i' && l1 == 'y'))
{
src += 2;
- op->type = A_PMODY_N;
+ op->type = AY_PMOD_N;
}
else
op->type = A_INC_N;
}
static void
-get_operand (ptr, op)
- char **ptr;
- sh_operand_info *op;
+get_operand (char **ptr, sh_operand_info *op)
{
char *src = *ptr;
int mode = -1;
}
static char *
-get_operands (info, args, operand)
- sh_opcode_info *info;
- char *args;
- sh_operand_info *operand;
+get_operands (sh_opcode_info *info, char *args, sh_operand_info *operand)
{
char *ptr = args;
if (info->arg[0])
provided. */
static sh_opcode_info *
-get_specific (opcode, operands)
- sh_opcode_info *opcode;
- sh_operand_info *operands;
+get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
{
sh_opcode_info *this_try = opcode;
char *name = opcode->name;
sh_operand_info *user = operands + n;
sh_arg_type arg = this_try->arg[n];
+ if (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh2a_nofpu_up)
+ && ( arg == A_DISP_REG_M
+ || arg == A_DISP_REG_N))
+ {
+ /* Check a few key IMM* fields for overflow. */
+ int opf;
+ long val = user->immediate.X_add_number;
+
+ for (opf = 0; opf < 4; opf ++)
+ switch (this_try->nibbles[opf])
+ {
+ case IMM0_4:
+ case IMM1_4:
+ if (val < 0 || val > 15)
+ goto fail;
+ break;
+ case IMM0_4BY2:
+ case IMM1_4BY2:
+ if (val < 0 || val > 15 * 2)
+ goto fail;
+ break;
+ case IMM0_4BY4:
+ case IMM1_4BY4:
+ if (val < 0 || val > 15 * 4)
+ goto fail;
+ break;
+ default:
+ break;
+ }
+ }
switch (arg)
{
case A_DISP_PC:
case A_BDISP12:
case A_BDISP8:
case A_DISP_GBR:
+ case A_DISP2_TBR:
case A_MACH:
case A_PR:
case A_MACL:
case V_REG_N:
case FPUL_N:
case FPSCR_N:
- case A_PMOD_N:
- case A_PMODY_N:
case DSP_REG_N:
/* Opcode needs rn */
if (user->type != arg)
reg_n = user->reg;
break;
case A_GBR:
+ case A_TBR:
case A_SR:
case A_VBR:
case A_DSR:
reg_b = user->reg;
break;
+ case A_INC_R15:
+ if (user->type != A_INC_N)
+ goto fail;
+ if (user->reg != 15)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case A_DEC_R15:
+ if (user->type != A_DEC_N)
+ goto fail;
+ if (user->reg != 15)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
case A_REG_M:
case A_INC_M:
case A_DEC_M:
reg_m = user->reg;
break;
+ case AS_DEC_N:
+ if (user->type != A_DEC_N)
+ goto fail;
+ if (user->reg < 2 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AS_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if (user->reg < 2 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AS_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if (user->reg < 2 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AS_PMOD_N:
+ if (user->type != AX_PMOD_N)
+ goto fail;
+ if (user->reg < 2 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AX_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if (user->reg < 4 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AX_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if (user->reg < 4 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AX_PMOD_N:
+ if (user->type != AX_PMOD_N)
+ goto fail;
+ if (user->reg < 4 || user->reg > 5)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AXY_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if ((user->reg < 4 || user->reg > 5)
+ && (user->reg < 0 || user->reg > 1))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AXY_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if ((user->reg < 4 || user->reg > 5)
+ && (user->reg < 0 || user->reg > 1))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AXY_PMOD_N:
+ if (user->type != AX_PMOD_N)
+ goto fail;
+ if ((user->reg < 4 || user->reg > 5)
+ && (user->reg < 0 || user->reg > 1))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AY_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if (user->reg < 6 || user->reg > 7)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AY_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if (user->reg < 6 || user->reg > 7)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AY_PMOD_N:
+ if (user->type != AY_PMOD_N)
+ goto fail;
+ if (user->reg < 6 || user->reg > 7)
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AYX_INC_N:
+ if (user->type != A_INC_N)
+ goto fail;
+ if ((user->reg < 6 || user->reg > 7)
+ && (user->reg < 2 || user->reg > 3))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AYX_IND_N:
+ if (user->type != A_IND_N)
+ goto fail;
+ if ((user->reg < 6 || user->reg > 7)
+ && (user->reg < 2 || user->reg > 3))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case AYX_PMOD_N:
+ if (user->type != AY_PMOD_N)
+ goto fail;
+ if ((user->reg < 6 || user->reg > 7)
+ && (user->reg < 2 || user->reg > 3))
+ goto fail;
+ reg_n = user->reg;
+ break;
+
+ case DSP_REG_A_M:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ if (user->reg != A_A0_NUM
+ && user->reg != A_A1_NUM)
+ goto fail;
+ reg_m = user->reg;
+ break;
+
+ case DSP_REG_AX:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_A0_NUM:
+ reg_x = 0;
+ break;
+ case A_A1_NUM:
+ reg_x = 2;
+ break;
+ case A_X0_NUM:
+ reg_x = 1;
+ break;
+ case A_X1_NUM:
+ reg_x = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_XY:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_X0_NUM:
+ reg_x = 0;
+ break;
+ case A_X1_NUM:
+ reg_x = 2;
+ break;
+ case A_Y0_NUM:
+ reg_x = 1;
+ break;
+ case A_Y1_NUM:
+ reg_x = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_AY:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_A0_NUM:
+ reg_y = 0;
+ break;
+ case A_A1_NUM:
+ reg_y = 1;
+ break;
+ case A_Y0_NUM:
+ reg_y = 2;
+ break;
+ case A_Y1_NUM:
+ reg_y = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ case DSP_REG_YX:
+ if (user->type != DSP_REG_N)
+ goto fail;
+ switch (user->reg)
+ {
+ case A_Y0_NUM:
+ reg_y = 0;
+ break;
+ case A_Y1_NUM:
+ reg_y = 1;
+ break;
+ case A_X0_NUM:
+ reg_y = 2;
+ break;
+ case A_X1_NUM:
+ reg_y = 3;
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
case DSP_REG_X:
if (user->type != DSP_REG_N)
goto fail;
goto fail;
}
}
- if ( !(valid_arch & this_try->arch))
+ if ( !SH_MERGE_ARCH_SET_VALID (valid_arch, this_try->arch))
goto fail;
- valid_arch &= this_try->arch;
+ valid_arch = SH_MERGE_ARCH_SET (valid_arch, this_try->arch);
return this_try;
fail:
;
}
static void
-insert (where, how, pcrel, op)
- char *where;
- int how;
- int pcrel;
- sh_operand_info *op;
+insert (char *where, int how, int pcrel, sh_operand_info *op)
{
fix_new_exp (frag_now,
where - frag_now->fr_literal,
}
static void
-build_relax (opcode, op)
- sh_opcode_info *opcode;
- sh_operand_info *op;
+insert4 (char * where, int how, int pcrel, sh_operand_info * op)
+{
+ fix_new_exp (frag_now,
+ where - frag_now->fr_literal,
+ 4,
+ & op->immediate,
+ pcrel,
+ how);
+}
+static void
+build_relax (sh_opcode_info *opcode, sh_operand_info *op)
{
int high_byte = target_big_endian ? 0 : 1;
char *p;
/* Insert ldrs & ldre with fancy relocations that relaxation can recognize. */
static char *
-insert_loop_bounds (output, operand)
- char *output;
- sh_operand_info *operand;
+insert_loop_bounds (char *output, sh_operand_info *operand)
{
char *name;
symbolS *end_sym;
/* Now we know what sort of opcodes it is, let's build the bytes. */
static unsigned int
-build_Mytes (opcode, operand)
- sh_opcode_info *opcode;
- sh_operand_info *operand;
+build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
{
int index;
- char nbuf[4];
- char *output = frag_more (2);
+ char nbuf[8];
+ char *output;
unsigned int size = 2;
int low_byte = target_big_endian ? 1 : 0;
+ int max_index = 4;
+
nbuf[0] = 0;
nbuf[1] = 0;
nbuf[2] = 0;
nbuf[3] = 0;
+ nbuf[4] = 0;
+ nbuf[5] = 0;
+ nbuf[6] = 0;
+ nbuf[7] = 0;
- for (index = 0; index < 4; index++)
+ if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
+ {
+ output = frag_more (4);
+ size = 4;
+ max_index = 8;
+ }
+ else
+ output = frag_more (2);
+
+ for (index = 0; index < max_index; index++)
{
sh_nibble_type i = opcode->nibbles[index];
if (i < 16)
switch (i)
{
case REG_N:
+ case REG_N_D:
nbuf[index] = reg_n;
break;
case REG_M:
case REG_B:
nbuf[index] = reg_b | 0x08;
break;
+ case REG_N_B01:
+ nbuf[index] = reg_n | 0x01;
+ break;
+ case IMM0_3s:
+ nbuf[index] |= 0x08;
+ case IMM0_3c:
+ insert (output + low_byte, BFD_RELOC_SH_IMM3, 0, operand);
+ break;
+ case IMM0_3Us:
+ nbuf[index] |= 0x80;
+ case IMM0_3Uc:
+ insert (output + low_byte, BFD_RELOC_SH_IMM3U, 0, operand);
+ break;
+ case DISP0_12:
+ insert (output + 2, BFD_RELOC_SH_DISP12, 0, operand);
+ break;
+ case DISP0_12BY2:
+ insert (output + 2, BFD_RELOC_SH_DISP12BY2, 0, operand);
+ break;
+ case DISP0_12BY4:
+ insert (output + 2, BFD_RELOC_SH_DISP12BY4, 0, operand);
+ break;
+ case DISP0_12BY8:
+ insert (output + 2, BFD_RELOC_SH_DISP12BY8, 0, operand);
+ break;
+ case DISP1_12:
+ insert (output + 2, BFD_RELOC_SH_DISP12, 0, operand+1);
+ break;
+ case DISP1_12BY2:
+ insert (output + 2, BFD_RELOC_SH_DISP12BY2, 0, operand+1);
+ break;
+ case DISP1_12BY4:
+ insert (output + 2, BFD_RELOC_SH_DISP12BY4, 0, operand+1);
+ break;
+ case DISP1_12BY8:
+ insert (output + 2, BFD_RELOC_SH_DISP12BY8, 0, operand+1);
+ break;
+ case IMM0_20_4:
+ break;
+ case IMM0_20:
+ insert4 (output, BFD_RELOC_SH_DISP20, 0, operand);
+ break;
+ case IMM0_20BY8:
+ insert4 (output, BFD_RELOC_SH_DISP20BY8, 0, operand);
+ break;
case IMM0_4BY4:
insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0, operand);
break;
output[0] = (nbuf[0] << 4) | (nbuf[1]);
output[1] = (nbuf[2] << 4) | (nbuf[3]);
}
+ if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
+ {
+ if (!target_big_endian)
+ {
+ output[3] = (nbuf[4] << 4) | (nbuf[5]);
+ output[2] = (nbuf[6] << 4) | (nbuf[7]);
+ }
+ else
+ {
+ output[2] = (nbuf[4] << 4) | (nbuf[5]);
+ output[3] = (nbuf[6] << 4) | (nbuf[7]);
+ }
+ }
return size;
}
*STR_P to the first character after the last one read. */
static sh_opcode_info *
-find_cooked_opcode (str_p)
- char **str_p;
+find_cooked_opcode (char **str_p)
{
char *str = *str_p;
unsigned char *op_start;
#define DDT_BASE 0xf000 /* Base value for double data transfer insns */
static unsigned int
-assemble_ppi (op_end, opcode)
- char *op_end;
- sh_opcode_info *opcode;
+assemble_ppi (char *op_end, sh_opcode_info *opcode)
{
int movx = 0;
int movy = 0;
if (opcode->arg[0] != A_END)
op_end = get_operands (opcode, op_end, operand);
+ try_another_opcode:
opcode = get_specific (opcode, operand);
if (opcode == 0)
{
movy = DDT_BASE;
break;
+ case MOVX_NOPY:
+ if (movx)
+ as_bad (_("multiple movx specifications"));
+ if ((reg_n < 4 || reg_n > 5)
+ && (reg_n < 0 || reg_n > 1))
+ as_bad (_("invalid movx address register"));
+ if (movy && movy != DDT_BASE)
+ as_bad (_("insn cannot be combined with non-nopy"));
+ movx = ((((reg_n & 1) != 0) << 9)
+ + (((reg_n & 4) == 0) << 8)
+ + (reg_x << 6)
+ + (opcode->nibbles[2] << 4)
+ + opcode->nibbles[3]
+ + DDT_BASE);
+ break;
+
+ case MOVY_NOPX:
+ if (movy)
+ as_bad (_("multiple movy specifications"));
+ if ((reg_n < 6 || reg_n > 7)
+ && (reg_n < 2 || reg_n > 3))
+ as_bad (_("invalid movy address register"));
+ if (movx && movx != DDT_BASE)
+ as_bad (_("insn cannot be combined with non-nopx"));
+ movy = ((((reg_n & 1) != 0) << 8)
+ + (((reg_n & 4) == 0) << 9)
+ + (reg_y << 6)
+ + (opcode->nibbles[2] << 4)
+ + opcode->nibbles[3]
+ + DDT_BASE);
+ break;
+
case MOVX:
if (movx)
as_bad (_("multiple movx specifications"));
+ if (movy & 0x2ac)
+ as_bad (_("previous movy requires nopx"));
if (reg_n < 4 || reg_n > 5)
as_bad (_("invalid movx address register"));
if (opcode->nibbles[2] & 8)
case MOVY:
if (movy)
as_bad (_("multiple movy specifications"));
+ if (movx & 0x153)
+ as_bad (_("previous movx requires nopy"));
if (opcode->nibbles[2] & 8)
{
/* Bit 3 in nibbles[2] is intended for bit 4 of the opcode,
| (operand[0].immediate.X_add_number & 127) << 4
| reg_n);
break;
+ case PPI3NC:
+ if (cond)
+ {
+ opcode++;
+ goto try_another_opcode;
+ }
+ /* Fall through. */
case PPI3:
if (field_b)
as_bad (_("multiple parallel processing specifications"));
field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
+ (reg_x << 6) + (reg_y << 4) + reg_n);
+ switch (opcode->nibbles[4])
+ {
+ case HEX_0:
+ case HEX_XX00:
+ case HEX_00YY:
+ break;
+ case HEX_1:
+ case HEX_4:
+ field_b += opcode->nibbles[4] << 4;
+ break;
+ default:
+ abort ();
+ }
break;
case PDC:
if (cond)
field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
+ cond + (reg_x << 6) + (reg_y << 4) + reg_n);
cond = 0;
+ switch (opcode->nibbles[4])
+ {
+ case HEX_0:
+ case HEX_XX00:
+ case HEX_00YY:
+ break;
+ case HEX_1:
+ case HEX_4:
+ field_b += opcode->nibbles[4] << 4;
+ break;
+ default:
+ abort ();
+ }
break;
case PMUL:
if (field_b)
{
- if ((field_b & 0xef00) != 0xa100)
+ if ((field_b & 0xef00) == 0xa100)
+ field_b -= 0x8100;
+ /* pclr Dz pmuls Se,Sf,Dg */
+ else if ((field_b & 0xff00) == 0x8d00
+ && (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh4al_dsp_up)))
+ {
+ valid_arch = SH_MERGE_ARCH_SET (valid_arch, arch_sh4al_dsp_up);
+ field_b -= 0x8cf0;
+ }
+ else
as_bad (_("insn cannot be combined with pmuls"));
- field_b -= 0x8100;
switch (field_b & 0xf)
{
case A_X0_NUM:
field_b += 3 - A_A1_NUM;
break;
default:
- as_bad (_("bad padd / psub pmuls output operand"));
+ as_bad (_("bad combined pmuls output operand"));
}
/* Generate warning if the destination register for padd / psub
and pmuls is the same ( only for A0 or A1 ).
the frags/bytes it assembles to. */
void
-md_assemble (str)
- char *str;
+md_assemble (char *str)
{
unsigned char *op_end;
sh_operand_info operand[3];
sh_opcode_info *opcode;
unsigned int size = 0;
+ char *initial_str = str;
#ifdef HAVE_SH64
if (sh64_isa_mode == sh64_isa_shmedia)
{
/* If we've seen pseudo-directives, make sure any emitted data or
frags are marked as data. */
- if (seen_insn == false)
+ if (!seen_insn)
{
- sh64_update_contents_mark (true);
+ sh64_update_contents_mark (TRUE);
sh64_set_contents_type (CRT_SH5_ISA16);
}
- seen_insn = true;
+ seen_insn = TRUE;
}
#endif /* HAVE_SH64 */
if (opcode == NULL)
{
- as_bad (_("unknown opcode"));
+ /* The opcode is not in the hash table.
+ This means we definately have an assembly failure,
+ but the instruction may be valid in another CPU variant.
+ In this case emit something better than 'unknown opcode'.
+ Search the full table in sh-opc.h to check. */
+
+ char *name = initial_str;
+ int name_length = 0;
+ const sh_opcode_info *op;
+ int found = 0;
+
+ /* identify opcode in string */
+ while (ISSPACE (*name))
+ {
+ name++;
+ }
+ while (!ISSPACE (name[name_length]))
+ {
+ name_length++;
+ }
+
+ /* search for opcode in full list */
+ for (op = sh_table; op->name; op++)
+ {
+ if (strncasecmp (op->name, name, name_length) == 0
+ && op->name[name_length] == '\0')
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if ( found )
+ {
+ as_bad (_("opcode not valid for this cpu variant"));
+ }
+ else
+ {
+ as_bad (_("unknown opcode"));
+ }
return;
}
if (opcode->arg[0] == A_BDISP12
|| opcode->arg[0] == A_BDISP8)
{
+ /* Since we skip get_specific here, we have to check & update
+ valid_arch now. */
+ if (SH_MERGE_ARCH_SET_VALID (valid_arch, opcode->arch))
+ valid_arch = SH_MERGE_ARCH_SET (valid_arch, opcode->arch);
+ else
+ as_bad (_("Delayed branches not available on SH1"));
parse_exp (op_end + 1, &operand[0]);
build_relax (opcode, &operand[0]);
}
emits a BFD_RELOC_SH_LABEL reloc if necessary. */
void
-sh_frob_label ()
+sh_frob_label (void)
{
static fragS *last_label_frag;
static int last_label_offset;
data. It emits a BFD_RELOC_SH_DATA reloc if necessary. */
void
-sh_flush_pending_output ()
+sh_flush_pending_output (void)
{
if (sh_relax
&& seg_info (now_seg)->tc_segment_info_data.in_code)
}
symbolS *
-md_undefined_symbol (name)
- char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
return 0;
}
#ifndef BFD_ASSEMBLER
void
-tc_crawl_symbol_chain (headers)
- object_headers *headers ATTRIBUTE_UNUSED;
+tc_crawl_symbol_chain (object_headers *headers ATTRIBUTE_UNUSED)
{
printf (_("call to tc_crawl_symbol_chain \n"));
}
void
-tc_headers_hook (headers)
- object_headers *headers ATTRIBUTE_UNUSED;
+tc_headers_hook (object_headers *headers ATTRIBUTE_UNUSED)
{
printf (_("call to tc_headers_hook \n"));
}
returned, or NULL on OK. */
char *
-md_atof (type, litP, sizeP)
- int type;
- char *litP;
- int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
{
int prec;
LITTLENUM_TYPE words[4];
special reloc for the linker. */
static void
-s_uses (ignore)
- int ignore ATTRIBUTE_UNUSED;
+s_uses (int ignore ATTRIBUTE_UNUSED)
{
expressionS ex;
#define OPTION_LITTLE (OPTION_BIG + 1)
#define OPTION_SMALL (OPTION_LITTLE + 1)
#define OPTION_DSP (OPTION_SMALL + 1)
+#define OPTION_ISA (OPTION_DSP + 1)
+#define OPTION_RENESAS (OPTION_ISA + 1)
{"relax", no_argument, NULL, OPTION_RELAX},
{"big", no_argument, NULL, OPTION_BIG},
{"little", no_argument, NULL, OPTION_LITTLE},
{"small", no_argument, NULL, OPTION_SMALL},
{"dsp", no_argument, NULL, OPTION_DSP},
+ {"isa", required_argument, NULL, OPTION_ISA},
+ {"renesas", no_argument, NULL, OPTION_RENESAS},
+
#ifdef HAVE_SH64
-#define OPTION_ISA (OPTION_DSP + 1)
-#define OPTION_ABI (OPTION_ISA + 1)
+#define OPTION_ABI (OPTION_RENESAS + 1)
#define OPTION_NO_MIX (OPTION_ABI + 1)
#define OPTION_SHCOMPACT_CONST_CRANGE (OPTION_NO_MIX + 1)
#define OPTION_NO_EXPAND (OPTION_SHCOMPACT_CONST_CRANGE + 1)
#define OPTION_PT32 (OPTION_NO_EXPAND + 1)
- {"isa", required_argument, NULL, OPTION_ISA},
{"abi", required_argument, NULL, OPTION_ABI},
{"no-mix", no_argument, NULL, OPTION_NO_MIX},
{"shcompact-const-crange", no_argument, NULL, OPTION_SHCOMPACT_CONST_CRANGE},
size_t md_longopts_size = sizeof (md_longopts);
int
-md_parse_option (c, arg)
- int c;
- char *arg ATTRIBUTE_UNUSED;
+md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
{
switch (c)
{
break;
case OPTION_DSP:
- sh_dsp = 1;
+ preset_target_arch = arch_sh_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu);
+ break;
+
+ case OPTION_RENESAS:
+ dont_adjust_reloc_32 = 1;
break;
-#ifdef HAVE_SH64
case OPTION_ISA:
- if (strcasecmp (arg, "shmedia") == 0)
+ if (strcasecmp (arg, "dsp") == 0)
+ preset_target_arch = arch_sh_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu);
+ else if (strcasecmp (arg, "fp") == 0)
+ preset_target_arch = arch_sh_up & ~arch_sh_has_dsp;
+ else if (strcasecmp (arg, "any") == 0)
+ preset_target_arch = arch_sh_up;
+#ifdef HAVE_SH64
+ else if (strcasecmp (arg, "shmedia") == 0)
{
if (sh64_isa_mode == sh64_isa_shcompact)
as_bad (_("Invalid combination: --isa=SHcompact with --isa=SHmedia"));
as_bad (_("Invalid combination: --abi=64 with --isa=SHcompact"));
sh64_isa_mode = sh64_isa_shcompact;
}
+#endif /* HAVE_SH64 */
else
- as_bad ("Invalid argument to --isa option: %s", arg);
+ {
+ extern const bfd_arch_info_type bfd_sh_arch;
+ bfd_arch_info_type const *bfd_arch = &bfd_sh_arch;
+ preset_target_arch = 0;
+ for (; bfd_arch; bfd_arch=bfd_arch->next)
+ {
+ int len = strlen(bfd_arch->printable_name);
+
+ if (bfd_arch->mach == bfd_mach_sh5)
+ continue;
+
+ if (strncasecmp (bfd_arch->printable_name, arg, len) != 0)
+ continue;
+
+ if (arg[len] == '\0')
+ preset_target_arch =
+ sh_get_arch_from_bfd_mach (bfd_arch->mach);
+ else if (strcasecmp(&arg[len], "-up") == 0)
+ preset_target_arch =
+ sh_get_arch_up_from_bfd_mach (bfd_arch->mach);
+ else
+ continue;
+ break;
+ }
+
+ if (!preset_target_arch)
+ as_bad ("Invalid argument to --isa option: %s", arg);
+ }
break;
+#ifdef HAVE_SH64
case OPTION_ABI:
if (strcmp (arg, "32") == 0)
{
break;
case OPTION_NO_MIX:
- sh64_mix = false;
+ sh64_mix = FALSE;
break;
case OPTION_SHCOMPACT_CONST_CRANGE:
- sh64_shcompact_const_crange = true;
+ sh64_shcompact_const_crange = TRUE;
break;
case OPTION_NO_EXPAND:
- sh64_expand = false;
+ sh64_expand = FALSE;
break;
case OPTION_PT32:
- sh64_pt32 = true;
+ sh64_pt32 = TRUE;
break;
#endif /* HAVE_SH64 */
}
void
-md_show_usage (stream)
- FILE *stream;
+md_show_usage (FILE *stream)
{
fprintf (stream, _("\
SH options:\n\
-little generate little endian code\n\
-big generate big endian code\n\
-relax alter jump instructions for long displacements\n\
+-renesas disable optimization with section symbol for\n\
+ compatibility with Renesas assembler.\n\
-small align sections to 4 byte boundaries, not 16\n\
--dsp enable sh-dsp insns, and disable sh3e / sh4 insns.\n"));
+-dsp enable sh-dsp insns, and disable floating-point ISAs.\n\
+-isa=[any use most appropriate isa\n\
+ | dsp same as '-dsp'\n\
+ | fp"));
+ {
+ extern const bfd_arch_info_type bfd_sh_arch;
+ bfd_arch_info_type const *bfd_arch = &bfd_sh_arch;
+ for (; bfd_arch; bfd_arch=bfd_arch->next)
+ if (bfd_arch->mach != bfd_mach_sh5)
+ {
+ fprintf (stream, "\n | %s", bfd_arch->printable_name);
+ fprintf (stream, "\n | %s-up", bfd_arch->printable_name);
+ }
+ }
+ fprintf (stream, "]\n");
#ifdef HAVE_SH64
fprintf (stream, _("\
--isa=[shmedia set default instruction set for SH64\n\
- | SHmedia\n\
- | shcompact\n\
- | SHcompact]\n\
+-isa=[shmedia set as the default instruction set for SH64\n\
+ | SHmedia\n\
+ | shcompact\n\
+ | SHcompact]\n"));
+ fprintf (stream, _("\
-abi=[32|64] set size of expanded SHmedia operands and object\n\
file type\n\
-shcompact-const-crange emit code-range descriptors for constants in\n\
constants and SHcompact code\n\
-no-expand do not expand MOVI, PT, PTA or PTB instructions\n\
-expand-pt32 with -abi=64, expand PT, PTA and PTB instructions\n\
- to 32 bits only"));
+ to 32 bits only\n"));
#endif /* HAVE_SH64 */
}
\f
bfd_map_over_sections. */
static void
-sh_count_relocs (abfd, sec, data)
- bfd *abfd ATTRIBUTE_UNUSED;
- segT sec;
- PTR data;
+sh_count_relocs (bfd *abfd ATTRIBUTE_UNUSED, segT sec, void *data)
{
struct sh_count_relocs *info = (struct sh_count_relocs *) data;
segment_info_type *seginfo;
BFD_ASSEMBLER, this is called via bfd_map_over_sections. */
static void
-sh_frob_section (abfd, sec, ignore)
- bfd *abfd ATTRIBUTE_UNUSED;
- segT sec;
- PTR ignore ATTRIBUTE_UNUSED;
+sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
+ void *ignore ATTRIBUTE_UNUSED)
{
segment_info_type *seginfo;
fixS *fix;
info.sym = sym;
info.count = 0;
#ifdef BFD_ASSEMBLER
- bfd_map_over_sections (stdoutput, sh_count_relocs, (PTR) &info);
+ bfd_map_over_sections (stdoutput, sh_count_relocs, &info);
#else
{
int iscan;
for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++)
- sh_count_relocs ((bfd *) NULL, iscan, (PTR) &info);
+ sh_count_relocs ((bfd *) NULL, iscan, &info);
}
#endif
the stored function address entirely. */
void
-sh_frob_file ()
+sh_frob_file (void)
{
#ifdef HAVE_SH64
shmedia_frob_file_before_adjust ();
return;
#ifdef BFD_ASSEMBLER
- bfd_map_over_sections (stdoutput, sh_frob_section, (PTR) NULL);
+ bfd_map_over_sections (stdoutput, sh_frob_section, NULL);
#else
{
int iseg;
for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++)
- sh_frob_section ((bfd *) NULL, iseg, (PTR) NULL);
+ sh_frob_section ((bfd *) NULL, iseg, NULL);
}
#endif
}
create relocs so that md_apply_fix3 will fill in the correct values. */
void
-md_convert_frag (headers, seg, fragP)
#ifdef BFD_ASSEMBLER
- bfd *headers ATTRIBUTE_UNUSED;
+md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP)
#else
- object_headers *headers ATTRIBUTE_UNUSED;
+md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED, segT seg,
+ fragS *fragP)
#endif
- segT seg;
- fragS *fragP;
{
int donerelax = 0;
default:
#ifdef HAVE_SH64
- shmedia_md_convert_frag (headers, seg, fragP, true);
+ shmedia_md_convert_frag (headers, seg, fragP, TRUE);
#else
abort ();
#endif
}
valueT
-md_section_align (seg, size)
- segT seg ATTRIBUTE_UNUSED;
- valueT size;
+md_section_align (segT seg ATTRIBUTE_UNUSED, valueT size)
{
#ifdef BFD_ASSEMBLER
#ifdef OBJ_ELF
}
/* This static variable is set by s_uacons to tell sh_cons_align that
- the expession does not need to be aligned. */
+ the expression does not need to be aligned. */
static int sh_no_align_cons = 0;
to be aligned. */
static void
-s_uacons (bytes)
- int bytes;
+s_uacons (int bytes)
{
/* Tell sh_cons_align not to align this value. */
sh_no_align_cons = 1;
enable this warning? */
void
-sh_cons_align (nbytes)
- int nbytes;
+sh_cons_align (int nbytes)
{
int nalign;
char *p;
also where we check for misaligned data. */
void
-sh_handle_align (frag)
- fragS *frag;
+sh_handle_align (fragS *frag)
{
int bytes = frag->fr_next->fr_address - frag->fr_address - frag->fr_fix;
/* See whether the relocation should be resolved locally. */
-static boolean
-sh_local_pcrel (fix)
- fixS *fix;
+static bfd_boolean
+sh_local_pcrel (fixS *fix)
{
- return (! sh_relax &&
- (fix->fx_r_type == BFD_RELOC_SH_PCDISP8BY2
- || fix->fx_r_type == BFD_RELOC_SH_PCDISP12BY2
- || fix->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY2
- || fix->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY4
- || fix->fx_r_type == BFD_RELOC_8_PCREL
- || fix->fx_r_type == BFD_RELOC_SH_SWITCH16
- || fix->fx_r_type == BFD_RELOC_SH_SWITCH32));
+ return (! sh_relax
+ && (fix->fx_r_type == BFD_RELOC_SH_PCDISP8BY2
+ || fix->fx_r_type == BFD_RELOC_SH_PCDISP12BY2
+ || fix->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY2
+ || fix->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY4
+ || fix->fx_r_type == BFD_RELOC_8_PCREL
+ || fix->fx_r_type == BFD_RELOC_SH_SWITCH16
+ || fix->fx_r_type == BFD_RELOC_SH_SWITCH32));
}
/* See whether we need to force a relocation into the output file.
relaxing. */
int
-sh_force_relocation (fix)
- fixS *fix;
+sh_force_relocation (fixS *fix)
{
/* These relocations can't make it into a DSO, so no use forcing
them for global symbols. */
return 0;
/* Make sure some relocations get emitted. */
- if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY
- || fix->fx_r_type == BFD_RELOC_SH_LOOP_START
+ if (fix->fx_r_type == BFD_RELOC_SH_LOOP_START
|| fix->fx_r_type == BFD_RELOC_SH_LOOP_END
|| fix->fx_r_type == BFD_RELOC_SH_TLS_GD_32
|| fix->fx_r_type == BFD_RELOC_SH_TLS_LD_32
|| fix->fx_r_type == BFD_RELOC_SH_TLS_IE_32
|| fix->fx_r_type == BFD_RELOC_SH_TLS_LDO_32
|| fix->fx_r_type == BFD_RELOC_SH_TLS_LE_32
- || S_FORCE_RELOC (fix->fx_addsy))
+ || generic_force_reloc (fix))
return 1;
if (! sh_relax)
}
#ifdef OBJ_ELF
-boolean
-sh_fix_adjustable (fixP)
- fixS *fixP;
+bfd_boolean
+sh_fix_adjustable (fixS *fixP)
{
if (fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL
|| fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL
|| fixP->fx_r_type == BFD_RELOC_SH_GOTPC
+ || ((fixP->fx_r_type == BFD_RELOC_32) && dont_adjust_reloc_32)
|| fixP->fx_r_type == BFD_RELOC_RVA)
return 0;
}
void
-sh_elf_final_processing ()
+sh_elf_final_processing (void)
{
int val;
/* Set file-specific flags to indicate if this code needs
- a processor with the sh-dsp / sh3e ISA to execute. */
+ a processor with the sh-dsp / sh2e ISA to execute. */
#ifdef HAVE_SH64
/* SH5 and above don't know about the valid_arch arch_sh* bits defined
in sh-opc.h, so check SH64 mode before checking valid_arch. */
if (sh64_isa_mode != sh64_isa_unspecified)
val = EF_SH5;
else
+#elif defined TARGET_SYMBIAN
+ if (1)
+ val = sh_symbian_find_elf_flags (valid_arch);
+ else
#endif /* HAVE_SH64 */
- if (valid_arch & arch_sh1)
- val = EF_SH1;
- else if (valid_arch & arch_sh2)
- val = EF_SH2;
- else if (valid_arch & arch_sh_dsp)
- val = EF_SH_DSP;
- else if (valid_arch & arch_sh3)
- val = EF_SH3;
- else if (valid_arch & arch_sh3_dsp)
- val = EF_SH_DSP;
- else if (valid_arch & arch_sh3e)
- val = EF_SH3E;
- else if (valid_arch & arch_sh4)
- val = EF_SH4;
- else
- abort ();
+ val = sh_find_elf_flags (valid_arch);
elf_elfheader (stdoutput)->e_flags &= ~EF_SH_MACH_MASK;
elf_elfheader (stdoutput)->e_flags |= val;
/* Apply a fixup to the object file. */
void
-md_apply_fix3 (fixP, valP, seg)
- fixS * fixP;
- valueT * valP;
- segT seg ATTRIBUTE_UNUSED;
+md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
int lowbyte = target_big_endian ? 1 : 0;
val -= S_GET_VALUE (fixP->fx_addsy);
#endif
-#ifndef BFD_ASSEMBLER
+#ifdef BFD_ASSEMBLER
+ if (SWITCH_TABLE (fixP))
+ val -= S_GET_VALUE (fixP->fx_subsy);
+#else
if (fixP->fx_r_type == 0)
{
if (fixP->fx_size == 2)
shift = 0;
switch (fixP->fx_r_type)
{
+ case BFD_RELOC_SH_IMM3:
+ max = 0x7;
+ * buf = (* buf & 0xf8) | (val & 0x7);
+ break;
+ case BFD_RELOC_SH_IMM3U:
+ max = 0x7;
+ * buf = (* buf & 0x8f) | ((val & 0x7) << 4);
+ break;
+ case BFD_RELOC_SH_DISP12:
+ max = 0xfff;
+ buf[lowbyte] = val & 0xff;
+ buf[highbyte] |= (val >> 8) & 0x0f;
+ break;
+ case BFD_RELOC_SH_DISP12BY2:
+ max = 0xfff;
+ shift = 1;
+ buf[lowbyte] = (val >> 1) & 0xff;
+ buf[highbyte] |= (val >> 9) & 0x0f;
+ break;
+ case BFD_RELOC_SH_DISP12BY4:
+ max = 0xfff;
+ shift = 2;
+ buf[lowbyte] = (val >> 2) & 0xff;
+ buf[highbyte] |= (val >> 10) & 0x0f;
+ break;
+ case BFD_RELOC_SH_DISP12BY8:
+ max = 0xfff;
+ shift = 3;
+ buf[lowbyte] = (val >> 3) & 0xff;
+ buf[highbyte] |= (val >> 11) & 0x0f;
+ break;
+ case BFD_RELOC_SH_DISP20:
+ if (! target_big_endian)
+ abort();
+ max = 0x7ffff;
+ min = -0x80000;
+ buf[1] = (buf[1] & 0x0f) | ((val >> 12) & 0xf0);
+ buf[2] = (val >> 8) & 0xff;
+ buf[3] = val & 0xff;
+ break;
+ case BFD_RELOC_SH_DISP20BY8:
+ if (!target_big_endian)
+ abort();
+ max = 0x7ffff;
+ min = -0x80000;
+ shift = 8;
+ buf[1] = (buf[1] & 0x0f) | ((val >> 20) & 0xf0);
+ buf[2] = (val >> 16) & 0xff;
+ buf[3] = (val >> 8) & 0xff;
+ break;
+
case BFD_RELOC_SH_IMM4:
max = 0xf;
*buf = (*buf & 0xf0) | (val & 0xf);
case BFD_RELOC_SH_PCRELIMM8BY4:
/* The lower two bits of the PC are cleared before the
displacement is added in. We can assume that the destination
- is on a 4 byte bounday. If this instruction is also on a 4
+ is on a 4 byte boundary. If this instruction is also on a 4
byte boundary, then we want
(target - here) / 4
and target - here is a multiple of 4.
/* Make the jump instruction point to the address of the operand. At
runtime we merely add the offset to the actual PLT entry. */
* valP = 0xfffffffc;
- val = 0;
+ val = fixP->fx_offset;
if (fixP->fx_subsy)
val -= S_GET_VALUE (fixP->fx_subsy);
fixP->fx_addnumber = val;
md_number_to_chars (buf, val, 4);
break;
- case BFD_RELOC_32_GOT_PCREL:
- case BFD_RELOC_SH_GOTPLT32:
case BFD_RELOC_SH_TLS_GD_32:
case BFD_RELOC_SH_TLS_LD_32:
case BFD_RELOC_SH_TLS_IE_32:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ /* Fallthrough */
+ case BFD_RELOC_32_GOT_PCREL:
+ case BFD_RELOC_SH_GOTPLT32:
* valP = 0; /* Fully resolved at runtime. No addend. */
md_number_to_chars (buf, 0, 4);
break;
- case BFD_RELOC_32_GOTOFF:
case BFD_RELOC_SH_TLS_LDO_32:
case BFD_RELOC_SH_TLS_LE_32:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ /* Fallthrough */
+ case BFD_RELOC_32_GOTOFF:
md_number_to_chars (buf, val, 4);
break;
#endif
by which a fragment must grow to reach it's destination. */
int
-md_estimate_size_before_relax (fragP, segment_type)
- register fragS *fragP;
- register segT segment_type;
+md_estimate_size_before_relax (fragS *fragP, segT segment_type)
{
int what;
/* Put number into target byte order. */
void
-md_number_to_chars (ptr, use, nbytes)
- char *ptr;
- valueT use;
- int nbytes;
+md_number_to_chars (char *ptr, valueT use, int nbytes)
{
#ifdef HAVE_SH64
/* We might need to set the contents type to data. */
eg for the sh-hms target. */
long
-md_pcrel_from (fixP)
- fixS *fixP;
+md_pcrel_from (fixS *fixP)
{
return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2;
}
long
-md_pcrel_from_section (fixP, sec)
- fixS *fixP;
- segT sec;
+md_pcrel_from_section (fixS *fixP, segT sec)
{
if (! sh_local_pcrel (fixP)
&& fixP->fx_addsy != (symbolS *) NULL
- && (S_FORCE_RELOC (fixP->fx_addsy)
+ && (generic_force_reloc (fixP)
|| S_GET_SEGMENT (fixP->fx_addsy) != sec))
{
/* The symbol is undefined (or is defined but not in this section,
#ifdef OBJ_COFF
int
-tc_coff_sizemachdep (frag)
- fragS *frag;
+tc_coff_sizemachdep (fragS *frag)
{
return md_relax_table[frag->fr_subtype].rlx_length;
}
but does some minor tweaking. */
void
-sh_coff_reloc_mangle (seg, fix, intr, paddr)
- segment_info_type *seg;
- fixS *fix;
- struct internal_reloc *intr;
- unsigned int paddr;
+sh_coff_reloc_mangle (segment_info_type *seg, fixS *fix,
+ struct internal_reloc *intr, unsigned int paddr)
{
symbolS *symbol_ptr = fix->fx_addsy;
symbolS *dot;
/* Create a reloc. */
arelent *
-tc_gen_reloc (section, fixp)
- asection *section ATTRIBUTE_UNUSED;
- fixS *fixp;
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
{
arelent *rel;
bfd_reloc_code_real_type r_type;
if (SWITCH_TABLE (fixp))
{
- rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy);
+ *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+ rel->addend = 0;
if (r_type == BFD_RELOC_16)
r_type = BFD_RELOC_SH_SWITCH16;
else if (r_type == BFD_RELOC_8)
rel->addend = 0;
rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
+
if (rel->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
assert (rel->howto != NULL);
}
+#ifdef OBJ_ELF
+ else if (rel->howto->type == R_SH_IND12W)
+ rel->addend += fixp->fx_offset - 4;
+#endif
return rel;
}
#ifdef OBJ_ELF
inline static char *
-sh_end_of_match (cont, what)
- char *cont, *what;
+sh_end_of_match (char *cont, char *what)
{
int len = strlen (what);
}
int
-sh_parse_name (name, exprP, nextcharP)
- char const *name;
- expressionS *exprP;
- char *nextcharP;
+sh_parse_name (char const *name, expressionS *exprP, char *nextcharP)
{
char *next = input_line_pointer;
char *next_end;
return 1;
}
-#endif
+
+void
+sh_cfi_frame_initial_instructions (void)
+{
+ cfi_add_CFA_def_cfa (15, 0);
+}
+
+int
+sh_regname_to_dw2regnum (const char *regname)
+{
+ unsigned int regnum = -1;
+ unsigned int i;
+ const char *p;
+ char *q;
+ static struct { char *name; int dw2regnum; } regnames[] =
+ {
+ { "pr", 17 }, { "t", 18 }, { "gbr", 19 }, { "mach", 20 },
+ { "macl", 21 }, { "fpul", 23 }
+ };
+
+ for (i = 0; i < ARRAY_SIZE (regnames); ++i)
+ if (strcmp (regnames[i].name, regname) == 0)
+ return regnames[i].dw2regnum;
+
+ if (regname[0] == 'r')
+ {
+ p = regname + 1;
+ regnum = strtoul (p, &q, 10);
+ if (p == q || *q || regnum >= 16)
+ return -1;
+ }
+ else if (regname[0] == 'f' && regname[1] == 'r')
+ {
+ p = regname + 2;
+ regnum = strtoul (p, &q, 10);
+ if (p == q || *q || regnum >= 16)
+ return -1;
+ regnum += 25;
+ }
+ else if (regname[0] == 'x' && regname[1] == 'd')
+ {
+ p = regname + 2;
+ regnum = strtoul (p, &q, 10);
+ if (p == q || *q || regnum >= 8)
+ return -1;
+ regnum += 87;
+ }
+ return regnum;
+}
+#endif /* OBJ_ELF */
#endif /* BFD_ASSEMBLER */