2001-02-20 Andreas Jaeger <aj@suse.de>
[deliverable/binutils-gdb.git] / gas / write.c
index 459933828a795a7a5d0338a8fd0a32118cf63085..2ae110d259aa1c59d170d1c73cc0041203a6bf0a 100644 (file)
 #undef  BFD_FAST_SECTION_FILL
 #define BFD_FAST_SECTION_FILL
 
-/* The NOP_OPCODE is for the alignment fill value.  Fill it with a nop
-   instruction so that the disassembler does not choke on it.  */
-#ifndef NOP_OPCODE
-#define NOP_OPCODE 0x00
-#endif
-
 #ifndef TC_ADJUST_RELOC_COUNT
 #define TC_ADJUST_RELOC_COUNT(FIXP,COUNT)
 #endif
@@ -383,6 +377,19 @@ record_alignment (seg, align)
 #endif
 }
 
+int
+get_recorded_alignment (seg)
+     segT seg;
+{
+  if (seg == absolute_section)
+    return 0;
+#ifdef BFD_ASSEMBLER
+  return bfd_get_section_alignment (stdoutput, seg);
+#else
+  return section_alignment[(int) seg];
+#endif
+}
+
 #ifdef BFD_ASSEMBLER
 
 /* Reset the section indices after removing the gas created sections.  */
@@ -494,6 +501,7 @@ cvt_frag_to_fill (headersP, sec, fragP)
     {
     case rs_align:
     case rs_align_code:
+    case rs_align_test:
     case rs_org:
     case rs_space:
 #ifdef HANDLE_ALIGN
@@ -1390,14 +1398,25 @@ subsegs_finish ()
 
   for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next)
     {
+      int alignment;
+
       subseg_set (frchainP->frch_seg, frchainP->frch_subseg);
 
       /* This now gets called even if we had errors.  In that case,
          any alignment is meaningless, and, moreover, will look weird
          if we are generating a listing.  */
-      frag_align (had_errors () ? 0 : SUB_SEGMENT_ALIGN (now_seg),
-                 subseg_text_p (now_seg) ? NOP_OPCODE : 0,
-                 0);
+      alignment = had_errors () ? 0 : SUB_SEGMENT_ALIGN (now_seg);
+
+      /* The last subsegment gets an aligment corresponding to the
+        alignment of the section.  This allows proper nop-filling
+        at the end of code-bearing sections.  */
+      if (!frchainP->frch_next || frchainP->frch_next->frch_seg != now_seg)
+       alignment = get_recorded_alignment (now_seg);
+
+      if (subseg_text_p (now_seg))
+       frag_align_code (alignment, 0);
+      else
+       frag_align (alignment, 0, 0);
 
       /* frag_align will have left a new frag.
         Use this last frag for an empty ".fill".
@@ -1979,21 +1998,30 @@ write_object_file ()
 static int is_dnrange PARAMS ((fragS *, fragS *));
 
 /* Subroutines of relax_segment.  */
+
 static int
 is_dnrange (f1, f2)
      fragS *f1;
      fragS *f2;
 {
+  addressT f2addr;
+
+  f2addr = f2->fr_address;
   for (; f1; f1 = f1->fr_next)
-    if (f1->fr_next == f2)
-      return 1;
+    {
+      if (f1->fr_next == f2)
+       return 1;
+      if (f1->fr_address > f2addr)
+       break;
+    }
   return 0;
 }
 
 /* Relax a fragment by scanning TC_GENERIC_RELAX_TABLE.  */
 
 long
-relax_frag (fragP, stretch)
+relax_frag (segment, fragP, stretch)
+     segT segment;
      fragS *fragP;
      long stretch;
 {
@@ -2015,6 +2043,10 @@ relax_frag (fragP, stretch)
 
   if (symbolP)
     {
+      fragS *sym_frag;
+
+      sym_frag = symbol_get_frag (symbolP);
+
 #ifndef DIFF_EXPR_OK
 #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
       know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE)
@@ -2022,23 +2054,24 @@ relax_frag (fragP, stretch)
            || (S_GET_SEGMENT (symbolP) == SEG_BSS)
            || (S_GET_SEGMENT (symbolP) == SEG_TEXT));
 #endif
-      know (symbolP->sy_frag);
+      know (sym_frag != NULL);
 #endif
       know (!(S_GET_SEGMENT (symbolP) == absolute_section)
-           || symbolP->sy_frag == &zero_address_frag);
-      target += S_GET_VALUE (symbolP) + symbol_get_frag (symbolP)->fr_address;
+           || sym_frag == &zero_address_frag);
+      target += S_GET_VALUE (symbolP) + sym_frag->fr_address;
 
       /* If frag has yet to be reached on this pass,
         assume it will move by STRETCH just as we did.
         If this is not so, it will be because some frag
         between grows, and that will force another pass.
 
-        Beware zero-length frags.
-
-        There should be a faster way to do this.  */
+        Beware zero-length frags.  */
 
-      if (symbol_get_frag (symbolP)->fr_address >= was_address
-         && is_dnrange (fragP, symbol_get_frag (symbolP)))
+      if (stretch != 0
+         && S_GET_SEGMENT (symbolP) == segment
+         && (sym_frag->fr_address > was_address
+             || (sym_frag->fr_address == was_address
+                 && is_dnrange (fragP, sym_frag))))
        {
          target += stretch;
        }
@@ -2156,6 +2189,7 @@ relax_segment (segment_frag_root, segment)
 
        case rs_align:
        case rs_align_code:
+       case rs_align_test:
          {
            addressT offset = relax_align (address, (int) fragP->fr_offset);
 
@@ -2305,6 +2339,7 @@ relax_segment (segment_frag_root, segment)
 #endif
              case rs_align:
              case rs_align_code:
+             case rs_align_test:
                {
                  addressT oldoff, newoff;
 
@@ -2392,12 +2427,12 @@ relax_segment (segment_frag_root, segment)
 
              case rs_machine_dependent:
 #ifdef md_relax_frag
-               growth = md_relax_frag (fragP, stretch);
+               growth = md_relax_frag (segment, fragP, stretch);
 #else
 #ifdef TC_GENERIC_RELAX_TABLE
                /* The default way to relax a frag is to look through
                   TC_GENERIC_RELAX_TABLE.  */
-               growth = relax_frag (fragP, stretch);
+               growth = relax_frag (segment, fragP, stretch);
 #endif /* TC_GENERIC_RELAX_TABLE  */
 #endif
                break;
This page took 0.026008 seconds and 4 git commands to generate.