2003-08-01 Jason Eckhardt <jle@rice.edu>
[deliverable/binutils-gdb.git] / gas / config / tc-sparc.c
index 5fa4fe980f3c153091770bcd06de52df62789f8f..2278411d61535e3011c95532334a1bcba1e599eb 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-sparc.c -- Assemble for the SPARC
    Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002
+   1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
    This file is part of GAS, the GNU Assembler.
 
@@ -138,7 +138,9 @@ static void s_common PARAMS ((int));
 static void s_empty PARAMS ((int));
 static void s_uacons PARAMS ((int));
 static void s_ncons PARAMS ((int));
+#ifdef OBJ_ELF
 static void s_register PARAMS ((int));
+#endif
 
 const pseudo_typeS md_pseudo_table[] =
 {
@@ -159,8 +161,6 @@ const pseudo_typeS md_pseudo_table[] =
   {"uaword", s_uacons, 4},
   {"uaxword", s_uacons, 8},
 #ifdef OBJ_ELF
-  {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
-  {"loc", dwarf2_directive_loc, 0},
   /* These are specific to sparc/svr4.  */
   {"2byte", s_uacons, 2},
   {"4byte", s_uacons, 4},
@@ -1804,10 +1804,88 @@ sparc_ip (str, pinsn)
              break;
 
            case '\0':          /* End of args.  */
-             if (*s == '\0')
+             if (s[0] == ',' && s[1] == '%')
                {
-                 match = 1;
+                 static const struct tls_ops {
+                   /* The name as it appears in assembler.  */
+                   char *name;
+                   /* strlen (name), precomputed for speed */
+                   int len;
+                   /* The reloc this pseudo-op translates to.  */
+                   int reloc;
+                   /* 1 if call.  */
+                   int call;
+                 } tls_ops[] = {
+                   { "tgd_add", 7, BFD_RELOC_SPARC_TLS_GD_ADD, 0 },
+                   { "tgd_call", 8, BFD_RELOC_SPARC_TLS_GD_CALL, 1 },
+                   { "tldm_add", 8, BFD_RELOC_SPARC_TLS_LDM_ADD, 0 },
+                   { "tldm_call", 9, BFD_RELOC_SPARC_TLS_LDM_CALL, 1 },
+                   { "tldo_add", 8, BFD_RELOC_SPARC_TLS_LDO_ADD, 0 },
+                   { "tie_ldx", 7, BFD_RELOC_SPARC_TLS_IE_LDX, 0 },
+                   { "tie_ld", 6, BFD_RELOC_SPARC_TLS_IE_LD, 0 },
+                   { "tie_add", 7, BFD_RELOC_SPARC_TLS_IE_ADD, 0 }
+                 };
+                 const struct tls_ops *o;
+                 char *s1;
+                 int npar = 0;
+
+                 for (o = tls_ops; o->name; o++)
+                   if (strncmp (s + 2, o->name, o->len) == 0)
+                     break;
+                 if (o->name == NULL)
+                   break;
+
+                 if (s[o->len + 2] != '(')
+                   {
+                     as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name);
+                     return special_case;
+                   }
+
+                 if (! o->call && the_insn.reloc != BFD_RELOC_NONE)
+                   {
+                     as_bad (_("Illegal operands: %%%s cannot be used together with other relocs in the insn ()"),
+                             o->name);
+                     return special_case;
+                   }
+
+                 if (o->call
+                     && (the_insn.reloc != BFD_RELOC_32_PCREL_S2
+                         || the_insn.exp.X_add_number != 0
+                         || the_insn.exp.X_add_symbol
+                            != symbol_find_or_make ("__tls_get_addr")))
+                   {
+                     as_bad (_("Illegal operands: %%%s can be only used with call __tls_get_addr"),
+                             o->name);
+                     return special_case;
+                   }
+
+                 the_insn.reloc = o->reloc;
+                 memset (&the_insn.exp, 0, sizeof (the_insn.exp));
+                 s += o->len + 3;
+
+                 for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++)
+                   if (*s1 == '(')
+                     npar++;
+                   else if (*s1 == ')')
+                     {
+                       if (!npar)
+                         break;
+                       npar--;
+                     }
+
+                 if (*s1 != ')')
+                   {
+                     as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name);
+                     return special_case;
+                   }
+
+                 *s1 = '\0';
+                 (void) get_expression (s);
+                 *s1 = ')';
+                 s = s1 + 1;
                }
+             if (*s == '\0')
+               match = 1;
              break;
 
            case '+':
@@ -2174,6 +2252,18 @@ sparc_ip (str, pinsn)
                      { "l44", 3, BFD_RELOC_SPARC_L44, 1, 0 },
                      { "uhi", 3, BFD_RELOC_SPARC_HH22, 1, 0 },
                      { "ulo", 3, BFD_RELOC_SPARC_HM10, 1, 0 },
+                     { "tgd_hi22", 8, BFD_RELOC_SPARC_TLS_GD_HI22, 0, 0 },
+                     { "tgd_lo10", 8, BFD_RELOC_SPARC_TLS_GD_LO10, 0, 0 },
+                     { "tldm_hi22", 9, BFD_RELOC_SPARC_TLS_LDM_HI22, 0, 0 },
+                     { "tldm_lo10", 9, BFD_RELOC_SPARC_TLS_LDM_LO10, 0, 0 },
+                     { "tldo_hix22", 10, BFD_RELOC_SPARC_TLS_LDO_HIX22, 0,
+                                                                        0 },
+                     { "tldo_lox10", 10, BFD_RELOC_SPARC_TLS_LDO_LOX10, 0,
+                                                                        0 },
+                     { "tie_hi22", 8, BFD_RELOC_SPARC_TLS_IE_HI22, 0, 0 },
+                     { "tie_lo10", 8, BFD_RELOC_SPARC_TLS_IE_LO10, 0, 0 },
+                     { "tle_hix22", 9, BFD_RELOC_SPARC_TLS_LE_HIX22, 0, 0 },
+                     { "tle_lox10", 9, BFD_RELOC_SPARC_TLS_LE_LOX10, 0, 0 },
                      { NULL, 0, 0, 0, 0 }
                    };
                    const struct ops *o;
@@ -2376,6 +2466,13 @@ sparc_ip (str, pinsn)
                      goto error;
                    }
 
+                 if (the_insn.reloc >= BFD_RELOC_SPARC_TLS_GD_HI22
+                     && the_insn.reloc <= BFD_RELOC_SPARC_TLS_TPOFF64)
+                   {
+                     error_message = _(": TLS operand can't be a constant");
+                     goto error;
+                   }
+
                  /* Constants that won't fit are checked in md_apply_fix3
                     and bfd_install_relocation.
                     ??? It would be preferable to install the constants
@@ -2891,7 +2988,7 @@ void
 md_apply_fix3 (fixP, valP, segment)
      fixS *fixP;
      valueT *valP;
-     segT segment;
+     segT segment ATTRIBUTE_UNUSED;
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   offsetT val = * (offsetT *) valP;
@@ -2902,34 +2999,9 @@ md_apply_fix3 (fixP, valP, segment)
   fixP->fx_addnumber = val;    /* Remember value for emit_reloc.  */
 
 #ifdef OBJ_ELF
-  /* FIXME: SPARC ELF relocations don't use an addend in the data
-     field itself.  This whole approach should be somehow combined
-     with the calls to bfd_install_relocation.  Also, the value passed
-     in by fixup_segment includes the value of a defined symbol.  We
-     don't want to include the value of an externally visible symbol.  */
+  /* SPARC ELF relocations don't use an addend in the data field.  */
   if (fixP->fx_addsy != NULL)
-    {
-       symbolS * sym = fixP->fx_addsy;
-        segT      seg = S_GET_SEGMENT (sym);
-
-      if (symbol_used_in_reloc_p (sym)
-         && (S_IS_EXTERNAL (sym)
-             || S_IS_WEAK (sym)
-             || (seg->flags & SEC_MERGE)
-             || (seg->flags & SEC_THREAD_LOCAL)
-             || (sparc_pic_code && ! fixP->fx_pcrel)
-             || (seg != segment
-                 && (((bfd_get_section_flags (stdoutput, seg) & SEC_LINK_ONCE) != 0)
-                     || (strncmp (segment_name (seg),
-                                  ".gnu.linkonce",
-                                  sizeof ".gnu.linkonce" - 1) == 0))))
-         && seg != absolute_section
-         && seg != undefined_section
-         && ! bfd_is_com_section (seg))
-       fixP->fx_addnumber -= S_GET_VALUE (sym);
-
-      return;
-    }
+    return;
 #endif
 
   /* This is a hack.  There should be a better way to
@@ -3271,7 +3343,7 @@ md_apply_fix3 (fixP, valP, segment)
 
 arelent **
 tc_gen_reloc (section, fixp)
-     asection *section;
+     asection *section ATTRIBUTE_UNUSED;
      fixS *fixp;
 {
   static arelent *relocs[3];
@@ -3328,6 +3400,26 @@ tc_gen_reloc (section, fixp)
     case BFD_RELOC_SPARC_PLT64:
     case BFD_RELOC_VTABLE_ENTRY:
     case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_SPARC_TLS_GD_HI22:
+    case BFD_RELOC_SPARC_TLS_GD_LO10:
+    case BFD_RELOC_SPARC_TLS_GD_ADD:
+    case BFD_RELOC_SPARC_TLS_GD_CALL:
+    case BFD_RELOC_SPARC_TLS_LDM_HI22:
+    case BFD_RELOC_SPARC_TLS_LDM_LO10:
+    case BFD_RELOC_SPARC_TLS_LDM_ADD:
+    case BFD_RELOC_SPARC_TLS_LDM_CALL:
+    case BFD_RELOC_SPARC_TLS_LDO_HIX22:
+    case BFD_RELOC_SPARC_TLS_LDO_LOX10:
+    case BFD_RELOC_SPARC_TLS_LDO_ADD:
+    case BFD_RELOC_SPARC_TLS_IE_HI22:
+    case BFD_RELOC_SPARC_TLS_IE_LO10:
+    case BFD_RELOC_SPARC_TLS_IE_LD:
+    case BFD_RELOC_SPARC_TLS_IE_LDX:
+    case BFD_RELOC_SPARC_TLS_IE_ADD:
+    case BFD_RELOC_SPARC_TLS_LE_HIX22:
+    case BFD_RELOC_SPARC_TLS_LE_LOX10:
+    case BFD_RELOC_SPARC_TLS_DTPOFF32:
+    case BFD_RELOC_SPARC_TLS_DTPOFF64:
       code = fixp->fx_r_type;
       break;
     default:
@@ -3352,10 +3444,7 @@ tc_gen_reloc (section, fixp)
       switch (code)
        {
        case BFD_RELOC_32_PCREL_S2:
-         if (! S_IS_DEFINED (fixp->fx_addsy)
-             || S_IS_COMMON (fixp->fx_addsy)
-             || S_IS_EXTERNAL (fixp->fx_addsy)
-             || S_IS_WEAK (fixp->fx_addsy))
+         if (generic_force_reloc (fixp))
            code = BFD_RELOC_SPARC_WPLT30;
          break;
        case BFD_RELOC_HI22:
@@ -3419,7 +3508,9 @@ tc_gen_reloc (section, fixp)
       && code != BFD_RELOC_SPARC_WDISP22
       && code != BFD_RELOC_SPARC_WDISP16
       && code != BFD_RELOC_SPARC_WDISP19
-      && code != BFD_RELOC_SPARC_WPLT30)
+      && code != BFD_RELOC_SPARC_WPLT30
+      && code != BFD_RELOC_SPARC_TLS_GD_CALL
+      && code != BFD_RELOC_SPARC_TLS_LDM_CALL)
     reloc->addend = fixp->fx_addnumber;
   else if (symbol_section_p (fixp->fx_addsy))
     reloc->addend = (section->vma
@@ -3673,7 +3764,7 @@ s_common (ignore)
   char *name;
   char c;
   char *p;
-  int temp, size;
+  offsetT temp, size;
   symbolS *symbolP;
 
   name = input_line_pointer;
@@ -3694,7 +3785,8 @@ s_common (ignore)
 
   if ((temp = get_absolute_expression ()) < 0)
     {
-      as_bad (_(".COMMon length (%d.) <0! Ignored."), temp);
+      as_bad (_(".COMMon length (%lu) out of range ignored"),
+             (unsigned long) temp);
       ignore_rest_of_line ();
       return;
     }
@@ -4222,6 +4314,16 @@ sparc_cons (exp, size)
              sparc_cons_special_reloc = "plt";
            }
        }
+      else if (strncmp (input_line_pointer + 3, "tls_dtpoff", 10) == 0)
+       {
+         if (size != 4 && size != 8)
+           as_bad (_("Illegal operands: %%r_tls_dtpoff in %d-byte data field"), size);
+         else
+           {
+             input_line_pointer += 13;
+             sparc_cons_special_reloc = "tls_dtpoff";
+           }
+       }
       if (sparc_cons_special_reloc)
        {
          int bad = 0;
@@ -4355,12 +4457,18 @@ cons_fix_new_sparc (frag, where, nbytes, exp)
          case 8: r = BFD_RELOC_64_PCREL; break;
          default: abort ();
          }
-      else
+      else if (*sparc_cons_special_reloc == 'p')
        switch (nbytes)
          {
          case 4: r = BFD_RELOC_SPARC_PLT32; break;
          case 8: r = BFD_RELOC_SPARC_PLT64; break;
          }
+      else
+       switch (nbytes)
+         {
+         case 4: r = BFD_RELOC_SPARC_TLS_DTPOFF32; break;
+         case 8: r = BFD_RELOC_SPARC_TLS_DTPOFF64; break;
+         }
     }
   else if (sparc_no_align_cons)
     {
@@ -4375,16 +4483,3 @@ cons_fix_new_sparc (frag, where, nbytes, exp)
 
   fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
 }
-
-#ifdef OBJ_ELF
-int
-elf32_sparc_force_relocation (fixp)
-     struct fix *fixp;
-{
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
-    return 1;
-
-  return 0;
-}
-#endif
This page took 0.026526 seconds and 4 git commands to generate.