* config/tc-sparc.c (tc_gen_reloc): If PIC, only change PCREL_S2
authorIan Lance Taylor <ian@airs.com>
Wed, 16 Aug 1995 20:21:49 +0000 (20:21 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 16 Aug 1995 20:21:49 +0000 (20:21 +0000)
to WPLT30 for an undefined or external symbol.  Don't consider
PC10 or PC22 to be a PC relative reloc when choosing between
fx_addnumber and fx_offset.

gas/ChangeLog
gas/config/tc-sparc.c

index b2e7c90..966a882 100644 (file)
@@ -1,5 +1,10 @@
 Wed Aug 16 12:49:17 1995  Ian Lance Taylor  <ian@cygnus.com>
 
+       * config/tc-sparc.c (tc_gen_reloc): If PIC, only change PCREL_S2
+       to WPLT30 for an undefined or external symbol.  Don't consider
+       PC10 or PC22 to be a PC relative reloc when choosing between
+       fx_addnumber and fx_offset.
+
        * config/tc-z8k.c (md_number_to_chars): Don't do it here, call
        number_to_chars_bigendian.
        * config/tc-z8k.h (TARGET_BYTES_BIG_ENDIAN): Define.
index faf2988..522d928 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-sparc.c -- Assemble for the SPARC
-   Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1989, 90, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -36,6 +36,9 @@ static enum sparc_architecture current_architecture = v6;
 static int architecture_requested;
 static int warn_on_bump;
 
+/* Non-zero if we are generating PIC code.  */
+int sparc_pic_code;
+
 extern int target_big_endian;
 
 /* handle of the OPCODE hash table */
@@ -1882,7 +1885,8 @@ md_apply_fix (fixP, value)
      don't want to include the value of an externally visible symbol.  */
   if (fixP->fx_addsy != NULL)
     {
-      if (S_IS_EXTERN (fixP->fx_addsy)
+      if ((S_IS_EXTERN (fixP->fx_addsy)
+          || (sparc_pic_code && ! fixP->fx_pcrel))
          && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section
          && S_GET_SEGMENT (fixP->fx_addsy) != undefined_section
          && ! bfd_is_com_section (S_GET_SEGMENT (fixP->fx_addsy)))
@@ -1908,6 +1912,17 @@ md_apply_fix (fixP, value)
   if (fixP->fx_addsy != NULL
       && fixP->fx_r_type != BFD_RELOC_32_PCREL_S2)
     val = 0;
+
+  /* When generating PIC code, we do not want an addend for a reloc
+     against a local symbol.  We adjust fx_addnumber to cancel out the
+     value already included in val, and to also cancel out the
+     adjustment which bfd_install_relocation will create.  */
+  if (sparc_pic_code
+      && fixP->fx_r_type != BFD_RELOC_32_PCREL_S2
+      && fixP->fx_addsy != NULL
+      && ! S_IS_COMMON (fixP->fx_addsy)
+      && (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) == 0)
+    fixP->fx_addnumber -= 2 * S_GET_VALUE (fixP->fx_addsy);
 #endif
 
   switch (fixP->fx_r_type)
@@ -1925,7 +1940,11 @@ md_apply_fix (fixP, value)
       break;
 
     case BFD_RELOC_32_PCREL_S2:
-      val = (val >>= 2) + 1;
+      val = (val >>= 2);
+      if (! sparc_pic_code
+         || fixP->fx_addsy == NULL
+         || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
+       ++val;
       buf[0] |= (val >> 24) & 0x3f;
       buf[1] = (val >> 16);
       buf[2] = val >> 8;
@@ -2115,6 +2134,49 @@ tc_gen_reloc (section, fixp)
     default:
       abort ();
     }
+
+#if defined (OBJ_ELF) || defined (OBJ_AOUT)
+  /* If we are generating PIC code, we need to generate a different
+     set of relocs.  */
+
+#ifdef OBJ_ELF
+#define GOT_NAME "_GLOBAL_OFFSET_TABLE_"
+#else
+#define GOT_NAME "__GLOBAL_OFFSET_TABLE_"
+#endif
+
+  if (sparc_pic_code)
+    {
+      switch (code)
+       {
+       case BFD_RELOC_32_PCREL_S2:
+         if (! S_IS_DEFINED (fixp->fx_addsy)
+             || S_IS_EXTERNAL (fixp->fx_addsy))
+           code = BFD_RELOC_SPARC_WPLT30;
+         break;
+       case BFD_RELOC_HI22:
+         if (fixp->fx_addsy != NULL
+             && strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
+           code = BFD_RELOC_SPARC_PC22;
+         else
+           code = BFD_RELOC_SPARC_GOT22;
+         break;
+       case BFD_RELOC_LO10:
+         if (fixp->fx_addsy != NULL
+             && strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
+           code = BFD_RELOC_SPARC_PC10;
+         else
+           code = BFD_RELOC_SPARC_GOT10;
+         break;
+       case BFD_RELOC_SPARC13:
+         code = BFD_RELOC_SPARC_GOT13;
+         break;
+       default:
+         break;
+       }
+    }
+#endif /* defined (OBJ_ELF) || defined (OBJ_AOUT) */
+
   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
   if (reloc->howto == 0)
     {
@@ -2123,19 +2185,22 @@ tc_gen_reloc (section, fixp)
                    fixp->fx_r_type, bfd_get_reloc_code_name (code));
       return 0;
     }
-  assert (!fixp->fx_pcrel == !reloc->howto->pc_relative);
 
   /* @@ Why fx_addnumber sometimes and fx_offset other times?  */
 #ifdef OBJ_AOUT
 
-  if (reloc->howto->pc_relative == 0)
+  if (reloc->howto->pc_relative == 0
+      || code == BFD_RELOC_SPARC_PC10
+      || code == BFD_RELOC_SPARC_PC22)
     reloc->addend = fixp->fx_addnumber;
   else
     reloc->addend = fixp->fx_offset - reloc->address;
 
 #else /* elf or coff */
 
-  if (reloc->howto->pc_relative == 0)
+  if (reloc->howto->pc_relative == 0
+      || code == BFD_RELOC_SPARC_PC10
+      || code == BFD_RELOC_SPARC_PC22)
     reloc->addend = fixp->fx_addnumber;
   else if ((fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
     reloc->addend = (section->vma
@@ -2143,7 +2208,6 @@ tc_gen_reloc (section, fixp)
                     + md_pcrel_from (fixp));
   else
     reloc->addend = fixp->fx_offset;
-
 #endif
 
   return reloc;
@@ -2241,8 +2305,12 @@ print_insn (insn)
 #ifdef OBJ_ELF
 CONST char *md_shortopts = "A:K:VQ:sq";
 #else
+#ifdef OBJ_AOUT
+CONST char *md_shortopts = "A:k";
+#else
 CONST char *md_shortopts = "A:";
 #endif
+#endif
 struct option md_longopts[] = {
 #define OPTION_BUMP (OPTION_MD_BASE)
   {"bump", no_argument, NULL, OPTION_BUMP},
@@ -2299,6 +2367,12 @@ md_parse_option (c, arg)
       /* Ignore -sparc, used by SunOS make default .s.o rule.  */
       break;
 
+#ifdef OBJ_AOUT
+    case 'k':
+      sparc_pic_code = 1;
+      break;
+#endif
+
 #ifdef OBJ_ELF
     case 'V':
       print_version_id ();
@@ -2321,10 +2395,8 @@ md_parse_option (c, arg)
       if (strcmp (arg, "PIC") != 0)
        as_warn ("Unrecognized option following -K");
       else
-       {
-         as_warn ("gas does not currently support PIC code for the SPARC");
-         as_fatal ("use /usr/ccs/bin/as instead");
-       }
+       sparc_pic_code = 1;
+      break;
 #endif
 
     default:
@@ -2350,8 +2422,13 @@ md_show_usage (stream)
                        specify variant of SPARC architecture\n\
 -bump                  warn when assembler switches architectures\n\
 -sparc                 ignored\n");
+#ifdef OBJ_AOUT
+  fprintf (stream, "\
+-k                     generate PIC\n");
+#endif
 #ifdef OBJ_ELF
-  fprintf(stream, "\
+  fprintf (stream, "\
+-KPIC                  generate PIC\n\
 -V                     print assembler version number\n\
 -q                     ignored\n\
 -Qy, -Qn               ignored\n\
@@ -2398,7 +2475,14 @@ long
 md_pcrel_from (fixP)
      fixS *fixP;
 {
-  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+  long ret;
+
+  ret = fixP->fx_where + fixP->fx_frag->fr_address;
+  if (! sparc_pic_code
+      || fixP->fx_addsy == NULL
+      || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
+    ret += fixP->fx_size;
+  return ret;
 }
 
 /* end of tc-sparc.c */