Additional parsing tests for PA gas.
[deliverable/binutils-gdb.git] / gas / write.c
index 2e7ae833d78ae7dbe2a5d1c485a9c2ee2cd5112a..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
@@ -69,9 +72,10 @@ static fixS *fix_new_internal PARAMS ((fragS *, int where, int size,
                                       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()
@@ -120,6 +124,8 @@ fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
   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
@@ -234,7 +240,7 @@ append (charPP, fromP, length)
   if (length == 0)
     return;
 
-  memcpy (*charPP, fromP, (int) length);
+  memcpy (*charPP, fromP, length);
   *charPP += length;
 }
 
@@ -318,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:
@@ -394,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)
@@ -517,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.  */
@@ -548,6 +573,7 @@ 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);
@@ -560,9 +586,8 @@ write_relocs (abfd, sec, xxx)
      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;
 
@@ -587,7 +612,6 @@ write_relocs (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;
 
@@ -612,6 +636,13 @@ write_relocs (abfd, sec, xxx)
       /* 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)
@@ -633,7 +664,6 @@ write_relocs (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;
@@ -676,7 +706,8 @@ write_relocs (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;
@@ -702,42 +733,40 @@ write_contents (abfd, sec, xxx)
 {
   segment_info_type *seginfo = seg_info (sec);
   unsigned long offset = 0;
-  fragS *frags;
-  int i, n;
-  arelent **relocs;
-  fixS *fixp;
+  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;
@@ -746,7 +775,7 @@ write_contents (abfd, sec, xxx)
 }
 #endif
 
-#if defined(BFD_ASSEMBLER) || !defined (BFD)
+#if defined(BFD_ASSEMBLER) || (!defined (BFD) && !defined(OBJ_AOUT))
 static void
 merge_data_into_text ()
 {
@@ -774,7 +803,7 @@ merge_data_into_text ()
   data_fix_root = NULL;
 #endif
 }
-#endif /* BFD_ASSEMBLER || ! BFD */
+#endif /* BFD_ASSEMBLER || (! BFD && ! OBJ_AOUT) */
 
 #if !defined (BFD_ASSEMBLER) && !defined (BFD)
 static void
@@ -847,6 +876,7 @@ relax_and_size_all_segments ()
   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)
@@ -859,8 +889,6 @@ relax_and_size_all_segments ()
        }                       /* 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);
@@ -875,7 +903,9 @@ 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
@@ -929,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".
@@ -1265,13 +1291,12 @@ 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)
@@ -1298,25 +1323,35 @@ write_object_file ()
                  symp->bsym->flags,
                  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_SYMS
@@ -1344,6 +1379,14 @@ write_object_file ()
              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);
@@ -1507,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;
@@ -1553,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),
@@ -1624,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;
@@ -1631,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)
@@ -1638,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 +=
@@ -1734,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
@@ -1807,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));
@@ -1834,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. */
@@ -1844,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];
@@ -1852,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
              }
          }
 
@@ -1876,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
              {
@@ -1923,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)
          {
@@ -1950,10 +2022,15 @@ fixup_segment (fixP, this_segment_type)
            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
@@ -1962,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 */
 
@@ -1988,4 +2067,6 @@ fixup_segment (fixP, this_segment_type)
   return (seg_reloc_count);
 }
 
+#endif /* defined (BFD_ASSEMBLER) || !defined (BFD) */
+
 /* end of write.c */
This page took 0.029499 seconds and 4 git commands to generate.