/* 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 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
else
demand_empty_rest_of_line ();
}
-#endif /* OBJ_ELF */
+/* The regular frag_offset_fixed_p doesn't work for rs_align_test
+ frags. */
+
+static bfd_boolean
+align_test_frag_offset_fixed_p (const fragS *frag1, const fragS *frag2,
+ bfd_vma *offset)
+{
+ const fragS *frag;
+ bfd_vma off;
+
+ /* Start with offset initialised to difference between the two frags.
+ Prior to assigning frag addresses this will be zero. */
+ off = frag1->fr_address - frag2->fr_address;
+ if (frag1 == frag2)
+ {
+ *offset = off;
+ return TRUE;
+ }
+
+ /* Maybe frag2 is after frag1. */
+ frag = frag1;
+ while (frag->fr_type == rs_fill
+ || frag->fr_type == rs_align_test)
+ {
+ if (frag->fr_type == rs_fill)
+ off += frag->fr_fix + frag->fr_offset * frag->fr_var;
+ else
+ off += frag->fr_fix;
+ frag = frag->fr_next;
+ if (frag == NULL)
+ break;
+ if (frag == frag2)
+ {
+ *offset = off;
+ return TRUE;
+ }
+ }
+
+ /* Maybe frag1 is after frag2. */
+ off = frag1->fr_address - frag2->fr_address;
+ frag = frag2;
+ while (frag->fr_type == rs_fill
+ || frag->fr_type == rs_align_test)
+ {
+ if (frag->fr_type == rs_fill)
+ off -= frag->fr_fix + frag->fr_offset * frag->fr_var;
+ else
+ off -= frag->fr_fix;
+ frag = frag->fr_next;
+ if (frag == NULL)
+ break;
+ if (frag == frag1)
+ {
+ *offset = off;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* Optimize a difference of symbols which have rs_align_test frag if
+ possible. */
+
+int
+sh_optimize_expr (expressionS *l, operatorT op, expressionS *r)
+{
+ bfd_vma frag_off;
+
+ if (op == O_subtract
+ && l->X_op == O_symbol
+ && r->X_op == O_symbol
+ && S_GET_SEGMENT (l->X_add_symbol) == S_GET_SEGMENT (r->X_add_symbol)
+ && (SEG_NORMAL (S_GET_SEGMENT (l->X_add_symbol))
+ || r->X_add_symbol == l->X_add_symbol)
+ && align_test_frag_offset_fixed_p (symbol_get_frag (l->X_add_symbol),
+ symbol_get_frag (r->X_add_symbol),
+ &frag_off))
+ {
+ l->X_add_number -= r->X_add_number;
+ l->X_add_number -= frag_off / OCTETS_PER_BYTE;
+ l->X_add_number += (S_GET_VALUE (l->X_add_symbol)
+ - S_GET_VALUE (r->X_add_symbol));
+ l->X_op = O_constant;
+ l->X_add_symbol = 0;
+ return 1;
+ }
+ return 0;
+}
+#endif /* OBJ_ELF */
\f
/* This function is called once, at assembler startup time. This should
set up all the tables, etc that the MD part of the assembler needs. */
as_bad (_("Delayed branches not available on SH1"));
parse_exp (op_end + 1, &operand[0]);
build_relax (opcode, &operand[0]);
+
+ /* All branches are currently 16 bit. */
+ size = 2;
}
else
{
}
/* Various routines to kill one day. */
-/* Equal to MAX_PRECISION in atof-ieee.c. */
-#define MAX_LITTLENUMS 6
-
-/* Turn a string in input_line_pointer into a floating point constant
- of type TYPE, and store the appropriate bytes in *LITP. The number
- of LITTLENUMS emitted is stored in *SIZEP . An error message is
- returned, or NULL on OK. */
char *
md_atof (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;
-
- if (! target_big_endian)
- {
- for (i = prec - 1; i >= 0; i--)
- {
- md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
- }
- }
- else
- {
- for (i = 0; i < prec; i++)
- {
- md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
- }
- }
-
- return NULL;
+ return ieee_md_atof (type, litP, sizeP, target_big_endian);
}
/* Handle the .uses pseudo-op. This pseudo-op is used just before a
{"relax", no_argument, NULL, OPTION_RELAX},
{"big", no_argument, NULL, OPTION_BIG},
{"little", no_argument, NULL, OPTION_LITTLE},
+ /* The next two switches are here because the
+ generic parts of the linker testsuite uses them. */
+ {"EB", no_argument, NULL, OPTION_BIG},
+ {"EL", no_argument, NULL, OPTION_LITTLE},
{"small", no_argument, NULL, OPTION_SMALL},
{"dsp", no_argument, NULL, OPTION_DSP},
{"isa", required_argument, NULL, OPTION_ISA},
if (seginfo == NULL)
return;
+ for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
+ {
+ symbolS *sym;
+
+ sym = fix->fx_addsy;
+ /* Check for a local_symbol. */
+ if (sym && sym->bsym == NULL)
+ {
+ struct local_symbol *ls = (struct local_symbol *)sym;
+ /* See if it's been converted. If so, canonicalize. */
+ if (local_symbol_converted_p (ls))
+ fix->fx_addsy = local_symbol_get_real_symbol (ls);
+ }
+ }
+
for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
{
symbolS *sym;
else if (frag->fr_type == rs_align_test)
{
if (bytes != 0)
- as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data"));
+ as_bad_where (frag->fr_file, frag->fr_line, _("misaligned data"));
}
if (sh_relax
}
#endif
+/* Apply fixup FIXP to SIZE-byte field BUF given that VAL is its
+ assembly-time value. If we're generating a reloc for FIXP,
+ see whether the addend should be stored in-place or whether
+ it should be in an ELF r_addend field. */
+
+static void
+apply_full_field_fix (fixS *fixP, char *buf, bfd_vma val, int size)
+{
+ reloc_howto_type *howto;
+
+ if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
+ {
+ howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+ if (howto && !howto->partial_inplace)
+ {
+ fixP->fx_addnumber = val;
+ return;
+ }
+ }
+ md_number_to_chars (buf, val, size);
+}
+
/* Apply a fixup to the object file. */
void
case BFD_RELOC_32:
case BFD_RELOC_32_PCREL:
- md_number_to_chars (buf, val, 4);
+ apply_full_field_fix (fixP, buf, val, 4);
break;
case BFD_RELOC_16:
- md_number_to_chars (buf, val, 2);
+ apply_full_field_fix (fixP, buf, val, 2);
break;
case BFD_RELOC_SH_USES:
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);
+ apply_full_field_fix (fixP, buf, val, 4);
break;
case BFD_RELOC_SH_GOTPC:
was used to store the correction, but since the expression is
not pcrel, I felt it would be confusing to do it this way. */
* valP -= 1;
- md_number_to_chars (buf, val, 4);
+ apply_full_field_fix (fixP, buf, val, 4);
break;
case BFD_RELOC_SH_TLS_GD_32:
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);
+ apply_full_field_fix (fixP, buf, 0, 4);
break;
case BFD_RELOC_SH_TLS_LDO_32:
S_SET_THREAD_LOCAL (fixP->fx_addsy);
/* Fallthrough */
case BFD_RELOC_32_GOTOFF:
- md_number_to_chars (buf, val, 4);
+ apply_full_field_fix (fixP, buf, val, 4);
break;
#endif
else if (shmedia_init_reloc (rel, fixp))
;
#endif
- else if (fixp->fx_pcrel)
- rel->addend = fixp->fx_addnumber;
- else if (r_type == BFD_RELOC_32 || r_type == BFD_RELOC_32_GOTOFF)
- rel->addend = fixp->fx_addnumber;
else
- rel->addend = 0;
+ rel->addend = fixp->fx_addnumber;
rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);