* subsegs.h (segment_info_type): Use fix_tail field even if
[deliverable/binutils-gdb.git] / gas / write.c
index 0b074d59b24c05de7ffbddc9f8f160dbe8402626..000e7907213ccbddec2ba630c0e45ae9553114c9 100644 (file)
@@ -1,5 +1,5 @@
 /* write.c - emit .o file
-   Copyright (C) 1986, 1987, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1986, 87, 90, 91, 92, 93, 1994 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
 #define NOP_OPCODE 0x00
 #endif
 
+#ifndef TC_ADJUST_RELOC_COUNT
+#define TC_ADJUST_RELOC_COUNT(FIXP,COUNT)
+#endif
+
+#ifndef TC_FORCE_RELOCATION
+#define TC_FORCE_RELOCATION(FIXP) 0
+#endif
+
 #ifndef WORKING_DOT_WORD
 extern CONST int md_short_jump_size;
 extern CONST int md_long_jump_size;
 #endif
 
+int symbol_table_frozen;
+
+#ifdef BFD_ASSEMBLER
+/* We generally attach relocs to frag chains.  However, after we have
+   chained these all together into a segment, any relocs we add after
+   that must be attached to a segment.  This will include relocs added
+   in md_estimate_size_for_relax, for example.  */
+static int frags_chained = 0;
+#endif
+
 #ifndef BFD_ASSEMBLER
 
 #ifndef MANY_SEGMENTS
@@ -47,7 +65,7 @@ struct frag *data_last_frag;  /* Last frag in segment. */
 static struct frag *bss_last_frag;     /* Last frag in segment. */
 #endif
 
-#if ! defined (BFD_ASSEMBLER) && ! defined (BFD)
+#ifndef BFD
 static object_headers headers;
 static char *the_object_file;
 #endif
@@ -117,13 +135,12 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
   fixP->fx_bit_fixP = 0;
   fixP->fx_addnumber = 0;
   fixP->tc_fix_data = NULL;
+  fixP->fx_tcbit = 0;
+  fixP->fx_done = 0;
 
 #ifdef TC_something
   fixP->fx_bsr = 0;
 #endif
-#ifdef TC_I960
-  fixP->fx_callj = 0;
-#endif
 
   as_where (&fixP->fx_file, &fixP->fx_line);
 
@@ -135,8 +152,12 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
   {
 
 #ifdef BFD_ASSEMBLER
-    fixS **seg_fix_rootP = & (seg_info (now_seg)->fix_root);
-    fixS **seg_fix_tailP = & (seg_info (now_seg)->fix_tail);
+    fixS **seg_fix_rootP = (frags_chained
+                           ? &seg_info (now_seg)->fix_root
+                           : &frchain_now->fix_root);
+    fixS **seg_fix_tailP = (frags_chained
+                           ? &seg_info (now_seg)->fix_tail
+                           : &frchain_now->fix_tail);
 #endif
 
 #ifdef REVERSE_SORT_RELOCS
@@ -280,10 +301,22 @@ chain_frchains_together_1 (section, frchp)
      struct frchain *frchp;
 {
   fragS dummy, *prev_frag = &dummy;
+  fixS fix_dummy, *prev_fix = &fix_dummy;
+
   for (; frchp && frchp->frch_seg == section; frchp = frchp->frch_next)
     {
       prev_frag->fr_next = frchp->frch_root;
       prev_frag = frchp->frch_last;
+#ifdef BFD_ASSEMBLER
+      if (frchp->fix_root != (fixS *) NULL)
+       {
+         if (seg_info (section)->fix_root == (fixS *) NULL)
+           seg_info (section)->fix_root = frchp->fix_root;
+         prev_fix->fx_next = frchp->fix_root;
+         seg_info (section)->fix_tail = frchp->fix_tail;
+         prev_fix = frchp->fix_tail;
+       }
+#endif
     }
   prev_frag->fr_next = 0;
   return prev_frag;
@@ -297,7 +330,7 @@ static void
 chain_frchains_together (abfd, section, xxx)
      bfd *abfd;                        /* unused */
      segT section;
-     char *xxx;                        /* unused */
+     PTR xxx;                  /* unused */
 {
   segment_info_type *info;
 
@@ -305,7 +338,12 @@ chain_frchains_together (abfd, section, xxx)
      subseg_new, so it is possible that seg_info is NULL.  */
   info = seg_info (section);
   if (info != (segment_info_type *) NULL)
-    chain_frchains_together_1 (section, info->frchainP);
+   info->frchainP->frch_last
+     = chain_frchains_together_1 (section, info->frchainP);
+
+  /* Now that we've chained the frags together, we must add new fixups
+     to the segment, not to the frag chain.  */
+  frags_chained = 1;
 }
 
 #endif
@@ -347,12 +385,10 @@ cvt_frag_to_fill (headers, fragP)
       HANDLE_ALIGN (fragP);
 #endif
       fragP->fr_type = rs_fill;
-      know (fragP->fr_var == 1);
       know (fragP->fr_next != NULL);
-
       fragP->fr_offset = (fragP->fr_next->fr_address
                          - fragP->fr_address
-                         - fragP->fr_fix);
+                         - fragP->fr_fix) / fragP->fr_var;
       break;
 
     case rs_fill:
@@ -407,7 +443,7 @@ static void
 relax_and_size_seg (abfd, sec, xxx)
      bfd *abfd;
      asection *sec;
-     char *xxx;
+     PTR xxx;
 {
   flagword flags;
   fragS *fragp;
@@ -431,17 +467,18 @@ relax_and_size_seg (abfd, sec, xxx)
     }
   else
     size = 0;
-  if (size > 0)
-    {
-      flags |= SEC_HAS_CONTENTS;
-      /* @@ This is just an approximation.  */
-      if (seginfo->fix_root)
-       flags |= SEC_RELOC;
-      else
-       flags &= ~SEC_RELOC;
-      x = bfd_set_section_flags (abfd, sec, flags);
-      assert (x == true);
-    }
+
+  if (size > 0 && ! seginfo->bss)
+    flags |= SEC_HAS_CONTENTS;
+
+  /* @@ This is just an approximation.  */
+  if (seginfo && seginfo->fix_root)
+    flags |= SEC_RELOC;
+  else
+    flags &= ~SEC_RELOC;
+  x = bfd_set_section_flags (abfd, sec, flags);
+  assert (x == true);
+
   newsize = md_section_align (sec, size);
   x = bfd_set_section_size (abfd, sec, newsize);
   assert (x == true);
@@ -486,9 +523,19 @@ dump_section_relocs (abfd, sec, stream_)
     {
       symbolS *s = fixp->fx_addsy;
       if (s)
-       fprintf (stream, "  %08x: %s(%s+%x)+%x\n", fixp,
-                S_GET_NAME (s), s->bsym->section->name,
-                S_GET_VALUE (s), fixp->fx_offset);
+       {
+         fprintf (stream, "  %08x: %s(%s", fixp, S_GET_NAME (s),
+                  s->bsym->section->name);
+         if (s->bsym->flags & BSF_SECTION_SYM)
+           {
+             fprintf (stream, " section sym");
+             if (S_GET_VALUE (s))
+               fprintf (stream, "+%x", S_GET_VALUE (s));
+           }
+         else
+           fprintf (stream, "+%x", S_GET_VALUE (s));
+         fprintf (stream, ")+%x\n", fixp->fx_offset);
+       }
       else
        fprintf (stream, "  %08x: type %d no sym\n", fixp, fixp->fx_r_type);
       fixp = fixp->fx_next;
@@ -498,11 +545,15 @@ dump_section_relocs (abfd, sec, stream_)
 #define dump_section_relocs(ABFD,SEC,STREAM)   (void)(ABFD,SEC,STREAM)
 #endif
 
+#ifndef EMIT_SECTION_SYMBOLS
+#define EMIT_SECTION_SYMBOLS 1
+#endif
+
 static void
 adjust_reloc_syms (abfd, sec, xxx)
      bfd *abfd;
      asection *sec;
-     char *xxx;
+     PTR xxx;
 {
   segment_info_type *seginfo = seg_info (sec);
   fixS *fixp;
@@ -513,14 +564,18 @@ adjust_reloc_syms (abfd, sec, xxx)
   dump_section_relocs (abfd, sec, stderr);
 
   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
-    if (fixp->fx_addsy)
+    if (fixp->fx_done)
+      /* ignore it */;
+    else if (fixp->fx_addsy)
       {
        symbolS *sym = fixp->fx_addsy;
        asection *symsec = sym->bsym->section;
-       segment_info_type *symseginfo = seg_info (symsec);
 
-       /* If it's one of these sections, assume the symbol is definitely
-          going to be output.  */
+       /* If it's one of these sections, assume the symbol is
+          definitely going to be output.  The code in
+          md_estimate_size_before_relax in tc-mips.c uses this test
+          as well, so if you change this code you should look at that
+          code.  */
        if (symsec == &bfd_und_section
            || symsec == &bfd_abs_section
            || bfd_is_com_section (symsec))
@@ -531,7 +586,7 @@ adjust_reloc_syms (abfd, sec, xxx)
 
        /* Since we're reducing to section symbols, don't attempt to reduce
           anything that's already using one.  */
-       if (sym->bsym == symsec->symbol)
+       if (sym->bsym->flags & BSF_SECTION_SYM)
          {
            fixp->fx_addsy->sy_used_in_reloc = 1;
            continue;
@@ -564,20 +619,21 @@ adjust_reloc_syms (abfd, sec, xxx)
        fixp->fx_offset += S_GET_VALUE (sym);
        if (sym->sy_frag)
          fixp->fx_offset += sym->sy_frag->fr_address;
-       if (symseginfo->sym)
-         fixp->fx_addsy = symseginfo->sym;
-       else
-         {
-           fixp->fx_addsy = symbol_find (symsec->name);
-           if (!fixp->fx_addsy)
-             {
-               fixp->fx_addsy = symbol_make (symsec->name);
-               fixp->fx_addsy->bsym = symsec->symbol;
-             }
-           symseginfo->sym = fixp->fx_addsy;
-         }
+       fixp->fx_addsy = section_symbol (symsec);
+       fixp->fx_addsy->sy_used_in_reloc = 1;
+      }
+#if 1/*def RELOC_REQUIRES_SYMBOL*/
+    else
+      {
+       /* There was no symbol required by this relocation.  However,
+          BFD doesn't really handle relocations without symbols well.
+          (At least, the COFF support doesn't.)  So for now we fake up
+          a local symbol in the absolute section.  */
+
+       fixp->fx_addsy = section_symbol (absolute_section);
        fixp->fx_addsy->sy_used_in_reloc = 1;
       }
+#endif
 
   dump_section_relocs (abfd, sec, stderr);
 }
@@ -586,13 +642,14 @@ static void
 write_relocs (abfd, sec, xxx)
      bfd *abfd;
      asection *sec;
-     char *xxx;
+     PTR xxx;
 {
   segment_info_type *seginfo = seg_info (sec);
   int i;
   unsigned int n;
   arelent **relocs;
   fixS *fixp;
+  char *err;
 
   /* If seginfo is NULL, we did not create this section; don't do
      anything with it.  */
@@ -618,10 +675,8 @@ write_relocs (abfd, sec, xxx)
       char *data;
       bfd_reloc_status_type s;
 
-      if (fixp->fx_addsy == 0)
+      if (fixp->fx_done)
        {
-         /* @@ Need some other flag to indicate which have already
-            been performed...  */
          n--;
          continue;
        }
@@ -632,13 +687,10 @@ write_relocs (abfd, sec, xxx)
          continue;
        }
       data = fixp->fx_frag->fr_literal + fixp->fx_where;
-      /* @@ Assumes max size of reloc is 4. */
-      if (fixp->fx_where + 4
+      if (fixp->fx_where + fixp->fx_size
          > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
        abort ();
-      /* Pass bogus address so that when bfd_perform_relocation adds
-        `address' back in, it'll come up with `data', which is where
-        we want it to operate.  */
+
       if (reloc->howto->partial_inplace == false
          && reloc->howto->pcrel_offset == true
          && reloc->howto->pc_relative == true)
@@ -646,12 +698,19 @@ write_relocs (abfd, sec, xxx)
          /* bfd_perform_relocation screws this up */
          reloc->addend += reloc->address;
        }
+      /* Pass bogus address so that when bfd_perform_relocation adds
+        `reloc->address' back in, it'll come up with `data', which is where
+        we want it to operate.  We can't just do it by fudging reloc->address,
+        since that might be used in the calculations(?).  */
       s = bfd_perform_relocation (stdoutput, reloc, data - reloc->address,
-                                 sec, stdoutput);
+                                 sec, stdoutput, &err);
       switch (s)
        {
        case bfd_reloc_ok:
          break;
+       case bfd_reloc_overflow:
+         as_bad_where (fixp->fx_file, fixp->fx_line, "relocation overflow");
+         break;
        default:
          as_fatal ("bad return from bfd_perform_relocation");
        }
@@ -671,10 +730,8 @@ write_relocs (abfd, sec, xxx)
       bfd_reloc_status_type s;
       int j;
 
-      if (fixp->fx_addsy == 0)
+      if (fixp->fx_done)
        {
-         /* @@ Need some other flag to indicate which have already
-            been performed...  */
          n--;
          continue;
        }
@@ -686,32 +743,52 @@ write_relocs (abfd, sec, xxx)
           assert(i <= n);
        }
       data = fixp->fx_frag->fr_literal + fixp->fx_where;
-      if (fixp->fx_where + 4
+      if (fixp->fx_where + fixp->fx_size
          > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
        abort ();
       for (j = 0; reloc[j]; j++)
         {
-          s = bfd_perform_relocation (stdoutput, reloc[j], data - reloc[j]->address,
-                                     sec, stdoutput);
+         s = bfd_perform_relocation (stdoutput, reloc[j],
+                                     data - reloc[0]->address,
+                                     sec, stdoutput, &err);
           switch (s)
            {
-             case bfd_reloc_ok:
-               break;
-             default:
-               as_fatal ("bad return from bfd_perform_relocation");
+           case bfd_reloc_ok:
+             break;
+           default:
+             as_fatal ("bad return from bfd_perform_relocation");
            }
         }
     }
   n = i;
 #endif
 
+#ifdef DEBUG4
+  {
+    int i, j, nsyms;
+    asymbol **sympp;
+    sympp = bfd_get_outsymbols (stdoutput);
+    nsyms = bfd_get_symcount (stdoutput);
+    for (i = 0; i < n; i++)
+      if (((*relocs[i]->sym_ptr_ptr)->flags & BSF_SECTION_SYM) == 0)
+       {
+         for (j = 0; j < nsyms; j++)
+           if (sympp[j] == *relocs[i]->sym_ptr_ptr)
+             break;
+         if (j == nsyms)
+           abort ();
+       }
+  }
+#endif
+
   if (n)
     bfd_set_reloc (stdoutput, sec, relocs, n);
   else
     bfd_set_section_flags (abfd, sec,
                           (bfd_get_section_flags (abfd, sec)
                            & (flagword) ~SEC_RELOC));
-#ifdef DEBUG2
+
+#ifdef DEBUG3
   {
     int i;
     arelent *r;
@@ -732,7 +809,7 @@ static void
 write_contents (abfd, sec, xxx)
      bfd *abfd;
      asection *sec;
-     char *xxx;
+     PTR xxx;
 {
   segment_info_type *seginfo = seg_info (sec);
   unsigned long offset = 0;
@@ -758,7 +835,12 @@ write_contents (abfd, sec, xxx)
          x = bfd_set_section_contents (stdoutput, sec,
                                        f->fr_literal, (file_ptr) offset,
                                        (bfd_size_type) f->fr_fix);
-         assert (x == true);
+         if (x == false)
+           {
+             bfd_perror (stdoutput->filename);
+             as_perror ("FATAL: Can't write %s", stdoutput->filename);
+             exit (42);
+           }
          offset += f->fr_fix;
        }
       fill_literal = f->fr_literal + f->fr_fix;
@@ -771,7 +853,12 @@ write_contents (abfd, sec, xxx)
            x = bfd_set_section_contents (stdoutput, sec,
                                          fill_literal, (file_ptr) offset,
                                          (bfd_size_type) fill_size);
-           assert (x == true);
+           if (x == false)
+             {
+               bfd_perror (stdoutput->filename);
+               as_perror ("FATAL: Can't write %s", stdoutput->filename);
+               exit (42);
+             }
            offset += fill_size;
          }
     }
@@ -902,15 +989,50 @@ relax_and_size_all_segments ()
 
 #if defined (BFD_ASSEMBLER) || !defined (BFD)
 
+#ifdef BFD_ASSEMBLER
+static void
+set_symtab ()
+{
+  int nsyms;
+  asymbol **asympp;
+  symbolS *symp;
+  boolean result;
+  extern PTR bfd_alloc PARAMS ((bfd *, size_t));
+
+  /* Count symbols.  We can't rely on a count made by the loop in
+     write_object_file, because *_frob_file may add a new symbol or
+     two.  */
+  nsyms = 0;
+  for (symp = symbol_rootP; symp; symp = symbol_next (symp))
+    nsyms++;
+
+  if (nsyms)
+    {
+      int i;
+
+      asympp = (asymbol **) bfd_alloc (stdoutput,
+                                      nsyms * sizeof (asymbol *));
+      symp = symbol_rootP;
+      for (i = 0; i < nsyms; i++, symp = symbol_next (symp))
+       {
+         asympp[i] = symp->bsym;
+         symp->written = 1;
+       }
+    }
+  else
+    asympp = 0;
+  result = bfd_set_symtab (stdoutput, asympp, nsyms);
+  assert (result == true);
+  symbol_table_frozen = 1;
+}
+#endif
+
 void 
 write_object_file ()
 {
-  register struct frchain *frchainP;   /* Track along all frchains. */
+  struct frchain *frchainP;    /* Track along all frchains. */
 #if ! defined (BFD_ASSEMBLER) || ! defined (WORKING_DOT_WORD)
-  register fragS *fragP;       /* Track along all frags. */
-#endif
-#if !defined (BFD_ASSEMBLER) && !defined (OBJ_VMS)
-  long object_file_size;
+  fragS *fragP;                        /* Track along all frags. */
 #endif
 
   /* Do we really want to write it?  */
@@ -937,12 +1059,9 @@ write_object_file ()
   }
 
 #ifdef OBJ_VMS
-  /*
-   *   Under VMS we try to be compatible with VAX-11 "C".  Thus, we
-   *   call a routine to check for the definition of the procedure
-   *   "_main", and if so -- fix it up so that it can be program
-   *   entry point.
-   */
+  /* Under VMS we try to be compatible with VAX-11 "C".  Thus, we call
+     a routine to check for the definition of the procedure "_main",
+     and if so -- fix it up so that it can be program entry point. */
   VMS_Check_For_Main ();
 #endif /* VMS */
 
@@ -1174,6 +1293,7 @@ write_object_file ()
 #ifndef BFD_ASSEMBLER
 #ifndef        OBJ_VMS
   {                            /* not vms */
+    long object_file_size;
     /*
      * Scan every FixS performing fixups. We had to wait until now to do
      * this because md_convert_frag() may have made some fixSs.
@@ -1271,8 +1391,6 @@ write_object_file ()
     /* Write the data to the file */
     output_file_append (the_object_file, object_file_size, out_file_name);
 #endif
-
-    output_file_close (out_file_name);
   }                            /* non vms output */
 #else /* VMS */
   /*
@@ -1285,21 +1403,17 @@ write_object_file ()
 #endif /* VMS */
 #else /* BFD_ASSEMBLER */
 
-#ifdef obj_check_file_symbols
-  obj_check_file_symbols ();
-#endif
-
   bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *)0);
 
   /* Set up symbol table, and write it out.  */
   if (symbol_rootP)
     {
-      unsigned int i = 0;
-      unsigned int n;
       symbolS *symp;
 
       for (symp = symbol_rootP; symp; symp = symbol_next (symp))
        {
+         int punt = 0;
+
          if (! symp->sy_resolved)
            {
              if (symp->sy_value.X_op == O_constant)
@@ -1326,59 +1440,34 @@ write_object_file ()
                  symp->bsym->flags,
                  segment_name (symp->bsym->section));
 #endif
-         if (! symp->sy_used_in_reloc)
-           {
+
 #ifdef obj_frob_symbol
-             {
-               int punt = 0;
-               obj_frob_symbol (symp, punt);
-               if (punt)
-                 goto punt_it;
-             }
+         obj_frob_symbol (symp, punt);
 #endif
 #ifdef tc_frob_symbol
-             {
-               int punt = 0;
-               tc_frob_symbol (symp, punt);
-               if (punt)
-                 goto punt_it;
-             }
-#endif
-           }
-
-         /* If we don't want to keep this symbol, splice it out of the
-            chain now.  */
-         if (! symp->sy_used_in_reloc
-             && S_IS_LOCAL (symp))
+         if (! punt || symp->sy_used_in_reloc)
+           tc_frob_symbol (symp, punt);
+#endif
+
+         /* If we don't want to keep this symbol, splice it out of
+            the chain now.  If EMIT_SECTION_SYMBOLS is 0, we never
+            want section symbols.  Otherwise, we skip local symbols
+            and symbols that the frob_symbol macros told us to punt,
+            but we keep such symbols if they are used in relocs.  */
+         if ((! EMIT_SECTION_SYMBOLS
+              && (symp->bsym->flags & BSF_SECTION_SYM) != 0)
+             /* Note that S_IS_EXTERN and S_IS_LOCAL are not always
+                opposites.  Sometimes the former checks flags and the
+                latter examines the name...  */
+             || (!S_IS_EXTERN (symp)
+                 && (S_IS_LOCAL (symp) || punt)
+                 && ! symp->sy_used_in_reloc))
            {
-             symbolS *prev, *next;
-#if defined (obj_frob_symbol) || defined (tc_frob_symbol)
-           punt_it:
-#endif
-             prev = symbol_previous (symp);
-             next = symbol_next (symp);
-#ifdef DEBUG_SYMS
-             verify_symbol_chain_2 (symp);
-#endif
-             if (prev)
-               {
-                 symbol_next (prev) = next;
-                 symp = prev;
-               }
-             else if (symp == symbol_rootP)
-               symbol_rootP = next;
-             else
-               abort ();
-             if (next)
-               symbol_previous (next) = prev;
-             else
-               symbol_lastP = prev;
-#ifdef DEBUG_SYMS
-             if (prev)
-               verify_symbol_chain_2 (prev);
-             else if (next)
-               verify_symbol_chain_2 (next);
-#endif
+             symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+             /* After symbol_remove, symbol_next(symp) still returns
+                the one that came after it in the chain.  So we don't
+                need to do any extra cleanup work here.  */
+
              continue;
            }
 
@@ -1393,45 +1482,27 @@ write_object_file ()
          /* Set the value into the BFD symbol.  Up til now the value
             has only been kept in the gas symbolS struct.  */
          symp->bsym->value = S_GET_VALUE (symp);
-
-         i++;
-       }
-      n = i;
-      if (n)
-       {
-         asymbol **asympp;
-         boolean result;
-         extern PTR bfd_alloc PARAMS ((bfd *, size_t));
-
-         asympp = (asymbol **) bfd_alloc (stdoutput,
-                                          n * sizeof (asymbol *));
-         symp = symbol_rootP;
-         for (i = 0; i < n; i++, symp = symbol_next (symp))
-           {
-             asympp[i] = symp->bsym;
-             symp->written = 1;
-           }
-         result = bfd_set_symtab (stdoutput, asympp, n);
-         assert (result == true);
        }
     }
 
-
-#ifdef obj_frob_file
-  /* If obj_frob_file changes the symbol value at this point, it is
+  /* If *_frob_file changes the symbol value at this point, it is
      responsible for moving the changed value into symp->bsym->value
      as well.  Hopefully all symbol value changing can be done in
-     {obj,tc}_frob_symbol.  */
+     *_frob_symbol.  */
+#ifdef tc_frob_file
+  tc_frob_file ();
+#endif
+#ifdef obj_frob_file
   obj_frob_file ();
 #endif
 
   /* Now that all the sizes are known, and contents correct, we can
-     start writing the file.  */
+     start writing to the file.  */
+  set_symtab ();
+
   bfd_map_over_sections (stdoutput, write_relocs, (char *) 0);
 
   bfd_map_over_sections (stdoutput, write_contents, (char *) 0);
-
-  output_file_close (out_file_name);
 #endif /* BFD_ASSEMBLER */
 }
 #endif /* ! BFD */
@@ -1449,6 +1520,8 @@ write_object_file ()
  * these frag addresses may not be the same as final object-file addresses.
  */
 
+#ifndef md_relax_frag
+
 /* Subroutines of relax_segment.  */
 static int 
 is_dnrange (f1, f2)
@@ -1461,6 +1534,8 @@ is_dnrange (f1, f2)
   return 0;
 }
 
+#endif /* ! defined (md_relax_frag) */
+
 /* Relax_align. Advance location counter to next address that has 'alignment'
    lowest order bits all 0s, return size of adjustment made.  */
 static relax_addressT
@@ -1508,7 +1583,16 @@ relax_segment (segment_frag_root, segment)
          break;
 
        case rs_align:
-         address += relax_align (address, (int) fragP->fr_offset);
+         {
+           int offset = relax_align (address, (int) fragP->fr_offset);
+           if (offset % fragP->fr_var != 0)
+             {
+               as_bad ("alignment padding (%d bytes) not a multiple of %ld",
+                       offset, (long) fragP->fr_var);
+               offset -= (offset % fragP->fr_var);
+             }
+           address += offset;
+         }
          break;
 
        case rs_org:
@@ -1664,6 +1748,11 @@ relax_segment (segment_frag_root, segment)
                break;
 
              case rs_machine_dependent:
+#ifdef md_relax_frag
+               growth = md_relax_frag (fragP, stretch);
+#else
+               /* The default way to relax a frag is to look through
+                  md_relax_table.  */
                {
                  const relax_typeS *this_type;
                  const relax_typeS *start_type;
@@ -1756,6 +1845,7 @@ relax_segment (segment_frag_root, segment)
                  if (growth != 0)
                    fragP->fr_subtype = this_state;
                }
+#endif
                break;
 
              default:
@@ -1800,276 +1890,343 @@ fixup_segment (fixP, this_segment_type)
      register fixS *fixP;
      segT this_segment_type;   /* N_TYPE bits for segment. */
 {
-  register long seg_reloc_count;
-  register symbolS *add_symbolP;
-  register symbolS *sub_symbolP;
+  long seg_reloc_count = 0;
+  symbolS *add_symbolP;
+  symbolS *sub_symbolP;
   valueT add_number;
-  register int size;
-  register char *place;
-  register long where;
-  register char pcrel;
-  register fragS *fragP;
-  register segT add_symbol_segment = absolute_section;
-
-  seg_reloc_count = 0;
-  /* If the linker is doing the relaxing, we must not do any fixups.  */
-  /* Well, strictly speaking that's not true -- we could do any that
-     are PC-relative and don't cross regions that could change size.
-     And for the i960 (the only machine for which we've got a relaxing
-     linker right now), we might be able to turn callx/callj into bal
-     in cases where we know the maximum displacement.  */
-  if (linkrelax)
-    for (; fixP; fixP = fixP->fx_next)
-      seg_reloc_count++;
-  else
-    for (; fixP; fixP = fixP->fx_next)
-      {
-       fragP = fixP->fx_frag;
-       know (fragP);
-       where = fixP->fx_where;
-       place = fragP->fr_literal + where;
-       size = fixP->fx_size;
-       add_symbolP = fixP->fx_addsy;
-#ifdef TC_I960
-       if (fixP->fx_callj && TC_S_IS_CALLNAME (add_symbolP))
-         {
-           /* Relocation should be done via the associated 'bal'
-              entry point symbol. */
-
-           if (!TC_S_IS_BALNAME (tc_get_bal_of_call (add_symbolP)))
-             {
-               as_bad ("No 'bal' entry point for leafproc %s",
-                       S_GET_NAME (add_symbolP));
-               continue;
-             }
-           fixP->fx_addsy = add_symbolP = tc_get_bal_of_call (add_symbolP);
-         }
-#endif
-       sub_symbolP = fixP->fx_subsy;
-       add_number = fixP->fx_offset;
-       pcrel = fixP->fx_pcrel;
-
-       if (add_symbolP)
-         add_symbol_segment = S_GET_SEGMENT (add_symbolP);
+  int size;
+  char *place;
+  long where;
+  char pcrel;
+  fragS *fragP;
+  segT add_symbol_segment = absolute_section;
+  
+  /* If the linker is doing the relaxing, we must not do any fixups.
 
-       if (sub_symbolP)
-         {
-           if (!add_symbolP)
-             {
-               /* Its just -sym */
-               /* @@ Should try converting to pcrel ref to fixed addr.  */
-               if (S_GET_SEGMENT (sub_symbolP) != absolute_section)
-                 as_bad ("Negative of non-absolute symbol %s",
-                         S_GET_NAME (sub_symbolP));
+     Well, strictly speaking that's not true -- we could do any that are
+     PC-relative and don't cross regions that could change size.  And for the
+     i960 (the only machine for which we've got a relaxing linker right now),
+     we might be able to turn callx/callj into bal anyways in cases where we
+     know the maximum displacement.  */
+  if (linkrelax)
+    {
+      for (; fixP; fixP = fixP->fx_next)
+       seg_reloc_count++;
+      TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count);
+      return seg_reloc_count;
+    }
 
+  for (; fixP; fixP = fixP->fx_next)
+    {
+      fragP = fixP->fx_frag;
+      know (fragP);
+      where = fixP->fx_where;
+      place = fragP->fr_literal + where;
+      size = fixP->fx_size;
+      add_symbolP = fixP->fx_addsy;
+#ifdef TC_VALIDATE_FIX
+      TC_VALIDATE_FIX (fixP, this_segment_type, skip);
+#endif
+      sub_symbolP = fixP->fx_subsy;
+      add_number = fixP->fx_offset;
+      pcrel = fixP->fx_pcrel;
+      
+      if (add_symbolP)
+       add_symbol_segment = S_GET_SEGMENT (add_symbolP);
+      
+      if (sub_symbolP)
+       {
+         if (!add_symbolP)
+           {
+             /* Its just -sym */
+             if (S_GET_SEGMENT (sub_symbolP) == absolute_section)
                add_number -= S_GET_VALUE (sub_symbolP);
-             }
-           else if ((S_GET_SEGMENT (sub_symbolP) == add_symbol_segment)
-                    && (SEG_NORMAL (add_symbol_segment)
-                        || (add_symbol_segment == absolute_section)))
-             {
-               /* Difference of 2 symbols from same segment.
-                  Can't make difference of 2 undefineds: 'value' means
-                  something different for N_UNDF. */
+             else if (pcrel
+                      && S_GET_SEGMENT (sub_symbolP) == this_segment_type)
+               {
+                 /* Should try converting to a constant.  */
+                 goto bad_sub_reloc;
+               }
+             else
+             bad_sub_reloc:
+               as_bad_where (fixP->fx_file, fixP->fx_line,
+                             "Negative of non-absolute symbol %s",
+                             S_GET_NAME (sub_symbolP));
+           }
+         else if ((S_GET_SEGMENT (sub_symbolP) == add_symbol_segment)
+                  && (SEG_NORMAL (add_symbol_segment)
+                      || (add_symbol_segment == absolute_section)))
+           {
+             /* Difference of 2 symbols from same segment.
+                Can't make difference of 2 undefineds: 'value' means
+                something different for N_UNDF. */
 #ifdef TC_I960
-               /* Makes no sense to use the difference of 2 arbitrary symbols
-                  as the target of a call instruction.  */
-               if (fixP->fx_callj)
-                 {
-                   as_bad ("callj to difference of 2 symbols");
-                 }
+             /* Makes no sense to use the difference of 2 arbitrary symbols
+                as the target of a call instruction.  */
+             if (fixP->fx_tcbit)
+               as_bad_where (fixP->fx_file, fixP->fx_line,
+                             "callj to difference of 2 symbols");
 #endif /* TC_I960 */
-               add_number += S_GET_VALUE (add_symbolP) -
-                 S_GET_VALUE (sub_symbolP);
+             add_number += S_GET_VALUE (add_symbolP) -
+               S_GET_VALUE (sub_symbolP);
 
-               add_symbolP = NULL;
-               fixP->fx_addsy = NULL;
-             }
-#if !defined(SEG_DIFF_ALLOWED) && !defined (GLOBAL_DIFF_ALLOWED)
-           else
-             {
-               /* Different segments in subtraction. */
-               know (!(S_IS_EXTERNAL (sub_symbolP)
-                       && (S_GET_SEGMENT (sub_symbolP) == absolute_section)));
+             add_symbolP = NULL;
+
+             /* Let the target machine make the final determination
+                as to whether or not a relocation will be needed to
+                handle this fixup.  */
+             if (!TC_FORCE_RELOCATION (fixP))
+               {
+                 fixP->fx_addsy = NULL;
+               }
+           }
+         else
+           {
+             /* Different segments in subtraction. */
+             know (!(S_IS_EXTERNAL (sub_symbolP)
+                     && (S_GET_SEGMENT (sub_symbolP) == absolute_section)));
+
+             if ((S_GET_SEGMENT (sub_symbolP) == absolute_section))
+               add_number -= S_GET_VALUE (sub_symbolP);
 
-               if ((S_GET_SEGMENT (sub_symbolP) == absolute_section))
-                 {
-                   add_number -= S_GET_VALUE (sub_symbolP);
-                 }
 #ifdef DIFF_EXPR_OK
-               else if (!pcrel
-                        && S_GET_SEGMENT (sub_symbolP) == this_segment_type)
-                 {
-                   /* Make it pc-relative.  */
-                   add_number += (md_pcrel_from (fixP)
-                                  - S_GET_VALUE (sub_symbolP));
-                   pcrel = 1;
-                   fixP->fx_pcrel = 1;
-                   sub_symbolP = 0;
-                   fixP->fx_subsy = 0;
-                 }
-#endif
-               else
-                 {
-                   char buf[50];
-                   sprint_value (buf, fragP->fr_address + where);
-                   as_bad ("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %s.",
-                           segment_name (S_GET_SEGMENT (sub_symbolP)),
-                           S_GET_NAME (sub_symbolP), buf);
-                 }
-             }
-#else
-              else
-                {
-                  seg_reloc_count++;
-                 fixP->fx_addnumber = add_number;      /* Remember value for emit_reloc */
-                  continue;
-                }              /* if absolute */
+             else if (S_GET_SEGMENT (sub_symbolP) == this_segment_type
+#if 0 /* Do this even if it's already described as pc-relative.  For example,
+        on the m68k, an operand of "pc@(foo-.-2)" should address "foo" in a
+        pc-relative mode.  */
+                      && pcrel
 #endif
-         }
+                      )
+               {
+                 /* Make it pc-relative.  */
+                 add_number += (md_pcrel_from (fixP)
+                                - S_GET_VALUE (sub_symbolP));
+                 pcrel = 1;
+                 fixP->fx_pcrel = 1;
+                 sub_symbolP = 0;
+                 fixP->fx_subsy = 0;
+               }
+#endif
+#ifdef BFD_ASSEMBLER
+             else if (fixP->fx_r_type == BFD_RELOC_GPREL32
+                      || fixP->fx_r_type == BFD_RELOC_GPREL16)
+               {
+                 /* Leave it alone.  */
+               }
+#endif
+             else
+               {
+                 char buf[50];
+                 sprint_value (buf, fragP->fr_address + where);
+                 as_bad_where (fixP->fx_file, fixP->fx_line,
+                               "Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %s.",
+                               segment_name (S_GET_SEGMENT (sub_symbolP)),
+                               S_GET_NAME (sub_symbolP), buf);
+               }
+           }
+       }
 
-       if (add_symbolP)
-         {
-           if (add_symbol_segment == this_segment_type && pcrel)
-             {
-               /*
-                * This fixup was made when the symbol's segment was
-                * SEG_UNKNOWN, but it is now in the local segment.
-                * So we know how to do the address without relocation.
-                */
+      if (add_symbolP)
+       {
+         if (add_symbol_segment == this_segment_type && pcrel)
+           {
+             /*
+              * This fixup was made when the symbol's segment was
+              * SEG_UNKNOWN, but it is now in the local segment.
+              * So we know how to do the address without relocation.
+              */
 #ifdef TC_I960
-               /* reloc_callj() may replace a 'call' with a 'calls' or a
-                  'bal', in which cases it modifies *fixP as appropriate.
-                  In the case of a 'calls', no further work is required,
-                  and *fixP has been set up to make the rest of the code
-                  below a no-op. */
-               reloc_callj (fixP);
+             /* reloc_callj() may replace a 'call' with a 'calls' or a
+                'bal', in which cases it modifies *fixP as appropriate.
+                In the case of a 'calls', no further work is required,
+                and *fixP has been set up to make the rest of the code
+                below a no-op. */
+             reloc_callj (fixP);
 #endif /* TC_I960 */
 
-               add_number += S_GET_VALUE (add_symbolP);
-               add_number -= md_pcrel_from (fixP);
-               pcrel = 0;      /* Lie. Don't want further pcrel processing. */
-#ifndef TC_HPPA
-               fixP->fx_addsy = NULL;  /* No relocations please. */
-#endif
-             }
-           else
-             {
-               if (add_symbol_segment == absolute_section)
-                 {
+             add_number += S_GET_VALUE (add_symbolP);
+             add_number -= md_pcrel_from (fixP);
+             pcrel = 0;        /* Lie. Don't want further pcrel processing. */
+             
+             /* Let the target machine make the final determination
+                as to whether or not a relocation will be needed to
+                handle this fixup.  */
+             if (!TC_FORCE_RELOCATION (fixP))
+               {
+                 fixP->fx_pcrel = 0;
+                 fixP->fx_addsy = NULL;
+               }
+           }
+         else
+           {
+             if (add_symbol_segment == absolute_section)
+               {
 #ifdef TC_I960
-                   /* See comment about reloc_callj() above.  */
-                   reloc_callj (fixP);
+                 /* See comment about reloc_callj() above.  */
+                 reloc_callj (fixP);
 #endif /* TC_I960 */
-                   add_number += S_GET_VALUE (add_symbolP);
-                   fixP->fx_addsy = NULL;
-                   add_symbolP = NULL;
-                 }
-               else if (add_symbol_segment == undefined_section
+                 add_number += S_GET_VALUE (add_symbolP);
+
+                 /* Let the target machine make the final determination
+                    as to whether or not a relocation will be needed to
+                    handle this fixup.  */
+                 if (!TC_FORCE_RELOCATION (fixP))
+                   {
+                     fixP->fx_addsy = NULL;
+                     add_symbolP = NULL;
+                   }
+               }
+             else if (add_symbol_segment == undefined_section
 #ifdef BFD_ASSEMBLER
-                        || bfd_is_com_section (add_symbol_segment)
+                      || bfd_is_com_section (add_symbol_segment)
 #endif
-                        )
-                 {
+                      )
+               {
 #ifdef TC_I960
-                   if ((int) fixP->fx_bit_fixP == 13)
-                     {
-                       /* This is a COBR instruction.  They have only a
-                        * 13-bit displacement and are only to be used
-                        * for local branches: flag as error, don't generate
-                        * relocation.
-                        */
-                       as_bad ("can't use COBR format with external label");
-                       fixP->fx_addsy = NULL;  /* No relocations please. */
-                       continue;
-                     }         /* COBR */
+                 if ((int) fixP->fx_bit_fixP == 13)
+                   {
+                     /* This is a COBR instruction.  They have only a
+                      * 13-bit displacement and are only to be used
+                      * for local branches: flag as error, don't generate
+                      * relocation.
+                      */
+                     as_bad_where (fixP->fx_file, fixP->fx_line,
+                                   "can't use COBR format with external label");
+                     fixP->fx_addsy = NULL;
+                     fixP->fx_done = 1;
+                     continue;
+                   }           /* COBR */
 #endif /* TC_I960 */
-
+                 
 #ifdef OBJ_COFF
 #ifdef TE_I386AIX
-                   if (S_IS_COMMON (add_symbolP))
-                     add_number += S_GET_VALUE (add_symbolP);
+                 if (S_IS_COMMON (add_symbolP))
+                   add_number += S_GET_VALUE (add_symbolP);
 #endif /* TE_I386AIX */
 #endif /* OBJ_COFF */
-                   ++seg_reloc_count;
-                 }
-               else
-                 {
-                   seg_reloc_count++;
-                   add_number += S_GET_VALUE (add_symbolP);
-                 }
-             }
-         }
+                 ++seg_reloc_count;
+               }
+             else
+               {
+                 seg_reloc_count++;
+                 add_number += S_GET_VALUE (add_symbolP);
+               }
+           }
+       }
 
-       if (pcrel)
-         {
-           add_number -= md_pcrel_from (fixP);
-           if (add_symbolP == 0)
-             {
-               fixP->fx_addsy = &abs_symbol;
-               ++seg_reloc_count;
-             }                 /* if there's an add_symbol */
-         }                     /* if pcrel */
+      if (pcrel)
+       {
+         add_number -= md_pcrel_from (fixP);
+         if (add_symbolP == 0)
+           {
+#ifndef BFD_ASSEMBLER
+             fixP->fx_addsy = &abs_symbol;
+#else
+             fixP->fx_addsy = section_symbol (absolute_section);
+#endif
+             fixP->fx_addsy->sy_used_in_reloc = 1;
+             ++seg_reloc_count;
+           }
+       }
 
-       if (!fixP->fx_bit_fixP)
-         {
-           valueT mask = 0;
-           /* set all bits to one */
-           mask--;
-           /* Technically speaking, combining these produces an
-              undefined result if size is sizeof (valueT), though I
-              think these two half-way operations should both be
-              defined.  */
-           mask <<= size * 4;
-           mask <<= size * 4;
-           if ((add_number & mask) != 0
-               && (add_number & mask) != mask)
-             {
-               char buf[50], buf2[50];
-               sprint_value (buf, fragP->fr_address + where);
-               if (add_number > 1000)
-                 sprint_value (buf2, add_number);
-               else
-                 sprintf (buf2, "%ld", (long) add_number);
-               as_bad_where (fixP->fx_file, fixP->fx_line,
-                             "Value of %s too large for field of %d bytes at %s",
-                             buf2, size, buf);
-             }                 /* generic error checking */
+      if (!fixP->fx_bit_fixP && size > 0)
+       {
+         valueT mask = 0;
+         if (size < sizeof (mask))
+           {
+             /* set all bits to one */
+             mask--;
+             /* Technically, combining these produces an undefined result
+                if size is sizeof (valueT), though I think these two
+                half-way operations should both be defined.  And the
+                compiler should be able to combine them if it's valid on
+                the host architecture.  */
+             mask <<= size * 4;
+             mask <<= size * 4;
+             if ((add_number & mask) != 0
+                 && (add_number & mask) != mask)
+               {
+                 char buf[50], buf2[50];
+                 sprint_value (buf, fragP->fr_address + where);
+                 if (add_number > 1000)
+                   sprint_value (buf2, add_number);
+                 else
+                   sprintf (buf2, "%ld", (long) add_number);
+                 as_bad_where (fixP->fx_file, fixP->fx_line,
+                               "Value of %s too large for field of %d bytes at %s",
+                               buf2, size, buf);
+               } /* generic error checking */
+           }
 #ifdef WARN_SIGNED_OVERFLOW_WORD
-           /* Warn if a .word value is too large when treated as a signed
-              number.  We already know it is not too negative.  This is to
-              catch over-large switches generated by gcc on the 68k.  */
-           if (!flagseen['J']
-               && size == 2
-               && add_number > 0x7fff)
-             as_bad_where (fixP->fx_file, fixP->fx_line,
-                           "Signed .word overflow; switch may be too large; %ld at 0x%lx",
-                           (long) add_number,
-                           (unsigned long) (fragP->fr_address + where));
-#endif
-         }                     /* not a bit fix */
-
+         /* Warn if a .word value is too large when treated as a signed
+            number.  We already know it is not too negative.  This is to
+            catch over-large switches generated by gcc on the 68k.  */
+         if (!flagseen['J']
+             && size == 2
+             && add_number > 0x7fff)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         "Signed .word overflow; switch may be too large; %ld at 0x%lx",
+                         (long) add_number,
+                         (unsigned long) (fragP->fr_address + where));
+#endif
+       }                       /* not a bit fix */
+
+      if (!fixP->fx_done)
+       {
 #ifdef BFD_ASSEMBLER
-       md_apply_fix (fixP, &add_number);
+         md_apply_fix (fixP, &add_number);
 #else
-       md_apply_fix (fixP, add_number);
+         md_apply_fix (fixP, add_number);
 #endif
-      }                                /* For each fixS in this segment. */
 
-#if defined (OBJ_COFF) && defined (TC_I960)
-  {
-    fixS *topP = fixP;
-
-    /* two relocs per callj under coff. */
-    for (fixP = topP; fixP; fixP = fixP->fx_next)
-      if (fixP->fx_callj && fixP->fx_addsy != 0)
-       ++seg_reloc_count;
-  }
-#endif /* OBJ_COFF && TC_I960 */
+#ifndef TC_HANDLES_FX_DONE
+         /* If the tc-* files haven't been converted, assume it's handling
+            it the old way, where a null fx_addsy means that the fix has
+            been applied completely, and no further work is needed.  */
+         if (fixP->fx_addsy == 0 && fixP->fx_pcrel == 0)
+           fixP->fx_done = 1;
+#endif
+       }
+#ifdef TC_VALIDATE_FIX
+    skip:
+#endif
+      ;
+    }                          /* For each fixS in this segment. */
 
-  return (seg_reloc_count);
+  TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count);
+  return seg_reloc_count;
 }
 
 #endif /* defined (BFD_ASSEMBLER) || !defined (BFD) */
 
+void
+number_to_chars_bigendian (buf, val, n)
+     char *buf;
+     valueT val;
+     int n;
+{
+  if (n > sizeof (val)|| n <= 0)
+    abort ();
+  while (n--)
+    {
+      buf[n] = val & 0xff;
+      val >>= 8;
+    }
+}
+
+void
+number_to_chars_littleendian (buf, val, n)
+     char *buf;
+     valueT val;
+     int n;
+{
+  if (n > sizeof (val) || n <= 0)
+    abort ();
+  while (n--)
+    {
+      *buf++ = val & 0xff;
+      val >>= 8;
+    }
+}
+
 /* end of write.c */
This page took 0.038987 seconds and 4 git commands to generate.