/* tc-sh.c -- Assemble code for the Renesas / SuperH SH
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
accommodate the insns seen so far. */
static unsigned int valid_arch;
+/* Whether --fdpic was given. */
+static int sh_fdpic;
+
const char EXP_CHARS[] = "eE";
/* Chars that mean this number is a floating point constant. */
if (exp->X_op == O_PIC_reloc)
{
-#ifdef HAVE_SH64
switch (*r_type_p)
{
case BFD_RELOC_NONE:
*r_type_p = exp->X_md;
break;
+ case BFD_RELOC_SH_DISP20:
+ switch (exp->X_md)
+ {
+ case BFD_RELOC_32_GOT_PCREL:
+ *r_type_p = BFD_RELOC_SH_GOT20;
+ break;
+
+ case BFD_RELOC_32_GOTOFF:
+ *r_type_p = BFD_RELOC_SH_GOTOFF20;
+ break;
+
+ case BFD_RELOC_SH_GOTFUNCDESC:
+ *r_type_p = BFD_RELOC_SH_GOTFUNCDESC20;
+ break;
+
+ case BFD_RELOC_SH_GOTOFFFUNCDESC:
+ *r_type_p = BFD_RELOC_SH_GOTOFFFUNCDESC20;
+ break;
+
+ default:
+ abort ();
+ }
+ break;
+
+#ifdef HAVE_SH64
case BFD_RELOC_SH_IMM_LOW16:
switch (exp->X_md)
{
abort ();
}
break;
+#endif
default:
abort ();
}
-#else
- *r_type_p = exp->X_md;
-#endif
if (exp == main_exp)
exp->X_op = O_symbol;
else
expression (&op->immediate);
if (op->immediate.X_op == O_absent)
as_bad (_("missing operand"));
-#ifdef OBJ_ELF
- else if (op->immediate.X_op == O_PIC_reloc
- || sh_PIC_related_p (op->immediate.X_add_symbol)
- || sh_PIC_related_p (op->immediate.X_op_symbol))
- as_bad (_("misplaced PIC operand"));
-#endif
new_pointer = input_line_pointer;
input_line_pointer = save;
return new_pointer;
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:
printf (_("unhandled %d\n"), arg);
goto fail;
}
+ 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;
+ }
+ }
}
if ( !SH_MERGE_ARCH_SET_VALID (valid_arch, this_try->arch))
goto fail;
unsigned int size = 2;
int low_byte = target_big_endian ? 1 : 0;
int max_index = 4;
+ bfd_reloc_code_real_type r_type;
+ int unhandled_pic = 0;
nbuf[0] = 0;
nbuf[1] = 0;
nbuf[6] = 0;
nbuf[7] = 0;
+ for (indx = 0; indx < 3; indx++)
+ if (opcode->arg[indx] == A_IMM
+ && operand[indx].type == A_IMM
+ && (operand[indx].immediate.X_op == O_PIC_reloc
+ || sh_PIC_related_p (operand[indx].immediate.X_add_symbol)
+ || sh_PIC_related_p (operand[indx].immediate.X_op_symbol)))
+ unhandled_pic = 1;
+
if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
{
output = frag_more (4);
case IMM0_20_4:
break;
case IMM0_20:
- insert4 (output, BFD_RELOC_SH_DISP20, 0, operand);
+ r_type = BFD_RELOC_SH_DISP20;
+ if (sh_check_fixup (&operand->immediate, &r_type))
+ as_bad (_("Invalid PIC expression."));
+ unhandled_pic = 0;
+ insert4 (output, r_type, 0, operand);
break;
case IMM0_20BY8:
insert4 (output, BFD_RELOC_SH_DISP20BY8, 0, operand);
}
}
}
+ if (unhandled_pic)
+ as_bad (_("misplaced PIC operand"));
if (!target_big_endian)
{
output[1] = (nbuf[0] << 4) | (nbuf[1]);
OPTION_PT32,
#endif
OPTION_H_TICK_HEX,
+#ifdef OBJ_ELF
+ OPTION_FDPIC,
+#endif
OPTION_DUMMY /* Not used. This is just here to make it easy to add and subtract options from this enum. */
};
#endif /* HAVE_SH64 */
{ "h-tick-hex", no_argument, NULL, OPTION_H_TICK_HEX },
+#ifdef OBJ_ELF
+ {"fdpic", no_argument, NULL, OPTION_FDPIC},
+#endif
+
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
enable_h_tick_hex = 1;
break;
+#ifdef OBJ_ELF
+ case OPTION_FDPIC:
+ sh_fdpic = TRUE;
+ break;
+#endif /* OBJ_ELF */
+
default:
return 0;
}
--expand-pt32 with -abi=64, expand PT, PTA and PTB instructions\n\
to 32 bits only\n"));
#endif /* HAVE_SH64 */
+#ifdef OBJ_ELF
+ fprintf (stream, _("\
+--fdpic generate an FDPIC object file\n"));
+#endif /* OBJ_ELF */
}
\f
/* This struct is used to pass arguments to sh_count_relocs through
{
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_GOT20
|| fixP->fx_r_type == BFD_RELOC_SH_GOTPC
+ || fixP->fx_r_type == BFD_RELOC_SH_GOTFUNCDESC
+ || fixP->fx_r_type == BFD_RELOC_SH_GOTFUNCDESC20
+ || fixP->fx_r_type == BFD_RELOC_SH_GOTOFFFUNCDESC
+ || fixP->fx_r_type == BFD_RELOC_SH_GOTOFFFUNCDESC20
+ || fixP->fx_r_type == BFD_RELOC_SH_FUNCDESC
|| ((fixP->fx_r_type == BFD_RELOC_32) && dont_adjust_reloc_32)
|| fixP->fx_r_type == BFD_RELOC_RVA)
return 0;
elf_elfheader (stdoutput)->e_flags &= ~EF_SH_MACH_MASK;
elf_elfheader (stdoutput)->e_flags |= val;
+
+ if (sh_fdpic)
+ elf_elfheader (stdoutput)->e_flags |= EF_SH_FDPIC;
+}
+#endif
+
+#ifdef TE_UCLINUX
+/* Return the target format for uClinux. */
+
+const char *
+sh_uclinux_target_format (void)
+{
+ if (sh_fdpic)
+ return (!target_big_endian ? "elf32-sh-fdpic" : "elf32-shbig-fdpic");
+ else
+ return (!target_big_endian ? "elf32-shl" : "elf32-sh");
}
#endif
S_SET_THREAD_LOCAL (fixP->fx_addsy);
/* Fallthrough */
case BFD_RELOC_32_GOT_PCREL:
+ case BFD_RELOC_SH_GOT20:
case BFD_RELOC_SH_GOTPLT32:
+ case BFD_RELOC_SH_GOTFUNCDESC:
+ case BFD_RELOC_SH_GOTFUNCDESC20:
+ case BFD_RELOC_SH_GOTOFFFUNCDESC:
+ case BFD_RELOC_SH_GOTOFFFUNCDESC20:
+ case BFD_RELOC_SH_FUNCDESC:
* valP = 0; /* Fully resolved at runtime. No addend. */
apply_full_field_fix (fixP, buf, 0, 4);
break;
S_SET_THREAD_LOCAL (fixP->fx_addsy);
/* Fallthrough */
case BFD_RELOC_32_GOTOFF:
+ case BFD_RELOC_SH_GOTOFF20:
apply_full_field_fix (fixP, buf, val, 4);
break;
#endif
reloc_type = BFD_RELOC_SH_TLS_LE_32;
else if ((next_end = sh_end_of_match (next + 1, "DTPOFF")))
reloc_type = BFD_RELOC_SH_TLS_LDO_32;
+ else if ((next_end = sh_end_of_match (next + 1, "PCREL")))
+ reloc_type = BFD_RELOC_32_PCREL;
+ else if ((next_end = sh_end_of_match (next + 1, "GOTFUNCDESC")))
+ reloc_type = BFD_RELOC_SH_GOTFUNCDESC;
+ else if ((next_end = sh_end_of_match (next + 1, "GOTOFFFUNCDESC")))
+ reloc_type = BFD_RELOC_SH_GOTOFFFUNCDESC;
+ else if ((next_end = sh_end_of_match (next + 1, "FUNCDESC")))
+ reloc_type = BFD_RELOC_SH_FUNCDESC;
else
goto no_suffix;