* config/tc-mips.c (cons_fix_new_mips): Only treat 8 byte reloc
[deliverable/binutils-gdb.git] / gas / write.c
index 6dd4ff1e725d93453f2b6dd797af6bcf07424a3a..736e1509ad80fe5c8017f0fafc3257683073bdc0 100644 (file)
@@ -1,5 +1,5 @@
 /* write.c - emit .o file
-   Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 1995
+   Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 1996
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 #define TC_FORCE_RELOCATION(FIXP) 0
 #endif
 
+#ifndef TC_FORCE_RELOCATION_SECTION
+#define TC_FORCE_RELOCATION_SECTION(FIXP,SEG) TC_FORCE_RELOCATION(FIXP)
+#endif
+
+#ifndef        MD_PCREL_FROM_SECTION
+#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from(FIXP)
+#endif
+
 #ifndef WORKING_DOT_WORD
 extern CONST int md_short_jump_size;
 extern CONST int md_long_jump_size;
@@ -86,6 +94,8 @@ int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE;
 
 #endif /* BFD_ASSEMBLER */
 
+static int n_fixups;
+
 #ifdef BFD_ASSEMBLER
 static fixS *fix_new_internal PARAMS ((fragS *, int where, int size,
                                       symbolS *add, symbolS *sub,
@@ -125,6 +135,8 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
 {
   fixS *fixP;
 
+  n_fixups++;
+
   fixP = (fixS *) obstack_alloc (&notes, sizeof (fixS));
 
   fixP->fx_frag = frag;
@@ -235,7 +247,7 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type)
   symbolS *add = NULL;
   symbolS *sub = NULL;
   offsetT off = 0;
-  
+
   switch (exp->X_op)
     {
     case O_absent:
@@ -254,6 +266,21 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type)
        return fix_new_exp (frag, where, size, exp, pcrel, r_type);
       }
 
+    case O_symbol_rva:
+      add = exp->X_add_symbol;
+      off = exp->X_add_number;
+
+#if defined(BFD_ASSEMBLER)
+      r_type = BFD_RELOC_RVA;
+#else
+#if defined(TC_RVA_RELOC)
+      r_type = TC_RVA_RELOC;
+#else
+      as_fatal("rva not supported");
+#endif
+#endif
+      break;
+
     case O_uminus:
       sub = exp->X_add_symbol;
       off = exp->X_add_number;
@@ -268,7 +295,7 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type)
     case O_constant:
       off = exp->X_add_number;
       break;
-      
+
     default:
       as_bad ("expression too complex for fixup");
     }
@@ -292,7 +319,7 @@ append (charPP, fromP, length)
   *charPP += length;
 }
 
-#ifndef BFD_ASSEMBLER 
+#ifndef BFD_ASSEMBLER
 int section_alignment[SEG_MAXIMUM_ORDINAL];
 #endif
 
@@ -302,7 +329,7 @@ int section_alignment[SEG_MAXIMUM_ORDINAL];
  * boundary, all of the other alignments within it will work.  At
  * least one object format really uses this info.
  */
-void 
+void
 record_alignment (seg, align)
      /* Segment to which alignment pertains */
      segT seg;
@@ -355,6 +382,7 @@ chain_frchains_together_1 (section, frchp)
     {
       prev_frag->fr_next = frchp->frch_root;
       prev_frag = frchp->frch_last;
+      assert (prev_frag->fr_type != 0);
 #ifdef BFD_ASSEMBLER
       if (frchp->fix_root != (fixS *) NULL)
        {
@@ -366,6 +394,7 @@ chain_frchains_together_1 (section, frchp)
        }
 #endif
     }
+  assert (prev_frag->fr_type != 0);
   prev_frag->fr_next = 0;
   return prev_frag;
 }
@@ -398,7 +427,7 @@ chain_frchains_together (abfd, section, xxx)
 
 #if !defined (BFD) && !defined (BFD_ASSEMBLER)
 
-void 
+void
 remove_subsegs (head, seg, root, last)
      frchainS *head;
      int seg;
@@ -600,7 +629,7 @@ dump_section_relocs (abfd, sec, stream_)
     }
 }
 #else
-#define dump_section_relocs(ABFD,SEC,STREAM)   (void)(ABFD,SEC,STREAM)
+#define dump_section_relocs(ABFD,SEC,STREAM)   ((void) 0)
 #endif
 
 #ifndef EMIT_SECTION_SYMBOLS
@@ -645,13 +674,27 @@ adjust_reloc_syms (abfd, sec, xxx)
            goto done;
          }
 
+       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))
+             {
+               fixp->fx_addsy->sy_used_in_reloc = 1;
+#ifdef UNDEFINED_DIFFERENCE_OK
+               if (fixp->fx_subsy != NULL)
+                 fixp->fx_subsy->sy_used_in_reloc = 1;
+#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_abs_section (symsec)
            || bfd_is_com_section (symsec))
          {
            fixp->fx_addsy->sy_used_in_reloc = 1;
@@ -684,7 +727,7 @@ adjust_reloc_syms (abfd, sec, xxx)
 #endif
 
        /* Is there some other (target cpu dependent) reason we can't adjust
-          this one?  (E.g. relocations involving function addresses on 
+          this one?  (E.g. relocations involving function addresses on
           the PA.  */
 #ifdef tc_fix_adjustable
        if (! tc_fix_adjustable (fixp))
@@ -717,9 +760,13 @@ adjust_reloc_syms (abfd, sec, xxx)
 
        /* 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.  */
+          when we run into that case.
+
+          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 (symsec);
+       fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym));
        fixp->fx_addsy->sy_used_in_reloc = 1;
 
       done:
@@ -776,21 +823,36 @@ write_relocs (abfd, sec, xxx)
     {
       arelent *reloc;
       bfd_reloc_status_type s;
+      symbolS *sym;
 
       if (fixp->fx_done)
        {
          n--;
          continue;
        }
+
+      /* If this is an undefined symbol which was equated to another
+         symbol, then use generate the reloc against the latter symbol
+         rather than the former.  */
+      sym = fixp->fx_addsy;
+      while (sym->sy_value.X_op == O_symbol
+            && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+       sym = sym->sy_value.X_add_symbol;
+      fixp->fx_addsy = sym;
+
       reloc = tc_gen_reloc (sec, fixp);
       if (!reloc)
        {
          n--;
          continue;
        }
+
+#if 0
+      /* This test is triggered inappropriately for the SH.  */
       if (fixp->fx_where + fixp->fx_size
          > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
        abort ();
+#endif
 
       s = bfd_install_relocation (stdoutput, reloc,
                                  fixp->fx_frag->fr_literal,
@@ -821,6 +883,7 @@ write_relocs (abfd, sec, xxx)
       arelent **reloc;
       char *data;
       bfd_reloc_status_type s;
+      symbolS *sym;
       int j;
 
       if (fixp->fx_done)
@@ -828,6 +891,16 @@ write_relocs (abfd, sec, xxx)
          n--;
          continue;
        }
+
+      /* If this is an undefined symbol which was equated to another
+         symbol, then use generate the reloc against the latter symbol
+         rather than the former.  */
+      sym = fixp->fx_addsy;
+      while (sym->sy_value.X_op == O_symbol
+            && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+       sym = sym->sy_value.X_add_symbol;
+      fixp->fx_addsy = sym;
+
       reloc = tc_gen_reloc (sec, fixp);
 
       for (j = 0; reloc[j]; j++)
@@ -1163,7 +1236,7 @@ set_symtab ()
 }
 #endif
 
-void 
+void
 write_object_file ()
 {
   struct frchain *frchainP;    /* Track along all frchains. */
@@ -1360,7 +1433,7 @@ write_object_file ()
 #else
          fix_new_exp (lie->frag,
                       lie->word_goes_here - lie->frag->fr_literal,
-                      2, &exp, 0, BFD_RELOC_NONE);
+                      2, &exp, 0, BFD_RELOC_16);
 #endif
 #else
 #if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE)
@@ -1571,6 +1644,13 @@ write_object_file ()
 
   PROGRESS (1);
 
+#ifdef tc_frob_file_before_adjust
+  tc_frob_file_before_adjust ();
+#endif
+#ifdef obj_frob_file_before_adjust
+  obj_frob_file_before_adjust ();
+#endif
+
   bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *)0);
 
   /* Set up symbol table, and write it out.  */
@@ -1619,6 +1699,15 @@ write_object_file ()
                resolve_symbol_value (symp);
            }
 
+         /* Skip symbols which were equated to undefined or common
+             symbols.  */
+         if (symp->sy_value.X_op == O_symbol
+             && (! S_IS_DEFINED (symp) || S_IS_COMMON (symp)))
+           {
+             symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+             continue;
+           }
+
          /* So far, common symbols have been treated like undefined symbols.
             Put them in the common section now.  */
          if (S_IS_DEFINED (symp) == 0
@@ -1680,6 +1769,9 @@ write_object_file ()
 
   /* Now do any format-specific adjustments to the symbol table, such
      as adding file symbols.  */
+#ifdef tc_adjust_symtab
+  tc_adjust_symtab ();
+#endif
 #ifdef obj_adjust_symtab
   obj_adjust_symtab ();
 #endif
@@ -1701,6 +1793,13 @@ write_object_file ()
 
   bfd_map_over_sections (stdoutput, write_relocs, (char *) 0);
 
+#ifdef tc_frob_file_after_relocs
+  tc_frob_file_after_relocs ();
+#endif
+#ifdef obj_frob_file_after_relocs
+  obj_frob_file_after_relocs ();
+#endif
+
   bfd_map_over_sections (stdoutput, write_contents, (char *) 0);
 #endif /* BFD_ASSEMBLER */
 }
@@ -1720,9 +1819,10 @@ write_object_file ()
  */
 
 #ifndef md_relax_frag
+#ifdef TC_GENERIC_RELAX_TABLE
 
 /* Subroutines of relax_segment.  */
-static int 
+static int
 is_dnrange (f1, f2)
      struct frag *f1;
      struct frag *f2;
@@ -1733,6 +1833,7 @@ is_dnrange (f1, f2)
   return 0;
 }
 
+#endif /* defined (TC_GENERIC_RELAX_TABLE) */
 #endif /* ! defined (md_relax_frag) */
 
 /* Relax_align. Advance location counter to next address that has 'alignment'
@@ -1756,7 +1857,7 @@ relax_align (address, alignment)
   return (new_address - address);
 }
 
-void 
+void
 relax_segment (segment_frag_root, segment)
      struct frag *segment_frag_root;
      segT segment;
@@ -2131,7 +2232,7 @@ fixup_segment (fixP, this_segment_type)
   int pcrel, plt;
   fragS *fragP;
   segT add_symbol_segment = absolute_section;
-  
+
   /* 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
@@ -2179,15 +2280,25 @@ fixup_segment (fixP, this_segment_type)
 
       if (add_symbolP)
        add_symbol_segment = S_GET_SEGMENT (add_symbolP);
-      
+
       if (sub_symbolP)
        {
          resolve_symbol_value (sub_symbolP);
-         if (!add_symbolP)
+         if (add_symbolP == NULL || add_symbol_segment == absolute_section)
            {
-             /* Its just -sym */
+             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);
+               {
+                 add_number -= S_GET_VALUE (sub_symbolP);
+                 fixP->fx_subsy = NULL;
+               }
              else if (pcrel
                       && S_GET_SEGMENT (sub_symbolP) == this_segment_type)
                {
@@ -2200,9 +2311,8 @@ fixup_segment (fixP, this_segment_type)
                              "Negative of non-absolute symbol %s",
                              S_GET_NAME (sub_symbolP));
            }
-         else if ((S_GET_SEGMENT (sub_symbolP) == add_symbol_segment)
-                  && (SEG_NORMAL (add_symbol_segment)
-                      || (add_symbol_segment == absolute_section)))
+         else if (S_GET_SEGMENT (sub_symbolP) == add_symbol_segment
+                  && SEG_NORMAL (add_symbol_segment))
            {
              /* Difference of 2 symbols from same segment.
                 Can't make difference of 2 undefineds: 'value' means
@@ -2223,10 +2333,11 @@ fixup_segment (fixP, this_segment_type)
              /* 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))
+             if (!TC_FORCE_RELOCATION_SECTION (fixP, this_segment_type))
                {
                  fixP->fx_pcrel = 0;
                  fixP->fx_addsy = NULL;
+                 fixP->fx_subsy = NULL;
                }
            }
          else
@@ -2248,7 +2359,7 @@ fixup_segment (fixP, this_segment_type)
                       )
                {
                  /* Make it pc-relative.  */
-                 add_number += (md_pcrel_from (fixP)
+                 add_number += (MD_PCREL_FROM_SECTION (fixP, this_segment_type)
                                 - S_GET_VALUE (sub_symbolP));
                  pcrel = 1;
                  fixP->fx_pcrel = 1;
@@ -2304,9 +2415,9 @@ fixup_segment (fixP, this_segment_type)
 #endif /* TC_I960 */
 
              add_number += S_GET_VALUE (add_symbolP);
-             add_number -= md_pcrel_from (fixP);
+             add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type);
              pcrel = 0;        /* Lie. Don't want further pcrel processing. */
-             
+
              /* Let the target machine make the final determination
                 as to whether or not a relocation will be needed to
                 handle this fixup.  */
@@ -2329,7 +2440,7 @@ fixup_segment (fixP, this_segment_type)
                  /* 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;
@@ -2357,7 +2468,7 @@ fixup_segment (fixP, this_segment_type)
                      continue;
                    }           /* COBR */
 #endif /* TC_I960 */
-                 
+
 #ifdef OBJ_COFF
 #ifdef TE_I386AIX
                  if (S_IS_COMMON (add_symbolP))
@@ -2369,8 +2480,10 @@ fixup_segment (fixP, this_segment_type)
              else
                {
                  seg_reloc_count++;
+#if !(defined (TC_M68K) && defined (OBJ_ELF))
 #if !defined (TC_I386) || !(defined (OBJ_ELF) || defined (OBJ_COFF))
                  add_number += S_GET_VALUE (add_symbolP);
+#endif
 #endif
                }
            }
@@ -2378,7 +2491,7 @@ fixup_segment (fixP, this_segment_type)
 
       if (pcrel)
        {
-         add_number -= md_pcrel_from (fixP);
+         add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type);
          if (add_symbolP == 0)
            {
 #ifndef BFD_ASSEMBLER
@@ -2498,6 +2611,13 @@ number_to_chars_littleendian (buf, val, n)
     }
 }
 
+void
+write_print_statistics (file)
+     FILE *file;
+{
+  fprintf (stderr, "fixups: %d\n", n_fixups);
+}
+
 /* for debugging */
 extern int indent_level;
 extern void print_symbol_value_1 ();
This page took 0.029217 seconds and 4 git commands to generate.