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

Cary Coutant ccoutant@google.com
Fri Jul 2 01:03:00 GMT 2010


> SEC_IN_MEMORY isn't sufficient.  Other sections will be SEC_IN_MEMORY
> too, eg. SHT_GROUP sections.  I think your alternate approach of
> twiddling the frag list is indicated.

Here's an updated patch that builds a new frag list. Since a frag
requires the data to follow the struct immediately, it didn't work
with the nice clean interface I added to bfd. It did lead to a more
efficient way of compressing, however: I now just stream each frag
through the compression engine, building new compressed frags as the
compressed data comes out, using the same obstack. At the end, I
replace the old frag list with the new one. I had to move the
zlib-specific code into a separate source file, because I can't
include as.h and zlib.h in the same file.

-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_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..76dcc6e
--- /dev/null
+++ b/gas/compress-debug.c
@@ -0,0 +1,123 @@
+/* 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 "obstack.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_frag (struct z_stream_s *strm ATTRIBUTE_UNUSED,
+	       char *contents ATTRIBUTE_UNUSED,
+	       int in_size ATTRIBUTE_UNUSED,
+	       struct obstack *ob ATTRIBUTE_UNUSED)
+{
+#ifndef HAVE_ZLIB_H
+  return -1;
+#else
+  int out_size = 0;
+  int room;
+  int x;
+
+  strm->next_in = (Bytef *) contents;
+  strm->avail_in = in_size;
+
+  /* Call the deflate routine repeatedly until
+     it has finished processing the frag.  */
+  while (strm->avail_in > 0)
+    {
+      /* 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);
+      strm->next_out = (Bytef *) obstack_next_free (ob) - room;
+      strm->avail_out = room;
+      x = deflate (strm, Z_NO_FLUSH);
+      if (x != Z_OK)
+	return -1;
+
+      /* Return unused space.  */
+      if (strm->avail_out > 0)
+	obstack_blank (ob, -((int) strm->avail_out));
+      out_size += room - strm->avail_out;
+    }
+
+  return out_size;
+#endif /* HAVE_ZLIB_H */
+}
+
+/* Finish the compression and consume the remaining compressed output.  */
+int
+compress_finish (struct z_stream_s *strm ATTRIBUTE_UNUSED,
+		 struct obstack *ob ATTRIBUTE_UNUSED)
+{
+#ifndef HAVE_ZLIB_H
+  return -1;
+#else
+  int out_size = 0;
+  int x;
+
+  for (;;)
+    {
+      obstack_blank (ob, 64);
+      strm->next_out = (Bytef *) obstack_next_free (ob) - 64;
+      strm->avail_out = 64;
+      x = deflate (strm, Z_FINISH);
+      out_size += 64 - strm->avail_out;
+      if (strm->avail_out > 0)
+	obstack_blank (ob, -((int) strm->avail_out));
+      if (x == Z_STREAM_END)
+	break;
+      if (strm->avail_out != 0)
+        return -1;
+    }
+  deflateEnd (strm);
+  return out_size;
+#endif /* HAVE_ZLIB_H */
+}
diff --git a/gas/compress-debug.h b/gas/compress-debug.h
new file mode 100644
index 0000000..c89d4f4
--- /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_frag (struct z_stream_s *, char *, int, struct obstack *);
+
+/* Finish the compression and consume the remaining compressed output.  */
+extern int
+compress_finish (struct z_stream_s *, struct obstack *ob);
+
+#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..d2c61bb 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)
@@ -1289,6 +1290,127 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 }
 
 static void
+compress_debug (bfd *abfd ATTRIBUTE_UNUSED,
+		asection *sec ATTRIBUTE_UNUSED,
+		void *xxx ATTRIBUTE_UNUSED)
+{
+  segment_info_type *seginfo = seg_info (sec);
+  fragS *f;
+  fragS *first_newf;
+  fragS *last_newf;
+  fragS *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.  */
+  obstack_blank (ob, SIZEOF_STRUCT_FRAG + 12);
+  first_newf = (fragS *) obstack_finish (ob);
+  memset (first_newf, 0, SIZEOF_STRUCT_FRAG);
+  first_newf->fr_type = rs_fill;
+  first_newf->fr_fix = 12;
+  header = first_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;
+  last_newf = first_newf;
+  compressed_size = 12;
+
+  /* Stream the frags through the compression engine, adding a new
+     frag of compressed data for each uncompressed frag.  */
+  for (f = seginfo->frchainP->frch_root;
+       f;
+       f = f->fr_next)
+    {
+      offsetT fill_size;
+      char *fill_literal;
+      offsetT count;
+      offsetT out_size;
+      offsetT newf_size = 0;
+
+      obstack_blank (ob, SIZEOF_STRUCT_FRAG);
+
+      gas_assert (f->fr_type == rs_fill);
+      if (f->fr_fix)
+	{
+	  out_size = compress_frag (strm, f->fr_literal, f->fr_fix, ob);
+	  if (out_size < 0)
+	    return;
+	  newf_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, ob);
+	      if (out_size < 0)
+		return;
+	      newf_size += out_size;
+	    }
+	}
+
+      /* If this is the last frag, flush the compression state.  */
+      if (f->fr_next == NULL)
+        {
+	  out_size = compress_finish (strm, ob);
+	  if (out_size < 0)
+	    return;
+	  newf_size += out_size;
+	}
+
+      newf = (fragS *) obstack_finish (ob);
+      memset (newf, 0, SIZEOF_STRUCT_FRAG);
+      newf->fr_type = rs_fill;
+      newf->fr_fix = newf_size;
+      last_newf->fr_next = newf;
+      last_newf = newf;
+      compressed_size += newf_size;
+    }
+
+  /* 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,
 		void *xxx ATTRIBUTE_UNUSED)
@@ -1912,6 +2034,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