gdb/ChangeLog:* gdb/valarith.c (vector_binop): New function.(scalar_binop): Likewise...
[binutils-gdb.git] / gas / write.c
index 1ded21f94fb51b80c639a3484f2d778cb055632c..71ac63562c9d5e28a346aa124e77114afd9acbda 100644 (file)
@@ -28,6 +28,7 @@
 #include "output-file.h"
 #include "dwarf2dbg.h"
 #include "libbfd.h"
+#include "compress-debug.h"
 
 #ifndef TC_ADJUST_RELOC_COUNT
 #define TC_ADJUST_RELOC_COUNT(FIX, COUNT)
@@ -150,7 +151,8 @@ fix_new_internal (fragS *frag,              /* Which frag?  */
                  symbolS *sub_symbol,  /* X_op_symbol.  */
                  offsetT offset,       /* X_add_number.  */
                  int pcrel,            /* TRUE if PC-relative relocation.  */
-                 RELOC_ENUM r_type ATTRIBUTE_UNUSED /* Relocation type.  */)
+                 RELOC_ENUM r_type ATTRIBUTE_UNUSED /* Relocation type.  */,
+                 int at_beginning)     /* Add to the start of the list?  */
 {
   fixS *fixP;
 
@@ -194,10 +196,6 @@ fix_new_internal (fragS *frag,             /* Which frag?  */
 
   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
-     time option.  xoxorich.  */
   {
 
     fixS **seg_fix_rootP = (frags_chained
@@ -207,22 +205,22 @@ fix_new_internal (fragS *frag,            /* Which frag?  */
                            ? &seg_info (now_seg)->fix_tail
                            : &frchain_now->fix_tail);
 
-#ifdef REVERSE_SORT_RELOCS
-
-    fixP->fx_next = *seg_fix_rootP;
-    *seg_fix_rootP = fixP;
-
-#else /* REVERSE_SORT_RELOCS  */
-
-    fixP->fx_next = NULL;
-
-    if (*seg_fix_tailP)
-      (*seg_fix_tailP)->fx_next = fixP;
+    if (at_beginning)
+      {
+       fixP->fx_next = *seg_fix_rootP;
+       *seg_fix_rootP = fixP;
+       if (fixP->fx_next == NULL)
+         *seg_fix_tailP = fixP;
+      }
     else
-      *seg_fix_rootP = fixP;
-    *seg_fix_tailP = fixP;
-
-#endif /* REVERSE_SORT_RELOCS  */
+      {
+       fixP->fx_next = NULL;
+       if (*seg_fix_tailP)
+         (*seg_fix_tailP)->fx_next = fixP;
+       else
+         *seg_fix_rootP = fixP;
+       *seg_fix_tailP = fixP;
+      }
   }
 
   return fixP;
@@ -240,7 +238,7 @@ fix_new (fragS *frag,               /* Which frag?  */
         RELOC_ENUM r_type              /* Relocation type.  */)
 {
   return fix_new_internal (frag, where, size, add_symbol,
-                          (symbolS *) NULL, offset, pcrel, r_type);
+                          (symbolS *) NULL, offset, pcrel, r_type, FALSE);
 }
 
 /* Create a fixup for an expression.  Currently we only support fixups
@@ -308,7 +306,19 @@ fix_new_exp (fragS *frag,          /* Which frag?  */
       break;
     }
 
-  return fix_new_internal (frag, where, size, add, sub, off, pcrel, r_type);
+  return fix_new_internal (frag, where, size, add, sub, off, pcrel,
+                          r_type, FALSE);
+}
+
+/* Create a fixup at the beginning of FRAG.  The arguments are the same
+   as for fix_new, except that WHERE is implicitly 0.  */
+
+fixS *
+fix_at_start (fragS *frag, int size, symbolS *add_symbol,
+             offsetT offset, int pcrel, RELOC_ENUM r_type)
+{
+  return fix_new_internal (frag, 0, size, add_symbol,
+                          (symbolS *) NULL, offset, pcrel, r_type, TRUE);
 }
 
 /* Generic function to determine whether a fixup requires a relocation.  */
@@ -1279,6 +1289,194 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 #endif
 }
 
+static int
+compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
+              fragS **last_newf, struct obstack *ob)
+{
+  int out_size;
+  int total_out_size = 0;
+  fragS *f = *last_newf;
+  char *next_out;
+  int avail_out;
+
+  /* Call the compression routine repeatedly until it has finished
+     processing the frag.  */
+  while (in_size > 0)
+    {
+      /* Reserve all the space available in the current chunk.
+         If none is available, start a new frag.  */
+      avail_out = obstack_room (ob);
+      if (avail_out <= 0)
+        {
+          obstack_finish (ob);
+          f = frag_alloc (ob);
+         f->fr_type = rs_fill;
+          (*last_newf)->fr_next = f;
+          *last_newf = f;
+          avail_out = obstack_room (ob);
+        }
+      if (avail_out <= 0)
+       as_fatal (_("can't extend frag"));
+      next_out = obstack_next_free (ob);
+      obstack_blank_fast (ob, avail_out);
+      out_size = compress_data (strm, &contents, &in_size,
+                               &next_out, &avail_out);
+      if (out_size < 0)
+        return -1;
+
+      f->fr_fix += out_size;
+      total_out_size += out_size;
+
+      /* Return unused space.  */
+      if (avail_out > 0)
+       obstack_blank_fast (ob, -avail_out);
+    }
+
+  return total_out_size;
+}
+
+static void
+compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
+{
+  segment_info_type *seginfo = seg_info (sec);
+  fragS *f;
+  fragS *first_newf;
+  fragS *last_newf;
+  struct obstack *ob = &seginfo->frchainP->frch_obstack;
+  bfd_size_type uncompressed_size = (bfd_size_type) sec->size;
+  bfd_size_type compressed_size;
+  const char *section_name;
+  char *compressed_name;
+  char *header;
+  struct z_stream_s *strm;
+  int x;
+
+  if (seginfo == NULL
+      || !(bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
+      || (bfd_get_section_flags (abfd, sec) & SEC_ALLOC))
+    return;
+
+  section_name = bfd_get_section_name (stdoutput, sec);
+  if (strncmp (section_name, ".debug_", 7) != 0)
+    return;
+
+  strm = compress_init ();
+  if (strm == NULL)
+    return;
+
+  /* Create a new frag to contain the "ZLIB" header.  */
+  first_newf = frag_alloc (ob);
+  if (obstack_room (ob) < 12)
+    first_newf = frag_alloc (ob);
+  if (obstack_room (ob) < 12)
+    as_fatal (_("can't extend frag %u chars"), 12);
+  last_newf = first_newf;
+  obstack_blank_fast (ob, 12);
+  last_newf->fr_type = rs_fill;
+  last_newf->fr_fix = 12;
+  header = last_newf->fr_literal;
+  memcpy (header, "ZLIB", 4);
+  header[11] = uncompressed_size; uncompressed_size >>= 8;
+  header[10] = uncompressed_size; uncompressed_size >>= 8;
+  header[9] = uncompressed_size; uncompressed_size >>= 8;
+  header[8] = uncompressed_size; uncompressed_size >>= 8;
+  header[7] = uncompressed_size; uncompressed_size >>= 8;
+  header[6] = uncompressed_size; uncompressed_size >>= 8;
+  header[5] = uncompressed_size; uncompressed_size >>= 8;
+  header[4] = uncompressed_size;
+  compressed_size = 12;
+
+  /* Stream the frags through the compression engine, adding new frags
+     as necessary to accomodate the compressed output.  */
+  for (f = seginfo->frchainP->frch_root;
+       f;
+       f = f->fr_next)
+    {
+      offsetT fill_size;
+      char *fill_literal;
+      offsetT count;
+      int out_size;
+
+      gas_assert (f->fr_type == rs_fill);
+      if (f->fr_fix)
+       {
+         out_size = compress_frag (strm, f->fr_literal, f->fr_fix,
+                                   &last_newf, ob);
+         if (out_size < 0)
+           return;
+         compressed_size += out_size;
+       }
+      fill_literal = f->fr_literal + f->fr_fix;
+      fill_size = f->fr_var;
+      count = f->fr_offset;
+      gas_assert (count >= 0);
+      if (fill_size && count)
+       {
+         while (count--)
+           {
+             out_size = compress_frag (strm, fill_literal, (int) fill_size,
+                                       &last_newf, ob);
+             if (out_size < 0)
+               return;
+             compressed_size += out_size;
+           }
+       }
+    }
+
+  /* Flush the compression state.  */
+  for (;;)
+    {
+      int avail_out;
+      char *next_out;
+      int out_size;
+
+      /* Reserve all the space available in the current chunk.
+        If none is available, start a new frag.  */
+      avail_out = obstack_room (ob);
+      if (avail_out <= 0)
+       {
+         fragS *newf;
+
+         obstack_finish (ob);
+         newf = frag_alloc (ob);
+         newf->fr_type = rs_fill;
+         last_newf->fr_next = newf;
+         last_newf = newf;
+         avail_out = obstack_room (ob);
+       }
+      if (avail_out <= 0)
+       as_fatal (_("can't extend frag"));
+      next_out = obstack_next_free (ob);
+      obstack_blank_fast (ob, avail_out);
+      x = compress_finish (strm, &next_out, &avail_out, &out_size);
+      if (x < 0)
+       return;
+
+      last_newf->fr_fix += out_size;
+      compressed_size += out_size;
+
+      /* Return unused space.  */
+      if (avail_out > 0)
+       obstack_blank_fast (ob, -avail_out);
+
+      if (x == 0)
+       break;
+    }
+
+  /* Replace the uncompressed frag list with the compressed frag list.  */
+  seginfo->frchainP->frch_root = first_newf;
+  seginfo->frchainP->frch_last = last_newf;
+
+  /* Update the section size and its name.  */
+  x = bfd_set_section_size (abfd, sec, compressed_size);
+  gas_assert (x);
+  compressed_name = (char *) xmalloc (strlen (section_name) + 2);
+  compressed_name[0] = '.';
+  compressed_name[1] = 'z';
+  strcpy (compressed_name + 2, section_name + 1);
+  bfd_section_name (stdoutput, sec) = compressed_name;
+}
+
 static void
 write_contents (bfd *abfd ATTRIBUTE_UNUSED,
                asection *sec,
@@ -1903,6 +2101,13 @@ write_object_file (void)
   obj_frob_file_after_relocs ();
 #endif
 
+  /* Once all relocations have been written, we can compress the
+     contents of the debug sections.  This needs to be done before
+     we start writing any sections, because it will affect the file
+     layout, which is fixed once we start writing contents.  */
+  if (flag_compress_debug)
+    bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
+
   bfd_map_over_sections (stdoutput, write_contents, (char *) 0);
 }