-/* tc-sh.c -- Assemble code for the Hitachi Super-H
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+/* tc-sh.c -- Assemble code for the Renesas / SuperH SH
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
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 bfd_boolean sh_local_pcrel PARAMS ((fixS *fix));
#ifdef OBJ_ELF
static void sh_elf_cons PARAMS ((int));
{"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. */
+/* preset architecture set, if given; zero otherwise. */
-static int sh_dsp;
+static int preset_target_arch;
/* The bit mask of architectures that could
accomodate the insns seen so far. */
#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 ();
void
md_begin ()
{
- sh_opcode_info *opcode;
+ const sh_opcode_info *opcode;
char *prev_name = "";
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_sh1_up & ~arch_sh_dsp_up;
valid_arch = target_arch;
#ifdef HAVE_SH64
/* Insert unique names into hash table. */
for (opcode = sh_table; opcode->name; opcode++)
{
- if (strcmp (prev_name, opcode->name))
+ if (strcmp (prev_name, opcode->name) != 0)
{
if (! (opcode->arch & target_arch))
continue;
prev_name = opcode->name;
hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
}
- else
- {
- /* Make all the opcodes with the same name point to the same
- string. */
- opcode->name = prev_name;
- }
}
}
while (opcode->name)
{
this_try = opcode++;
- if (this_try->name != name)
+ if ((this_try->name != name) && (strcmp (this_try->name, name) != 0))
{
/* We've looked so far down the table that we've run out of
opcodes with the same name. */
int move_code;
unsigned int size;
- /* Some insn ignore one or more register fields, e.g. psts machl,a0.
- Make sure we encode a defined insn pattern. */
- reg_x = 0;
- reg_y = 0;
- reg_n = 0;
-
for (;;)
{
sh_operand_info operand[3];
+ /* Some insn ignore one or more register fields, e.g. psts machl,a0.
+ Make sure we encode a defined insn pattern. */
+ reg_x = 0;
+ reg_y = 0;
+ reg_n = 0;
+
if (opcode->arg[0] != A_END)
op_end = get_operands (opcode, op_end, operand);
opcode = get_specific (opcode, operand);
{
/* 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->arg[0] == A_BDISP12
|| opcode->arg[0] == A_BDISP8)
{
+ /* Since we skip get_specific here, we have to check & update
+ valid_arch now. */
+ if (valid_arch & opcode->arch)
+ 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]);
}
#define OPTION_LITTLE (OPTION_BIG + 1)
#define OPTION_SMALL (OPTION_LITTLE + 1)
#define OPTION_DSP (OPTION_SMALL + 1)
+#define OPTION_ISA (OPTION_DSP + 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},
#ifdef HAVE_SH64
-#define OPTION_ISA (OPTION_DSP + 1)
#define OPTION_ABI (OPTION_ISA + 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},
break;
case OPTION_DSP:
- sh_dsp = 1;
+ preset_target_arch = arch_sh1_up & ~arch_sh3e_up;
break;
-#ifdef HAVE_SH64
case OPTION_ISA:
- if (strcasecmp (arg, "shmedia") == 0)
+ if (strcasecmp (arg, "sh4") == 0)
+ preset_target_arch = arch_sh4;
+ else if (strcasecmp (arg, "any") == 0)
+ preset_target_arch = arch_sh1_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);
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 */
-big generate big endian code\n\
-relax alter jump instructions for long displacements\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 sh2e/sh3e/sh4 insns.\n"));
#ifdef HAVE_SH64
fprintf (stream, _("\
-isa=[shmedia set default instruction set for SH64\n\
default:
#ifdef HAVE_SH64
- shmedia_md_convert_frag (headers, seg, fragP, true);
+ shmedia_md_convert_frag (headers, seg, fragP, TRUE);
#else
abort ();
#endif
/* See whether the relocation should be resolved locally. */
-static boolean
+static bfd_boolean
sh_local_pcrel (fix)
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.
if (sh_local_pcrel (fix))
return 0;
- 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
+ /* Make sure some relocations get emitted. */
+ if (fix->fx_r_type == BFD_RELOC_SH_LOOP_START
|| fix->fx_r_type == BFD_RELOC_SH_LOOP_END
- || S_FORCE_RELOC (fix->fx_addsy))
+ || 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
+ || generic_force_reloc (fix))
return 1;
if (! sh_relax)
}
#ifdef OBJ_ELF
-boolean
+bfd_boolean
sh_fix_adjustable (fixP)
fixS *fixP;
{
val = EF_SH1;
else if (valid_arch & arch_sh2)
val = EF_SH2;
+ else if (valid_arch & arch_sh2e)
+ val = EF_SH2E;
else if (valid_arch & arch_sh_dsp)
val = EF_SH_DSP;
else if (valid_arch & arch_sh3)
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)
/* 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_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_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;
{
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,
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);
+#ifdef OBJ_ELF
+ if (rel->howto->type == R_SH_IND12W)
+ rel->addend += fixp->fx_offset - 4;
+#endif
if (rel->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
reloc_type = BFD_RELOC_32_GOT_PCREL;
else if ((next_end = sh_end_of_match (next + 1, "PLT")))
reloc_type = BFD_RELOC_32_PLT_PCREL;
+ else if ((next_end = sh_end_of_match (next + 1, "TLSGD")))
+ reloc_type = BFD_RELOC_SH_TLS_GD_32;
+ else if ((next_end = sh_end_of_match (next + 1, "TLSLDM")))
+ reloc_type = BFD_RELOC_SH_TLS_LD_32;
+ else if ((next_end = sh_end_of_match (next + 1, "GOTTPOFF")))
+ reloc_type = BFD_RELOC_SH_TLS_IE_32;
+ else if ((next_end = sh_end_of_match (next + 1, "TPOFF")))
+ 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
goto no_suffix;