* tc-ppc.c (ppc_biei): Cache the last symbol we inserted
authorRichard Henderson <rth@redhat.com>
Fri, 20 Feb 1998 06:27:12 +0000 (06:27 +0000)
committerRichard Henderson <rth@redhat.com>
Fri, 20 Feb 1998 06:27:12 +0000 (06:27 +0000)
so we don't have to scan the entire list.

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

index 0116f8f81ee2a5b1b0132ebb63c2875a805958f3..6432d3bbd4826f3de63210ccb12e06a566ab03b3 100644 (file)
@@ -1,3 +1,8 @@
+Thu Feb 19 22:25:42 1998  Richard Henderson  <rth@cygnus.com>
+
+       * tc-ppc.c (ppc_biei): Cache the last symbol we inserted
+       so we don't have to scan the entire list.
+
 start-sanitize-d30v
 Tue Feb 17 17:02:15 1998  Fred Fish  <fnf@cygnus.com>
 
index 4f8771e67ca5508065c74c45d356ce162323258d..34b48d8c86ca717a72f9ce553e9637e802a58f4e 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
-   Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GAS, the GNU Assembler.
@@ -1206,8 +1206,17 @@ ppc_elf_suffix (str_p, exp_p)
 
   ch = ident[0];
   for (ptr = &mapping[0]; ptr->length > 0; ptr++)
-    if (ch == ptr->string[0] && len == ptr->length && memcmp (ident, ptr->string, ptr->length) == 0)
+    if (ch == ptr->string[0]
+       && len == ptr->length
+       && memcmp (ident, ptr->string, ptr->length) == 0)
       {
+       if (exp_p->X_add_number != 0
+           && (ptr->reloc == BFD_RELOC_16_GOTOFF
+               || ptr->reloc == BFD_RELOC_LO16_GOTOFF
+               || ptr->reloc == BFD_RELOC_HI16_GOTOFF
+               || ptr->reloc == BFD_RELOC_HI16_S_GOTOFF))
+         as_warn ("identifier+constant@got means identifier@got+constant");
+
        /* Now check for identifier@suffix+constant */
        if (*str == '-' || *str == '+')
          {
@@ -2857,6 +2866,8 @@ static void
 ppc_biei (ei)
      int ei;
 {
+  static symbolS *last_biei;
+
   char *name;
   int len;
   symbolS *sym;
@@ -2879,7 +2890,7 @@ ppc_biei (ei)
   S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL);
   sym->sy_tc.output = 1;
   
-  for (look = symbol_rootP;
+  for (look = last_biei ? last_biei : symbol_rootP;
        (look != (symbolS *) NULL
        && (S_GET_STORAGE_CLASS (look) == C_FILE
            || S_GET_STORAGE_CLASS (look) == C_BINCL
@@ -2890,6 +2901,7 @@ ppc_biei (ei)
     {
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
       symbol_insert (sym, look, &symbol_rootP, &symbol_lastP);
+      last_biei = sym;
     }
 
   demand_empty_rest_of_line ();
@@ -4405,13 +4417,6 @@ md_pcrel_from_section (fixp, sec)
      fixS *fixp;
      segT sec;
 {
-#ifdef OBJ_ELF
-  if (fixp->fx_addsy != (symbolS *) NULL
-      && (! S_IS_DEFINED (fixp->fx_addsy)
-         || TC_FORCE_RELOCATION_SECTION (fixp, sec)))
-    return 0;
-#endif
-
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
 
@@ -4466,7 +4471,13 @@ ppc_fix_adjustable (fix)
       && fix->fx_addsy->sy_tc.subseg == 0
       && fix->fx_addsy->sy_tc.class != XMC_TC0
       && fix->fx_addsy->sy_tc.class != XMC_TC
-      && S_GET_SEGMENT (fix->fx_addsy) != bss_section)
+      && S_GET_SEGMENT (fix->fx_addsy) != bss_section
+      /* Don't adjust if this is a reloc in the toc section.  */
+      && (S_GET_SEGMENT (fix->fx_addsy) != data_section
+         || ppc_toc_csect == NULL
+         || fix->fx_frag->fr_address < ppc_toc_frag->fr_address
+         || (ppc_after_toc_frag != NULL
+             && fix->fx_frag->fr_address >= ppc_after_toc_frag->fr_address)))
     {
       symbolS *csect;
 
@@ -4592,6 +4603,29 @@ md_apply_fix3 (fixp, valuep, seg)
 {
   valueT value;
 
+#ifdef OBJ_ELF
+  value = *valuep;
+  if (fixp->fx_addsy != NULL)
+    {
+      /* `*valuep' may contain the value of the symbol on which the reloc
+        will be based; we have to remove it.  */
+      if (fixp->fx_addsy->sy_used_in_reloc
+         && 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)))
+       value -= S_GET_VALUE (fixp->fx_addsy);
+
+      /* FIXME: Why '+'?  Better yet, what exactly is '*valuep'
+        supposed to be?  I think this is related to various similar
+        FIXMEs in tc-i386.c and tc-sparc.c.  */
+      if (fixp->fx_pcrel)
+       value += fixp->fx_frag->fr_address + fixp->fx_where;
+    }
+  else
+    {
+      fixp->fx_done = 1;
+    }
+#else
   /* FIXME FIXME FIXME: The value we are passed in *valuep includes
      the symbol values.  Since we are using BFD_ASSEMBLER, if we are
      doing this relocation the code in write.c is going to call
@@ -4602,7 +4636,6 @@ md_apply_fix3 (fixp, valuep, seg)
      *valuep, and must use fx_offset instead.  However, if the reloc
      is PC relative, we do want to use *valuep since it includes the
      result of md_pcrel_from.  This is confusing.  */
-
   if (fixp->fx_addsy == (symbolS *) NULL)
     {
       value = *valuep;
@@ -4625,6 +4658,7 @@ md_apply_fix3 (fixp, valuep, seg)
            }
        }
     }
+#endif
 
   if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
@@ -4753,8 +4787,6 @@ md_apply_fix3 (fixp, valuep, seg)
          break;
 
        case BFD_RELOC_LO16:
-       case BFD_RELOC_HI16:
-       case BFD_RELOC_HI16_S:
        case BFD_RELOC_16:
        case BFD_RELOC_GPREL16:
        case BFD_RELOC_16_GOT_PCREL:
@@ -4791,6 +4823,22 @@ md_apply_fix3 (fixp, valuep, seg)
                              value, 2);
          break;
 
+         /* This case happens when you write, for example,
+            lis %r3,(L1-L2)@ha
+            where L1 and L2 are defined later.  */
+       case BFD_RELOC_HI16:
+         if (fixp->fx_pcrel)
+           abort ();
+         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+                             value >> 16, 2);
+         break;
+       case BFD_RELOC_HI16_S:
+         if (fixp->fx_pcrel)
+           abort ();
+         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+                             value + 0x8000 >> 16, 2);
+         break;
+
          /* Because SDA21 modifies the register field, the size is set to 4
             bytes, rather than 2, so offset it here appropriately */
        case BFD_RELOC_PPC_EMB_SDA21:
@@ -4830,7 +4878,8 @@ md_apply_fix3 (fixp, valuep, seg)
            if ((value & 3) != 0)
              as_bad_where (fixp->fx_file, fixp->fx_line,
                            "must branch to an address a multiple of 4");
-           if ((long)value << 6 >> 6 != value)
+           if ((offsetT) value < -0x40000000
+               || (offsetT) value >= 0x40000000)
              as_bad_where (fixp->fx_file, fixp->fx_line,
                            "@local or @plt branch destination is too far "
                            "away, %ld bytes",