bfd/ChangeLog:
authorCary Coutant <ccoutant@google.com>
Sat, 3 Jul 2010 20:52:24 +0000 (20:52 +0000)
committerCary Coutant <ccoutant@google.com>
Sat, 3 Jul 2010 20:52:24 +0000 (20:52 +0000)
* 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.

15 files changed:
bfd/ChangeLog
bfd/compress.c
bfd/dwarf2.c
binutils/ChangeLog
binutils/objdump.c
binutils/readelf.c
gas/ChangeLog
gas/Makefile.am
gas/Makefile.in
gas/as.c
gas/as.h
gas/config.in
gas/configure
gas/configure.in
gas/write.c

index 91ed31f..a18507f 100644 (file)
@@ -1,3 +1,10 @@
+2010-07-03  Cary Coutant  <ccoutant@google.com>
+
+       * compress.c (bfd_uncompress_section_contents): Add ATTRIBUTE_UNUSED.
+       * dwarf2.c (read_and_uncompress_section): New function.
+       (read_section): Call it.
+       (find_line): Likewise.
+
 2010-07-01  Alan Modra  <amodra@gmail.com>
 
        * elf64-ppc.c (ppc64_elf_edit_toc): Use SYMBOL_CALLS_LOCAL rather
index e074eca..fe1b0fd 100644 (file)
@@ -1,4 +1,4 @@
-/* ELF attributes support (based on ARM EABI attributes).
+/* Compressed section support (intended for debug sections).
    Copyright 2008, 2010
    Free Software Foundation, Inc.
 
index 9b194aa..ffe1108 100644 (file)
@@ -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)
index 0007863..74d22ed 100644 (file)
@@ -1,3 +1,10 @@
+2010-07-03  Cary Coutant  <ccoutant@google.com>
+
+       * objdump.c (load_specific_debug_section): Decompress section contents
+       before applying relocations.
+       * readelf.c (load_specific_debug_section): Update section size after
+       decompression.
+
 2010-06-29  Alan Modra  <amodra@gmail.com>
 
        PR binutils/3166
index 2a419b7..f94dee9 100644 (file)
@@ -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;
 }
 
index d4f47ca..1c3cb8b 100644 (file)
@@ -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);
index 86b3c35..50dd6c1 100644 (file)
@@ -1,3 +1,21 @@
+2010-07-03  Cary Coutant  <ccoutant@google.com>
+
+       * 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.
+
 2010-07-03  Andreas Schwab  <schwab@linux-m68k.org>
 
        * config/tc-ppc.c (ppc_set_cpu): Cast PPC_OPCODE_xxx to ppc_cpu_t
index d23b472..6971f73 100644 (file)
@@ -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 \
index 84e2f50..6793520 100644 (file)
@@ -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 \
@@ -771,6 +773,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@
index d617b33..e494fa5 100644 (file)
--- 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;
index 2b2562e..7c16382 100644 (file)
--- 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;
 
index 55f4c9c..c63b1c6 100644 (file)
 /* 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
 
index b466d5f..530fa0d 100755 (executable)
@@ -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
@@ -11193,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 11196 "configure"
+#line 11198 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11299,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 11302 "configure"
+#line 11304 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13984,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
index 4fbf292..0d5e3e1 100644 (file)
@@ -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
index a148b24..71ac635 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)
@@ -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);
 }