gas/
authorRichard Sandiford <rdsandiford@googlemail.com>
Sat, 8 Feb 2003 17:05:55 +0000 (17:05 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Sat, 8 Feb 2003 17:05:55 +0000 (17:05 +0000)
* config/tc-mips.c (reloc_needs_lo_p): New function.
(fixup_has_matching_lo_p): New function.
(append_insn): Use reloc_needs_lo_p to check whether a relocation
might need a matching %lo().  Reuse the head of mips_hi_fixup_list
if that fixup already has a matching %lo().  Don't call frag_wane here.
(macro): Call frag_wane here if the last unmatched hi was in the
current frag.
(pic_need_relax): New function, split out from...
(md_estimate_size_before_relax): ...here.
(mips_frob_file): Use reloc_needs_lo_p.  Use pic_need_relax to test
whether BFD_RELOC_MIPS_GOT16 fixups refer to global symbols.

gas/testsuite/
* gas/mips/rel12.[sd], gas/mips/rel13.[sd]: New tests.
* gas/mips/mips.exp: Run them.

gas/ChangeLog
gas/config/tc-mips.c
gas/testsuite/ChangeLog
gas/testsuite/gas/mips/elf-rel12.d [new file with mode: 0644]
gas/testsuite/gas/mips/elf-rel12.s [new file with mode: 0644]
gas/testsuite/gas/mips/elf-rel13.d [new file with mode: 0644]
gas/testsuite/gas/mips/elf-rel13.s [new file with mode: 0644]
gas/testsuite/gas/mips/mips.exp

index 265d152..698a405 100644 (file)
@@ -1,3 +1,17 @@
+2003-02-08  Richard Sandiford  <rsandifo@redhat.com>
+
+       * config/tc-mips.c (reloc_needs_lo_p): New function.
+       (fixup_has_matching_lo_p): New function.
+       (append_insn): Use reloc_needs_lo_p to check whether a relocation
+       might need a matching %lo().  Reuse the head of mips_hi_fixup_list
+       if that fixup already has a matching %lo().  Don't call frag_wane here.
+       (macro): Call frag_wane here if the last unmatched hi was in the
+       current frag.
+       (pic_need_relax): New function, split out from...
+       (md_estimate_size_before_relax): ...here.
+       (mips_frob_file): Use reloc_needs_lo_p.  Use pic_need_relax to test
+       whether BFD_RELOC_MIPS_GOT16 fixups refer to global symbols.
+
 2003-02-07  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/tc-mips.c (my_getSmallExpression): Rework bracket handling.
index 57c1196..4c0052b 100644 (file)
@@ -801,6 +801,10 @@ static int mips_relax_branch;
 
 enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
+static inline bfd_boolean reloc_needs_lo_p
+  PARAMS ((bfd_reloc_code_real_type));
+static inline bfd_boolean fixup_has_matching_lo_p
+  PARAMS ((fixS *));
 static int insn_uses_reg
   PARAMS ((struct mips_cl_insn *ip, unsigned int reg,
           enum mips_regclass class));
@@ -932,6 +936,8 @@ static void s_mips_file
   PARAMS ((int));
 static void s_mips_loc
   PARAMS ((int));
+static bfd_boolean pic_need_relax
+  PARAMS ((symbolS *, asection *));
 static int mips16_extended_frag
   PARAMS ((fragS *, asection *, long));
 static int relaxed_branch_length (fragS *, asection *, int);
@@ -1439,6 +1445,31 @@ md_assemble (str)
     }
 }
 
+/* Return true if the given relocation might need a matching %lo().
+   Note that R_MIPS_GOT16 relocations only need a matching %lo() when
+   applied to local symbols.  */
+
+static inline bfd_boolean
+reloc_needs_lo_p (reloc)
+     bfd_reloc_code_real_type reloc;
+{
+  return (reloc == BFD_RELOC_HI16_S
+         || reloc == BFD_RELOC_MIPS_GOT16);
+}
+
+/* Return true if the given fixup is followed by a matching R_MIPS_LO16
+   relocation.  */
+
+static inline bfd_boolean
+fixup_has_matching_lo_p (fixp)
+     fixS *fixp;
+{
+  return (fixp->fx_next != NULL
+         && fixp->fx_next->fx_r_type == BFD_RELOC_LO16
+         && fixp->fx_addsy == fixp->fx_next->fx_addsy
+         && fixp->fx_offset == fixp->fx_next->fx_offset);
+}
+
 /* See whether instruction IP reads register REG.  CLASS is the type
    of register.  */
 
@@ -1593,14 +1624,12 @@ append_insn (place, ip, address_expr, reloc_type)
   char *f;
   fixS *fixp[3];
   int nops = 0;
-  bfd_boolean unmatched_reloc_p;
 
   /* Mark instruction labels in mips16 mode.  */
   mips16_mark_labels ();
 
   prev_pinfo = prev_insn.insn_mo->pinfo;
   pinfo = ip->insn_mo->pinfo;
-  unmatched_reloc_p = FALSE;
 
   if (place == NULL && (! mips_opts.noreorder || prev_nop_frag != NULL))
     {
@@ -2144,17 +2173,22 @@ append_insn (place, ip, address_expr, reloc_type)
                   || *reloc_type == BFD_RELOC_MIPS_RELGOT))
                fixp[0]->fx_no_overflow = 1;
 
-             if (reloc_type[0] == BFD_RELOC_HI16_S)
+             if (reloc_needs_lo_p (*reloc_type))
                {
                  struct mips_hi_fixup *hi_fixup;
 
-                 hi_fixup = ((struct mips_hi_fixup *)
-                             xmalloc (sizeof (struct mips_hi_fixup)));
+                 /* Reuse the last entry if it already has a matching %lo.  */
+                 hi_fixup = mips_hi_fixup_list;
+                 if (hi_fixup == 0
+                     || !fixup_has_matching_lo_p (hi_fixup->fixp))
+                   {
+                     hi_fixup = ((struct mips_hi_fixup *)
+                                 xmalloc (sizeof (struct mips_hi_fixup)));
+                     hi_fixup->next = mips_hi_fixup_list;
+                     mips_hi_fixup_list = hi_fixup;
+                   }
                  hi_fixup->fixp = fixp[0];
                  hi_fixup->seg = now_seg;
-                 hi_fixup->next = mips_hi_fixup_list;
-                 mips_hi_fixup_list = hi_fixup;
-                 unmatched_reloc_p = TRUE;
                }
 
              if (reloc_type[1] != BFD_RELOC_UNUSED)
@@ -2706,16 +2740,6 @@ append_insn (place, ip, address_expr, reloc_type)
 
   /* We just output an insn, so the next one doesn't have a label.  */
   mips_clear_insn_labels ();
-
-  /* We must ensure that a fixup associated with an unmatched %hi
-     reloc does not become a variant frag.  Otherwise, the
-     rearrangement of %hi relocs in frob_file may confuse
-     tc_gen_reloc.  */
-  if (unmatched_reloc_p)
-    {
-      frag_wane (frag_now);
-      frag_new (0);
-    }
 }
 
 /* This function forgets that there was any previous instruction or
@@ -4070,6 +4094,27 @@ macro (ip)
   expr1.X_add_symbol = NULL;
   expr1.X_add_number = 1;
 
+  /* Umatched fixups should not be put in the same frag as a relaxable
+     macro.  For example, suppose we have:
+
+       lui $4,%hi(l1)          # 1
+       la $5,l2                # 2
+       addiu $4,$4,%lo(l1)     # 3
+
+     If instructions 1 and 2 were put in the same frag, md_frob_file would
+     move the fixup for #1 after the fixups for the "unrelaxed" version of
+     #2.  This would confuse tc_gen_reloc, which expects the relocations
+     for #2 to be the last for that frag.
+
+     If it looks like this situation could happen, put the macro
+     in a new frag.  */
+  if (mips_hi_fixup_list != 0
+      && mips_hi_fixup_list->fixp->fx_frag == frag_now)
+    {
+      frag_wane (frag_now);
+      frag_new (0);
+    }
+
   switch (mask)
     {
     case M_DABS:
@@ -10858,14 +10903,16 @@ mips_frob_file ()
       segment_info_type *seginfo;
       int pass;
 
-      assert (l->fixp->fx_r_type == BFD_RELOC_HI16_S);
+      assert (reloc_needs_lo_p (l->fixp->fx_r_type));
 
-      /* Check quickly whether the next fixup happens to be a matching
-         %lo.  */
-      if (l->fixp->fx_next != NULL
-         && l->fixp->fx_next->fx_r_type == BFD_RELOC_LO16
-         && l->fixp->fx_addsy == l->fixp->fx_next->fx_addsy
-         && l->fixp->fx_offset == l->fixp->fx_next->fx_offset)
+      /* If a GOT16 relocation turns out to be against a global symbol,
+        there isn't supposed to be a matching LO.  */
+      if (l->fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
+         && !pic_need_relax (l->fixp->fx_addsy, l->seg))
+       continue;
+
+      /* Check quickly whether the next fixup happens to be a matching %lo.  */
+      if (fixup_has_matching_lo_p (l->fixp))
        continue;
 
       /* Look through the fixups for this segment for a matching %lo.
@@ -10887,9 +10934,8 @@ mips_frob_file ()
                  && f->fx_offset == l->fixp->fx_offset
                  && (pass == 1
                      || prev == NULL
-                     || prev->fx_r_type != BFD_RELOC_HI16_S
-                     || prev->fx_addsy != f->fx_addsy
-                     || prev->fx_offset !=  f->fx_offset))
+                     || !reloc_needs_lo_p (prev->fx_r_type)
+                     || !fixup_has_matching_lo_p (prev)))
                {
                  fixS **pf;
 
@@ -12672,6 +12718,64 @@ nopic_need_relax (sym, before_relaxing)
     return 1;
 }
 
+
+/* Return true if the given symbol should be considered local for SVR4 PIC.  */
+
+static bfd_boolean
+pic_need_relax (sym, segtype)
+     symbolS *sym;
+     asection *segtype;
+{
+  asection *symsec;
+  bfd_boolean linkonce;
+
+  /* Handle the case of a symbol equated to another symbol.  */
+  while (symbol_equated_reloc_p (sym))
+    {
+      symbolS *n;
+
+      /* It's possible to get a loop here in a badly written
+        program.  */
+      n = symbol_get_value_expression (sym)->X_add_symbol;
+      if (n == sym)
+       break;
+      sym = n;
+    }
+
+  symsec = S_GET_SEGMENT (sym);
+
+  /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
+  linkonce = FALSE;
+  if (symsec != segtype && ! S_IS_LOCAL (sym))
+    {
+      if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
+         != 0)
+       linkonce = TRUE;
+
+      /* The GNU toolchain uses an extension for ELF: a section
+        beginning with the magic string .gnu.linkonce is a linkonce
+        section.  */
+      if (strncmp (segment_name (symsec), ".gnu.linkonce",
+                  sizeof ".gnu.linkonce" - 1) == 0)
+       linkonce = TRUE;
+    }
+
+  /* This must duplicate the test in adjust_reloc_syms.  */
+  return (symsec != &bfd_und_section
+         && symsec != &bfd_abs_section
+         && ! bfd_is_com_section (symsec)
+         && !linkonce
+#ifdef OBJ_ELF
+         /* A global or weak symbol is treated as external.  */
+         && (OUTPUT_FLAVOR != bfd_target_elf_flavour
+             || (! S_IS_WEAK (sym)
+                 && (! S_IS_EXTERNAL (sym)
+                     || mips_pic == EMBEDDED_PIC)))
+#endif
+         );
+}
+
+
 /* Given a mips16 variant frag FRAGP, return non-zero if it needs an
    extended opcode.  SEC is the section the frag is in.  */
 
@@ -12950,8 +13054,7 @@ md_estimate_size_before_relax (fragp, segtype)
      fragS *fragp;
      asection *segtype;
 {
-  int change = 0;
-  bfd_boolean linkonce = FALSE;
+  int change;
 
   if (RELAX_BRANCH_P (fragp->fr_subtype))
     {
@@ -12967,60 +13070,9 @@ md_estimate_size_before_relax (fragp, segtype)
     return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2);
 
   if (mips_pic == NO_PIC)
-    {
-      change = nopic_need_relax (fragp->fr_symbol, 0);
-    }
+    change = nopic_need_relax (fragp->fr_symbol, 0);
   else if (mips_pic == SVR4_PIC)
-    {
-      symbolS *sym;
-      asection *symsec;
-
-      sym = fragp->fr_symbol;
-
-      /* Handle the case of a symbol equated to another symbol.  */
-      while (symbol_equated_reloc_p (sym))
-       {
-         symbolS *n;
-
-         /* It's possible to get a loop here in a badly written
-             program.  */
-         n = symbol_get_value_expression (sym)->X_add_symbol;
-         if (n == sym)
-           break;
-         sym = n;
-       }
-
-      symsec = S_GET_SEGMENT (sym);
-
-      /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
-      if (symsec != segtype && ! S_IS_LOCAL (sym))
-       {
-         if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
-             != 0)
-           linkonce = TRUE;
-
-         /* The GNU toolchain uses an extension for ELF: a section
-            beginning with the magic string .gnu.linkonce is a linkonce
-            section.  */
-         if (strncmp (segment_name (symsec), ".gnu.linkonce",
-                      sizeof ".gnu.linkonce" - 1) == 0)
-           linkonce = TRUE;
-       }
-
-      /* This must duplicate the test in adjust_reloc_syms.  */
-      change = (symsec != &bfd_und_section
-               && symsec != &bfd_abs_section
-               && ! bfd_is_com_section (symsec)
-               && !linkonce
-#ifdef OBJ_ELF
-               /* A global or weak symbol is treated as external.  */
-               && (OUTPUT_FLAVOR != bfd_target_elf_flavour
-                   || (! S_IS_WEAK (sym)
-                       && (! S_IS_EXTERNAL (sym)
-                           || mips_pic == EMBEDDED_PIC)))
-#endif
-               );
-    }
+    change = pic_need_relax (fragp->fr_symbol, segtype);
   else
     abort ();
 
index 0bbc35a..c9be2ed 100644 (file)
@@ -1,5 +1,10 @@
 2003-02-07  Richard Sandiford  <rsandifo@redhat.com>
 
+       * gas/mips/rel12.[sd], gas/mips/rel13.[sd]: New tests.
+       * gas/mips/mips.exp: Run them.
+
+2003-02-07  Richard Sandiford  <rsandifo@redhat.com>
+
        * gas/mips/expr1.[sd]: New test.
        * gas/mips/mips.exp: Run it.
 
diff --git a/gas/testsuite/gas/mips/elf-rel12.d b/gas/testsuite/gas/mips/elf-rel12.d
new file mode 100644 (file)
index 0000000..c57a83c
--- /dev/null
@@ -0,0 +1,11 @@
+#as: -march=mips1 -mabi=32
+#readelf: --relocs
+#name: MIPS ELF reloc 12
+
+Relocation section '\.rel\.text' at offset .* contains 4 entries:
+ *Offset * Info * Type * Sym\.Value * Sym\. Name
+0+0004 * 0+..05 * R_MIPS_HI16 * 0+0000 * l1
+0+0008 * 0+..06 * R_MIPS_LO16 * 0+0000 * l1
+0+0000 * 0+..05 * R_MIPS_HI16 * 0+0004 * l2
+0+000c * 0+..06 * R_MIPS_LO16 * 0+0004 * l2
+#pass
diff --git a/gas/testsuite/gas/mips/elf-rel12.s b/gas/testsuite/gas/mips/elf-rel12.s
new file mode 100644 (file)
index 0000000..a3c4021
--- /dev/null
@@ -0,0 +1,14 @@
+       .ent    foo
+foo:
+       lui     $4,%hi(l2)
+       la      $3,l1
+       addiu   $4,$4,%lo(l2)
+
+       .space  64
+       .end    foo
+
+       .globl  l1
+       .globl  l2
+       .data
+l1:    .word   1
+l2:    .word   2
diff --git a/gas/testsuite/gas/mips/elf-rel13.d b/gas/testsuite/gas/mips/elf-rel13.d
new file mode 100644 (file)
index 0000000..0c3289d
--- /dev/null
@@ -0,0 +1,17 @@
+#as: -march=mips2 -mabi=32 -KPIC
+#readelf: --relocs
+#name: MIPS ELF reloc 13
+
+Relocation section '\.rel\.text' at offset .* contains 9 entries:
+ *Offset * Info * Type * Sym\.Value * Sym\. Name
+0+0000 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.data
+0+0014 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.data
+0+0010 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.data
+0+0018 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.data
+# The next two lines could be in either order.
+0+000c * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.rodata
+0+0008 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.rodata
+0+001c * 0+..06 * R_MIPS_LO16 * 0+0000 * \.rodata
+0+0004 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.bss
+0+0020 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.bss
+#pass
diff --git a/gas/testsuite/gas/mips/elf-rel13.s b/gas/testsuite/gas/mips/elf-rel13.s
new file mode 100644 (file)
index 0000000..761fcbb
--- /dev/null
@@ -0,0 +1,22 @@
+       .ent    foo
+foo:
+       lw      $4,%got(l1)($gp)
+       lw      $4,%got(l2)($gp)
+       lw      $4,%got(l3)($gp)
+       lw      $4,%got(l3)($gp)
+       lw      $4,%got(l1+0x400)($gp)
+       addiu   $4,$4,%lo(l1)
+       addiu   $4,$4,%lo(l1+0x400)
+       addiu   $4,$4,%lo(l3)
+       addiu   $4,$4,%lo(l2)
+       .space  64
+       .end    foo
+
+       .data
+l1:    .word   1
+
+       .lcomm  l2, 4
+
+       .rdata
+       .word   1
+l3:    .word   2
index 090e0b5..9d950a4 100644 (file)
@@ -608,6 +608,8 @@ if { [istarget mips*-*-*] } then {
            run_dump_test "elf-rel10"
            run_dump_test "elf-rel11"
        }
+       run_dump_test "elf-rel12"
+       run_dump_test "elf-rel13"
        run_dump_test "${tmips}${el}empic"
        run_dump_test "empic2"
        run_dump_test "empic3_e"