[patch] Add --compress-debug-sections option to gas

Cary Coutant ccoutant@google.com
Fri Jul 2 20:46:00 GMT 2010


>> +      /* Reserve all the space we can.  If none is available, force
>> +      the obstack to grow by at least as many bytes as we have
>> +      remaining in the input stream.  */
>> +      room = obstack_room (ob);
>> +      if (room <= 0)
>> +     room = strm->avail_in;
>> +      obstack_blank (ob, room);
> obstack_blank_fast.  You don't really need to zero the mem do you?

In the (room <= 0) case, I needed to use obstack_blank so that it
would reallocate the current obstack object. I wasn't happy with that
approach anyway, since it didn't make effective use of the obstack, so
I've rewritten the patch to fill each new compressed frag until
there's no room left in the current obstack chunk, at which point it
will create another frag (instead of creating one new frag for each
original frag). With this rewrite, the isolation of the zlib interface
is also cleaner.

>> +  /* Create a new frag to contain the "ZLIB" header.  */
>> +  obstack_blank (ob, SIZEOF_STRUCT_FRAG + 12);
>
> You should use frag_alloc here and later where you create frags

I couldn't use frag_alloc because I was relying on obstack_blank
reallocating as necessary, and I needed the frag structure to get
reallocated with the data that followed. With this new patch, I can
now use frag_alloc as you suggest.

Since this new patch changes a bit more than you asked for, I'll wait
for a new approval.

(Side question: I'm puzzled by the alignment stuff in frag_alloc() --
it seems to be setting the alignment mask to 0 before calling
obstack_alloc(). Doesn't that mean that the frag structure will be
allocated on an arbitrary byte boundary?)

(Also: in relax_frag(), I found the following code:

      newf = frag_alloc (ob);
      obstack_blank_fast (ob, fragP->fr_var);
      obstack_finish (ob);

But I couldn't find any code that would guarantee that there was
enough room for the obstack_blank_fast call to succeed. Am I missing
something, or is there a potential bug there?)

Thanks so much for the quick and helpful reviews!

-cary


bfd/ChangeLog:

        * compress.c (bfd_uncompress_section_contents): Add ATTRIBUTE_UNUSED.
        * dwarf2.c (read_and_uncompress_section): New function.
        (read_section): Call it.
        (find_line): Likewise.

binutils/ChangeLog:

        * objdump.c (load_specific_debug_section): Decompress section contents
        before applying relocations.
        * readelf.c (load_specific_debug_section): Update section size after
        decompression.

gas/ChangeLog:

        * Makefile.am: Add compress-debug.c and compress-debug.h.
        * Makefile.in: Regenerate.
        * config.in: Add HAVE_ZLIB_H.
        * configure.in: Check for zlib.h.
        * configure: Regenerate.

        * as.c (parse_args): Add --compress-debug-sections and
        --nocompress-debug-sections.
        * as.h (flag_compress_debug): New variable.
        * compress-debug.c: New file.
        * compress-debug.h: New file.
        * write.c: Include compress-debug.h.
        (compress_frag): New function.
        (compress_debug): New function.
        (write_object_file): Compress debug sections if requested.
-------------- next part --------------
diff --git a/bfd/compress.c b/bfd/compress.c
index 5b6ee0e..323694c 100644
--- a/bfd/compress.c
+++ b/bfd/compress.c
@@ -1,4 +1,4 @@
-/* ELF attributes support (based on ARM EABI attributes).
+/* Compressed section support (intended for debug sections).
    Copyright 2008
    Free Software Foundation, Inc.
 
@@ -51,12 +51,10 @@ DESCRIPTION
 */
 
 bfd_boolean
-bfd_uncompress_section_contents (bfd_byte **buffer, bfd_size_type *size)
+bfd_uncompress_section_contents (bfd_byte **buffer ATTRIBUTE_UNUSED,
+				 bfd_size_type *size ATTRIBUTE_UNUSED)
 {
 #ifndef HAVE_ZLIB_H
-  /* These are just to quiet gcc.  */
-  buffer = 0;
-  size = 0;
   return FALSE;
 #else
   bfd_size_type compressed_size = *size;
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index 9b194aa..ffe1108 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -405,6 +405,54 @@ lookup_info_hash_table (struct info_hash_table *hash_table, const char *key)
   return entry ? entry->head : NULL;
 }
 
+/* Read a section, uncompress it if necessary, and relocate it.  */
+
+static bfd_boolean
+read_and_uncompress_section (bfd *           abfd,
+			     asection *      msec,
+			     bfd_boolean     section_is_compressed,
+			     asymbol **      syms,
+			     bfd_byte **     section_buffer,
+			     bfd_size_type * section_size)
+{
+  /* Get the unrelocated contents of the section.  */
+  *section_buffer = (bfd_byte *) bfd_malloc (*section_size);
+  if (! *section_buffer)
+    return FALSE;
+  if (! bfd_get_section_contents (abfd, msec, *section_buffer,
+				  0, *section_size))
+    return FALSE;
+
+  if (section_is_compressed)
+    {
+      if (! bfd_uncompress_section_contents (section_buffer, section_size))
+	{
+	  (*_bfd_error_handler) (_("Dwarf Error: unable to decompress %s section."),
+				 bfd_get_section_name (abfd, msec));
+	  bfd_set_error (bfd_error_bad_value);
+	  return FALSE;
+	}
+    }
+
+  if (syms)
+    {
+      /* We want to relocate the data we've already read (and
+	 decompressed), so we store a pointer to the data in
+	 the bfd_section, and tell it that the contents are
+	 already in memory.  */
+      BFD_ASSERT (msec->contents == NULL && (msec->flags & SEC_IN_MEMORY) == 0);
+      msec->contents = *section_buffer;
+      msec->flags |= SEC_IN_MEMORY;
+      msec->size = *section_size;
+      *section_buffer
+	  = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
+      if (! *section_buffer)
+	return FALSE;
+    }
+
+  return TRUE;
+}
+
 /* Read a section into its appropriate place in the dwarf2_debug
    struct (indicated by SECTION_BUFFER and SECTION_SIZE).  If SYMS is
    not NULL, use bfd_simple_get_relocated_section_contents to read the
@@ -440,32 +488,10 @@ read_section (bfd *           abfd,
 	}
 
       *section_size = msec->rawsize ? msec->rawsize : msec->size;
-      if (syms)
-	{
-	  *section_buffer
-	      = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
-	  if (! *section_buffer)
-	    return FALSE;
-	}
-      else
-	{
-	  *section_buffer = (bfd_byte *) bfd_malloc (*section_size);
-	  if (! *section_buffer)
-	    return FALSE;
-	  if (! bfd_get_section_contents (abfd, msec, *section_buffer,
-					  0, *section_size))
-	    return FALSE;
-	}
 
-      if (section_is_compressed)
-	{
-	  if (! bfd_uncompress_section_contents (section_buffer, section_size))
-	    {
-	      (*_bfd_error_handler) (_("Dwarf Error: unable to decompress %s section."), compressed_section_name);
-	      bfd_set_error (bfd_error_bad_value);
-	      return FALSE;
-	    }
-	}
+      if (! read_and_uncompress_section (abfd, msec, section_is_compressed,
+					 syms, section_buffer, section_size))
+	return FALSE;
     }
 
   /* It is possible to get a bad value for the offset into the section
@@ -3242,23 +3268,17 @@ find_line (bfd *abfd,
 		{
 		  bfd_size_type size = msec->size;
 		  bfd_byte *buffer, *tmp;
+		  bfd_boolean is_compressed =
+		      strcmp (msec->name, DWARF2_COMPRESSED_DEBUG_INFO) == 0;
 
 		  if (size == 0)
 		    continue;
 
-		  buffer = (bfd_simple_get_relocated_section_contents
-			    (debug_bfd, msec, NULL, symbols));
-		  if (! buffer)
+		  if (! read_and_uncompress_section (debug_bfd, msec,
+		  				     is_compressed, symbols,
+		  				     &buffer, &size))
 		    goto done;
 
-		  if (strcmp (msec->name, DWARF2_COMPRESSED_DEBUG_INFO) == 0)
-		    {
-		      if (! bfd_uncompress_section_contents (&buffer, &size))
-			{
-			  free (buffer);
-			  goto done;
-			}
-		    }
 		  tmp = (bfd_byte *) bfd_realloc (stash->info_ptr_memory,
 						  total_size + size);
 		  if (tmp == NULL)
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 2a419b7..f94dee9 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -2205,14 +2205,8 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
   section->size = bfd_get_section_size (sec);
   section->start = (unsigned char *) xmalloc (section->size);
 
-  if (is_relocatable && debug_displays [debug].relocate)
-    ret = bfd_simple_get_relocated_section_contents (abfd,
-						     sec,
-						     section->start,
-						     syms) != NULL;
-  else
-    ret = bfd_get_section_contents (abfd, sec, section->start, 0,
-				    section->size);
+  ret = bfd_get_section_contents (abfd, sec, section->start, 0,
+				  section->size);
 
   if (! ret)
     {
@@ -2234,6 +2228,30 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
       section->size = size;
     }
 
+  if (is_relocatable && debug_displays [debug].relocate)
+    {
+      /* We want to relocate the data we've already read (and
+         decompressed), so we store a pointer to the data in
+         the bfd_section, and tell it that the contents are
+         already in memory.  */
+      sec->contents = section->start;
+      sec->flags |= SEC_IN_MEMORY;
+      sec->size = section->size;
+
+      ret = bfd_simple_get_relocated_section_contents (abfd,
+						       sec,
+						       section->start,
+						       syms) != NULL;
+
+      if (! ret)
+        {
+          free_debug_section (debug);
+          printf (_("\nCan't get contents for section '%s'.\n"),
+	          section->name);
+          return 0;
+        }
+    }
+
   return 1;
 }
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index d4f47ca..1c3cb8b 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -9962,8 +9962,11 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
     return 0;
 
   if (section_is_compressed)
-    if (! uncompress_section_contents (&section->start, &section->size))
-      return 0;
+    {
+      if (! uncompress_section_contents (&section->start, &section->size))
+        return 0;
+      sec->sh_size = section->size;
+    }
 
   if (debug_displays [debug].relocate)
     apply_relocations ((FILE *) file, sec, section->start);
diff --git a/gas/Makefile.am b/gas/Makefile.am
index 36ae957..f2c0fe8 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -43,6 +43,7 @@ GAS_CFILES = \
 	app.c \
 	as.c \
 	atof-generic.c \
+	compress-debug.c \
 	cond.c \
 	depend.c \
 	dwarf2dbg.c \
@@ -78,6 +79,7 @@ HFILES = \
 	bignum.h \
 	bit_fix.h \
 	cgen.h \
+	compress-debug.h \
 	dwarf2dbg.h \
 	dw2gencfi.h \
 	ecoff.h \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index 5b3521b..0487170 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -73,14 +73,14 @@ CONFIG_CLEAN_FILES = gdb.ini .gdbinit po/Makefile.in
 CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
 am__objects_1 = app.$(OBJEXT) as.$(OBJEXT) atof-generic.$(OBJEXT) \
-	cond.$(OBJEXT) depend.$(OBJEXT) dwarf2dbg.$(OBJEXT) \
-	dw2gencfi.$(OBJEXT) ecoff.$(OBJEXT) ehopt.$(OBJEXT) \
-	expr.$(OBJEXT) flonum-copy.$(OBJEXT) flonum-konst.$(OBJEXT) \
-	flonum-mult.$(OBJEXT) frags.$(OBJEXT) hash.$(OBJEXT) \
-	input-file.$(OBJEXT) input-scrub.$(OBJEXT) listing.$(OBJEXT) \
-	literal.$(OBJEXT) macro.$(OBJEXT) messages.$(OBJEXT) \
-	output-file.$(OBJEXT) read.$(OBJEXT) remap.$(OBJEXT) \
-	sb.$(OBJEXT) stabs.$(OBJEXT) subsegs.$(OBJEXT) \
+	compress-debug.$(OBJEXT) cond.$(OBJEXT) depend.$(OBJEXT) \
+	dwarf2dbg.$(OBJEXT) dw2gencfi.$(OBJEXT) ecoff.$(OBJEXT) \
+	ehopt.$(OBJEXT) expr.$(OBJEXT) flonum-copy.$(OBJEXT) \
+	flonum-konst.$(OBJEXT) flonum-mult.$(OBJEXT) frags.$(OBJEXT) \
+	hash.$(OBJEXT) input-file.$(OBJEXT) input-scrub.$(OBJEXT) \
+	listing.$(OBJEXT) literal.$(OBJEXT) macro.$(OBJEXT) \
+	messages.$(OBJEXT) output-file.$(OBJEXT) read.$(OBJEXT) \
+	remap.$(OBJEXT) sb.$(OBJEXT) stabs.$(OBJEXT) subsegs.$(OBJEXT) \
 	symbols.$(OBJEXT) write.$(OBJEXT)
 am_as_new_OBJECTS = $(am__objects_1)
 as_new_OBJECTS = $(am_as_new_OBJECTS)
@@ -311,6 +311,7 @@ GAS_CFILES = \
 	app.c \
 	as.c \
 	atof-generic.c \
+	compress-debug.c \
 	cond.c \
 	depend.c \
 	dwarf2dbg.c \
@@ -345,6 +346,7 @@ HFILES = \
 	bignum.h \
 	bit_fix.h \
 	cgen.h \
+	compress-debug.h \
 	dwarf2dbg.h \
 	dw2gencfi.h \
 	ecoff.h \
@@ -773,6 +775,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atof-vax.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfin-parse.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compress-debug.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cond.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/depend.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dw2gencfi.Po@am__quote@
diff --git a/gas/as.c b/gas/as.c
index d617b33..e494fa5 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -437,7 +437,9 @@ parse_args (int * pargc, char *** pargv)
       OPTION_AL,
       OPTION_HASH_TABLE_SIZE,
       OPTION_REDUCE_MEMORY_OVERHEADS,
-      OPTION_WARN_FATAL
+      OPTION_WARN_FATAL,
+      OPTION_COMPRESS_DEBUG,
+      OPTION_NOCOMPRESS_DEBUG
     /* When you add options here, check that they do
        not collide with OPTION_MD_BASE.  See as.h.  */
     };
@@ -455,6 +457,8 @@ parse_args (int * pargc, char *** pargv)
     ,{"a", optional_argument, NULL, 'a'}
     /* Handle -al=<FILE>.  */
     ,{"al", optional_argument, NULL, OPTION_AL}
+    ,{"compress-debug-sections", no_argument, NULL, OPTION_COMPRESS_DEBUG}
+    ,{"nocompress-debug-sections", no_argument, NULL, OPTION_NOCOMPRESS_DEBUG}
     ,{"debug-prefix-map", required_argument, NULL, OPTION_DEBUG_PREFIX_MAP}
     ,{"defsym", required_argument, NULL, OPTION_DEFSYM}
     ,{"dump-config", no_argument, NULL, OPTION_DUMPCONFIG}
@@ -634,6 +638,14 @@ This program has absolutely no warranty.\n"));
 #endif
 	  exit (EXIT_SUCCESS);
 
+	case OPTION_COMPRESS_DEBUG:
+	  flag_compress_debug = 1;
+	  break;
+
+	case OPTION_NOCOMPRESS_DEBUG:
+	  flag_compress_debug = 0;
+	  break;
+
 	case OPTION_DEBUG_PREFIX_MAP:
 	  add_debug_prefix_map (optarg);
 	  break;
diff --git a/gas/as.h b/gas/as.h
index 2b2562e..7c16382 100644
--- a/gas/as.h
+++ b/gas/as.h
@@ -365,6 +365,9 @@ COMMON int flag_strip_local_absolute;
 /* True if we should generate a traditional format object file.  */
 COMMON int flag_traditional_format;
 
+/* TRUE if debug sections should be compressed.  */
+COMMON int flag_compress_debug;
+
 /* TRUE if .note.GNU-stack section with SEC_CODE should be created */
 COMMON int flag_execstack;
 
diff --git a/gas/compress-debug.c b/gas/compress-debug.c
new file mode 100644
index 0000000..c2a8d3d
--- /dev/null
+++ b/gas/compress-debug.c
@@ -0,0 +1,119 @@
+/* compress-debug.c - compress debug sections
+   Copyright 2010 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GAS is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include <stdio.h>
+
+#include "ansidecl.h"
+
+#include "config.h"
+#include "compress-debug.h"
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+/* Initialize the compression engine.  */
+
+struct z_stream_s *
+compress_init (void)
+{
+#ifndef HAVE_ZLIB_H
+  return NULL;
+#else
+  static struct z_stream_s strm;
+
+  strm.zalloc = NULL;
+  strm.zfree = NULL;
+  strm.opaque = NULL;
+  deflateInit (&strm, Z_DEFAULT_COMPRESSION);
+  return &strm;
+#endif /* HAVE_ZLIB_H */
+}
+
+/* Stream the contents of a frag to the compression engine.  Output
+   from the engine goes into the current frag on the obstack.  */
+
+int
+compress_data (struct z_stream_s *strm ATTRIBUTE_UNUSED,
+	       const char **next_in ATTRIBUTE_UNUSED,
+	       int *avail_in ATTRIBUTE_UNUSED,
+	       char **next_out ATTRIBUTE_UNUSED,
+	       int *avail_out ATTRIBUTE_UNUSED)
+{
+#ifndef HAVE_ZLIB_H
+  return -1;
+#else
+  int out_size = 0;
+  int x;
+
+  strm->next_in = (Bytef *) (*next_in);
+  strm->avail_in = *avail_in;
+  strm->next_out = (Bytef *) (*next_out);
+  strm->avail_out = *avail_out;
+
+  x = deflate (strm, Z_NO_FLUSH);
+  if (x != Z_OK)
+    return -1;
+
+  out_size = *avail_out - strm->avail_out;
+  *next_in = (char *) (strm->next_in);
+  *avail_in = strm->avail_in;
+  *next_out = (char *) (strm->next_out);
+  *avail_out = strm->avail_out;
+
+  return out_size;
+#endif /* HAVE_ZLIB_H */
+}
+
+/* Finish the compression and consume the remaining compressed output.
+   Returns -1 for error, 0 when done, 1 when more output buffer is
+   needed.  */
+
+int
+compress_finish (struct z_stream_s *strm ATTRIBUTE_UNUSED,
+		 char **next_out ATTRIBUTE_UNUSED,
+		 int *avail_out ATTRIBUTE_UNUSED,
+		 int *out_size ATTRIBUTE_UNUSED)
+{
+#ifndef HAVE_ZLIB_H
+  return -1;
+#else
+  int x;
+
+  strm->avail_in = 0;
+  strm->next_out = (Bytef *) (*next_out);
+  strm->avail_out = *avail_out;
+
+  x = deflate (strm, Z_FINISH);
+
+  *out_size = *avail_out - strm->avail_out;
+  *next_out = (char *) (strm->next_out);
+  *avail_out = strm->avail_out;
+
+  if (x == Z_STREAM_END)
+    {
+      deflateEnd (strm);
+      return 0;
+    }
+  if (strm->avail_out != 0)
+    return -1;
+  return 1;
+#endif /* HAVE_ZLIB_H */
+}
diff --git a/gas/compress-debug.h b/gas/compress-debug.h
new file mode 100644
index 0000000..9d821e9
--- /dev/null
+++ b/gas/compress-debug.h
@@ -0,0 +1,39 @@
+/* compress-debug.h - Header file for compressed debug sections.
+   Copyright 2010 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GAS is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#ifndef COMPRESS_DEBUG_H
+#define COMPRESS_DEBUG_H
+
+struct z_stream_s;
+
+/* Initialize the compression engine.  */
+extern struct z_stream_s *
+compress_init (void);
+
+/* Stream the contents of a frag to the compression engine.  Output
+   from the engine goes into the current frag on the obstack.  */
+extern int
+compress_data (struct z_stream_s *, const char **, int *, char **, int *);
+
+/* Finish the compression and consume the remaining compressed output.  */
+extern int
+compress_finish (struct z_stream_s *, char **, int *, int *);
+
+#endif /* COMPRESS_DEBUG_H */
diff --git a/gas/config.in b/gas/config.in
index 55f4c9c..c63b1c6 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -114,6 +114,9 @@
 /* Define to 1 if you have the `unlink' function. */
 #undef HAVE_UNLINK
 
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
 /* Using i386 COFF? */
 #undef I386COFF
 
diff --git a/gas/configure b/gas/configure
index 1781b4e..530fa0d 100755
--- a/gas/configure
+++ b/gas/configure
@@ -766,6 +766,7 @@ enable_werror
 enable_build_warnings
 enable_nls
 enable_maintainer_mode
+with_zlib
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1419,6 +1420,7 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-zlib             include zlib support (auto/yes/no) default=auto
 
 Some influential environment variables:
   CC          C compiler command
@@ -1869,8 +1871,10 @@ $as_echo "$ac_res" >&6; }
 ac_fn_c_check_decl ()
 {
   as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5
-$as_echo_n "checking whether $2 is declared... " >&6; }
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
 if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 else
@@ -1880,8 +1884,12 @@ $4
 int
 main ()
 {
-#ifndef $2
-  (void) $2;
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
 #endif
 
   ;
@@ -11187,7 +11195,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11190 "configure"
+#line 11198 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11293,7 +11301,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11296 "configure"
+#line 11304 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13978,6 +13986,92 @@ $as_echo "#define USE_BINARY_FOPEN 1" >>confdefs.h
  ;;
 esac
 
+# Link in zlib if we can.  This allows us to write compressed debug sections.
+
+  # See if the user specified whether he wants zlib support or not.
+
+# Check whether --with-zlib was given.
+if test "${with_zlib+set}" = set; then :
+  withval=$with_zlib;
+else
+  with_zlib=auto
+fi
+
+
+  if test "$with_zlib" != "no"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing zlibVersion" >&5
+$as_echo_n "checking for library containing zlibVersion... " >&6; }
+if test "${ac_cv_search_zlibVersion+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char zlibVersion ();
+int
+main ()
+{
+return zlibVersion ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' z; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_zlibVersion=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_zlibVersion+set}" = set; then :
+  break
+fi
+done
+if test "${ac_cv_search_zlibVersion+set}" = set; then :
+
+else
+  ac_cv_search_zlibVersion=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_zlibVersion" >&5
+$as_echo "$ac_cv_search_zlibVersion" >&6; }
+ac_res=$ac_cv_search_zlibVersion
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+  for ac_header in zlib.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_zlib_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_ZLIB_H 1
+_ACEOF
+
+fi
+
+done
+
+fi
+
+    if test "$with_zlib" = "yes" -a "$ac_cv_header_zlib_h" != "yes"; then
+      as_fn_error "zlib (libz) library was explicitly requested but not found" "$LINENO" 5
+    fi
+  fi
+
+
 # Support for VMS timestamps via cross compile
 
 if test "$ac_cv_header_time_h" = yes; then
diff --git a/gas/configure.in b/gas/configure.in
index 4fbf292..0d5e3e1 100644
--- a/gas/configure.in
+++ b/gas/configure.in
@@ -709,6 +709,9 @@ AC_CHECK_DECLS([vsnprintf])
 
 BFD_BINARY_FOPEN
 
+# Link in zlib if we can.  This allows us to write compressed debug sections.
+AM_ZLIB
+
 # Support for VMS timestamps via cross compile
 
 if test "$ac_cv_header_time_h" = yes; then
diff --git a/gas/write.c b/gas/write.c
index a148b24..71ac635 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -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)
@@ -1288,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,
@@ -1912,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);
 }
 


More information about the Binutils mailing list