s/boolean/bfd_boolean/ s/true/TRUE/ s/false/FALSE/. Simplify
[deliverable/binutils-gdb.git] / gas / write.c
index b94c05eed71b7fa33855225984eca7c8893e75be..14e23fbc2f3fcab523c7737be60f7c9c157fc22a 100644 (file)
@@ -1,6 +1,6 @@
 /* write.c - emit .o file
    Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001
+   1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 #include "output-file.h"
 #include "dwarf2dbg.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
-
 #ifndef TC_ADJUST_RELOC_COUNT
-#define TC_ADJUST_RELOC_COUNT(FIXP,COUNT)
+#define TC_ADJUST_RELOC_COUNT(FIXCOUNT)
 #endif
 
 #ifndef TC_FORCE_RELOCATION
-#define TC_FORCE_RELOCATION(FIXP) 0
+#define TC_FORCE_RELOCATION(FIX)               \
+  (S_FORCE_RELOC ((FIX)->fx_addsy))
+#endif
+
+#ifndef TC_FORCE_RELOCATION_ABS
+#define TC_FORCE_RELOCATION_ABS(FIX)           \
+  (TC_FORCE_RELOCATION (FIX))
+#endif
+
+#ifndef TC_FORCE_RELOCATION_LOCAL
+#define TC_FORCE_RELOCATION_LOCAL(FIX)         \
+  (!(FIX)->fx_pcrel                            \
+   || (FIX)->fx_plt                            \
+   || TC_FORCE_RELOCATION (FIX))
 #endif
 
-#ifndef TC_FORCE_RELOCATION_SECTION
-#define TC_FORCE_RELOCATION_SECTION(FIXP,SEG) TC_FORCE_RELOCATION(FIXP)
+#ifndef TC_FORCE_RELOCATION_SUB_SAME
+#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) \
+  (! SEG_NORMAL (SEG))
+#endif
+
+#ifndef TC_FORCE_RELOCATION_SUB_ABS
+#define TC_FORCE_RELOCATION_SUB_ABS(FIX)       0
+#endif
+
+#ifndef TC_FORCE_RELOCATION_SUB_LOCAL
+#ifdef DIFF_EXPR_OK
+#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX)     0
+#else
+#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX)     1
+#endif
+#endif
+
+#ifndef TC_VALIDATE_FIX_SUB
+#ifdef UNDEFINED_DIFFERENCE_OK
+/* The PA needs this for PIC code generation.  */
+#define TC_VALIDATE_FIX_SUB(FIX) 1
+#else
+#ifdef BFD_ASSEMBLER
+#define TC_VALIDATE_FIX_SUB(FIX)               \
+  ((FIX)->fx_r_type == BFD_RELOC_GPREL32       \
+   || (FIX)->fx_r_type == BFD_RELOC_GPREL16)
+#else
+#define TC_VALIDATE_FIX_SUB(FIX) 0
+#endif
+#endif
 #endif
 
 #ifndef TC_LINKRELAX_FIXUP
 #define TC_LINKRELAX_FIXUP(SEG) 1
 #endif
 
-#ifndef TC_FIX_ADJUSTABLE
-#define TC_FIX_ADJUSTABLE(fix) 1
+#ifndef MD_APPLY_SYM_VALUE
+#define MD_APPLY_SYM_VALUE(FIX) 1
+#endif
+
+#ifndef TC_FINALIZE_SYMS_BEFORE_SIZE_SEG
+#define TC_FINALIZE_SYMS_BEFORE_SIZE_SEG 1
 #endif
 
 #ifndef        MD_PCREL_FROM_SECTION
-#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from(FIXP)
+#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from (FIX)
 #endif
 
 #ifndef WORKING_DOT_WORD
-extern CONST int md_short_jump_size;
-extern CONST int md_long_jump_size;
+extern const int md_short_jump_size;
+extern const int md_long_jump_size;
 #endif
 
+/* Used to control final evaluation of expressions.  */
+int finalize_syms = 0;
+
 int symbol_table_frozen;
+
+symbolS *abs_section_sym;
+
+/* Remember the value of dot when parsing expressions.  */
+addressT dot_value;
+
 void print_fixup PARAMS ((fixS *));
 
 #ifdef BFD_ASSEMBLER
@@ -102,18 +152,17 @@ int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE;
 static int n_fixups;
 
 #ifdef BFD_ASSEMBLER
-static fixS *fix_new_internal PARAMS ((fragS *, int where, int size,
-                                      symbolS *add, symbolS *sub,
-                                      offsetT offset, int pcrel,
-                                      bfd_reloc_code_real_type r_type));
+#define RELOC_ENUM enum bfd_reloc_code_real
 #else
+#define RELOC_ENUM int
+#endif
+
 static fixS *fix_new_internal PARAMS ((fragS *, int where, int size,
                                       symbolS *add, symbolS *sub,
                                       offsetT offset, int pcrel,
-                                      int r_type));
-#endif
+                                      RELOC_ENUM r_type));
 #if defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS))
-static long fixup_segment PARAMS ((fixS * fixP, segT this_segment_type));
+static long fixup_segment PARAMS ((fixS *, segT));
 #endif
 static relax_addressT relax_align PARAMS ((relax_addressT addr, int align));
 #if defined (BFD_ASSEMBLER) || ! defined (BFD)
@@ -122,8 +171,8 @@ static fragS *chain_frchains_together_1 PARAMS ((segT, struct frchain *));
 #ifdef BFD_ASSEMBLER
 static void chain_frchains_together PARAMS ((bfd *, segT, PTR));
 static void cvt_frag_to_fill PARAMS ((segT, fragS *));
-static void relax_and_size_seg PARAMS ((bfd *, asection *, PTR));
 static void adjust_reloc_syms PARAMS ((bfd *, asection *, PTR));
+static void fix_segment PARAMS ((bfd *, asection *, PTR));
 static void write_relocs PARAMS ((bfd *, asection *, PTR));
 static void write_contents PARAMS ((bfd *, asection *, PTR));
 static void set_symtab PARAMS ((void));
@@ -136,9 +185,6 @@ static void cvt_frag_to_fill PARAMS ((object_headers *, segT, fragS *));
 static void remove_subsegs PARAMS ((frchainS *, int, fragS **, fragS **));
 static void relax_and_size_all_segments PARAMS ((void));
 #endif
-#if defined (BFD_ASSEMBLER) && defined (OBJ_COFF) && defined (TE_GO32)
-static void set_segment_vma PARAMS ((bfd *, asection *, PTR));
-#endif
 
 /* Create a fixS in obstack 'notes'.  */
 
@@ -152,11 +198,7 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
      symbolS *sub_symbol;      /* X_op_symbol.  */
      offsetT offset;           /* X_add_number.  */
      int pcrel;                        /* TRUE if PC-relative relocation.  */
-#ifdef BFD_ASSEMBLER
-     bfd_reloc_code_real_type r_type; /* Relocation type.  */
-#else
-     int r_type;               /* Relocation type.  */
-#endif
+     RELOC_ENUM r_type ATTRIBUTE_UNUSED; /* Relocation type.  */
 {
   fixS *fixP;
 
@@ -176,6 +218,7 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
   fixP->fx_addsy = add_symbol;
   fixP->fx_subsy = sub_symbol;
   fixP->fx_offset = offset;
+  fixP->fx_dot_value = dot_value;
   fixP->fx_pcrel = pcrel;
   fixP->fx_plt = 0;
 #if defined(NEED_FX_R_TYPE) || defined (BFD_ASSEMBLER)
@@ -247,11 +290,7 @@ fix_new (frag, where, size, add_symbol, offset, pcrel, r_type)
      symbolS *add_symbol;      /* X_add_symbol.  */
      offsetT offset;           /* X_add_number.  */
      int pcrel;                        /* TRUE if PC-relative relocation.  */
-#ifdef BFD_ASSEMBLER
-     bfd_reloc_code_real_type r_type; /* Relocation type.  */
-#else
-     int r_type;               /* Relocation type.  */
-#endif
+     RELOC_ENUM r_type;                /* Relocation type.  */
 {
   return fix_new_internal (frag, where, size, add_symbol,
                           (symbolS *) NULL, offset, pcrel, r_type);
@@ -268,11 +307,7 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type)
      int size;                 /* 1, 2, or 4 usually.  */
      expressionS *exp;         /* Expression.  */
      int pcrel;                        /* TRUE if PC-relative relocation.  */
-#ifdef BFD_ASSEMBLER
-     bfd_reloc_code_real_type r_type; /* Relocation type.  */
-#else
-     int r_type;               /* Relocation type.  */
-#endif
+     RELOC_ENUM r_type;                /* Relocation type.  */
 {
   symbolS *add = NULL;
   symbolS *sub = NULL;
@@ -521,6 +556,7 @@ cvt_frag_to_fill (headersP, sec, fragP)
          as_bad_where (fragP->fr_file, fragP->fr_line,
                        _("attempt to .org/.space backwards? (%ld)"),
                        (long) fragP->fr_offset);
+         fragP->fr_offset = 0;
        }
       fragP->fr_type = rs_fill;
       break;
@@ -597,8 +633,26 @@ cvt_frag_to_fill (headersP, sec, fragP)
 #endif /* defined (BFD_ASSEMBLER) || !defined (BFD)  */
 
 #ifdef BFD_ASSEMBLER
+static void relax_seg PARAMS ((bfd *, asection *, PTR));
 static void
-relax_and_size_seg (abfd, sec, xxx)
+relax_seg (abfd, sec, xxx)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     PTR xxx;
+{
+  segment_info_type *seginfo = seg_info (sec);
+
+  if (seginfo && seginfo->frchainP
+      && relax_segment (seginfo->frchainP->frch_root, sec))
+    {
+      int *result = (int *) xxx;
+      *result = 1;
+    }
+}
+
+static void size_seg PARAMS ((bfd *, asection *, PTR));
+static void
+size_seg (abfd, sec, xxx)
      bfd *abfd;
      asection *sec;
      PTR xxx ATTRIBUTE_UNUSED;
@@ -611,12 +665,9 @@ relax_and_size_seg (abfd, sec, xxx)
 
   subseg_change (sec, 0);
 
-  flags = bfd_get_section_flags (abfd, sec);
-
   seginfo = seg_info (sec);
   if (seginfo && seginfo->frchainP)
     {
-      relax_segment (seginfo->frchainP->frch_root, sec);
       for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
        cvt_frag_to_fill (sec, fragp);
       for (fragp = seginfo->frchainP->frch_root;
@@ -629,6 +680,8 @@ relax_and_size_seg (abfd, sec, xxx)
   else
     size = 0;
 
+  flags = bfd_get_section_flags (abfd, sec);
+
   if (size > 0 && ! seginfo->bss)
     flags |= SEC_HAS_CONTENTS;
 
@@ -638,11 +691,11 @@ relax_and_size_seg (abfd, sec, xxx)
   else
     flags &= ~SEC_RELOC;
   x = bfd_set_section_flags (abfd, sec, flags);
-  assert (x == true);
+  assert (x);
 
   newsize = md_section_align (sec, size);
   x = bfd_set_section_size (abfd, sec, newsize);
-  assert (x == true);
+  assert (x);
 
   /* If the size had to be rounded up, add some padding in the last
      non-empty frag.  */
@@ -654,7 +707,14 @@ relax_and_size_seg (abfd, sec, xxx)
       while (fragp->fr_next != last)
        fragp = fragp->fr_next;
       last->fr_address = size;
-      fragp->fr_offset += newsize - size;
+      if ((newsize - size) % fragp->fr_var == 0)
+       fragp->fr_offset += (newsize - size) / fragp->fr_var;
+      else
+       /* If we hit this abort, it's likely due to subsegs_finish not
+          providing sufficient alignment on the last frag, and the
+          machine dependent code using alignment frags with fr_var
+          greater than 1.  */
+       abort ();
     }
 
 #ifdef tc_frob_section
@@ -704,6 +764,9 @@ dump_section_relocs (abfd, sec, stream_)
 #define EMIT_SECTION_SYMBOLS 1
 #endif
 
+/* This pass over fixups decides whether symbols can be replaced with
+   section symbols.  */
+
 static void
 adjust_reloc_syms (abfd, sec, xxx)
      bfd *abfd ATTRIBUTE_UNUSED;
@@ -738,65 +801,53 @@ adjust_reloc_syms (abfd, sec, xxx)
           point.  It is possible to see unresolved expression
           symbols, though, since they are not in the regular symbol
           table.  */
-       if (sym != NULL)
-         resolve_symbol_value (sym, 1);
+       resolve_symbol_value (sym);
 
        if (fixp->fx_subsy != NULL)
-         resolve_symbol_value (fixp->fx_subsy, 1);
+         resolve_symbol_value (fixp->fx_subsy);
 
        /* If this symbol is equated to an undefined symbol, convert
            the fixup to being against that symbol.  */
-       if (sym != NULL && symbol_equated_p (sym)
-           && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+       if (symbol_equated_reloc_p (sym))
          {
            fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number;
            sym = symbol_get_value_expression (sym)->X_add_symbol;
            fixp->fx_addsy = sym;
          }
 
-       if (sym != NULL && symbol_mri_common_p (sym))
+       if (symbol_mri_common_p (sym))
          {
            /* These symbols are handled specially in fixup_segment.  */
-           goto done;
+           continue;
          }
 
-       symsec = S_GET_SEGMENT (sym);
+       /* If the symbol is undefined, common, weak, or global (ELF
+          shared libs), we can't replace it with the section symbol.  */
+       if (S_FORCE_RELOC (fixp->fx_addsy))
+         continue;
+
+       /* Is there some other (target cpu dependent) reason we can't adjust
+          this one?  (E.g. relocations involving function addresses on
+          the PA.  */
+#ifdef tc_fix_adjustable
+       if (! tc_fix_adjustable (fixp))
+         continue;
+#endif
 
+       /* Since we're reducing to section symbols, don't attempt to reduce
+          anything that's already using one.  */
+       if (symbol_section_p (sym))
+         continue;
+
+       symsec = S_GET_SEGMENT (sym);
        if (symsec == NULL)
          abort ();
 
        if (bfd_is_abs_section (symsec))
          {
-           /* The fixup_segment routine will not use this symbol in a
-               relocation unless TC_FORCE_RELOCATION returns 1.  */
-           if (TC_FORCE_RELOCATION (fixp))
-             {
-               symbol_mark_used_in_reloc (fixp->fx_addsy);
-#ifdef UNDEFINED_DIFFERENCE_OK
-               if (fixp->fx_subsy != NULL)
-                 symbol_mark_used_in_reloc (fixp->fx_subsy);
-#endif
-             }
-           goto done;
-         }
-
-       /* 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 (bfd_is_und_section (symsec)
-           || bfd_is_com_section (symsec))
-         {
-           symbol_mark_used_in_reloc (fixp->fx_addsy);
-#ifdef UNDEFINED_DIFFERENCE_OK
-           /* We have the difference of an undefined symbol and some
-              other symbol.  Make sure to mark the other symbol as used
-              in a relocation so that it will always be output.  */
-           if (fixp->fx_subsy)
-             symbol_mark_used_in_reloc (fixp->fx_subsy);
-#endif
-           goto done;
+           /* The fixup_segment routine normally will not use this
+               symbol in a relocation.  */
+           continue;
          }
 
        /* Don't try to reduce relocs which refer to non-local symbols
@@ -805,111 +856,51 @@ adjust_reloc_syms (abfd, sec, xxx)
            this will always be correct.  */
        if (symsec != sec && ! S_IS_LOCAL (sym))
          {
-           boolean linkonce;
-
-           linkonce = false;
-#ifdef BFD_ASSEMBLER
-           if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
-               != 0)
-             linkonce = true;
-#endif
-#ifdef OBJ_ELF
-           /* The GNU toolchain uses an extension for ELF: a section
-               beginning with the magic string .gnu.linkonce is a
-               linkonce section.  */
-           if (strncmp (segment_name (symsec), ".gnu.linkonce",
-                        sizeof ".gnu.linkonce" - 1) == 0)
-             linkonce = true;
-#endif
-
-           if (linkonce)
-             {
-               symbol_mark_used_in_reloc (fixp->fx_addsy);
-#ifdef UNDEFINED_DIFFERENCE_OK
-               if (fixp->fx_subsy != NULL)
-                 symbol_mark_used_in_reloc (fixp->fx_subsy);
-#endif
-               goto done;
-             }
-         }
-
-       /* Since we're reducing to section symbols, don't attempt to reduce
-          anything that's already using one.  */
-       if (symbol_section_p (sym))
-         {
-           symbol_mark_used_in_reloc (fixp->fx_addsy);
-           goto done;
-         }
-
-#ifdef BFD_ASSEMBLER
-       /* We can never adjust a reloc against a weak symbol.  If we
-           did, and the weak symbol was overridden by a real symbol
-           somewhere else, then our relocation would be pointing at
-           the wrong area of memory.  */
-       if (S_IS_WEAK (sym))
-         {
-           symbol_mark_used_in_reloc (fixp->fx_addsy);
-           goto done;
+           if ((symsec->flags & SEC_LINK_ONCE) != 0
+               || (IS_ELF
+                   /* The GNU toolchain uses an extension for ELF: a
+                      section beginning with the magic string
+                      .gnu.linkonce is a linkonce section.  */
+                   && strncmp (segment_name (symsec), ".gnu.linkonce",
+                               sizeof ".gnu.linkonce" - 1) == 0))
+             continue;
          }
-#endif
 
-       /* Is there some other reason we can't adjust this one?  (E.g.,
-          call/bal links in i960-bout symbols.)  */
-#ifdef obj_fix_adjustable
-       if (! obj_fix_adjustable (fixp))
-         {
-           symbol_mark_used_in_reloc (fixp->fx_addsy);
-           goto done;
-         }
-#endif
-
-       /* Is there some other (target cpu dependent) reason we can't adjust
-          this one?  (E.g. relocations involving function addresses on
-          the PA.  */
-#ifdef tc_fix_adjustable
-       if (! tc_fix_adjustable (fixp))
-         {
-           symbol_mark_used_in_reloc (fixp->fx_addsy);
-           goto done;
-         }
-#endif
+       /* Never adjust a reloc against local symbol in a merge section
+          with non-zero addend.  */
+       if ((symsec->flags & SEC_MERGE) != 0
+           && (fixp->fx_offset != 0 || fixp->fx_subsy != NULL))
+         continue;
 
-       /* 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.
+       /* Never adjust a reloc against TLS local symbol.  */
+       if ((symsec->flags & SEC_THREAD_LOCAL) != 0)
+         continue;
 
-          We refetch the segment when calling section_symbol, rather
+       /* We refetch the segment when calling section_symbol, rather
           than using symsec, because S_GET_VALUE may wind up changing
           the section when it calls resolve_symbol_value.  */
        fixp->fx_offset += S_GET_VALUE (sym);
        fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym));
-       symbol_mark_used_in_reloc (fixp->fx_addsy);
 #ifdef DEBUG5
        fprintf (stderr, "\nadjusted fixup:\n");
        print_fixup (fixp);
 #endif
-
-      done:
-       ;
       }
-#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);
-#if 0
-       fixp->fx_addsy->sy_used_in_reloc = 1;
-#endif
-      }
-#endif
 
   dump_section_relocs (abfd, sec, stderr);
 }
 
+static void
+fix_segment (abfd, sec, xxx)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     PTR xxx ATTRIBUTE_UNUSED;
+{
+  segment_info_type *seginfo = seg_info (sec);
+
+  fixup_segment (seginfo->fix_root, sec);
+}
+
 static void
 write_relocs (abfd, sec, xxx)
      bfd *abfd;
@@ -928,8 +919,6 @@ write_relocs (abfd, sec, xxx)
   if (seginfo == NULL)
     return;
 
-  fixup_segment (seginfo->fix_root, sec);
-
   n = 0;
   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
     n++;
@@ -953,11 +942,10 @@ write_relocs (abfd, sec, xxx)
        }
 
       /* If this is an undefined symbol which was equated to another
-         symbol, then use generate the reloc against the latter symbol
+         symbol, then generate the reloc against the latter symbol
          rather than the former.  */
       sym = fixp->fx_addsy;
-      while (symbol_equated_p (sym)
-            && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+      while (symbol_equated_reloc_p (sym))
        {
          symbolS *n;
 
@@ -994,10 +982,12 @@ write_relocs (abfd, sec, xxx)
        case bfd_reloc_ok:
          break;
        case bfd_reloc_overflow:
-         as_bad_where (fixp->fx_file, fixp->fx_line, _("relocation overflow"));
+         as_bad_where (fixp->fx_file, fixp->fx_line,
+                       _("relocation overflow"));
          break;
        case bfd_reloc_outofrange:
-         as_bad_where (fixp->fx_file, fixp->fx_line, _("relocation out of range"));
+         as_bad_where (fixp->fx_file, fixp->fx_line,
+                       _("relocation out of range"));
          break;
        default:
          as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
@@ -1029,9 +1019,18 @@ write_relocs (abfd, sec, xxx)
          symbol, then generate the reloc against the latter symbol
          rather than the former.  */
       sym = fixp->fx_addsy;
-      while (symbol_equated_p (sym)
-            && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
-       sym = symbol_get_value_expression (sym)->X_add_symbol;
+      while (symbol_equated_reloc_p (sym))
+       {
+         symbolS *n;
+
+         /* We must avoid looping, as that can occur with a badly
+            written program.  */
+         n = symbol_get_value_expression (sym)->X_add_symbol;
+         if (n == sym)
+           break;
+         fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number;
+         sym = n;
+       }
       fixp->fx_addsy = sym;
 
       reloc = tc_gen_reloc (sec, fixp);
@@ -1060,9 +1059,13 @@ write_relocs (abfd, sec, xxx)
              as_bad_where (fixp->fx_file, fixp->fx_line,
                            _("relocation overflow"));
              break;
+           case bfd_reloc_outofrange:
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           _("relocation out of range"));
+             break;
            default:
-             as_fatal (_("%s:%u: bad return from bfd_install_relocation"),
-                       fixp->fx_file, fixp->fx_line);
+             as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
+                       fixp->fx_file, fixp->fx_line, s);
            }
        }
     }
@@ -1145,7 +1148,7 @@ write_contents (abfd, sec, xxx)
          x = bfd_set_section_contents (stdoutput, sec,
                                        f->fr_literal, (file_ptr) offset,
                                        (bfd_size_type) f->fr_fix);
-         if (x == false)
+         if (!x)
            {
              bfd_perror (stdoutput->filename);
              as_perror (_("FATAL: Can't write %s"), stdoutput->filename);
@@ -1169,7 +1172,7 @@ write_contents (abfd, sec, xxx)
                                                fill_literal,
                                                (file_ptr) offset,
                                                (bfd_size_type) fill_size);
-                 if (x == false)
+                 if (!x)
                    {
                      bfd_perror (stdoutput->filename);
                      as_perror (_("FATAL: Can't write %s"),
@@ -1203,8 +1206,8 @@ write_contents (abfd, sec, xxx)
                  x = bfd_set_section_contents
                    (stdoutput, sec, buf, (file_ptr) offset,
                     (bfd_size_type) n_per_buf * fill_size);
-                 if (x != true)
-                   as_fatal (_("Cannot write to output file."));
+                 if (!x)
+                   as_fatal (_("cannot write to output file"));
                  offset += n_per_buf * fill_size;
                }
            }
@@ -1337,8 +1340,8 @@ set_symtab ()
   int nsyms;
   asymbol **asympp;
   symbolS *symp;
-  boolean result;
-  extern PTR bfd_alloc PARAMS ((bfd *, size_t));
+  bfd_boolean result;
+  extern PTR bfd_alloc PARAMS ((bfd *, bfd_size_type));
 
   /* 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
@@ -1350,9 +1353,9 @@ set_symtab ()
   if (nsyms)
     {
       int i;
+      bfd_size_type amt = (bfd_size_type) nsyms * sizeof (asymbol *);
 
-      asympp = (asymbol **) bfd_alloc (stdoutput,
-                                      nsyms * sizeof (asymbol *));
+      asympp = (asymbol **) bfd_alloc (stdoutput, amt);
       symp = symbol_rootP;
       for (i = 0; i < nsyms; i++, symp = symbol_next (symp))
        {
@@ -1363,25 +1366,11 @@ set_symtab ()
   else
     asympp = 0;
   result = bfd_set_symtab (stdoutput, asympp, nsyms);
-  assert (result == true);
+  assert (result);
   symbol_table_frozen = 1;
 }
 #endif
 
-#if defined (BFD_ASSEMBLER) && defined (OBJ_COFF) && defined (TE_GO32)
-static void
-set_segment_vma (abfd, sec, xxx)
-     bfd *abfd;
-     asection *sec;
-     PTR xxx ATTRIBUTE_UNUSED;
-{
-  static bfd_vma addr = 0;
-
-  bfd_set_section_vma (abfd, sec, addr);
-  addr += bfd_section_size (abfd, sec);
-}
-#endif /* BFD_ASSEMBLER && OBJ_COFF && !TE_PE  */
-
 /* Finish the subsegments.  After every sub-segment, we fake an
    ".align ...".  This conforms to BSD4.2 brane-damage.  We then fake
    ".fill 0" because that is the kind of frag that requires least
@@ -1389,10 +1378,19 @@ set_segment_vma (abfd, sec, xxx)
    makes calculating their intended length trivial.  */
 
 #ifndef SUB_SEGMENT_ALIGN
+#ifdef HANDLE_ALIGN
+/* 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.  */
+#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN)                                        \
+  (!(FRCHAIN)->frch_next || (FRCHAIN)->frch_next->frch_seg != (SEG)    \
+   ? get_recorded_alignment (SEG) : 0)
+#else
 #ifdef BFD_ASSEMBLER
-#define SUB_SEGMENT_ALIGN(SEG) (0)
+#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0
 #else
-#define SUB_SEGMENT_ALIGN(SEG) (2)
+#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 2
+#endif
 #endif
 #endif
 
@@ -1403,20 +1401,33 @@ subsegs_finish ()
 
   for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next)
     {
-      int alignment;
+      int alignment = 0;
 
       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.  */
-      alignment = had_errors () ? 0 : SUB_SEGMENT_ALIGN (now_seg);
+      if (!had_errors ())
+       {
+         alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
+#ifdef BFD_ASSEMBLER
+         if ((bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE)
+             && now_seg->entsize)
+           {
+             unsigned int entsize = now_seg->entsize;
+             int entalign = 0;
 
-      /* 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);
+             while ((entsize & 1) == 0)
+               {
+                 ++entalign;
+                 entsize >>= 1;
+               }
+             if (entalign > alignment)
+               alignment = entalign;
+           }
+#endif
+       }
 
       if (subseg_text_p (now_seg))
        frag_align_code (alignment, 0);
@@ -1453,14 +1464,14 @@ write_object_file ()
     if (flag_always_generate_output)
       {
        if (n_warns || n_errs)
-         as_warn (_("%d error%s, %d warning%s, generating bad object file.\n"),
+         as_warn (_("%d error%s, %d warning%s, generating bad object file"),
                   n_errs, n_errs == 1 ? "" : "s",
                   n_warns, n_warns == 1 ? "" : "s");
       }
     else
       {
        if (n_errs)
-         as_fatal (_("%d error%s, %d warning%s, no object file generated.\n"),
+         as_fatal (_("%d error%s, %d warning%s, no object file generated"),
                    n_errs, n_errs == 1 ? "" : "s",
                    n_warns, n_warns == 1 ? "" : "s");
       }
@@ -1479,22 +1490,18 @@ write_object_file ()
 #ifdef BFD_ASSEMBLER
   /* Remove the sections created by gas for its own purposes.  */
   {
-    asection **seclist, *sec;
+    asection **seclist;
     int i;
 
     seclist = &stdoutput->sections;
-    while (seclist && *seclist)
+    while (*seclist)
       {
-       sec = *seclist;
-       while (sec == reg_section || sec == expr_section)
+       if (*seclist == reg_section || *seclist == expr_section)
          {
-           sec = sec->next;
-           *seclist = sec;
+           bfd_section_list_remove (stdoutput, seclist);
            stdoutput->section_count--;
-           if (!sec)
-             break;
          }
-       if (*seclist)
+       else
          seclist = &(*seclist)->next;
       }
     i = 0;
@@ -1519,18 +1526,52 @@ write_object_file ()
 #endif
 
 #ifdef BFD_ASSEMBLER
-  bfd_map_over_sections (stdoutput, relax_and_size_seg, (char *) 0);
+  while (1)
+    {
+      int changed;
+
+#ifndef WORKING_DOT_WORD
+      /* We need to reset the markers in the broken word list and
+        associated frags between calls to relax_segment (via
+        relax_seg).  Since the broken word list is global, we do it
+        once per round, rather than locally in relax_segment for each
+        segment.  */
+      struct broken_word *brokp;
+
+      for (brokp = broken_words;
+          brokp != (struct broken_word *) NULL;
+          brokp = brokp->next_broken_word)
+       {
+         brokp->added = 0;
+
+         if (brokp->dispfrag != (fragS *) NULL
+             && brokp->dispfrag->fr_type == rs_broken_word)
+           brokp->dispfrag->fr_subtype = 0;
+       }
+#endif
+
+      changed = 0;
+      bfd_map_over_sections (stdoutput, relax_seg, &changed);
+      if (!changed)
+       break;
+    }
+
+  /* Note - Most ports will use the default value of
+     TC_FINALIZE_SYMS_BEFORE_SIZE_SEG, which 1.  This will force
+     local symbols to be resolved, removing their frag information.
+     Some ports however, will not have finished relaxing all of
+     their frags and will still need the local symbol frag
+     information.  These ports can set
+     TC_FINALIZE_SYMS_BEFORE_SIZE_SEG to 0.  */
+  finalize_syms = TC_FINALIZE_SYMS_BEFORE_SIZE_SEG;
+
+  bfd_map_over_sections (stdoutput, size_seg, (char *) 0);
 #else
   relax_and_size_all_segments ();
 #endif /* BFD_ASSEMBLER  */
 
-#if defined (BFD_ASSEMBLER) && defined (OBJ_COFF) && defined (TE_GO32)
-  /* Now that the segments have their final sizes, run through the
-     sections and set their vma and lma. !BFD gas sets them, and BFD gas
-     should too. Currently, only DJGPP uses this code, but other
-     COFF targets may need to execute this too.  */
-  bfd_map_over_sections (stdoutput, set_segment_vma, (char *) 0);
-#endif
+  /* Relaxation has completed.  Freeze all syms.  */
+  finalize_syms = 1;
 
 #ifndef BFD_ASSEMBLER
   /* Crawl the symbol chain.
@@ -1678,9 +1719,6 @@ 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 -= symbol_get_frag (lie->sub)->fr_address;
-#endif
 #ifdef TC_CHECK_ADJUSTED_BROKEN_DOT_WORD
            TC_CHECK_ADJUSTED_BROKEN_DOT_WORD (to_addr, lie);
 #endif
@@ -1697,9 +1735,6 @@ 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 += symbol_get_frag (lie->add)->fr_address;
-#endif
            md_create_long_jump (table_ptr, from_addr, to_addr, lie->dispfrag,
                                 lie->add);
            table_ptr += md_long_jump_size;
@@ -1817,8 +1852,8 @@ write_object_file ()
       obj_emit_strings (&next_object_file_charP);
 
 #ifdef BFD_HEADERS
-    bfd_seek (stdoutput, 0, 0);
-    bfd_write (the_object_file, 1, object_file_size, stdoutput);
+    bfd_seek (stdoutput, (file_ptr) 0, 0);
+    bfd_bwrite (the_object_file, (bfd_size_type) object_file_size, stdoutput);
 #else
 
     /* Write the data to the file.  */
@@ -1842,7 +1877,7 @@ write_object_file ()
       symbolS *symp;
 
       for (symp = symbol_rootP; symp; symp = symbol_next (symp))
-       resolve_symbol_value (symp, 1);
+       resolve_symbol_value (symp);
     }
   resolve_local_symbol_values ();
 
@@ -1857,6 +1892,15 @@ write_object_file ()
 
   bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *) 0);
 
+#ifdef tc_frob_file_before_fix
+  tc_frob_file_before_fix ();
+#endif
+#ifdef obj_frob_file_before_fix
+  obj_frob_file_before_fix ();
+#endif
+
+  bfd_map_over_sections (stdoutput, fix_segment, (char *) 0);
+
   /* Set up symbol table, and write it out.  */
   if (symbol_rootP)
     {
@@ -1884,18 +1928,17 @@ write_object_file ()
              /* They only differ if `name' is a fb or dollar local
                 label name.  */
              if (name2 != name && ! S_IS_DEFINED (symp))
-               as_bad (_("local label %s is not defined"), name2);
+               as_bad (_("local label `%s' is not defined"), name2);
            }
 
          /* 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.  */
-         resolve_symbol_value (symp, 1);
+         resolve_symbol_value (symp);
 
          /* Skip symbols which were equated to undefined or common
              symbols.  */
-         if (symbol_equated_p (symp)
-             && (! S_IS_DEFINED (symp) || S_IS_COMMON (symp)))
+         if (symbol_equated_reloc_p (symp))
            {
              symbol_remove (symp, &symbol_rootP, &symbol_lastP);
              continue;
@@ -1927,13 +1970,14 @@ write_object_file ()
             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
-              && symbol_section_p (symp))
+         if (symp == abs_section_sym
+             || (! EMIT_SECTION_SYMBOLS
+                 && symbol_section_p (symp))
              /* 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)
+                 && (punt || S_IS_LOCAL (symp))
                  && ! symbol_used_in_reloc_p (symp)))
            {
              symbol_remove (symp, &symbol_rootP, &symbol_lastP);
@@ -1947,7 +1991,7 @@ write_object_file ()
          /* Make sure we really got a value for the symbol.  */
          if (! symbol_resolved_p (symp))
            {
-             as_bad (_("can't resolve value for symbol \"%s\""),
+             as_bad (_("can't resolve value for symbol `%s'"),
                      S_GET_NAME (symp));
              symbol_mark_resolved (symp);
            }
@@ -2041,9 +2085,9 @@ relax_frag (segment, fragP, stretch)
 #endif
       know (sym_frag != NULL);
 #endif
-      know (!(S_GET_SEGMENT (symbolP) == absolute_section)
+      know (S_GET_SEGMENT (symbolP) != absolute_section
            || sym_frag == &zero_address_frag);
-      target += S_GET_VALUE (symbolP) + sym_frag->fr_address;
+      target += S_GET_VALUE (symbolP);
 
       /* If frag has yet to be reached on this pass,
         assume it will move by STRETCH just as we did.
@@ -2141,13 +2185,15 @@ relax_align (address, alignment)
    these frag addresses may not be the same as final object-file
    addresses.  */
 
-void
+int
 relax_segment (segment_frag_root, segment)
      struct frag *segment_frag_root;
      segT segment;
 {
   register struct frag *fragP;
   register relax_addressT address;
+  int ret;
+
 #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
   know (segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS);
 #endif
@@ -2180,8 +2226,9 @@ relax_segment (segment_frag_root, segment)
 
            if (offset % fragP->fr_var != 0)
              {
-               as_bad (_("alignment padding (%lu bytes) not a multiple of %ld"),
-                       (unsigned long) offset, (long) fragP->fr_var);
+               as_bad_where (fragP->fr_file, fragP->fr_line,
+                             _("alignment padding (%lu bytes) not a multiple of %ld"),
+                             (unsigned long) offset, (long) fragP->fr_var);
                offset -= (offset % fragP->fr_var);
              }
 
@@ -2195,6 +2242,12 @@ relax_segment (segment_frag_root, segment)
          break;
 
        case rs_machine_dependent:
+         /* If fr_symbol is an expression, this call to
+            resolve_symbol_value sets up the correct segment, which will
+            likely be needed in md_estimate_size_before_relax.  */
+         if (fragP->fr_symbol)
+           resolve_symbol_value (fragP->fr_symbol);
+
          address += md_estimate_size_before_relax (fragP, segment);
          break;
 
@@ -2229,14 +2282,15 @@ relax_segment (segment_frag_root, segment)
     long stretch;      /* May be any size, 0 or negative.  */
     /* Cumulative number of addresses we have relaxed this pass.
        We may have relaxed more than one address.  */
-    long stretched;    /* Have we stretched on this pass?  */
+    int stretched;     /* Have we stretched on this pass?  */
     /* This is 'cuz stretch may be zero, when, in fact some piece of code
        grew, and another shrank.  If a branch instruction doesn't fit anymore,
        we could be scrod.  */
 
     do
       {
-       stretch = stretched = 0;
+       stretch = 0;
+       stretched = 0;
 
        for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
          {
@@ -2280,21 +2334,20 @@ relax_segment (segment_frag_root, segment)
                      if (lie->added)
                        continue;
 
-                     offset = (symbol_get_frag (lie->add)->fr_address
-                               + S_GET_VALUE (lie->add)
+                     offset = (S_GET_VALUE (lie->add)
                                + lie->addnum
-                               - (symbol_get_frag (lie->sub)->fr_address
-                                  + S_GET_VALUE (lie->sub)));
+                               - S_GET_VALUE (lie->sub));
                      if (offset <= -32768 || offset >= 32767)
                        {
                          if (flag_warn_displacement)
                            {
                              char buf[50];
                              sprint_value (buf, (addressT) lie->addnum);
-                             as_warn (_(".word %s-%s+%s didn't fit"),
-                                      S_GET_NAME (lie->add),
-                                      S_GET_NAME (lie->sub),
-                                      buf);
+                             as_warn_where (fragP->fr_file, fragP->fr_line,
+                                            _(".word %s-%s+%s didn't fit"),
+                                            S_GET_NAME (lie->add),
+                                            S_GET_NAME (lie->sub),
+                                            buf);
                            }
                          lie->added = 1;
                          if (fragP->fr_subtype == 0)
@@ -2345,8 +2398,8 @@ relax_segment (segment_frag_root, segment)
 
              case rs_org:
                {
-                 long target = offset;
-                 long after;
+                 addressT target = offset;
+                 addressT after;
 
                  if (symbolP)
                    {
@@ -2359,9 +2412,13 @@ relax_segment (segment_frag_root, segment)
                      know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE)
                            || (symbolP->sy_frag == &zero_address_frag));
 #endif
-                     target += (S_GET_VALUE (symbolP)
-                                + symbol_get_frag (symbolP)->fr_address);
-                   }           /* if we have a symbol  */
+                      /* Convert from an actual address to an octet offset
+                         into the section.  Here it is assumed that the
+                         section's VMA is zero, and can omit subtracting it
+                         from the symbol's value to get the address offset.  */
+                      know (S_GET_SECTION (symbolP)->vma == 0);
+                     target += S_GET_VALUE (symbolP) * OCTETS_PER_BYTE;
+                   }
 
                  know (fragP->fr_next);
                  after = fragP->fr_next->fr_address;
@@ -2372,7 +2429,7 @@ relax_segment (segment_frag_root, segment)
                         cannot have fewer than 0 chars.  That is, we can't
                         .org backwards.  */
                      as_bad_where (fragP->fr_file, fragP->fr_line,
-                                   _("attempt to .org backwards ignored"));
+                                   _("attempt to .org backwards"));
 
                      /* We've issued an error message.  Change the
                          frag to avoid cascading errors.  */
@@ -2389,23 +2446,31 @@ relax_segment (segment_frag_root, segment)
                }
 
              case rs_space:
+               growth = 0;
                if (symbolP)
                  {
-                   growth = S_GET_VALUE (symbolP);
-                   if (symbol_get_frag (symbolP) != &zero_address_frag
+                   offsetT amount;
+
+                   amount = S_GET_VALUE (symbolP);
+                   if (S_GET_SEGMENT (symbolP) != absolute_section
                        || S_IS_COMMON (symbolP)
                        || ! S_IS_DEFINED (symbolP))
-                     as_bad_where (fragP->fr_file, fragP->fr_line,
-                                   _(".space specifies non-absolute value"));
-                   fragP->fr_symbol = 0;
-                   if (growth < 0)
                      {
-                       as_warn (_(".space or .fill with negative value, ignored"));
-                       growth = 0;
+                       as_bad_where (fragP->fr_file, fragP->fr_line,
+                                     _(".space specifies non-absolute value"));
+                       /* Prevent repeat of this error message.  */
+                       fragP->fr_symbol = 0;
+                     }
+                   else if (amount < 0)
+                     {
+                       as_warn_where (fragP->fr_file, fragP->fr_line,
+                                      _(".space or .fill with negative value, ignored"));
+                       fragP->fr_symbol = 0;
                      }
+                   else
+                     growth = (was_address + fragP->fr_fix + amount
+                               - fragP->fr_next->fr_address);
                  }
-               else
-                 growth = 0;
                break;
 
              case rs_machine_dependent:
@@ -2425,7 +2490,7 @@ relax_segment (segment_frag_root, segment)
                  valueT value;
                  int size;
 
-                 value = resolve_symbol_value (fragP->fr_symbol, 0);
+                 value = resolve_symbol_value (fragP->fr_symbol);
                  size = sizeof_leb128 (value, fragP->fr_subtype);
                  growth = size - fragP->fr_offset;
                  fragP->fr_offset = size;
@@ -2447,63 +2512,79 @@ relax_segment (segment_frag_root, segment)
            if (growth)
              {
                stretch += growth;
-               stretched++;
+               stretched = 1;
              }
          }                     /* For each frag in the segment.  */
       }
     while (stretched);         /* Until nothing further to relax.  */
   }                            /* do_relax  */
 
-  /* We now have valid fr_address'es for each frag.  */
-
-  /* All fr_address's are correct, relative to their own segment.
-     We have made all the fixS we will ever make.  */
+  ret = 0;
+  for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
+    if (fragP->last_fr_address != fragP->fr_address)
+      {
+       fragP->last_fr_address = fragP->fr_address;
+       ret = 1;
+      }
+  return ret;
 }
 
 #if defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS))
 
-#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
    handled now.  (These consist of fixS where we have since discovered
    the value of a symbol, or the address of the frag involved.)
-   For each one, call md_apply_fix to put the fix into the frag data.
+   For each one, call md_apply_fix3 to put the fix into the frag data.
 
    Result is a count of how many relocation structs will be needed to
    handle the remaining fixS's that we couldn't completely handle here.
    These will be output later by emit_relocations().  */
 
 static long
-fixup_segment (fixP, this_segment_type)
-     register fixS *fixP;
-     segT this_segment_type;   /* N_TYPE bits for segment.  */
+fixup_segment (fixP, this_segment)
+     fixS *fixP;
+     segT this_segment;
 {
   long seg_reloc_count = 0;
-  symbolS *add_symbolP;
-  symbolS *sub_symbolP;
   valueT add_number;
-  int size;
-  char *place;
-  long where;
-  int pcrel, plt;
   fragS *fragP;
   segT add_symbol_segment = absolute_section;
 
+  if (fixP != NULL && abs_section_sym == NULL)
+    {
+#ifndef BFD_ASSEMBLER
+      abs_section_sym = &abs_symbol;
+#else
+      abs_section_sym = section_symbol (absolute_section);
+#endif
+    }
+
   /* 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 anyways in cases where we
-     know the maximum displacement.  */
-  if (linkrelax && TC_LINKRELAX_FIXUP (this_segment_type))
+     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 we might be able to turn callx/callj into bal
+     anyways in cases where we know the maximum displacement.  */
+  if (linkrelax && TC_LINKRELAX_FIXUP (this_segment))
     {
       for (; fixP; fixP = fixP->fx_next)
-       seg_reloc_count++;
+       if (!fixP->fx_done)
+         {
+           if (fixP->fx_addsy == NULL)
+             {
+               /* There was no symbol required by this relocation.
+                  However, BFD doesn't really handle relocations
+                  without symbols well. So fake up a local symbol in
+                  the absolute section.  */
+               fixP->fx_addsy = abs_section_sym;
+             }
+           symbol_mark_used_in_reloc (fixP->fx_addsy);
+           if (fixP->fx_subsy != NULL)
+             symbol_mark_used_in_reloc (fixP->fx_subsy);
+           seg_reloc_count++;
+         }
       TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count);
       return seg_reloc_count;
     }
@@ -2517,296 +2598,166 @@ fixup_segment (fixP, this_segment_type)
 
       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);
+      TC_VALIDATE_FIX (fixP, this_segment, skip);
 #endif
-      sub_symbolP = fixP->fx_subsy;
       add_number = fixP->fx_offset;
-      pcrel = fixP->fx_pcrel;
-      plt = fixP->fx_plt;
 
-      if (add_symbolP != NULL
-         && symbol_mri_common_p (add_symbolP))
+      if (fixP->fx_addsy != NULL
+         && symbol_mri_common_p (fixP->fx_addsy))
        {
-         know (add_symbolP->sy_value.X_op == O_symbol);
-         add_number += S_GET_VALUE (add_symbolP);
+         know (fixP->fx_addsy->sy_value.X_op == O_symbol);
+         add_number += S_GET_VALUE (fixP->fx_addsy);
          fixP->fx_offset = add_number;
-         add_symbolP = fixP->fx_addsy =
-           symbol_get_value_expression (add_symbolP)->X_add_symbol;
+         fixP->fx_addsy
+           = symbol_get_value_expression (fixP->fx_addsy)->X_add_symbol;
        }
 
-      if (add_symbolP)
-       add_symbol_segment = S_GET_SEGMENT (add_symbolP);
+      if (fixP->fx_addsy != NULL)
+       add_symbol_segment = S_GET_SEGMENT (fixP->fx_addsy);
 
-      if (sub_symbolP)
+      if (fixP->fx_subsy != NULL)
        {
-         resolve_symbol_value (sub_symbolP, 1);
-         if (add_symbolP == NULL || add_symbol_segment == absolute_section)
+         segT sub_symbol_segment;
+         resolve_symbol_value (fixP->fx_subsy);
+         sub_symbol_segment = S_GET_SEGMENT (fixP->fx_subsy);
+         if (fixP->fx_addsy != NULL
+             && sub_symbol_segment == add_symbol_segment
+             && !TC_FORCE_RELOCATION_SUB_SAME (fixP, add_symbol_segment))
            {
-             if (add_symbolP != NULL)
-               {
-                 add_number += S_GET_VALUE (add_symbolP);
-                 add_symbolP = NULL;
-                 fixP->fx_addsy = NULL;
-               }
-
-             /* It's just -sym.  */
-             if (S_GET_SEGMENT (sub_symbolP) == absolute_section)
-               {
-                 add_number -= S_GET_VALUE (sub_symbolP);
-                 fixP->fx_subsy = NULL;
-               }
-             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));
+             add_number += S_GET_VALUE (fixP->fx_addsy);
+             add_number -= S_GET_VALUE (fixP->fx_subsy);
+             fixP->fx_offset = add_number;
+             /* If the back-end code has selected a pc-relative
+                reloc, adjust the value to be pc-relative.  */
+             if (1
+#ifdef TC_M68K
+                 /* See the comment below about 68k weirdness.  */
+                 && 0
+#endif
+                 && fixP->fx_pcrel)
+               add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment); 
+             fixP->fx_addsy = NULL;
+             fixP->fx_subsy = NULL;
+             fixP->fx_pcrel = 0;
            }
-         else if (S_GET_SEGMENT (sub_symbolP) == add_symbol_segment
-                  && SEG_NORMAL (add_symbol_segment))
+         else if (sub_symbol_segment == absolute_section
+                  && !TC_FORCE_RELOCATION_SUB_ABS (fixP))
            {
-             /* 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_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_symbolP = NULL;
-             pcrel = 0;        /* No 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_SECTION (fixP, this_segment_type))
-               {
-                 fixP->fx_pcrel = 0;
-                 fixP->fx_addsy = NULL;
-                 fixP->fx_subsy = NULL;
-               }
+             add_number -= S_GET_VALUE (fixP->fx_subsy);
+             fixP->fx_offset = add_number;
+             fixP->fx_subsy = NULL;
            }
-         else
+         else if (sub_symbol_segment == this_segment
+                  && !TC_FORCE_RELOCATION_SUB_LOCAL (fixP))
            {
-             /* 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);
-
-#ifdef DIFF_EXPR_OK
-             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_SECTION (fixP, this_segment_type)
-                                - S_GET_VALUE (sub_symbolP));
-                 pcrel = 1;
-                 fixP->fx_pcrel = 1;
-                 sub_symbolP = 0;
-                 fixP->fx_subsy = 0;
-               }
-#endif
-#ifdef UNDEFINED_DIFFERENCE_OK
-             /* The PA needs this for PIC code generation.  We basically
-                don't want to do anything if we have the difference of two
-                symbols at this point.  */
-             else if (1)
-               {
-                 /* Leave it alone.  */
-               }
-#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,
-                               _("Subtraction of two symbols in different sections \"%s\" {%s section} - \"%s\" {%s section} at file address %s."),
-                               S_GET_NAME (add_symbolP),
-                               segment_name (S_GET_SEGMENT (add_symbolP)),
-                               S_GET_NAME (sub_symbolP),
-                               segment_name (S_GET_SEGMENT (sub_symbolP)),
-                               buf);
-               }
+             add_number -= S_GET_VALUE (fixP->fx_subsy);
+             fixP->fx_offset = (add_number + fixP->fx_dot_value
+                                + fixP->fx_frag->fr_address);
+
+             /* Make it pc-relative.  If the back-end code has not
+                selected a pc-relative reloc, cancel the adjustment
+                we do later on all pc-relative relocs.  */
+             if (0
+#ifdef TC_M68K
+                 /* Do this for m68k even if it's already described
+                    as pc-relative.  On the m68k, an operand of
+                    "pc@(foo-.-2)" should address "foo" in a
+                    pc-relative mode.  */
+                 || 1
+#endif
+                 || !fixP->fx_pcrel)
+               add_number += MD_PCREL_FROM_SECTION (fixP, this_segment);
+             fixP->fx_subsy = NULL;
+             fixP->fx_pcrel = 1;
+           }
+         else if (!TC_VALIDATE_FIX_SUB (fixP))
+           {
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                           _("can't resolve `%s' {%s section} - `%s' {%s section}"),
+                           fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0",
+                           segment_name (add_symbol_segment),
+                           S_GET_NAME (fixP->fx_subsy),
+                           segment_name (sub_symbol_segment));
            }
        }
 
-      if (add_symbolP)
+      if (fixP->fx_addsy)
        {
-         if (add_symbol_segment == this_segment_type && pcrel && !plt
-             && TC_RELOC_RTSYM_LOC_FIXUP (fixP))
+         if (add_symbol_segment == this_segment
+             && !TC_FORCE_RELOCATION_LOCAL (fixP))
            {
              /* 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);
-#endif /* TC_I960  */
-
-             add_number += S_GET_VALUE (add_symbolP);
-             add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type);
-             /* Lie.  Don't want further pcrel processing.  */
-             pcrel = 0;
-
-             /* 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;
-               }
+             add_number += S_GET_VALUE (fixP->fx_addsy);
+             fixP->fx_offset = add_number;
+             if (fixP->fx_pcrel)
+               add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment);
+             fixP->fx_addsy = NULL;
+             fixP->fx_pcrel = 0;
            }
-         else
+         else if (add_symbol_segment == absolute_section
+                  && !TC_FORCE_RELOCATION_ABS (fixP))
            {
-             if (add_symbol_segment == absolute_section
-                 && ! pcrel)
-               {
-#ifdef TC_I960
-                 /* See comment about reloc_callj() above.  */
-                 reloc_callj (fixP);
-#endif /* TC_I960  */
-                 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
+             add_number += S_GET_VALUE (fixP->fx_addsy);
+             fixP->fx_offset = add_number;
+             fixP->fx_addsy = 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_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);
-#endif /* TE_I386AIX  */
-#endif /* OBJ_COFF  */
-                 ++seg_reloc_count;
-               }
-             else
-               {
-                 seg_reloc_count++;
-                 if (TC_FIX_ADJUSTABLE (fixP))
-                   add_number += S_GET_VALUE (add_symbolP);
-               }
-           }
+                  && MD_APPLY_SYM_VALUE (fixP))
+           add_number += S_GET_VALUE (fixP->fx_addsy);
        }
 
-      if (pcrel)
+      if (fixP->fx_pcrel)
        {
-         add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type);
-         if (add_symbolP == 0)
+         add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment);
+         if (!fixP->fx_done && fixP->fx_addsy == NULL)
            {
-#ifndef BFD_ASSEMBLER
-             fixP->fx_addsy = &abs_symbol;
-#else
-             fixP->fx_addsy = section_symbol (absolute_section);
-#endif
-             symbol_mark_used_in_reloc (fixP->fx_addsy);
-             ++seg_reloc_count;
+             /* There was no symbol required by this relocation.
+                However, BFD doesn't really handle relocations
+                without symbols well. So fake up a local symbol in
+                the absolute section.  */
+             fixP->fx_addsy = abs_section_sym;
            }
        }
 
       if (!fixP->fx_done)
-       {
-#ifdef MD_APPLY_FIX3
-         md_apply_fix3 (fixP, &add_number, this_segment_type);
-#else
-#ifdef BFD_ASSEMBLER
-         md_apply_fix (fixP, &add_number);
-#else
-         md_apply_fix (fixP, add_number);
-#endif
-#endif
+       md_apply_fix3 (fixP, &add_number, this_segment);
 
-#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
+      if (!fixP->fx_done)
+       {
+         ++seg_reloc_count;
+         if (fixP->fx_addsy == NULL)
+           fixP->fx_addsy = abs_section_sym;
+         symbol_mark_used_in_reloc (fixP->fx_addsy);
+         if (fixP->fx_subsy != NULL)
+           symbol_mark_used_in_reloc (fixP->fx_subsy);
        }
 
-      if (!fixP->fx_bit_fixP && !fixP->fx_no_overflow && size > 0)
+      if (!fixP->fx_bit_fixP && !fixP->fx_no_overflow && fixP->fx_size != 0)
        {
-         if ((size_t) size < sizeof (valueT))
+         if (fixP->fx_size < sizeof (valueT))
            {
              valueT mask;
 
              mask = 0;
              mask--;           /* Set all bits to one.  */
-             mask <<= size * 8 - (fixP->fx_signed ? 1 : 0);
+             mask <<= fixP->fx_size * 8 - (fixP->fx_signed ? 1 : 0);
              if ((add_number & mask) != 0 && (add_number & mask) != mask)
                {
                  char buf[50], buf2[50];
-                 sprint_value (buf, fragP->fr_address + where);
+                 sprint_value (buf, fragP->fr_address + fixP->fx_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);
+                               _("value of %s too large for field of %d bytes at %s"),
+                               buf2, fixP->fx_size, buf);
                } /* Generic error checking.  */
            }
 #ifdef WARN_SIGNED_OVERFLOW_WORD
@@ -2814,12 +2765,12 @@ fixup_segment (fixP, this_segment_type)
             number.  We already know it is not too negative.  This is to
             catch over-large switches generated by gcc on the 68k.  */
          if (!flag_signed_overflow_ok
-             && size == 2
+             && fixP->fx_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"),
+                         _("signed .word overflow; switch may be too large; %ld at 0x%lx"),
                          (long) add_number,
-                         (unsigned long) (fragP->fr_address + where));
+                         (long) (fragP->fr_address + fixP->fx_where));
 #endif
        }                       /* Not a bit fix.  */
 
@@ -2845,7 +2796,7 @@ number_to_chars_bigendian (buf, val, n)
      valueT val;
      int n;
 {
-  if ((size_t) n > sizeof (val) || n <= 0)
+  if (n <= 0)
     abort ();
   while (n--)
     {
@@ -2860,7 +2811,7 @@ number_to_chars_littleendian (buf, val, n)
      valueT val;
      int n;
 {
-  if ((size_t) n > sizeof (val) || n <= 0)
+  if (n <= 0)
     abort ();
   while (n--)
     {
This page took 0.044141 seconds and 4 git commands to generate.