Support for @GOTOFF in .long expressions.
[deliverable/binutils-gdb.git] / gas / config / tc-a29k.c
index 286b73b60ef788ad0dcd552d42d388c6d7f5d285..d4d4c4359440028c6c1cb0683b2aa6c6d7aead63 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-a29k.c -- Assemble for the AMD 29000.
-   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+   Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1998, 2000
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -14,8 +15,9 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   along with GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 /* John Gilmore has reorganized this module somewhat, to make it easier
    to convert it to new machines' assemblers as desired.  There was too
@@ -77,8 +79,6 @@ md_pseudo_table[] =
   {NULL, 0, 0},
 };
 
-int md_short_jump_size = 4;
-int md_long_jump_size = 4;
 #if defined(BFD_HEADERS)
 #ifdef RELSZ
 const int md_reloc_size = RELSZ;       /* Coff headers */
@@ -98,7 +98,7 @@ const char comment_chars[] = ";";
    .line and .file directives will appear in the pre-processed output */
 /* Note that input_file.c hand checks for '#' at the beginning of the
    first line of the input file.  This is because the compiler outputs
-   #NO_APP at the beginning of its output. */
+   #NO_APP at the beginning of its output.  */
 /* Also note that comments like this one will always work */
 const char line_comment_chars[] = "#";
 
@@ -148,7 +148,7 @@ s_use (ignore)
       return;
     }
   /* Literals can't go in the text segment because you can't read from
-     instruction memory on some 29k's.  So, into initialized data. */
+     instruction memory on some 29k's.  So, into initialized data.  */
   if (strncmp (input_line_pointer, ".lit", 4) == 0)
     {
       input_line_pointer += 4;
@@ -157,7 +157,7 @@ s_use (ignore)
       return;
     }
 
-  as_bad ("Unknown segment type");
+  as_bad (_("Unknown segment type"));
   demand_empty_rest_of_line ();
 }
 
@@ -283,7 +283,7 @@ md_begin ()
        }
 
       /* Hack to avoid multiple opcode entries.  We pre-locate all the
-        variations (b/i field and P/A field) and handle them. */
+        variations (b/i field and P/A field) and handle them.  */
 
       if (!strcmp (name, machine_opcodes[i + 1].name))
        {
@@ -327,7 +327,7 @@ md_begin ()
     }
 
   if (lose)
-    as_fatal ("Broken assembler.  No assembly attempted.");
+    as_fatal (_("Broken assembler.  No assembly attempted."));
 
   define_some_regs ();
 }
@@ -372,7 +372,7 @@ parse_operand (s, operandp, opt)
   input_line_pointer = s;
   expression (operandp);
   if (operandp->X_op == O_absent && ! opt)
-    as_bad ("missing operand");
+    as_bad (_("missing operand"));
   new = input_line_pointer;
   input_line_pointer = save;
   return new;
@@ -412,12 +412,12 @@ machine_ip (str)
       break;
 
     default:
-      as_bad ("Unknown opcode: `%s'", str);
+      as_bad (_("Unknown opcode: `%s'"), str);
       return;
     }
   if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL)
     {
-      as_bad ("Unknown opcode `%s'.", str);
+      as_bad (_("Unknown opcode `%s'."), str);
       return;
     }
   argsStart = s;
@@ -427,7 +427,7 @@ machine_ip (str)
 
   /* Build the opcode, checking as we go to make sure that the
      operands match.
-   
+
      If an operand matches, we modify the_insn or opcode appropriately,
      and do a "continue".  If an operand fails to match, we "break".  */
 
@@ -445,11 +445,11 @@ machine_ip (str)
        case '\0':              /* end of args */
          if (*s == '\0')
            {
-             /* We are truly done. */
+             /* We are truly done.  */
              the_insn.opcode = opcode;
              return;
            }
-         as_bad ("Too many operands: %s", s);
+         as_bad (_("Too many operands: %s"), s);
          break;
 
        case ',':               /* Must match a comma */
@@ -471,7 +471,7 @@ machine_ip (str)
                }
              else
                {
-                 as_bad ("Immediate value of %ld is too large",
+                 as_bad (_("Immediate value of %ld is too large"),
                          (long) operand->X_add_number);
                  continue;
                }
@@ -502,7 +502,7 @@ machine_ip (str)
                }
              else
                {
-                 as_bad ("Immediate value of %ld is too large",
+                 as_bad (_("Immediate value of %ld is too large"),
                          (long) operand->X_add_number);
                  continue;
                }
@@ -541,7 +541,7 @@ machine_ip (str)
              opcode |= reg << 16;
              continue;
            }
-         as_fatal ("failed sanity check.");
+         as_fatal (_("failed sanity check."));
          break;
 
        case 'x':               /* 16 bit constant, zero-extended */
@@ -669,7 +669,6 @@ machine_ip (str)
            }
          break;
 
-
        case 'f':               /* FS bits of CONVERT */
          if (operand->X_op == O_constant &&
              operand->X_add_number < 4)
@@ -710,8 +709,8 @@ machine_ip (str)
    but I'm not sure.
 
    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
+   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.  */
 
 /* Equal to MAX_PRECISION in atof-ieee.c */
@@ -792,7 +791,6 @@ md_apply_fix (fixP, val)
 
   fixP->fx_addnumber = val;    /* Remember value for emit_reloc */
 
-
   know (fixP->fx_size == 4);
   know (fixP->fx_r_type < NO_RELOC);
 
@@ -851,11 +849,21 @@ md_apply_fix (fixP, val)
 
     case RELOC_JUMPTARG:       /* 00XX00XX pattern in a word */
       if (!fixP->fx_done)
-       /* let linker deal */
-       ;
+       {
+         /* The linker tries to support both AMD and old GNU style
+             R_IREL relocs.  That means that if the addend is exactly
+             the negative of the address within the section, the
+             linker will not handle it correctly.  */
+         if (fixP->fx_pcrel
+             && val != 0
+             && val == - (fixP->fx_frag->fr_address + fixP->fx_where))
+           as_bad_where
+             (fixP->fx_file, fixP->fx_line,
+              "the linker will not handle this relocation correctly");
+       }
       else if (fixP->fx_pcrel)
        {
-         long v = val >> 16;
+         long v = val >> 17;
          if (v != 0 && v != -1)
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          "call/jmp target out of range");
@@ -879,7 +887,7 @@ md_apply_fix (fixP, val)
 
     case NO_RELOC:
     default:
-      as_bad ("bad relocation type: 0x%02x", fixP->fx_r_type);
+      as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type);
       break;
     }
 }
@@ -903,7 +911,7 @@ tc_coff_fix2rtype (fixP)
     case RELOC_JUMPTARG:
       return (R_IREL);
     default:
-      printf ("need %o3\n", fixP->fx_r_type);
+      printf (_("need %o3\n"), fixP->fx_r_type);
       abort ();
     }                          /* switch on type */
 
@@ -914,34 +922,12 @@ tc_coff_fix2rtype (fixP)
 
 /* should never be called for 29k */
 void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  as_fatal ("a29k_create_short_jmp\n");
-}
-
-/* should never be called for 29k */
-void
-md_convert_frag (headers, fragP)
+md_convert_frag (headers, seg, fragP)
      object_headers *headers;
+     segT seg;
      register fragS *fragP;
 {
-  as_fatal ("a29k_convert_frag\n");
-}
-
-/* should never be called for 29k */
-void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr;
-     addressT to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  as_fatal ("a29k_create_long_jump\n");
+  as_fatal (_("a29k_convert_frag\n"));
 }
 
 /* should never be called for a29k */
@@ -950,7 +936,7 @@ md_estimate_size_before_relax (fragP, segtype)
      register fragS *fragP;
      segT segtype;
 {
-  as_fatal ("a29k_estimate_size_before_relax\n");
+  as_fatal (_("a29k_estimate_size_before_relax\n"));
   return 0;
 }
 
@@ -1016,7 +1002,7 @@ print_insn (insn)
    On sparc/29k: first 4 bytes are normal unsigned long address, next three
    bytes are index, most sig. byte first.  Byte 7 is broken up with
    bit 7 as external, bits 6 & 5 unused, and the lower
-   five bits as relocation type.  Next 4 bytes are long addend. */
+   five bits as relocation type.  Next 4 bytes are long addend.  */
 /* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
 
 #ifdef OBJ_AOUT
@@ -1054,7 +1040,7 @@ CONST char *md_shortopts = "";
 struct option md_longopts[] = {
   {NULL, no_argument, NULL, 0}
 };
-size_t md_longopts_size = sizeof(md_longopts);
+size_t md_longopts_size = sizeof (md_longopts);
 
 int
 md_parse_option (c, arg)
@@ -1070,6 +1056,48 @@ md_show_usage (stream)
 {
 }
 \f
+/* This is called when a line is unrecognized.  This is used to handle
+   definitions of a29k style local labels.  */
+
+int
+a29k_unrecognized_line (c)
+     int c;
+{
+  int lab;
+  char *s;
+
+  if (c != '$'
+      || ! isdigit ((unsigned char) input_line_pointer[0]))
+    return 0;
+
+  s = input_line_pointer;
+
+  lab = 0;
+  while (isdigit ((unsigned char) *s))
+    {
+      lab = lab * 10 + *s - '0';
+      ++s;
+    }
+
+  if (*s != ':')
+    {
+      /* Not a label definition.  */
+      return 0;
+    }
+
+  if (dollar_label_defined (lab))
+    {
+      as_bad (_("label \"$%d\" redefined"), lab);
+      return 0;
+    }
+
+  define_dollar_label (lab);
+  colon (dollar_label_name (lab, 0));
+  input_line_pointer = s + 1;
+
+  return 1;
+}
+
 /* Default the values of symbols known that should be "predefined".  We
    don't bother to predefine them unless you actually use one, since there
    are a lot of them.  */
@@ -1091,7 +1119,7 @@ md_undefined_symbol (name)
          long maxreg;
 
          /* Parse the number, make sure it has no extra zeroes or
-            trailing chars. */
+            trailing chars.  */
          regnum = atol (&name[2]);
 
          if (name[0] == 's' || name[0] == 'S')
@@ -1132,7 +1160,7 @@ md_operand (expressionP)
       (void) expression (expressionP);
       if (expressionP->X_op != O_constant
          || expressionP->X_add_number > 255)
-       as_bad ("Invalid expression after %%%%\n");
+       as_bad (_("Invalid expression after %%%%\n"));
       expressionP->X_op = O_register;
     }
   else if (input_line_pointer[0] == '&')
@@ -1143,10 +1171,105 @@ md_operand (expressionP)
       input_line_pointer++;    /* Skip & */
       (void) expression (expressionP);
       if (expressionP->X_op != O_register)
-       as_bad ("Invalid register in & expression");
+       as_bad (_("Invalid register in & expression"));
       else
        expressionP->X_op = O_constant;
     }
+  else if (input_line_pointer[0] == '$'
+          && isdigit ((unsigned char) input_line_pointer[1]))
+    {
+      long lab;
+      char *name;
+      symbolS *sym;
+
+      /* This is a local label.  */
+      ++input_line_pointer;
+      lab = (long) get_absolute_expression ();
+      if (dollar_label_defined (lab))
+       {
+         name = dollar_label_name (lab, 0);
+         sym = symbol_find (name);
+       }
+      else
+       {
+         name = dollar_label_name (lab, 1);
+         sym = symbol_find_or_make (name);
+       }
+
+      expressionP->X_op = O_symbol;
+      expressionP->X_add_symbol = sym;
+      expressionP->X_add_number = 0;
+    }
+  else if (input_line_pointer[0] == '$')
+    {
+      char *s;
+      char type;
+      int fieldnum, fieldlimit;
+      LITTLENUM_TYPE floatbuf[8];
+
+      /* $float(), $doubleN(), or $extendN() convert floating values
+        to integers.  */
+
+      s = input_line_pointer;
+
+      ++s;
+
+      fieldnum = 0;
+      if (strncmp (s, "double", sizeof "double" - 1) == 0)
+       {
+         s += sizeof "double" - 1;
+         type = 'd';
+         fieldlimit = 2;
+       }
+      else if (strncmp (s, "float", sizeof "float" - 1) == 0)
+       {
+         s += sizeof "float" - 1;
+         type = 'f';
+         fieldlimit = 1;
+       }
+      else if (strncmp (s, "extend", sizeof "extend" - 1) == 0)
+       {
+         s += sizeof "extend" - 1;
+         type = 'x';
+         fieldlimit = 4;
+       }
+      else
+       {
+         return;
+       }
+
+      if (isdigit (*s))
+       {
+         fieldnum = *s - '0';
+         ++s;
+       }
+      if (fieldnum >= fieldlimit)
+       return;
+
+      SKIP_WHITESPACE ();
+      if (*s != '(')
+       return;
+      ++s;
+      SKIP_WHITESPACE ();
+
+      s = atof_ieee (s, type, floatbuf);
+      if (s == NULL)
+       return;
+      s = s;
+
+      SKIP_WHITESPACE ();
+      if (*s != ')')
+       return;
+      ++s;
+      SKIP_WHITESPACE ();
+
+      input_line_pointer = s;
+      expressionP->X_op = O_constant;
+      expressionP->X_unsigned = 1;
+      expressionP->X_add_number = ((floatbuf[fieldnum * 2]
+                                   << LITTLENUM_NUMBER_OF_BITS)
+                                  + floatbuf[fieldnum * 2 + 1]);
+    }
 }
 
 /* Round up a section size to the appropriate boundary.  */
@@ -1167,5 +1290,3 @@ md_pcrel_from (fixP)
 {
   return fixP->fx_where + fixP->fx_frag->fr_address;
 }
-
-/* end of tc-a29k.c */
This page took 0.028516 seconds and 4 git commands to generate.