Support for @GOTOFF in .long expressions.
authorAlan Modra <amodra@gmail.com>
Tue, 13 Mar 2001 04:37:13 +0000 (04:37 +0000)
committerAlan Modra <amodra@gmail.com>
Tue, 13 Mar 2001 04:37:13 +0000 (04:37 +0000)
gas/ChangeLog
gas/config/tc-i386.c
gas/config/tc-i386.h

index e88ebff4b40ba7327aa78e220b022afd8b482fc9..2d6241db0af5d980b3fe2d94fbde0869978e213d 100644 (file)
@@ -1,3 +1,19 @@
+2001-03-13  Alan Modra  <alan@linuxcare.com.au>
+
+       * config/tc-i386.c (RELOC_ENUM): Define.  Use throughout file.
+       (NUM_FLAG_CODE): Define.
+       (lex_got): New function.
+       (got_reloc): New global var.
+       (x86_cons_fix_new): New function.
+       (x86_cons): New function.
+       (i386_immediate): Use lex_got here, replacing inline code.  Change
+       "ignoring junk.." error message to "junk.."
+       (i386_displacement): Likewise.
+       * config/tc-i386.h (TC_PARSE_CONS_EXPRESSION): Define.
+       (x86_cons): Declare.
+       (TC_CONS_FIX_NEW): Define.
+       (x86_cons_fix_new): Declare.
+
 2001-03-12  Nick Clifton  <nickc@redhat.com>
 
        * config/tc-arm.c (md_begin): Always set machine type based on
 2001-03-07  Alan Modra  <alan@linuxcare.com.au>
 
        * config/tc-i386.c (struct _i386_insn): Rename disp_reloc to reloc.
-       (md_assemble [smallest displacement]): Use correct field of i.op[]
+       (md_assemble) <smallest displacement>: Use correct field of i.op[]
        union.
-       (md_assemble [JumpInterSegment output]): Use correct i.disp_reloc[].
-       (md_assemble [immediate output]): Likewise.
+       <JumpInterSegment output>: Use correct i.disp_reloc[].
+       <immediate output>: Likewise.
 
 2001-03-06  Nick Clifton  <nickc@redhat.com>
 
index 7300a25f0742d125b99adfd4802cab9aab7f6fb5..74e5e13a7d946b0a99027fae0506113572179eb4 100644 (file)
@@ -70,6 +70,9 @@ static void set_cpu_arch PARAMS ((int));
 #ifdef BFD_ASSEMBLER
 static bfd_reloc_code_real_type reloc
   PARAMS ((int, int, int, bfd_reloc_code_real_type));
+#define RELOC_ENUM enum bfd_reloc_code_real
+#else
+#define RELOC_ENUM int
 #endif
 
 #ifndef DEFAULT_ARCH
@@ -117,11 +120,7 @@ struct _i386_insn
 #define Operand_PCrel 1
 
     /* Relocation type for operand */
-#ifdef BFD_ASSEMBLER
-    enum bfd_reloc_code_real reloc[MAX_OPERANDS];
-#else
-    int reloc[MAX_OPERANDS];
-#endif
+    RELOC_ENUM reloc[MAX_OPERANDS];
 
     /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode
        the base index byte below.  */
@@ -241,6 +240,7 @@ enum flag_code {
        CODE_32BIT,
        CODE_16BIT,
        CODE_64BIT };
+#define NUM_FLAG_CODE ((int) CODE_64BIT + 1)
 
 static enum flag_code flag_code;
 static int use_rela_relocations = 0;
@@ -1546,11 +1546,7 @@ md_assemble (line)
       {
        union i386_op temp_op;
        unsigned int temp_type;
-#ifdef BFD_ASSEMBLER
-       enum bfd_reloc_code_real temp_reloc;
-#else
-       int temp_reloc;
-#endif
+       RELOC_ENUM temp_reloc;
        int xchg1 = 0;
        int xchg2 = 0;
 
@@ -3068,11 +3064,7 @@ md_assemble (line)
                           Need a 32-bit fixup (don't support 8bit
                           non-absolute imms).  Try to support other
                           sizes ...  */
-#ifdef BFD_ASSEMBLER
-                       enum bfd_reloc_code_real reloc_type;
-#else
-                       int reloc_type;
-#endif
+                       RELOC_ENUM reloc_type;
                        int size = 4;
                        int sign = 0;
 
@@ -3127,6 +3119,130 @@ md_assemble (line)
   }
 }
 \f
+#ifndef LEX_AT
+static char *lex_got PARAMS ((RELOC_ENUM *, int *));
+
+/* Parse operands of the form
+   <symbol>@GOTOFF+<nnn>
+   and similar .plt or .got references.
+
+   If we find one, set up the correct relocation in RELOC and copy the
+   input string, minus the `@GOTOFF' into a malloc'd buffer for
+   parsing by the calling routine.  Return this buffer, and if ADJUST
+   is non-null set it to the length of the string we removed from the
+   input line.  Otherwise return NULL.  */
+static char *
+lex_got (reloc, adjust)
+     RELOC_ENUM *reloc;
+     int *adjust;
+{
+  static const char * const mode_name[NUM_FLAG_CODE] = { "32", "16", "64" };
+  static const struct {
+    const char *str;
+    const RELOC_ENUM rel[NUM_FLAG_CODE];
+  } gotrel[] = {
+    { "PLT",      { BFD_RELOC_386_PLT32,  0, BFD_RELOC_X86_64_PLT32    } },
+    { "GOTOFF",   { BFD_RELOC_386_GOTOFF, 0, 0                         } },
+    { "GOTPCREL", { 0,                    0, BFD_RELOC_X86_64_GOTPCREL } },
+    { "GOT",      { BFD_RELOC_386_GOT32,  0, BFD_RELOC_X86_64_GOT32    } }
+  };
+  char *cp;
+  unsigned int j;
+
+  for (cp = input_line_pointer; *cp != '@'; cp++)
+    if (is_end_of_line[(unsigned char) *cp])
+      return NULL;
+
+  for (j = 0; j < sizeof (gotrel) / sizeof (gotrel[0]); j++)
+    {
+      int len;
+
+      len = strlen (gotrel[j].str);
+      if (strncmp (cp + 1, gotrel[j].str, len) == 0)
+       {
+         if (gotrel[j].rel[(unsigned int) flag_code] != 0)
+           {
+             int first;
+             char *tmpbuf;
+
+             *reloc = gotrel[j].rel[(unsigned int) flag_code];
+
+             if (GOT_symbol == NULL)
+               GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
+
+             /* Replace the relocation token with ' ', so that
+                errors like foo@GOTOFF1 will be detected.  */
+             first = cp - input_line_pointer;
+             tmpbuf = xmalloc (strlen (input_line_pointer));
+             memcpy (tmpbuf, input_line_pointer, first);
+             tmpbuf[first] = ' ';
+             strcpy (tmpbuf + first + 1, cp + 1 + len);
+             if (adjust)
+               *adjust = len;
+             return tmpbuf;
+           }
+
+         as_bad (_("@%s reloc is not supported in %s bit mode"),
+                 gotrel[j].str, mode_name[(unsigned int) flag_code]);
+         return NULL;
+       }
+    }
+
+  /* Might be a symbol version string.  Don't as_bad here.  */
+  return NULL;
+}
+
+/* x86_cons_fix_new is called via the expression parsing code when a
+   reloc is needed.  We use this hook to get the correct .got reloc.  */
+static RELOC_ENUM got_reloc = NO_RELOC;
+
+void
+x86_cons_fix_new (frag, off, len, exp)
+     fragS *frag;
+     unsigned int off;
+     unsigned int len;
+     expressionS *exp;
+{
+  RELOC_ENUM r = reloc (len, 0, 0, got_reloc);
+  got_reloc = NO_RELOC;
+  fix_new_exp (frag, off, len, exp, 0, r);
+}
+
+void
+x86_cons (exp, size)
+     expressionS *exp;
+     int size;
+{
+  if (size == 4)
+    {
+      /* Handle @GOTOFF and the like in an expression.  */
+      char *save;
+      char *gotfree_input_line;
+      int adjust;
+
+      save = input_line_pointer;
+      gotfree_input_line = lex_got (&got_reloc, &adjust);
+      if (gotfree_input_line)
+       input_line_pointer = gotfree_input_line;
+
+      expression (exp);
+
+      if (gotfree_input_line)
+       {
+         /* expression () has merrily parsed up to the end of line,
+            or a comma - in the wrong buffer.  Transfer how far
+            input_line_pointer has moved to the right buffer.  */
+         input_line_pointer = (save
+                               + (input_line_pointer - gotfree_input_line)
+                               + adjust);
+         free (gotfree_input_line);
+       }
+    }
+  else
+    expression (exp);
+}
+#endif
+
 static int i386_immediate PARAMS ((char *));
 
 static int
@@ -3134,6 +3250,9 @@ i386_immediate (imm_start)
      char *imm_start;
 {
   char *save_input_line_pointer;
+#ifndef LEX_AT
+  char *gotfree_input_line;
+#endif
   segT exp_seg = 0;
   expressionS *exp;
 
@@ -3153,80 +3272,22 @@ i386_immediate (imm_start)
   input_line_pointer = imm_start;
 
 #ifndef LEX_AT
-  {
-    /* We can have operands of the form
-         <symbol>@GOTOFF+<nnn>
-       Take the easy way out here and copy everything
-       into a temporary buffer...  */
-    register char *cp;
-
-    cp = strchr (input_line_pointer, '@');
-    if (cp != NULL)
-      {
-       char *tmpbuf;
-       int len = 0;
-       int first;
-
-       /* GOT relocations are not supported in 16 bit mode.  */
-       if (flag_code == CODE_16BIT)
-         as_bad (_("GOT relocations not supported in 16 bit mode"));
-
-       if (GOT_symbol == NULL)
-         GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
-
-       if (strncmp (cp + 1, "PLT", 3) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.reloc[this_operand] = BFD_RELOC_X86_64_PLT32;
-           else
-             i.reloc[this_operand] = BFD_RELOC_386_PLT32;
-           len = 3;
-         }
-       else if (strncmp (cp + 1, "GOTOFF", 6) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             as_bad ("GOTOFF relocations are unsupported in 64bit mode.");
-           i.reloc[this_operand] = BFD_RELOC_386_GOTOFF;
-           len = 6;
-         }
-       else if (strncmp (cp + 1, "GOTPCREL", 8) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.reloc[this_operand] = BFD_RELOC_X86_64_GOTPCREL;
-           else
-             as_bad ("GOTPCREL relocations are supported only in 64bit mode.");
-           len = 8;
-         }
-       else if (strncmp (cp + 1, "GOT", 3) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.reloc[this_operand] = BFD_RELOC_X86_64_GOT32;
-           else
-             i.reloc[this_operand] = BFD_RELOC_386_GOT32;
-           len = 3;
-         }
-       else
-         as_bad (_("bad reloc specifier in expression"));
-
-       /* Replace the relocation token with ' ', so that errors like
-          foo@GOTOFF1 will be detected.  */
-       first = cp - input_line_pointer;
-       tmpbuf = (char *) alloca (strlen (input_line_pointer));
-       memcpy (tmpbuf, input_line_pointer, first);
-       tmpbuf[first] = ' ';
-       strcpy (tmpbuf + first + 1, cp + 1 + len);
-       input_line_pointer = tmpbuf;
-      }
-  }
+  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL);
+  if (gotfree_input_line)
+    input_line_pointer = gotfree_input_line;
 #endif
 
   exp_seg = expression (exp);
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer)
-    as_bad (_("ignoring junk `%s' after expression"), input_line_pointer);
+    as_bad (_("junk `%s' after expression"), input_line_pointer);
 
   input_line_pointer = save_input_line_pointer;
+#ifndef LEX_AT
+  if (gotfree_input_line)
+    free (gotfree_input_line);
+#endif
 
   if (exp->X_op == O_absent || exp->X_op == O_big)
     {
@@ -3331,6 +3392,9 @@ i386_displacement (disp_start, disp_end)
   register expressionS *exp;
   segT exp_seg = 0;
   char *save_input_line_pointer;
+#ifndef LEX_AT
+  char *gotfree_input_line;
+#endif
   int bigdisp = Disp32;
 
   if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
@@ -3391,70 +3455,9 @@ i386_displacement (disp_start, disp_end)
     }
 #endif
 #ifndef LEX_AT
-  {
-    /* We can have operands of the form
-         <symbol>@GOTOFF+<nnn>
-       Take the easy way out here and copy everything
-       into a temporary buffer...  */
-    register char *cp;
-
-    cp = strchr (input_line_pointer, '@');
-    if (cp != NULL)
-      {
-       char *tmpbuf;
-       int len = 0;
-       int first;
-
-       /* GOT relocations are not supported in 16 bit mode.  */
-       if (flag_code == CODE_16BIT)
-         as_bad (_("GOT relocations not supported in 16 bit mode"));
-
-       if (GOT_symbol == NULL)
-         GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
-
-       if (strncmp (cp + 1, "PLT", 3) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.reloc[this_operand] = BFD_RELOC_X86_64_PLT32;
-           else
-             i.reloc[this_operand] = BFD_RELOC_386_PLT32;
-           len = 3;
-         }
-       else if (strncmp (cp + 1, "GOTOFF", 6) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             as_bad ("GOTOFF relocation is not supported in 64bit mode.");
-           i.reloc[this_operand] = BFD_RELOC_386_GOTOFF;
-           len = 6;
-         }
-       else if (strncmp (cp + 1, "GOTPCREL", 8) == 0)
-         {
-           if (flag_code != CODE_64BIT)
-             as_bad ("GOTPCREL relocation is supported only in 64bit mode.");
-           i.reloc[this_operand] = BFD_RELOC_X86_64_GOTPCREL;
-           len = 8;
-         }
-       else if (strncmp (cp + 1, "GOT", 3) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.reloc[this_operand] = BFD_RELOC_X86_64_GOT32;
-           else
-             i.reloc[this_operand] = BFD_RELOC_386_GOT32;
-           len = 3;
-         }
-       else
-         as_bad (_("bad reloc specifier in expression"));
-
-       /* Replace the relocation token with ' ', so that errors like
-          foo@GOTOFF1 will be detected.  */
-       first = cp - input_line_pointer;
-       tmpbuf = (char *) alloca (strlen (input_line_pointer));
-       memcpy (tmpbuf, input_line_pointer, first);
-       tmpbuf[first] = ' ';
-       strcpy (tmpbuf + first + 1, cp + 1 + len);
-       input_line_pointer = tmpbuf;
-      }
-  }
+  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL);
+  if (gotfree_input_line)
+    input_line_pointer = gotfree_input_line;
 #endif
 
   exp_seg = expression (exp);
@@ -3481,13 +3484,16 @@ i386_displacement (disp_start, disp_end)
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer)
-    as_bad (_("ignoring junk `%s' after expression"),
-           input_line_pointer);
+    as_bad (_("junk `%s' after expression"), input_line_pointer);
 #if GCC_ASM_O_HACK
   RESTORE_END_STRING (disp_end + 1);
 #endif
   RESTORE_END_STRING (disp_end);
   input_line_pointer = save_input_line_pointer;
+#ifndef LEX_AT
+  if (gotfree_input_line)
+    free (gotfree_input_line);
+#endif
 
   if (exp->X_op == O_absent || exp->X_op == O_big)
     {
@@ -3927,11 +3933,7 @@ md_estimate_size_before_relax (fragP, segment)
       /* Symbol is undefined in this segment, or we need to keep a
         reloc so that weak symbols can be overridden.  */
       int size = (fragP->fr_subtype & CODE16) ? 2 : 4;
-#ifdef BFD_ASSEMBLER
-      enum bfd_reloc_code_real reloc_type;
-#else
-      int reloc_type;
-#endif
+      RELOC_ENUM reloc_type;
       unsigned char *opcode;
       int old_fr_fix;
 
index 9e53ad6632b835550468b5dcd589ba913189ee49..71e0c88be31bbdbe859a47370befd5a08be9d68e 100644 (file)
@@ -155,6 +155,15 @@ extern int tc_coff_sizemachdep PARAMS ((fragS *frag));
 
 #endif /* ! BFD_ASSEMBLER */
 
+#ifndef LEX_AT
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) x86_cons (EXP, NBYTES)
+extern void x86_cons PARAMS ((expressionS *, int));
+
+#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) x86_cons_fix_new(FRAG, OFF, LEN, EXP)
+extern void x86_cons_fix_new
+  PARAMS ((fragS *, unsigned int, unsigned int, expressionS *));
+#endif
+
 #define TC_FORCE_RELOCATION(fixp) tc_i386_force_relocation(fixp)
 extern int tc_i386_force_relocation PARAMS ((struct fix *));