* config/tc-sparc.c (U0x80000000, U0xffffffff): New constants.
[binutils-gdb.git] / gas / config / tc-h8300.c
index 724aea19211d526726892577f3cb27d3b9c5e042..940e6d67f5f494aa41965b9f836c67006765166b 100644 (file)
 #define DEFINE_TABLE
 #define h8_opcodes ops
 #include "opcode/h8300.h"
-#include <ctype.h>
+#include "safe-ctype.h"
 
 #ifdef OBJ_ELF
 #include "elf/h8.h"
-
-#define R_MOV24B1 BFD_RELOC_H8_DIR24A8
-#define R_MOVL1 BFD_RELOC_H8_DIR32A16
-#define R_MOV24B1 BFD_RELOC_H8_DIR24A8
-#define R_MOVL1 BFD_RELOC_H8_DIR32A16
-#define R_RELLONG BFD_RELOC_32
-#define R_MOV16B1 BFD_RELOC_H8_DIR16A8
-#define R_RELWORD BFD_RELOC_16
-#define R_RELBYTE BFD_RELOC_8
-#define R_PCRWORD BFD_RELOC_16_PCREL
-#define R_PCRBYTE BFD_RELOC_8_PCREL
-#define R_JMPL1 BFD_RELOC_H8_DIR24R8
 #endif
 
 const char comment_chars[] = ";";
@@ -359,7 +347,7 @@ skip_colonthing (ptr, exp, mode)
            {
              *mode |= L_16;
            }
-         while (isdigit (*ptr))
+         while (ISDIGIT (*ptr))
            ptr++;
        }
     }
@@ -430,8 +418,8 @@ get_operand (ptr, op, dst, direction)
 
   /* Gross.  Gross.  ldm and stm have a format not easily handled
      by get_operand.  We deal with it explicitly here.  */
-  if (src[0] == 'e' && src[1] == 'r' && isdigit (src[2])
-      && src[3] == '-' && src[4] == 'e' && src[5] == 'r' && isdigit (src[6]))
+  if (src[0] == 'e' && src[1] == 'r' && ISDIGIT (src[2])
+      && src[3] == '-' && src[4] == 'e' && src[5] == 'r' && ISDIGIT (src[6]))
     {
       int low, high;
 
@@ -825,6 +813,14 @@ check_operand (operand, width, string)
                 fit a 16 bit address truncated into an 8 bit address
                 of something like bset.  */
            }
+         else if (strcmp (string, "@") == 0
+                  && width == 0xffff
+                  && (operand->exp.X_add_number & 0xff8000) == 0xff8000)
+           {
+             /* Just ignore this one - which happens when trying to
+                fit a 24 bit address truncated into a 16 bit address
+                of something like mov.w.  */
+           }
          else
            {
              as_warn (_("operand %s0x%lx out of range."), string,
@@ -1110,6 +1106,7 @@ build_bytes (this_try, operand)
          int where = size16 ? 2 : 1;
          int size = size16 ? 2 : 1;
          int type = size16 ? R_PCRWORD : R_PCRBYTE;
+         fixS *fixP;
 
          check_operand (operand + i, size16 ? 0x7fff : 0x7f, "@");
 
@@ -1119,16 +1116,25 @@ build_bytes (this_try, operand)
                       (unsigned long) operand->exp.X_add_number);
            }
 
+#ifndef OBJ_ELF
+         /* The COFF port has always been off by one, changing it
+            now would be an incompatible change, so we leave it as-is.
+
+            We don't want to do this for ELF as we want to be
+            compatible with the proposed ELF format from Hitachi.  */
          operand[i].exp.X_add_number -= 1;
+#endif
+
          operand[i].exp.X_add_number =
            ((operand[i].exp.X_add_number & 0xff) ^ 0x80) - 0x80;
 
-         fix_new_exp (frag_now,
-                      output - frag_now->fr_literal + where,
-                      size,
-                      &operand[i].exp,
-                      1,
-                      type);
+         fixP = fix_new_exp (frag_now,
+                             output - frag_now->fr_literal + where,
+                             size,
+                             &operand[i].exp,
+                             1,
+                             type);
+         fixP->fx_signed = 1;
        }
       else if (x & MEMIND)
        {
@@ -1142,6 +1148,15 @@ build_bytes (this_try, operand)
        }
       else if (x & ABSJMP)
        {
+         int where = 0;
+
+#ifdef OBJ_ELF
+         /* To be compatible with the proposed H8 ELF format, we
+            want the relocation's offset to point to the first byte
+            that will be modified, not to the start of the instruction.  */
+         where += 1;
+#endif
+
          /* This jmp may be a jump or a branch.  */
 
          check_operand (operand + i, Hmode ? 0xffffff : 0xffff, "@");
@@ -1154,7 +1169,7 @@ build_bytes (this_try, operand)
            operand[i].exp.X_add_number =
              ((operand[i].exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
          fix_new_exp (frag_now,
-                      output - frag_now->fr_literal,
+                      output - frag_now->fr_literal + where,
                       4,
                       &operand[i].exp,
                       0,
@@ -1448,7 +1463,11 @@ tc_aout_fix_to_chars ()
 
 void
 md_convert_frag (headers, seg, fragP)
+#ifdef BFD_ASSEMBLER
+     bfd *headers ATTRIBUTE_UNUSED;
+#else
      object_headers *headers ATTRIBUTE_UNUSED;
+#endif
      segT seg ATTRIBUTE_UNUSED;
      fragS *fragP ATTRIBUTE_UNUSED;
 {
@@ -1456,21 +1475,35 @@ md_convert_frag (headers, seg, fragP)
   abort ();
 }
 
+#ifdef BFD_ASSEMBLER
+valueT
+md_section_align (segment, size)
+     segT segment;
+     valueT size;
+{
+  int align = bfd_get_section_alignment (stdoutput, segment);
+  return ((size + (1 << align) - 1) & (-1 << align));
+}
+#else
 valueT
 md_section_align (seg, size)
      segT seg;
      valueT size;
 {
   return ((size + (1 << section_alignment[(int) seg]) - 1)
-         & (-1 << section_alignment[(int) seg]));
+          & (-1 << section_alignment[(int) seg]));
 }
+#endif
+
 
 void
-md_apply_fix (fixP, val)
+md_apply_fix3 (fixP, valP, seg)
      fixS *fixP;
-     long val;
+     valueT *valP;
+     segT seg ATTRIBUTE_UNUSED;
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  long val = * (long *) valP;
 
   switch (fixP->fx_size)
     {
@@ -1490,6 +1523,9 @@ md_apply_fix (fixP, val)
     default:
       abort ();
     }
+
+  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+    fixP->fx_done = 1;
 }
 
 int
@@ -1590,6 +1626,17 @@ tc_gen_reloc (section, fixp)
   arelent *rel;
   bfd_reloc_code_real_type r_type;
 
+  if (fixp->fx_addsy && fixp->fx_subsy)
+    {
+      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");
+         return NULL;
+       }
+    }
+
   rel = (arelent *) xmalloc (sizeof (arelent));
   rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);