Additional parsing tests for PA gas.
[deliverable/binutils-gdb.git] / gas / write.c
index 245cd836719a0742cdfaef642ce3e4e4f038302b..30ab74611fe563aec28958af73eb901271ff2171 100644 (file)
@@ -47,9 +47,12 @@ 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)
 static object_headers headers;
-long string_byte_count;
 static char *the_object_file;
+#endif
+
+long string_byte_count;
 char *next_object_file_charP;  /* Tracks object file bytes. */
 
 #ifndef OBJ_VMS
@@ -58,22 +61,35 @@ int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE;
 
 #endif /* BFD_ASSEMBLER */
 
+#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));
+#else
+static fixS *fix_new_internal PARAMS ((fragS *, int where, int size,
+                                      symbolS *add, symbolS *sub,
+                                      offsetT offset, int pcrel,
+                                      int r_type));
+#endif
+#if defined (BFD_ASSEMBLER) || !defined (BFD)
 static long fixup_segment PARAMS ((fixS * fixP, segT this_segment_type));
+#endif
 static relax_addressT relax_align PARAMS ((relax_addressT addr, int align));
-void relax_segment PARAMS ((struct frag * seg_frag_root, segT seg_type));
 
 /*
  *                     fix_new()
  *
  * Create a fixS in obstack 'notes'.
  */
-fixS *
-fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
+static fixS *
+fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
+                 r_type)
      fragS *frag;              /* Which frag? */
      int where;                        /* Where in that frag? */
-     short int size;           /* 1, 2, or 4 usually. */
+     int size;                 /* 1, 2, or 4 usually. */
      symbolS *add_symbol;      /* X_add_symbol. */
-     symbolS *sub_symbol;      /* X_subtract_symbol. */
+     symbolS *sub_symbol;      /* X_op_symbol. */
      offsetT offset;           /* X_add_number. */
      int pcrel;                        /* TRUE if PC-relative relocation. */
 #ifdef BFD_ASSEMBLER
@@ -108,6 +124,8 @@ fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
   fixP->fx_callj = 0;
 #endif
 
+  as_where (&fixP->fx_file, &fixP->fx_line);
+
   /* Usually, we want relocs sorted numerically, but while
      comparing to older versions of gas that have relocs
      reverse sorted, it is convenient to have this compile
@@ -142,6 +160,75 @@ fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
   return fixP;
 }
 
+/* Create a fixup relative to a symbol (plus a constant).  */
+
+fixS *
+fix_new (frag, where, size, add_symbol, offset, pcrel, r_type)
+     fragS *frag;              /* Which frag? */
+     int where;                        /* Where in that frag? */
+     short int size;           /* 1, 2, or 4 usually. */
+     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
+{
+  return fix_new_internal (frag, where, size, add_symbol,
+                          (symbolS *) NULL, offset, pcrel, r_type);
+}
+
+/* Create a fixup for an expression.  Currently we only support fixups
+   for difference expressions.  That is itself more than most object
+   file formats support anyhow.  */
+
+fixS *
+fix_new_exp (frag, where, size, exp, pcrel, r_type)
+     fragS *frag;              /* Which frag? */
+     int where;                        /* Where in that frag? */
+     short 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
+{
+  symbolS *add = NULL;
+  symbolS *sub = NULL;
+  offsetT off = 0;
+  
+  switch (exp->X_op)
+    {
+    case O_absent:
+      break;
+
+    case O_uminus:
+      sub = exp->X_add_symbol;
+      off = exp->X_add_number;
+      break;
+
+    case O_subtract:
+      sub = exp->X_op_symbol;
+      /* Fall through.  */
+    case O_symbol:
+      add = exp->X_add_symbol;
+      /* Fall through.   */
+    case O_constant:
+      off = exp->X_add_number;
+      break;
+      
+    default:
+      as_bad ("expression too complex for fixup");
+    }
+
+  return fix_new_internal (frag, where, size, add, sub, off,
+                          pcrel, r_type);
+}
+
 /* Append a string onto another string, bumping the pointer along.  */
 void
 append (charPP, fromP, length)
@@ -153,7 +240,7 @@ append (charPP, fromP, length)
   if (length == 0)
     return;
 
-  memcpy (*charPP, fromP, (int) length);
+  memcpy (*charPP, fromP, length);
   *charPP += length;
 }
 
@@ -237,21 +324,20 @@ remove_subsegs (head, seg, root, last)
 
 #endif /* BFD */
 
-static void
-cvt_frag_to_fill (x, fragP)
+#if defined (BFD_ASSEMBLER) || !defined (BFD)
+
 #ifdef BFD_ASSEMBLER
-     segT x;
-#else
-     object_headers *x;
-#endif
+static void
+cvt_frag_to_fill (sec, fragP)
+     segT sec;
      fragS *fragP;
-{
-#ifdef BFD_ASSEMBLER
-  segT sec = x;
 #else
-  object_headers *headers = x;
+static void
+cvt_frag_to_fill (headers, fragP)
+     object_headers *headers;
+     fragS *fragP;
 #endif
-
+{
   switch (fragP->fr_type)
     {
     case rs_align:
@@ -313,6 +399,8 @@ cvt_frag_to_fill (x, fragP)
     }
 }
 
+#endif /* defined (BFD_ASSEMBLER) || !defined (BFD) */
+
 #ifdef BFD_ASSEMBLER
 static void
 relax_and_size_seg (abfd, sec, xxx)
@@ -321,59 +409,56 @@ relax_and_size_seg (abfd, sec, xxx)
      char *xxx;
 {
   flagword flags;
+  fragS *fragp;
+  segment_info_type *seginfo;
+  int x;
+  valueT size, newsize;
 
   flags = bfd_get_section_flags (abfd, sec);
 
-  if (/*flags & SEC_ALLOC*/ 1)
+  seginfo = (segment_info_type *) bfd_get_section_userdata (abfd, sec);
+  if (seginfo && seginfo->frchainP)
     {
-      fragS *fragp;
-      segment_info_type *seginfo;
-      int x;
-      valueT size, newsize;
-
-      seginfo = (segment_info_type *) bfd_get_section_userdata (abfd, 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;
-              fragp->fr_next;
-              fragp = fragp->fr_next)
-           /* walk to last elt */;
-         size = fragp->fr_address + fragp->fr_fix;
-       }
+      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;
+          fragp->fr_next;
+          fragp = fragp->fr_next)
+       /* walk to last elt */;
+      size = fragp->fr_address + fragp->fr_fix;
+    }
+  else
+    size = 0;
+  if (size > 0)
+    {
+      flags |= SEC_HAS_CONTENTS;
+      /* @@ This is just an approximation.  */
+      if (seginfo->fix_root)
+       flags |= SEC_RELOC;
       else
-       size = 0;
-      if (size > 0)
-       {
-         flags |= SEC_HAS_CONTENTS;
-         /* @@ This is just an approximation.  */
-         if (seginfo->fix_root)
-           flags |= SEC_RELOC;
-         else
-           flags &= ~SEC_RELOC;
-         x = bfd_set_section_flags (abfd, sec, flags);
-         assert (x == true);
-       }
-      size = md_section_align (sec, size);
-      x = bfd_set_section_size (abfd, sec, size);
+       flags &= ~SEC_RELOC;
+      x = bfd_set_section_flags (abfd, sec, flags);
       assert (x == true);
-
-      /* If the size had to be rounded up, add some padding in the last
-        non-empty frag.  */
-      newsize = bfd_get_section_size_before_reloc (sec);
-      assert (newsize >= size);
-      if (size != newsize)
-       {
-         fragS *last = seginfo->frchainP->frch_last;
-         fragp = seginfo->frchainP->frch_root;
-         while (fragp->fr_next != last)
-           fragp = fragp->fr_next;
-         last->fr_address = size;
-         fragp->fr_offset += newsize - size;
-       }
     }
+  size = md_section_align (sec, size);
+  x = bfd_set_section_size (abfd, sec, size);
+  assert (x == true);
+
+  /* If the size had to be rounded up, add some padding in the last
+     non-empty frag.  */
+  newsize = bfd_get_section_size_before_reloc (sec);
+  assert (newsize >= size);
+  if (size != newsize)
+    {
+      fragS *last = seginfo->frchainP->frch_last;
+      fragp = seginfo->frchainP->frch_root;
+      while (fragp->fr_next != last)
+       fragp = fragp->fr_next;
+      last->fr_address = size;
+      fragp->fr_offset += newsize - size;
+    }
+
 #ifdef tc_frob_section
   tc_frob_section (sec);
 #endif
@@ -439,19 +524,37 @@ adjust_reloc_syms (abfd, sec, xxx)
        if (symsec == &bfd_und_section
            || symsec == &bfd_abs_section
            || bfd_is_com_section (symsec))
-         continue;
+         {
+           fixp->fx_addsy->sy_used_in_reloc = 1;
+           continue;
+         }
 
        /* Since we're reducing to section symbols, don't attempt to reduce
           anything that's already using one.  */
        if (sym->bsym == symsec->symbol)
-         continue;
+         {
+           fixp->fx_addsy->sy_used_in_reloc = 1;
+           continue;
+         }
 
        /* 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))
+         {
+           fixp->fx_addsy->sy_used_in_reloc = 1;
+           continue;
+         }
+#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))
          continue;
 #endif
+
        /* 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.  */
@@ -470,21 +573,21 @@ adjust_reloc_syms (abfd, sec, xxx)
              }
            symseginfo->sym = fixp->fx_addsy;
          }
+       fixp->fx_addsy->sy_used_in_reloc = 1;
       }
 
   dump_section_relocs (abfd, sec, stderr);
 }
 
 static void
-write_contents (abfd, sec, xxx)
+write_relocs (abfd, sec, xxx)
      bfd *abfd;
      asection *sec;
      char *xxx;
 {
   segment_info_type *seginfo = seg_info (sec);
-  unsigned long offset = 0;
-  fragS *frags;
-  int i, n;
+  int i;
+  unsigned int n;
   arelent **relocs;
   fixS *fixp;
 
@@ -503,13 +606,12 @@ write_contents (abfd, sec, xxx)
   /* Set up reloc information as well.  */
   relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
                                             n * sizeof (arelent *));
-  bzero ((char*)relocs, n * sizeof (arelent*));
+  memset ((char*)relocs, 0, n * sizeof (arelent*));
 
   i = 0;
   for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
     {
       arelent *reloc;
-      extern arelent *tc_gen_reloc ();
       char *data;
       bfd_reloc_status_type s;
 
@@ -527,12 +629,20 @@ write_contents (abfd, sec, xxx)
          continue;
        }
       data = fixp->fx_frag->fr_literal + fixp->fx_where;
+      /* @@ Assumes max size of reloc is 4. */
       if (fixp->fx_where + 4
          > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
        abort ();
       /* Pass bogus address so that when bfd_perform_relocation adds
         `address' back in, it'll come up with `data', which is where
         we want it to operate.  */
+      if (reloc->howto->partial_inplace == false
+         && reloc->howto->pcrel_offset == true
+         && reloc->howto->pc_relative == true)
+       {
+         /* bfd_perform_relocation screws this up */
+         reloc->addend += reloc->address;
+       }
       s = bfd_perform_relocation (stdoutput, reloc, data - reloc->address,
                                  sec, stdoutput);
       switch (s)
@@ -554,7 +664,6 @@ write_contents (abfd, sec, xxx)
   for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
     {
       arelent **reloc;
-      extern arelent *tc_gen_reloc ();
       char *data;
       bfd_reloc_status_type s;
       int j;
@@ -597,7 +706,8 @@ write_contents (abfd, sec, xxx)
     bfd_set_reloc (stdoutput, sec, relocs, n);
   else
     bfd_set_section_flags (abfd, sec,
-                          bfd_get_section_flags (abfd, sec) & ~SEC_RELOC);
+                          (bfd_get_section_flags (abfd, sec)
+                           & (flagword) ~SEC_RELOC));
 #ifdef DEBUG2
   {
     int i;
@@ -613,41 +723,50 @@ write_contents (abfd, sec, xxx)
       }
   }
 #endif
+}
 
-  /* Force calculations (size, vma) to get done.  */
-  bfd_set_section_contents (stdoutput, sec, "", 0, (addressT) 0);
+static void
+write_contents (abfd, sec, xxx)
+     bfd *abfd;
+     asection *sec;
+     char *xxx;
+{
+  segment_info_type *seginfo = seg_info (sec);
+  unsigned long offset = 0;
+  fragS *f;
 
   /* Write out the frags.  */
-  if (! (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS))
+  if (seginfo == NULL
+      || ! (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS))
     return;
 
-  for (frags = seginfo->frchainP->frch_root;
-       frags;
-       frags = frags->fr_next)
+  for (f = seginfo->frchainP->frch_root;
+       f;
+       f = f->fr_next)
     {
       int x;
       unsigned long fill_size;
       char *fill_literal;
       long count;
 
-      assert (frags->fr_type == rs_fill);
-      if (frags->fr_fix)
+      assert (f->fr_type == rs_fill);
+      if (f->fr_fix)
        {
          x = bfd_set_section_contents (stdoutput, sec,
-                                       frags->fr_literal, offset,
-                                       frags->fr_fix);
+                                       f->fr_literal, (file_ptr) offset,
+                                       (bfd_size_type) f->fr_fix);
          assert (x == true);
-         offset += frags->fr_fix;
+         offset += f->fr_fix;
        }
-      fill_literal = frags->fr_literal + frags->fr_fix;
-      fill_size = frags->fr_var;
-      count = frags->fr_offset;
+      fill_literal = f->fr_literal + f->fr_fix;
+      fill_size = f->fr_var;
+      count = f->fr_offset;
       assert (count >= 0);
       if (fill_size && count)
        while (count--)
          {
            x = bfd_set_section_contents (stdoutput, sec,
-                                         fill_literal, offset,
+                                         fill_literal, (file_ptr) offset,
                                          (bfd_size_type) fill_size);
            assert (x == true);
            offset += fill_size;
@@ -656,14 +775,137 @@ write_contents (abfd, sec, xxx)
 }
 #endif
 
+#if defined(BFD_ASSEMBLER) || (!defined (BFD) && !defined(OBJ_AOUT))
+static void
+merge_data_into_text ()
+{
+#if defined(BFD_ASSEMBLER) || defined(MANY_SEGMENTS)
+  seg_info (text_section)->frchainP->frch_last->fr_next =
+    seg_info (data_section)->frchainP->frch_root;
+  seg_info (text_section)->frchainP->frch_last =
+    seg_info (data_section)->frchainP->frch_last;
+  seg_info (data_section)->frchainP = 0;
+#else
+  fixS *tmp;
+
+  text_last_frag->fr_next = data_frag_root;
+  text_last_frag = data_last_frag;
+  data_last_frag = NULL;
+  data_frag_root = NULL;
+  if (text_fix_root)
+    {
+      for (tmp = text_fix_root; tmp->fx_next; tmp = tmp->fx_next);;
+      tmp->fx_next = data_fix_root;
+      text_fix_tail = data_fix_tail;
+    }
+  else
+    text_fix_root = data_fix_root;
+  data_fix_root = NULL;
+#endif
+}
+#endif /* BFD_ASSEMBLER || (! BFD && ! OBJ_AOUT) */
+
+#if !defined (BFD_ASSEMBLER) && !defined (BFD)
+static void
+relax_and_size_all_segments ()
+{
+  fragS *fragP;
+
+  relax_segment (text_frag_root, SEG_TEXT);
+  relax_segment (data_frag_root, SEG_DATA);
+  relax_segment (bss_frag_root, SEG_BSS);
+  /*
+   * Now the addresses of frags are correct within the segment.
+   */
+
+  know (text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0);
+  H_SET_TEXT_SIZE (&headers, text_last_frag->fr_address);
+  text_last_frag->fr_address = H_GET_TEXT_SIZE (&headers);
+
+  /*
+   * Join the 2 segments into 1 huge segment.
+   * To do this, re-compute every rn_address in the SEG_DATA frags.
+   * Then join the data frags after the text frags.
+   *
+   * Determine a_data [length of data segment].
+   */
+  if (data_frag_root)
+    {
+      register relax_addressT slide;
+
+      know ((text_last_frag->fr_type == rs_fill) && (text_last_frag->fr_offset == 0));
+
+      H_SET_DATA_SIZE (&headers, data_last_frag->fr_address);
+      data_last_frag->fr_address = H_GET_DATA_SIZE (&headers);
+      slide = H_GET_TEXT_SIZE (&headers);      /* & in file of the data segment. */
+#ifdef OBJ_BOUT
+#define RoundUp(N,S) (((N)+(S)-1)&-(S))
+      /* For b.out: If the data section has a strict alignment
+        requirement, its load address in the .o file will be
+        rounded up from the size of the text section.  These
+        two values are *not* the same!  Similarly for the bss
+        section....  */
+      slide = RoundUp (slide, 1 << section_alignment[SEG_DATA]);
+#endif
+
+      for (fragP = data_frag_root; fragP; fragP = fragP->fr_next)
+       {
+         fragP->fr_address += slide;
+       }                       /* for each data frag */
+
+      know (text_last_frag != 0);
+      text_last_frag->fr_next = data_frag_root;
+    }
+  else
+    {
+      H_SET_DATA_SIZE (&headers, 0);
+    }
+
+#ifdef OBJ_BOUT
+  /* See above comments on b.out data section address.  */
+  {
+    long bss_vma;
+    if (data_last_frag == 0)
+      bss_vma = H_GET_TEXT_SIZE (&headers);
+    else
+      bss_vma = data_last_frag->fr_address;
+    bss_vma = RoundUp (bss_vma, 1 << section_alignment[SEG_BSS]);
+    bss_address_frag.fr_address = bss_vma;
+  }
+#else /* ! OBJ_BOUT */
+  bss_address_frag.fr_address = (H_GET_TEXT_SIZE (&headers) +
+                                H_GET_DATA_SIZE (&headers));
+
+#endif /* ! OBJ_BOUT */
+
+  /* Slide all the frags */
+  if (bss_frag_root)
+    {
+      relax_addressT slide = bss_address_frag.fr_address;
+
+      for (fragP = bss_frag_root; fragP; fragP = fragP->fr_next)
+       {
+         fragP->fr_address += slide;
+       }                       /* for each bss frag */
+    }
+
+  if (bss_last_frag)
+    H_SET_BSS_SIZE (&headers,
+                   bss_last_frag->fr_address - bss_frag_root->fr_address);
+  else
+    H_SET_BSS_SIZE (&headers, 0);
+}
+#endif /* ! BFD_ASSEMBLER && ! BFD */
+
 #if defined (BFD_ASSEMBLER) || !defined (BFD)
 
 void 
 write_object_file ()
 {
   register 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;
 #endif
@@ -717,11 +959,7 @@ write_object_file ()
 #endif
   for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next)
     {
-#ifdef BFD_ASSEMBLER
       subseg_set (frchainP->frch_seg, frchainP->frch_subseg);
-#else
-      subseg_new (frchainP->frch_seg, frchainP->frch_subseg);
-#endif
       frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE);
       /* frag_align will have left a new frag.
         Use this last frag for an empty ".fill".
@@ -731,8 +969,6 @@ write_object_file ()
       frag_wane (frag_now);
       frag_now->fr_fix = 0;
       know (frag_now->fr_next == NULL);
-      /* know( frags . obstack_c_base == frags . obstack_c_next_free ); */
-      /* Above shows we haven't left a half-completed object on obstack. */
     }
 
   /* From now on, we don't care about sub-segments.  Build one frag chain
@@ -746,11 +982,7 @@ write_object_file ()
     while (seclist && *seclist)
       {
        sec = *seclist;
-       while (sec == big_section
-              || sec == reg_section
-              || sec == pass1_section
-              || sec == diff_section
-              || sec == absent_section)
+       while (sec == reg_section || sec == expr_section)
          {
            sec = sec->next;
            *seclist = sec;
@@ -776,120 +1008,14 @@ write_object_file ()
 #if !defined (OBJ_AOUT) || defined (BFD_ASSEMBLER)
   if (flagseen['R'])
     {
-#ifdef BFD_ASSEMBLER
-      seg_info (text_section)->frchainP->frch_last->fr_next =
-       seg_info (data_section)->frchainP->frch_root;
-      seg_info (text_section)->frchainP->frch_last =
-       seg_info (data_section)->frchainP->frch_last;
-      seg_info (data_section)->frchainP = 0;
-#else
-      fixS *tmp;
-
-      text_last_frag->fr_next = data_frag_root;
-      text_last_frag = data_last_frag;
-      data_last_frag = NULL;
-      data_frag_root = NULL;
-      if (text_fix_root)
-       {
-         for (tmp = text_fix_root; tmp->fx_next; tmp = tmp->fx_next);;
-         tmp->fx_next = data_fix_root;
-         text_fix_tail = data_fix_tail;
-       }
-      else
-       text_fix_root = data_fix_root;
-      data_fix_root = NULL;
-#endif
+      merge_data_into_text ();
     }
 #endif
 
 #ifdef BFD_ASSEMBLER
-
   bfd_map_over_sections (stdoutput, relax_and_size_seg, (char *) 0);
 #else
-  relax_segment (text_frag_root, SEG_TEXT);
-  relax_segment (data_frag_root, SEG_DATA);
-  relax_segment (bss_frag_root, SEG_BSS);
-  /*
-   * Now the addresses of frags are correct within the segment.
-   */
-
-  know (text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0);
-  H_SET_TEXT_SIZE (&headers, text_last_frag->fr_address);
-  text_last_frag->fr_address = H_GET_TEXT_SIZE (&headers);
-
-  /*
-   * Join the 2 segments into 1 huge segment.
-   * To do this, re-compute every rn_address in the SEG_DATA frags.
-   * Then join the data frags after the text frags.
-   *
-   * Determine a_data [length of data segment].
-   */
-  if (data_frag_root)
-    {
-      register relax_addressT slide;
-
-      know ((text_last_frag->fr_type == rs_fill) && (text_last_frag->fr_offset == 0));
-
-      H_SET_DATA_SIZE (&headers, data_last_frag->fr_address);
-      data_last_frag->fr_address = H_GET_DATA_SIZE (&headers);
-      slide = H_GET_TEXT_SIZE (&headers);      /* & in file of the data segment. */
-#ifdef OBJ_BOUT
-#define RoundUp(N,S) (((N)+(S)-1)&-(S))
-      /* For b.out: If the data section has a strict alignment
-        requirement, its load address in the .o file will be
-        rounded up from the size of the text section.  These
-        two values are *not* the same!  Similarly for the bss
-        section....  */
-      slide = RoundUp (slide, 1 << section_alignment[SEG_DATA]);
-#endif
-
-      for (fragP = data_frag_root; fragP; fragP = fragP->fr_next)
-       {
-         fragP->fr_address += slide;
-       }                       /* for each data frag */
-
-      know (text_last_frag != 0);
-      text_last_frag->fr_next = data_frag_root;
-    }
-  else
-    {
-      H_SET_DATA_SIZE (&headers, 0);
-    }
-
-#ifdef OBJ_BOUT
-  /* See above comments on b.out data section address.  */
-  {
-    long bss_vma;
-    if (data_last_frag == 0)
-      bss_vma = H_GET_TEXT_SIZE (&headers);
-    else
-      bss_vma = data_last_frag->fr_address;
-    bss_vma = RoundUp (bss_vma, 1 << section_alignment[SEG_BSS]);
-    bss_address_frag.fr_address = bss_vma;
-  }
-#else /* ! OBJ_BOUT */
-  bss_address_frag.fr_address = (H_GET_TEXT_SIZE (&headers) +
-                                H_GET_DATA_SIZE (&headers));
-
-
-  /* Slide all the frags */
-  if (bss_frag_root)
-    {
-      relax_addressT slide = bss_address_frag.fr_address;
-
-      for (fragP = bss_frag_root; fragP; fragP = fragP->fr_next)
-       {
-         fragP->fr_address += slide;
-       }                       /* for each bss frag */
-    }
-
-#endif /* ! OBJ_BOUT */
-
-  if (bss_last_frag)
-    H_SET_BSS_SIZE (&headers,
-                   bss_last_frag->fr_address - bss_frag_root->fr_address);
-  else
-    H_SET_BSS_SIZE (&headers, 0);
+  relax_and_size_all_segments ();
 #endif /* BFD_ASSEMBLER */
 
 #ifndef BFD_ASSEMBLER
@@ -958,30 +1084,30 @@ write_object_file ()
     for (lie = broken_words; lie; lie = lie->next_broken_word)
       if (!lie->added)
        {
+         expressionS exp;
+
+         exp.X_op = O_subtract;
+         exp.X_add_symbol = lie->add;
+         exp.X_op_symbol = lie->sub;
+         exp.X_add_number = lie->addnum;
 #ifdef BFD_ASSEMBLER
-         fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal,
-                  2, lie->add, lie->sub, lie->addnum, 0,
-                  BFD_RELOC_NONE);
+         fix_new_exp (lie->frag,
+                      lie->word_goes_here - lie->frag->fr_literal,
+                      2, &exp, 0, BFD_RELOC_NONE);
 #else
 #if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE)
-         fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal,
-                  2, lie->add,
-                  lie->sub, lie->addnum,
-                  0, NO_RELOC);
+         fix_new_exp (lie->frag,
+                      lie->word_goes_here - lie->frag->fr_literal,
+                      2, &exp, 0, NO_RELOC);
 #else
 #ifdef TC_NS32K
-         fix_new_ns32k (lie->frag,
-                        lie->word_goes_here - lie->frag->fr_literal,
-                        2,
-                        lie->add,
-                        lie->sub,
-                        lie->addnum,
-                        0, 0, 2, 0, 0);
+         fix_new_ns32k_exp (lie->frag,
+                            lie->word_goes_here - lie->frag->fr_literal,
+                            2, &exp, 0, 0, 2, 0, 0);
 #else
-         fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal,
-                  2, lie->add,
-                  lie->sub, lie->addnum,
-                  0, 0);
+         fix_new_exp (lie->frag,
+                      lie->word_goes_here - lie->frag->fr_literal,
+                      2, &exp, 0, 0);
 #endif /* TC_NS32K */
 #endif /* TC_SPARC|TC_A29K|NEED_FX_R_TYPE */
 #endif /* BFD_ASSEMBLER */
@@ -1165,49 +1291,70 @@ write_object_file ()
   /* Set up symbol table, and write it out.  */
   if (symbol_rootP)
     {
-      int i = 0, n;
+      unsigned int i = 0;
+      unsigned int n;
       symbolS *symp;
 
       for (symp = symbol_rootP; symp; symp = symbol_next (symp))
        {
-         int keep = 0;
+         if (! symp->sy_resolved)
+           {
+             if (symp->sy_value.X_op == O_constant)
+               {
+                 /* This is the normal case; skip the call.  */
+                 S_SET_VALUE (symp,
+                              (S_GET_VALUE (symp)
+                               + symp->sy_frag->fr_address));
+                 symp->sy_resolved = 1;
+               }
+             else
+               resolve_symbol_value (symp);
+           }
 
-         S_SET_VALUE (symp, S_GET_VALUE (symp) + symp->sy_frag->fr_address);
          /* So far, common symbols have been treated like undefined symbols.
             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);
 #if 0
-         printf ("symbol `%s'\n\t@%x: value=%d flags=%x forward=%x seg=%s\n",
+         printf ("symbol `%s'\n\t@%x: value=%d flags=%x seg=%s\n",
                  S_GET_NAME (symp), symp,
                  S_GET_VALUE (symp),
                  symp->bsym->flags,
-                 symp->sy_forward,
                  segment_name (symp->bsym->section));
 #endif
-         {
-           int punt = 0;
+         if (! symp->sy_used_in_reloc)
+           {
 #ifdef obj_frob_symbol
-           obj_frob_symbol (symp, punt);
-           if (punt)
-             goto punt_it;
+             {
+               int punt = 0;
+               obj_frob_symbol (symp, punt);
+               if (punt)
+                 goto punt_it;
+             }
 #endif
 #ifdef tc_frob_symbol
-           tc_frob_symbol (symp, punt);
-           if (punt)
-             goto punt_it;
+             {
+               int punt = 0;
+               tc_frob_symbol (symp, punt);
+               if (punt)
+                 goto punt_it;
+             }
 #endif
-         }
+           }
+
          /* If we don't want to keep this symbol, splice it out of the
             chain now.  */
-         if (S_IS_LOCAL (symp))
+         if (! symp->sy_used_in_reloc
+             && S_IS_LOCAL (symp))
            {
              symbolS *prev, *next;
+#if defined (obj_frob_symbol) || defined (tc_frob_symbol)
            punt_it:
+#endif
              prev = symbol_previous (symp);
              next = symbol_next (symp);
-#ifdef DEBUG
+#ifdef DEBUG_SYMS
              verify_symbol_chain_2 (symp);
 #endif
              if (prev)
@@ -1223,7 +1370,7 @@ write_object_file ()
                symbol_previous (next) = prev;
              else
                symbol_lastP = prev;
-#ifdef DEBUG
+#ifdef DEBUG_SYMS
              if (prev)
                verify_symbol_chain_2 (prev);
              else if (next)
@@ -1231,6 +1378,19 @@ write_object_file ()
 #endif
              continue;
            }
+
+         /* Make sure we really got a value for the symbol.  */
+         if (! symp->sy_resolved)
+           {
+             as_bad ("can't resolve value for symbol \"%s\"",
+                     S_GET_NAME (symp));
+             symp->sy_resolved = 1;
+           }
+
+         /* 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;
@@ -1255,11 +1415,17 @@ write_object_file ()
 
 
 #ifdef obj_frob_file
+  /* If obj_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.  */
   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);
 
   output_file_close (out_file_name);
@@ -1384,7 +1550,6 @@ relax_segment (segment_frag_root, segment)
            symbolS *symbolP;
            long target;
            long after;
-           long aim;
 
            was_address = fragP->fr_address;
            address = fragP->fr_address += stretch;
@@ -1430,7 +1595,7 @@ relax_segment (segment_frag_root, segment)
                          if (flagseen['K'])
                            {
                              char buf[50];
-                             sprint_value (buf, lie->addnum);
+                             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),
@@ -1501,6 +1666,7 @@ relax_segment (segment_frag_root, segment)
                  const relax_typeS *start_type;
                  relax_substateT next_state;
                  relax_substateT this_state;
+                 long aim;
 
                  this_state = fragP->fr_subtype;
                  start_type = this_type = md_relax_table + this_state;
@@ -1508,6 +1674,7 @@ relax_segment (segment_frag_root, segment)
 
                  if (symbolP)
                    {
+#ifndef DIFF_EXPR_OK
 #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
                      know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE)
                            || (S_GET_SEGMENT (symbolP) == SEG_DATA)
@@ -1515,6 +1682,7 @@ relax_segment (segment_frag_root, segment)
                            || (S_GET_SEGMENT (symbolP) == SEG_TEXT));
 #endif
                      know (symbolP->sy_frag);
+#endif
                      know (!(S_GET_SEGMENT (symbolP) == absolute_section)
                            || symbolP->sy_frag == &zero_address_frag);
                      target +=
@@ -1611,6 +1779,8 @@ relax_segment (segment_frag_root, segment)
    */
 }                              /* relax_segment() */
 
+#if defined (BFD_ASSEMBLER) || !defined (BFD)
+
 /* fixup_segment()
 
    Go through all the fixS's in a segment and see which ones can be
@@ -1639,7 +1809,12 @@ fixup_segment (fixP, this_segment_type)
   register segT add_symbol_segment = absolute_section;
 
   seg_reloc_count = 0;
-  /* If the linker is doing the relaxing, we must not do any fixups */
+  /* If the linker is doing the relaxing, we must not do any fixups.  */
+  /* Well, strictly speaking that's not true -- we could do any that
+     are PC-relative and don't cross regions that could change size.
+     And for the i960 (the only machine for which we've got a relaxing
+     linker right now), we might be able to turn callx/callj into bal
+     in cases where we know the maximum displacement.  */
   if (linkrelax)
     for (; fixP; fixP = fixP->fx_next)
       seg_reloc_count++;
@@ -1679,6 +1854,7 @@ fixup_segment (fixP, this_segment_type)
            if (!add_symbolP)
              {
                /* Its just -sym */
+               /* @@ Should try converting to pcrel ref to fixed addr.  */
                if (S_GET_SEGMENT (sub_symbolP) != absolute_section)
                  as_bad ("Negative of non-absolute symbol %s",
                          S_GET_NAME (sub_symbolP));
@@ -1706,6 +1882,7 @@ fixup_segment (fixP, this_segment_type)
                add_symbolP = NULL;
                fixP->fx_addsy = NULL;
              }
+#if !defined(SEG_DIFF_ALLOWED) && !defined (GLOBAL_DIFF_ALLOWED)
            else
              {
                /* Different segments in subtraction. */
@@ -1716,6 +1893,19 @@ fixup_segment (fixP, this_segment_type)
                  {
                    add_number -= S_GET_VALUE (sub_symbolP);
                  }
+#ifdef DIFF_EXPR_OK
+               else if (!pcrel
+                        && S_GET_SEGMENT (sub_symbolP) == this_segment_type)
+                 {
+                   /* Make it pc-relative.  */
+                   add_number += (md_pcrel_from (fixP)
+                                  - S_GET_VALUE (sub_symbolP));
+                   pcrel = 1;
+                   fixP->fx_pcrel = 1;
+                   sub_symbolP = 0;
+                   fixP->fx_subsy = 0;
+                 }
+#endif
                else
                  {
                    char buf[50];
@@ -1724,6 +1914,14 @@ fixup_segment (fixP, this_segment_type)
                            segment_name (S_GET_SEGMENT (sub_symbolP)),
                            S_GET_NAME (sub_symbolP), buf);
                  }
+#else
+                else
+                  {
+                    seg_reloc_count++;
+                   fixP->fx_addnumber = add_number;    /* Remember value for emit_reloc */
+                    continue;
+                  }            /* if absolute */
+#endif
              }
          }
 
@@ -1748,7 +1946,9 @@ fixup_segment (fixP, this_segment_type)
                add_number += S_GET_VALUE (add_symbolP);
                add_number -= md_pcrel_from (fixP);
                pcrel = 0;      /* Lie. Don't want further pcrel processing. */
+#ifndef TC_HPPA
                fixP->fx_addsy = NULL;  /* No relocations please. */
+#endif
              }
            else
              {
@@ -1764,7 +1964,7 @@ fixup_segment (fixP, this_segment_type)
                  }
                else if (add_symbol_segment == undefined_section
 #ifdef BFD_ASSEMBLER
-                        || add_symbol_segment == &bfd_com_section
+                        || bfd_is_com_section (add_symbol_segment)
 #endif
                         )
                  {
@@ -1795,8 +1995,8 @@ fixup_segment (fixP, this_segment_type)
                    seg_reloc_count++;
                    add_number += S_GET_VALUE (add_symbolP);
                  }
-             }                 /* if not in local seg */
-         }                     /* if there was a + symbol */
+             }
+         }
 
        if (pcrel)
          {
@@ -1810,21 +2010,27 @@ fixup_segment (fixP, this_segment_type)
 
        if (!fixP->fx_bit_fixP)
          {
-           if ((size == 1
-                && (add_number & ~0xFF)
-                && ((add_number & ~0xFF) != (-1 & ~0xFF)))
-               || (size == 2
-                   && (add_number & ~0xFFFF)
-                   && ((add_number & ~0xFFFF) != (-1 & ~0xFFFF)))
-               || (size == 4
-                   && (add_number & ~(valueT)0xFFFFFFFF)
-                   && ((add_number & ~(valueT)0xFFFFFFFF) != (-1 & ~(valueT)0xFFFFFFFF)))
-               )
+           valueT mask = 0;
+           /* set all bits to one */
+           mask--;
+           /* Technically speaking, combining these produces an
+              undefined result if size is sizeof (valueT), though I
+              think these two half-way operations should both be
+              defined.  */
+           mask <<= size * 4;
+           mask <<= size * 4;
+           if ((add_number & mask) != 0
+               && (add_number & mask) != mask)
              {
-               char buf[50];
+               char buf[50], buf2[50];
                sprint_value (buf, fragP->fr_address + where);
-               as_bad ("Value of %d too large for field of %d bytes at %s",
-                       add_number, size, buf);
+               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
@@ -1833,8 +2039,10 @@ fixup_segment (fixP, this_segment_type)
            if (!flagseen['J']
                && size == 2
                && add_number > 0x7fff)
-             as_bad ("Signed .word overflow; switch may be too large; %d at 0x%x",
-                     add_number, fragP->fr_address + where);
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                           "Signed .word overflow; switch may be too large; %ld at 0x%lx",
+                           (long) add_number,
+                           (unsigned long) (fragP->fr_address + where));
 #endif
          }                     /* not a bit fix */
 
@@ -1845,24 +2053,20 @@ fixup_segment (fixP, this_segment_type)
 #endif
       }                                /* For each fixS in this segment. */
 
-#ifdef OBJ_COFF
-#ifdef TC_I960
+#if defined (OBJ_COFF) && defined (TC_I960)
   {
     fixS *topP = fixP;
 
     /* two relocs per callj under coff. */
     for (fixP = topP; fixP; fixP = fixP->fx_next)
-      {
-       if (fixP->fx_callj && fixP->fx_addsy != 0)
-         {
-           ++seg_reloc_count;
-         }                     /* if callj and not already fixed. */
-      }                                /* for each fix */
+      if (fixP->fx_callj && fixP->fx_addsy != 0)
+       ++seg_reloc_count;
   }
-#endif /* TC_I960 */
+#endif /* OBJ_COFF && TC_I960 */
 
-#endif /* OBJ_COFF */
   return (seg_reloc_count);
 }
 
+#endif /* defined (BFD_ASSEMBLER) || !defined (BFD) */
+
 /* end of write.c */
This page took 0.035498 seconds and 4 git commands to generate.