* arc.h (ARC_MACH_{BASE,HOST,GRAPHICS,AUDIO}): Define.
[deliverable/binutils-gdb.git] / gas / write.c
index 4ec756d64ad40ebacbca07fb599e4cf6a2789a74..efc363b97aa15ca92620b899f98092f3b5c895c8 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.
 
 #include "obstack.h"
 #include "output-file.h"
 
+/* This looks like a good idea.  Let's try turning it on always, for now.  */
+#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
@@ -43,6 +47,19 @@ extern CONST int md_short_jump_size;
 extern CONST int md_long_jump_size;
 #endif
 
+int symbol_table_frozen;
+void print_fixup PARAMS ((fixS *));
+
+#ifdef BFD_ASSEMBLER
+static void renumber_sections PARAMS ((bfd *, asection *, PTR));
+
+/* 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
@@ -55,7 +72,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,6 +134,7 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
   fixP->fx_subsy = sub_symbol;
   fixP->fx_offset = offset;
   fixP->fx_pcrel = pcrel;
+  fixP->fx_plt = 0;
 #if defined(NEED_FX_R_TYPE) || defined (BFD_ASSEMBLER)
   fixP->fx_r_type = r_type;
 #endif
@@ -126,8 +144,9 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
   fixP->fx_addnumber = 0;
   fixP->tc_fix_data = NULL;
   fixP->fx_tcbit = 0;
+  fixP->fx_done = 0;
 
-#ifdef TC_something
+#if defined (TC_I960) || defined (TC_NS32K)
   fixP->fx_bsr = 0;
 #endif
 
@@ -141,8 +160,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
@@ -213,6 +236,19 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type)
     case O_absent:
       break;
 
+    case O_add:
+      /* This comes up when _GLOBAL_OFFSET_TABLE_+(.-L0) is read, if
+        the difference expression cannot immediately be reduced.  */
+      {
+       extern symbolS *make_expr_symbol ();
+       symbolS *stmp = make_expr_symbol (exp);
+       exp->X_op = O_symbol;
+       exp->X_op_symbol = 0;
+       exp->X_add_symbol = stmp;
+       exp->X_add_number = 0;
+       return fix_new_exp (frag, where, size, exp, pcrel, r_type);
+      }
+
     case O_uminus:
       sub = exp->X_add_symbol;
       off = exp->X_add_number;
@@ -278,6 +314,24 @@ record_alignment (seg, align)
 #endif
 }
 
+#ifdef BFD_ASSEMBLER
+
+/* Reset the section indices after removing the gas created sections.  */
+
+static void
+renumber_sections (abfd, sec, countparg)
+     bfd *abfd;
+     asection *sec;
+     PTR countparg;
+{
+  int *countp = (int *) countparg;
+
+  sec->index = *countp;
+  ++*countp;
+}
+
+#endif /* defined (BFD_ASSEMBLER) */
+
 #if defined (BFD_ASSEMBLER) || ! defined (BFD)
 
 static fragS *
@@ -286,10 +340,25 @@ chain_frchains_together_1 (section, frchp)
      struct frchain *frchp;
 {
   fragS dummy, *prev_frag = &dummy;
+  fixS fix_dummy;
+#ifdef BFD_ASSEMBLER
+  fixS *prev_fix = &fix_dummy;
+#endif
+
   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;
@@ -313,6 +382,10 @@ chain_frchains_together (abfd, section, xxx)
   if (info != (segment_info_type *) NULL)
    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
@@ -349,17 +422,18 @@ cvt_frag_to_fill (headers, fragP)
   switch (fragP->fr_type)
     {
     case rs_align:
+    case rs_align_code:
     case rs_org:
+    case rs_space:
 #ifdef HANDLE_ALIGN
       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;
+      assert (fragP->fr_offset >= 0);
+      fragP->fr_type = rs_fill;
       break;
 
     case rs_fill:
@@ -424,7 +498,7 @@ relax_and_size_seg (abfd, sec, xxx)
 
   flags = bfd_get_section_flags (abfd, sec);
 
-  seginfo = (segment_info_type *) bfd_get_section_userdata (abfd, sec);
+  seginfo = seg_info (sec);
   if (seginfo && seginfo->frchainP)
     {
       relax_segment (seginfo->frchainP->frch_root, sec);
@@ -494,9 +568,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;
@@ -506,6 +590,10 @@ 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;
@@ -521,31 +609,42 @@ 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);
+       symbolS *sym;
+       asection *symsec;
+
+      reduce_fixup:
+
+#ifdef DEBUG5
+       fprintf (stderr, "\n\nadjusting fixup:\n");
+       print_fixup (fixp);
+#endif
+
+       sym = fixp->fx_addsy;
+       symsec = sym->bsym->section;
 
        /* 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
+       if (bfd_is_und_section (symsec)
+           || bfd_is_abs_section (symsec)
            || bfd_is_com_section (symsec))
          {
            fixp->fx_addsy->sy_used_in_reloc = 1;
-           continue;
+           goto done;
          }
 
        /* 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;
+           goto done;
          }
 
        /* Is there some other reason we can't adjust this one?  (E.g.,
@@ -554,7 +653,7 @@ adjust_reloc_syms (abfd, sec, xxx)
        if (! obj_fix_adjustable (fixp))
          {
            fixp->fx_addsy->sy_used_in_reloc = 1;
-           continue;
+           goto done;
          }
 #endif
 
@@ -565,34 +664,51 @@ adjust_reloc_syms (abfd, sec, xxx)
        if (! tc_fix_adjustable (fixp))
          {
            fixp->fx_addsy->sy_used_in_reloc = 1;
-           continue;
+           goto done;
          }
 #endif
 
+       /* For PIC support: We may get expressions like
+          "_GLOBAL_OFFSET_TABLE_+(.-L5)" where "." and "L5" may not
+          necessarily have had a fixed difference initially.  But now
+          it should be a known constant, so we can reduce it.  Since
+          we can't easily handle a symbol value that looks like
+          someUndefinedSymbol+const, though, we convert the fixup to
+          access the undefined symbol directly, and discard the
+          intermediate symbol.  */
+       if (S_GET_SEGMENT (sym) == expr_section
+           && sym->sy_value.X_op == O_add
+           && (resolve_symbol_value (sym->sy_value.X_add_symbol),
+               S_GET_SEGMENT (sym->sy_value.X_add_symbol) == undefined_section)
+           && (resolve_symbol_value (sym->sy_value.X_op_symbol),
+               S_GET_SEGMENT (sym->sy_value.X_op_symbol) == absolute_section))
+         {
+           fixp->fx_offset += S_GET_VALUE (sym->sy_value.X_op_symbol);
+           fixp->fx_offset += sym->sy_value.X_add_number;
+           fixp->fx_addsy = sym->sy_value.X_add_symbol;
+           goto reduce_fixup;
+         }
+
        /* If the section symbol isn't going to be output, the relocs
           at least should still work.  If not, figure out what to do
           when we run into that case.  */
        fixp->fx_offset += S_GET_VALUE (sym);
-       if (sym->sy_frag)
-         fixp->fx_offset += sym->sy_frag->fr_address;
        fixp->fx_addsy = section_symbol (symsec);
        fixp->fx_addsy->sy_used_in_reloc = 1;
+
+      done:
+       ;
       }
-#ifdef RELOC_REQUIRES_SYMBOL
+#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.  */
-       static symbolS *abs_sym;
-       if (!abs_sym)
-         {
-           abs_sym = symbol_new ("*absolute0zero*", &bfd_abs_section, 0,
-                                 &zero_address_frag);
-           abs_sym->sy_used_in_reloc = 1;
-         }
-       fixp->fx_addsy = abs_sym;
+
+       fixp->fx_addsy = section_symbol (absolute_section);
+/*     fixp->fx_addsy->sy_used_in_reloc = 1; */
       }
 #endif
 
@@ -610,6 +726,7 @@ write_relocs (abfd, sec, xxx)
   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.  */
@@ -632,13 +749,10 @@ write_relocs (abfd, sec, xxx)
   for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
     {
       arelent *reloc;
-      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;
        }
@@ -648,30 +762,24 @@ write_relocs (abfd, sec, xxx)
          n--;
          continue;
        }
-      data = fixp->fx_frag->fr_literal + fixp->fx_where;
       if (fixp->fx_where + fixp->fx_size
          > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
        abort ();
 
-      if (reloc->howto->partial_inplace == false
-         && reloc->howto->pcrel_offset == true
-         && reloc->howto->pc_relative == true)
-       {
-         /* 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);
+      s = bfd_install_relocation (stdoutput, reloc,
+                                 fixp->fx_frag->fr_literal,
+                                 fixp->fx_frag->fr_address,
+                                 sec, &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");
+         as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+                   fixp->fx_file, fixp->fx_line);
        }
       relocs[i++] = reloc;
     }
@@ -689,10 +797,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;
        }
@@ -709,28 +815,53 @@ write_relocs (abfd, sec, xxx)
        abort ();
       for (j = 0; reloc[j]; j++)
         {
-          s = bfd_perform_relocation (stdoutput, reloc[j],
-                                     data - reloc[0]->address,
-                                     sec, stdoutput);
+         s = bfd_install_relocation (stdoutput, reloc[j],
+                                     fixp->fx_frag->fr_literal,
+                                     fixp->fx_frag->fr_address,
+                                     sec, &err);
           switch (s)
            {
-             case bfd_reloc_ok:
-               break;
-             default:
-               as_fatal ("bad return from bfd_perform_relocation");
+           case bfd_reloc_ok:
+             break;
+           case bfd_reloc_overflow:
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           "relocation overflow");
+             break;
+           default:
+             as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+                       fixp->fx_file, fixp->fx_line);
            }
         }
     }
   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;
@@ -777,7 +908,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 (EXIT_FAILURE);
+           }
          offset += f->fr_fix;
        }
       fill_literal = f->fr_literal + f->fr_fix;
@@ -785,6 +921,55 @@ write_contents (abfd, sec, xxx)
       count = f->fr_offset;
       assert (count >= 0);
       if (fill_size && count)
+#ifdef BFD_FAST_SECTION_FILL
+       {
+         char buf[256];
+         if (fill_size > sizeof(buf)) {
+           /* Do it the old way. Can this ever happen? */
+       while (count--)
+         {
+           x = bfd_set_section_contents (stdoutput, sec,
+                                         fill_literal, (file_ptr) offset,
+                                         (bfd_size_type) fill_size);
+           if (x == false)
+             {
+               bfd_perror (stdoutput->filename);
+               as_perror ("FATAL: Can't write %s", stdoutput->filename);
+               exit (EXIT_FAILURE);
+             }
+           offset += fill_size;
+         }
+    }
+         else {
+           /* Build a buffer full of fill objects and output it as
+            * often as necessary. This saves on the overhead of potentially
+            * lots of bfd_set_section_contents calls.
+            */
+           int n_per_buf, i;
+           if (fill_size == 1)
+             {
+               n_per_buf = sizeof (buf);
+               memset (buf, *fill_literal, n_per_buf);
+             }
+           else
+             {
+               char *bufp;
+               n_per_buf = sizeof(buf)/fill_size;
+               for (i = n_per_buf, bufp = buf; i; i--, bufp += fill_size)
+                 memcpy(bufp, fill_literal, fill_size);
+             }
+           for (; count > 0; count -= n_per_buf)
+             {
+               n_per_buf = n_per_buf > count ? count : n_per_buf;
+               x = bfd_set_section_contents (stdoutput, sec,
+                                             buf, (file_ptr) offset,
+                                             (bfd_size_type) n_per_buf * fill_size);
+               assert (x == true);
+               offset += n_per_buf * fill_size;
+             }
+         }
+       }
+#else
        while (count--)
          {
            x = bfd_set_section_contents (stdoutput, sec,
@@ -793,6 +978,7 @@ write_contents (abfd, sec, xxx)
            assert (x == true);
            offset += fill_size;
          }
+#endif
     }
 }
 #endif
@@ -921,15 +1107,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?  */
@@ -939,7 +1160,7 @@ write_object_file ()
     n_errs = had_errors ();
     /* The -Z flag indicates that an object file should be generated,
        regardless of warnings and errors.  */
-    if (flagseen['Z'])
+    if (flag_always_generate_output)
       {
        if (n_warns || n_errs)
          as_warn ("%d error%s, %d warning%s, generating bad object file.\n",
@@ -956,13 +1177,10 @@ 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.
-   */
-  VMS_Check_For_Main ();
+  /* 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 */
 
   /* After every sub-segment, we fake an ".align ...". This conforms to
@@ -1000,6 +1218,8 @@ write_object_file ()
   /* Remove the sections created by gas for its own purposes.  */
   {
     asection **seclist, *sec;
+    int i;
+
     seclist = &stdoutput->sections;
     while (seclist && *seclist)
       {
@@ -1015,6 +1235,8 @@ write_object_file ()
        if (*seclist)
          seclist = &(*seclist)->next;
       }
+    i = 0;
+    bfd_map_over_sections (stdoutput, renumber_sections, &i);
   }
 
   bfd_map_over_sections (stdoutput, chain_frchains_together, (char *) 0);
@@ -1028,7 +1250,7 @@ write_object_file ()
      data frags into the text segment. Do this before relaxing so
      we know to take advantage of -R and make shorter addresses.  */
 #if !defined (OBJ_AOUT) || defined (BFD_ASSEMBLER)
-  if (flagseen['R'])
+  if (flag_readonly_data_in_text)
     {
       merge_data_into_text ();
     }
@@ -1113,9 +1335,15 @@ write_object_file ()
          exp.X_op_symbol = lie->sub;
          exp.X_add_number = lie->addnum;
 #ifdef BFD_ASSEMBLER
+#ifdef TC_CONS_FIX_NEW
+         TC_CONS_FIX_NEW (lie->frag,
+                      lie->word_goes_here - lie->frag->fr_literal,
+                      2, &exp);
+#else
          fix_new_exp (lie->frag,
                       lie->word_goes_here - lie->frag->fr_literal,
                       2, &exp, 0, BFD_RELOC_NONE);
+#endif
 #else
 #if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE)
          fix_new_exp (lie->frag,
@@ -1171,6 +1399,9 @@ write_object_file ()
            /* Patch the jump table */
            /* This is the offset from ??? to table_ptr+0 */
            to_addr = table_addr - S_GET_VALUE (lie->sub);
+#ifdef BFD_ASSEMBLER
+           to_addr -= lie->sub->sy_frag->fr_address;
+#endif
            md_number_to_chars (lie->word_goes_here, to_addr, 2);
            for (untruth = lie->next_broken_word; untruth && untruth->dispfrag == fragP; untruth = untruth->next_broken_word)
              {
@@ -1182,6 +1413,9 @@ write_object_file ()
            /* this is a long jump from table_ptr+0 to the final target */
            from_addr = table_addr;
            to_addr = S_GET_VALUE (lie->add) + lie->addnum;
+#ifdef BFD_ASSEMBLER
+           to_addr += lie->add->sy_frag->fr_address;
+#endif
            md_create_long_jump (table_ptr, from_addr, to_addr, lie->dispfrag, lie->add);
            table_ptr += md_long_jump_size;
            table_addr += md_long_jump_size;
@@ -1193,6 +1427,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.
@@ -1295,24 +1530,38 @@ write_object_file ()
   /*
    *   Now do the VMS-dependent part of writing the object file
    */
-  VMS_write_object_file (H_GET_TEXT_SIZE (&headers),
+  vms_write_object_file (H_GET_TEXT_SIZE (&headers),
                         H_GET_DATA_SIZE (&headers),
                         H_GET_BSS_SIZE (&headers),
                         text_frag_root, data_frag_root);
 #endif /* VMS */
 #else /* BFD_ASSEMBLER */
 
+  /* Resolve symbol values.  This needs to be done before processing
+     the relocations.  */
+  if (symbol_rootP)
+    {
+      symbolS *symp;
+
+      for (symp = symbol_rootP; symp; symp = symbol_next (symp))
+       if (!symp->sy_resolved)
+         resolve_symbol_value (symp);
+    }
+
   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;
+
+         /* Do it again, because adjust_reloc_syms might introduce
+            more symbols.  They'll probably only be section symbols,
+            but they'll still need to have the values computed.  */
          if (! symp->sy_resolved)
            {
              if (symp->sy_value.X_op == O_constant)
@@ -1331,7 +1580,7 @@ write_object_file ()
             Put them in the common section now.  */
          if (S_IS_DEFINED (symp) == 0
              && S_GET_VALUE (symp) != 0)
-           S_SET_SEGMENT (symp, &bfd_com_section);
+           S_SET_SEGMENT (symp, bfd_com_section_ptr);
 #if 0
          printf ("symbol `%s'\n\t@%x: value=%d flags=%x seg=%s\n",
                  S_GET_NAME (symp), symp,
@@ -1341,56 +1590,33 @@ write_object_file ()
 #endif
 
 #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;
+         if (! punt || symp->sy_used_in_reloc)
            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 (S_IS_LOCAL (symp))
+         /* 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))
            {
-           punt_it:
-             if (! symp->sy_used_in_reloc)
-               {
-                 symbolS *prev, *next;
-                 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
-                 continue;
-               }
+             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;
            }
 
          /* Make sure we really got a value for the symbol.  */
@@ -1404,40 +1630,30 @@ 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);
        }
     }
 
+  /* Now do any format-specific adjustments to the symbol table, such
+     as adding file symbols.  */
+#ifdef obj_adjust_symtab
+  obj_adjust_symtab ();
+#endif
 
-#ifdef obj_frob_file
-  /* If obj_frob_file changes the symbol value at this point, it is
+  /* Now that all the sizes are known, and contents correct, we can
+     start writing to the file.  */
+  set_symtab ();
+
+  /* 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.  */
   bfd_map_over_sections (stdoutput, write_relocs, (char *) 0);
 
   bfd_map_over_sections (stdoutput, write_contents, (char *) 0);
@@ -1521,10 +1737,21 @@ relax_segment (segment_frag_root, segment)
          break;
 
        case rs_align:
-         address += relax_align (address, (int) fragP->fr_offset);
+       case rs_align_code:
+         {
+           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:
+       case rs_space:
          /* Assume .org is nugatory. It will grow with 1st relax.  */
          break;
 
@@ -1608,7 +1835,7 @@ relax_segment (segment_frag_root, segment)
                                   + S_GET_VALUE (lie->sub)));
                      if (offset <= -32768 || offset >= 32767)
                        {
-                         if (flagseen['K'])
+                         if (flag_warn_displacement)
                            {
                              char buf[50];
                              sprint_value (buf, (addressT) lie->addnum);
@@ -1640,6 +1867,7 @@ relax_segment (segment_frag_root, segment)
                }               /* case rs_broken_word */
 #endif
              case rs_align:
+             case rs_align_code:
                growth = (relax_align ((relax_addressT) (address
                                                         + fragP->fr_fix),
                                       (int) offset)
@@ -1676,6 +1904,23 @@ relax_segment (segment_frag_root, segment)
                growth -= stretch;      /* This is an absolute growth factor */
                break;
 
+             case rs_space:
+               if (symbolP)
+                 {
+                   growth = S_GET_VALUE (symbolP);
+                   if (symbolP->sy_frag != &zero_address_frag)
+                     as_bad (".space specifies non-absolute value");
+                   fragP->fr_symbol = 0;
+                   if (growth < 0)
+                     {
+                       as_warn (".space or .fill with negative value, ignored");
+                       growth = 0;
+                     }
+                 }
+               else
+                 growth = 0;
+               break;
+
              case rs_machine_dependent:
 #ifdef md_relax_frag
                growth = md_relax_frag (fragP, stretch);
@@ -1727,16 +1972,14 @@ relax_segment (segment_frag_root, segment)
                    }
 
                  aim = target - address - fragP->fr_fix;
-                 /* The displacement is affected by the instruction size
-                    for the 32k architecture. I think we ought to be able
-                    to add fragP->fr_pcrel_adjust in all cases (it should be
-                    zero if not used), but just in case it breaks something
-                    else we'll put this inside #ifdef NS32K ... #endif  */
-#ifndef TC_NS32K
-                 if (fragP->fr_pcrel_adjust)
-                   abort ();
+#ifdef TC_PCREL_ADJUST
+                 /* Currently only the ns32k family needs this */
+                 aim += TC_PCREL_ADJUST(fragP);
+#else
+                 /* This machine doesn't want to use pcrel_adjust.
+                    In that case, pcrel_adjust should be zero.  */
+                 assert (fragP->fr_pcrel_adjust == 0);
 #endif
-                 aim += fragP->fr_pcrel_adjust;
 
                  if (aim < 0)
                    {
@@ -1803,6 +2046,10 @@ relax_segment (segment_frag_root, segment)
 
 #if defined (BFD_ASSEMBLER) || !defined (BFD)
 
+#ifndef TC_RELOC_RTSYM_LOC_FIXUP
+#define TC_RELOC_RTSYM_LOC_FIXUP(X) (1)
+#endif
+
 /* fixup_segment()
 
    Go through all the fixS's in a segment and see which ones can be
@@ -1826,7 +2073,7 @@ fixup_segment (fixP, this_segment_type)
   int size;
   char *place;
   long where;
-  char pcrel;
+  int pcrel, plt;
   fragS *fragP;
   segT add_symbol_segment = absolute_section;
   
@@ -1847,6 +2094,11 @@ fixup_segment (fixP, this_segment_type)
 
   for (; fixP; fixP = fixP->fx_next)
     {
+#ifdef DEBUG5
+      fprintf (stderr, "\nprocessing fixup:\n");
+      print_fixup (fixP);
+#endif
+
       fragP = fixP->fx_frag;
       know (fragP);
       where = fixP->fx_where;
@@ -1859,7 +2111,8 @@ fixup_segment (fixP, this_segment_type)
       sub_symbolP = fixP->fx_subsy;
       add_number = fixP->fx_offset;
       pcrel = fixP->fx_pcrel;
-      
+      plt = fixP->fx_plt;
+
       if (add_symbolP)
        add_symbol_segment = S_GET_SEGMENT (add_symbolP);
       
@@ -1878,8 +2131,9 @@ fixup_segment (fixP, this_segment_type)
                }
              else
              bad_sub_reloc:
-               as_bad ("Negative of non-absolute symbol %s",
-                       S_GET_NAME (sub_symbolP));
+               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)
@@ -1892,7 +2146,8 @@ fixup_segment (fixP, this_segment_type)
              /* Makes no sense to use the difference of 2 arbitrary symbols
                 as the target of a call instruction.  */
              if (fixP->fx_tcbit)
-               as_bad ("callj to difference of 2 symbols");
+               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);
@@ -1903,7 +2158,9 @@ fixup_segment (fixP, this_segment_type)
                 as to whether or not a relocation will be needed to
                 handle this fixup.  */
              if (!TC_FORCE_RELOCATION (fixP))
-               fixP->fx_addsy = NULL;
+               {
+                 fixP->fx_addsy = NULL;
+               }
            }
          else
            {
@@ -1931,21 +2188,30 @@ fixup_segment (fixP, this_segment_type)
                  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 ("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %s.",
-                         segment_name (S_GET_SEGMENT (sub_symbolP)),
-                         S_GET_NAME (sub_symbolP), buf);
+                 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)
+         if (add_symbol_segment == this_segment_type && pcrel && !plt
+             && TC_RELOC_RTSYM_LOC_FIXUP (fixP->fx_r_type))
            {
              /*
               * This fixup was made when the symbol's segment was
@@ -1969,7 +2235,10 @@ fixup_segment (fixP, this_segment_type)
                 as to whether or not a relocation will be needed to
                 handle this fixup.  */
              if (!TC_FORCE_RELOCATION (fixP))
-               fixP->fx_addsy = NULL;
+               {
+                 fixP->fx_pcrel = 0;
+                 fixP->fx_addsy = NULL;
+               }
            }
          else
            {
@@ -2004,13 +2273,10 @@ fixup_segment (fixP, this_segment_type)
                       * for local branches: flag as error, don't generate
                       * relocation.
                       */
-                     as_bad ("can't use COBR format with external label");
-                     
-                     /* 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;
+                     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 */
@@ -2026,7 +2292,9 @@ fixup_segment (fixP, this_segment_type)
              else
                {
                  seg_reloc_count++;
+#if !defined (TC_I386) || !(defined (OBJ_ELF) || defined (OBJ_COFF))
                  add_number += S_GET_VALUE (add_symbolP);
+#endif
                }
            }
        }
@@ -2036,40 +2304,49 @@ fixup_segment (fixP, this_segment_type)
          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 there's an add_symbol */
-       }                       /* if pcrel */
+           }
+       }
 
       if (!fixP->fx_bit_fixP && size > 0)
        {
          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)
+         if (size < sizeof (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 */
+             /* 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']
+         if (!flag_signed_overflow_ok
              && size == 2
              && add_number > 0x7fff)
            as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -2079,13 +2356,29 @@ fixup_segment (fixP, this_segment_type)
 #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
+
+#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
+#ifdef DEBUG5
+      fprintf (stderr, "result:\n");
+      print_fixup (fixP);
 #endif
-    skip:
-      ;
     }                          /* For each fixS in this segment. */
 
   TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count);
@@ -2124,4 +2417,56 @@ number_to_chars_littleendian (buf, val, n)
     }
 }
 
+/* for debugging */
+extern int indent_level;
+extern void print_symbol_value_1 ();
+
+void
+print_fixup (fixp)
+     fixS *fixp;
+{
+  indent_level = 1;
+  fprintf (stderr, "fix %lx %s:%d", (long) fixp, fixp->fx_file, fixp->fx_line);
+  if (fixp->fx_pcrel)
+    fprintf (stderr, " pcrel");
+  if (fixp->fx_pcrel_adjust)
+    fprintf (stderr, " pcrel_adjust=%d", fixp->fx_pcrel_adjust);
+  if (fixp->fx_im_disp)
+    {
+#ifdef TC_NS32K
+      fprintf (stderr, " im_disp=%d", fixp->fx_im_disp);
+#else
+      fprintf (stderr, " im_disp");
+#endif
+    }
+  if (fixp->fx_tcbit)
+    fprintf (stderr, " tcbit");
+  if (fixp->fx_done)
+    fprintf (stderr, " done");
+  fprintf (stderr, "\n    size=%d frag=%lx where=%ld offset=%lx addnumber=%lx",
+          fixp->fx_size, (long) fixp->fx_frag, (long) fixp->fx_where,
+          (long) fixp->fx_offset, (long) fixp->fx_addnumber);
+#ifdef BFD_ASSEMBLER
+  fprintf (stderr, "\n    %s (%d)", bfd_get_reloc_code_name (fixp->fx_r_type),
+          fixp->fx_r_type);
+#else
+#ifdef NEED_FX_R_TYPE
+  fprintf (stderr, " r_type=%d", fixp->fx_r_type);
+#endif
+#endif
+  if (fixp->fx_addsy)
+    {
+      fprintf (stderr, "\n   +<");
+      print_symbol_value_1 (stderr, fixp->fx_addsy);
+      fprintf (stderr, ">");
+    }
+  if (fixp->fx_subsy)
+    {
+      fprintf (stderr, "\n   -<");
+      print_symbol_value_1 (stderr, fixp->fx_subsy);
+      fprintf (stderr, ">");
+    }
+  fprintf (stderr, "\n");
+}
+
 /* end of write.c */
This page took 0.038172 seconds and 4 git commands to generate.