Add --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 15 Apr 2015 05:01:25 +0000 (22:01 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 15 Apr 2015 05:01:38 +0000 (22:01 -0700)
This patch adds --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]
to ld for ELF targets to support generating compressed DWARF debug
sections.  We always generate .zdebug_* section since section names have
been finalized and they can't be changed easily when compression is
being performed.

bfd/

* bfd-in.h (compressed_debug_section_type): New.
* compress.c (bfd_compress_section_contents): Add an argument
for linker write compression and always generate .zdebug_*
section when linking.
(bfd_init_section_compress_status): Pass FALSE to
bfd_compress_section_contents.
(bfd_compress_section): New function.
* elf.c (elf_fake_sections): For linking, set SEC_ELF_COMPRESS
on DWARF debug sections if COMPRESS_DEBUG is set and rename
section if COMPRESS_DEBUG_GABI_ZLIB isn't set.
(assign_file_positions_for_non_load_sections): Set sh_offset
to -1 if SEC_ELF_COMPRESS is set.
(assign_file_positions_except_relocs): Likwise.
(_bfd_elf_assign_file_positions_for_relocs): Renamed to ...
(_bfd_elf_assign_file_positions_for_non_load): This.  Change
return time to bfd_boolean.  Compress the section if
SEC_ELF_COMPRESS is set.
(_bfd_elf_write_object_contents): Updated.
(_bfd_elf_set_section_contents): Write section contents to
the buffer if SEC_ELF_COMPRESS is set.
* merge.c: Include "elf-bfd.h".
(sec_merge_emit): Add arguments for contents and offset.  Write
to contents with offset if contents isn't NULL.
(_bfd_write_merged_section): Write section contents to the
buffer if SEC_ELF_COMPRESS is set.  Pass contents and
output_offset to sec_merge_emit.
* elflink.c (bfd_elf_final_link): Allocate the buffer for
output section contents if SEC_ELF_COMPRESS is set.
* section.c (SEC_ELF_COMPRESS): New.
* bfd-in2.h: Regenerated.

gas/

* as.h (compressed_debug_section_type): Removed.

include/

* bfdlink.h (bfd_link_info): Add compress_debug.

ld/

* ld.texinfo: Document --compress-debug-sections=.
* ldmain.c (main): Set BFD_COMPRESS on output_bfd if
COMPRESS_DEBUG is set.  Set BFD_COMPRESS_GABI on output_bfd
for COMPRESS_DEBUG_GABI_ZLIB.
* lexsup.c (elf_static_list_options): Add
--compress-debug-sections=.
* emultempl/elf32.em (OPTION_COMPRESS_DEBUG): New.
(xtra_long): Add "compress-debug-sections".
(gld${EMULATION_NAME}_handle_option): Handle
OPTION_COMPRESS_DEBUG.

ld/testsuite/

* ld-elf/compress.exp (build_tests): Add tests for
--compress-debug-sections=.
(run_tests): Likewise.
Add additonal tests for --compress-debug-sections=.
* ld-elf/gabiend.rt: New file.
* ld-elf/gabinormal.rt: Likewise.
* ld-elf/gnubegin.rS: Likewise.
* ld-elf/gnunormal.rS: Likewise.
* ld-elf/zlibbegin.rS: Likewise.
* ld-elf/zlibnormal.rS: Likewise.

25 files changed:
bfd/ChangeLog
bfd/bfd-in.h
bfd/bfd-in2.h
bfd/compress.c
bfd/elf.c
bfd/elflink.c
bfd/merge.c
bfd/section.c
gas/ChangeLog
gas/as.h
include/ChangeLog
include/bfdlink.h
ld/ChangeLog
ld/emultempl/elf32.em
ld/ld.texinfo
ld/ldmain.c
ld/lexsup.c
ld/testsuite/ChangeLog
ld/testsuite/ld-elf/compress.exp
ld/testsuite/ld-elf/gabiend.rt [new file with mode: 0644]
ld/testsuite/ld-elf/gabinormal.rt [new file with mode: 0644]
ld/testsuite/ld-elf/gnubegin.rS [new file with mode: 0644]
ld/testsuite/ld-elf/gnunormal.rS [new file with mode: 0644]
ld/testsuite/ld-elf/zlibbegin.rS [new file with mode: 0644]
ld/testsuite/ld-elf/zlibnormal.rS [new file with mode: 0644]

index 17610e06ef87f99c7abc9d1ab66e4a685b212a59..abb87dc88c4dc970ccf84f5f40275a352aa6e0cb 100644 (file)
@@ -1,3 +1,36 @@
+2015-04-14  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * bfd-in.h (compressed_debug_section_type): New.
+       * compress.c (bfd_compress_section_contents): Add an argument
+       for linker write compression and always generate .zdebug_*
+       section when linking.
+       (bfd_init_section_compress_status): Pass FALSE to
+       bfd_compress_section_contents.
+       (bfd_compress_section): New function.
+       * elf.c (elf_fake_sections): For linking, set SEC_ELF_COMPRESS
+       on DWARF debug sections if COMPRESS_DEBUG is set and rename
+       section if COMPRESS_DEBUG_GABI_ZLIB isn't set.
+       (assign_file_positions_for_non_load_sections): Set sh_offset
+       to -1 if SEC_ELF_COMPRESS is set.
+       (assign_file_positions_except_relocs): Likwise.
+       (_bfd_elf_assign_file_positions_for_relocs): Renamed to ...
+       (_bfd_elf_assign_file_positions_for_non_load): This.  Change
+       return time to bfd_boolean.  Compress the section if
+       SEC_ELF_COMPRESS is set.
+       (_bfd_elf_write_object_contents): Updated.
+       (_bfd_elf_set_section_contents): Write section contents to
+       the buffer if SEC_ELF_COMPRESS is set.
+       * merge.c: Include "elf-bfd.h".
+       (sec_merge_emit): Add arguments for contents and offset.  Write
+       to contents with offset if contents isn't NULL.
+       (_bfd_write_merged_section): Write section contents to the
+       buffer if SEC_ELF_COMPRESS is set.  Pass contents and
+       output_offset to sec_merge_emit.
+       * elflink.c (bfd_elf_final_link): Allocate the buffer for
+       output section contents if SEC_ELF_COMPRESS is set.
+       * section.c (SEC_ELF_COMPRESS): New.
+       * bfd-in2.h: Regenerated.
+
 2015-04-15  Alan Modra  <amodra@gmail.com>
 
        * elf32-rl78.c (rl78_elf_relocate_section): Typo fix.
index 1f8a72c40eb3efceac0c6d063546d73ae6a59080..2e324cdc9e9f943c0823b206fcc2fad5484f8c75 100644 (file)
@@ -437,6 +437,17 @@ extern void bfd_hash_traverse
    this size.  */
 extern unsigned long bfd_hash_set_default_size (unsigned long);
 
+/* Types of compressed DWARF debug sections.  We currently support
+   zlib.  */
+enum compressed_debug_section_type
+{
+  COMPRESS_DEBUG_NONE = 0,
+  COMPRESS_DEBUG = 1 << 0,
+  COMPRESS_DEBUG_ZLIB = COMPRESS_DEBUG | 1 << 1,
+  COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 2,
+  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 3
+};
+
 /* This structure is used to keep track of stabs in sections
    information while linking.  */
 
index 679595e0c5add8545d79492704fe83ab136bffc7..122caa09ff432d4ddb3154a0df1aa6b7ee4f2f6c 100644 (file)
@@ -444,6 +444,17 @@ extern void bfd_hash_traverse
    this size.  */
 extern unsigned long bfd_hash_set_default_size (unsigned long);
 
+/* Types of compressed DWARF debug sections.  We currently support
+   zlib.  */
+enum compressed_debug_section_type
+{
+  COMPRESS_DEBUG_NONE = 0,
+  COMPRESS_DEBUG = 1 << 0,
+  COMPRESS_DEBUG_ZLIB = COMPRESS_DEBUG | 1 << 1,
+  COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 2,
+  COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 3
+};
+
 /* This structure is used to keep track of stabs in sections
    information while linking.  */
 
@@ -1378,6 +1389,10 @@ typedef struct bfd_section
      executables or shared objects. This is for COFF only.  */
 #define SEC_COFF_SHARED 0x8000000
 
+  /* This section should be compressed.  This is for ELF linker
+     internal use only.  */
+#define SEC_ELF_COMPRESS 0x8000000
+
   /* When a section with this flag is being linked, then if the size of
      the input section is less than a page, it should not cross a page
      boundary.  If the size of the input section is one page or more,
@@ -7316,6 +7331,9 @@ bfd_boolean bfd_init_section_decompress_status
 bfd_boolean bfd_init_section_compress_status
    (bfd *abfd, asection *section);
 
+bfd_boolean bfd_compress_section
+   (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer);
+
 #ifdef __cplusplus
 }
 #endif
index 770ea570d48b69313b8ac7ac7560d0d5c241d592..dfde50e81c6b57ec4e4618063a168b5e6865fd5e 100644 (file)
@@ -72,7 +72,8 @@ decompress_contents (bfd_byte *compressed_buffer,
 static bfd_size_type
 bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
                               bfd_byte *uncompressed_buffer,
-                              bfd_size_type uncompressed_size)
+                              bfd_size_type uncompressed_size,
+                              bfd_boolean write_compress)
 {
   uLong compressed_size;
   bfd_byte *buffer;
@@ -176,8 +177,11 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
 
       compressed_size += header_size;
       /* PR binutils/18087: If compression didn't make the section smaller,
-        just keep it uncompressed.  */
-      if (compressed_size < uncompressed_size)
+        just keep it uncompressed.  We always generate .zdebug_* section
+        when linking since section names have been finalized and they
+        can't be changed easily.  */
+      if ((write_compress && compression_header_size == 0)
+          || compressed_size < uncompressed_size)
        {
          bfd_update_compression_header (abfd, buffer, sec);
 
@@ -543,9 +547,48 @@ bfd_init_section_compress_status (bfd *abfd, sec_ptr sec)
     {
       uncompressed_size = bfd_compress_section_contents (abfd, sec,
                                                         uncompressed_buffer,
-                                                        uncompressed_size);
+                                                        uncompressed_size,
+                                                        FALSE);
       ret = uncompressed_size != 0;
     }
 
   return ret;
 }
+
+/*
+FUNCTION
+       bfd_compress_section
+
+SYNOPSIS
+       bfd_boolean bfd_compress_section
+         (bfd *abfd, asection *section, bfd_byte *uncompressed_buffer);
+
+DESCRIPTION
+       If open for write, compress section, update section size with
+       compressed size and set compress_status to COMPRESS_SECTION_DONE.
+
+       Return @code{FALSE} if compression fail.  Otherwise, return
+       @code{TRUE}.
+*/
+
+bfd_boolean
+bfd_compress_section (bfd *abfd, sec_ptr sec, bfd_byte *uncompressed_buffer)
+{
+  bfd_size_type uncompressed_size = sec->size;
+
+  /* Error if not opened for write.  */
+  if (abfd->direction != write_direction
+      || uncompressed_size == 0
+      || uncompressed_buffer == NULL
+      || sec->contents != NULL
+      || sec->compressed_size != 0
+      || sec->compress_status != COMPRESS_SECTION_NONE)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return FALSE;
+    }
+
+  /* Compress it.  */
+  return bfd_compress_section_contents (abfd, sec, uncompressed_buffer,
+                                       uncompressed_size, TRUE) != 0;
+}
index 41fb023c498b3a5f59a4f10db0150c23faf8d40c..85a4b6b348dc77547416bc709f1f45c83eca5519 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -2752,6 +2752,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
   struct bfd_elf_section_data *esd = elf_section_data (asect);
   Elf_Internal_Shdr *this_hdr;
   unsigned int sh_type;
+  const char *name = asect->name;
 
   if (arg->failed)
     {
@@ -2762,8 +2763,38 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
 
   this_hdr = &esd->this_hdr;
 
+  /* For linking, compress DWARF debug sections with names: .debug_*.  */
+  if (arg->link_info
+      && (arg->link_info->compress_debug & COMPRESS_DEBUG)
+      && (asect->flags & SEC_DEBUGGING)
+      && name[1] == 'd'
+      && name[6] == '_')
+    {
+      /* Set SEC_ELF_COMPRESS to indicate this section should be
+        compressed.  */
+      asect->flags |= SEC_ELF_COMPRESS;
+
+      if (arg->link_info->compress_debug != COMPRESS_DEBUG_GABI_ZLIB)
+       {
+         /* If SHF_COMPRESSED isn't used, rename compressed DWARF
+            debug section to .zdebug_*.  */
+         unsigned int len = strlen (name);
+         char *new_name = bfd_alloc (abfd, len + 2);
+         if (new_name == NULL)
+           {
+             arg->failed = TRUE;
+             return;
+           }
+         new_name[0] = '.';
+         new_name[1] = 'z';
+         memcpy (new_name + 2, name + 1, len);
+         bfd_rename_section (abfd, asect, new_name);
+         name = asect->name;
+       }
+    }
+
   this_hdr->sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
-                                                         asect->name, FALSE);
+                                                         name, FALSE);
   if (this_hdr->sh_name == (unsigned int) -1)
     {
       arg->failed = TRUE;
@@ -5116,6 +5147,9 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
        }
       else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
                && hdr->bfd_section == NULL)
+              || (hdr->bfd_section != NULL
+                  && (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
+                  /* Compress DWARF debug sections.  */
               || hdr == i_shdrpp[elf_onesymtab (abfd)]
               || hdr == i_shdrpp[elf_symtab_shndx (abfd)]
               || hdr == i_shdrpp[elf_strtab_sec (abfd)])
@@ -5365,6 +5399,9 @@ assign_file_positions_except_relocs (bfd *abfd,
          hdr = *hdrpp;
          if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
               && hdr->bfd_section == NULL)
+             || (hdr->bfd_section != NULL
+                 && (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
+                 /* Compress DWARF debug sections.  */
              || i == elf_onesymtab (abfd)
              || i == elf_symtab_shndx (abfd)
              || i == elf_strtab_sec (abfd))
@@ -5518,8 +5555,8 @@ prep_headers (bfd *abfd)
 /* Assign file positions for all the reloc sections which are not part
    of the loadable file image, and the file position of section headers.  */
 
-static void
-_bfd_elf_assign_file_positions_for_relocs (bfd *abfd)
+static bfd_boolean
+_bfd_elf_assign_file_positions_for_non_load (bfd *abfd)
 {
   file_ptr off;
   unsigned int i, num_sec;
@@ -5535,9 +5572,30 @@ _bfd_elf_assign_file_positions_for_relocs (bfd *abfd)
       Elf_Internal_Shdr *shdrp;
 
       shdrp = *shdrpp;
-      if ((shdrp->sh_type == SHT_REL || shdrp->sh_type == SHT_RELA)
-         && shdrp->sh_offset == -1)
-       off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE);
+      if (shdrp->sh_offset == -1)
+       {
+         bfd_boolean is_rel = (shdrp->sh_type == SHT_REL
+                               || shdrp->sh_type == SHT_RELA);
+         if (is_rel
+             || (shdrp->bfd_section != NULL
+                 && (shdrp->bfd_section->flags & SEC_ELF_COMPRESS)))
+           {
+             if (!is_rel)
+               {
+                 /* Compress DWARF debug sections.  */
+                 if (!bfd_compress_section (abfd, shdrp->bfd_section,
+                                            shdrp->contents))
+                   return FALSE;
+                 /* Update section size and contents.  */
+                 shdrp->sh_size = shdrp->bfd_section->size;
+                 shdrp->contents = shdrp->bfd_section->contents;
+                 shdrp->bfd_section->contents = NULL;
+               }
+             off = _bfd_elf_assign_file_position_for_section (shdrp,
+                                                              off,
+                                                              TRUE);
+           }
+       }
     }
 
 /* Place the section headers.  */
@@ -5547,6 +5605,8 @@ _bfd_elf_assign_file_positions_for_relocs (bfd *abfd)
   i_ehdrp->e_shoff = off;
   off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize;
   elf_next_file_pos (abfd) = off;
+
+  return TRUE;
 }
 
 bfd_boolean
@@ -5569,7 +5629,8 @@ _bfd_elf_write_object_contents (bfd *abfd)
   if (failed)
     return FALSE;
 
-  _bfd_elf_assign_file_positions_for_relocs (abfd);
+  if (!_bfd_elf_assign_file_positions_for_non_load (abfd))
+    return FALSE;
 
   /* After writing the headers, we need to write the sections too...  */
   num_sec = elf_numsections (abfd);
@@ -7922,7 +7983,21 @@ _bfd_elf_set_section_contents (bfd *abfd,
       && ! _bfd_elf_compute_section_file_positions (abfd, NULL))
     return FALSE;
 
+  if (!count)
+    return TRUE;
+
   hdr = &elf_section_data (section)->this_hdr;
+  if (hdr->sh_offset == (file_ptr) -1)
+    {
+      /* We must compress this section.  Write output to the buffer.  */
+      unsigned char *contents = hdr->contents;
+      if ((offset + count) > hdr->sh_size
+         || (section->flags & SEC_ELF_COMPRESS) == 0
+         || contents == NULL)
+       abort ();
+      memcpy (contents + offset, location, count);
+      return TRUE;
+    }
   pos = hdr->sh_offset + offset;
   if (bfd_seek (abfd, pos, SEEK_SET) != 0
       || bfd_bwrite (location, count, abfd) != count)
index ea9246b6562933ab825a5dd1494743cf989f8c4d..6efe1e4a61d4b660cfb275c10ac0ef9bb5ccec58 100644 (file)
@@ -10890,6 +10890,21 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
         to count upwards while actually outputting the relocations.  */
       esdo->rel.count = 0;
       esdo->rela.count = 0;
+
+      if (esdo->this_hdr.sh_offset == (file_ptr) -1)
+       {
+         /* Cache the section contents so that they can be compressed
+            later.  Use bfd_malloc since it will be freed by
+            bfd_compress_section_contents.  */
+         unsigned char *contents = esdo->this_hdr.contents;
+         if ((o->flags & SEC_ELF_COMPRESS) == 0 || contents != NULL)
+           abort ();
+         contents
+           = (unsigned char *) bfd_malloc (esdo->this_hdr.sh_size);
+         if (contents == NULL)
+           goto error_return;
+         esdo->this_hdr.contents = contents;
+       }
     }
 
   /* We have now assigned file positions for all the sections except
index 5f45ba6e106cad4b7dd2b05d6c1413a0761aab9e..174ec90bff2aceccadcf557780eef67f7ead9373 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "sysdep.h"
 #include "bfd.h"
+#include "elf-bfd.h"
 #include "libbfd.h"
 #include "hashtab.h"
 #include "libiberty.h"
@@ -283,7 +284,8 @@ sec_merge_add (struct sec_merge_hash *tab, const char *str,
 }
 
 static bfd_boolean
-sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
+sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry,
+               unsigned char *contents, file_ptr offset)
 {
   struct sec_merge_sec_info *secinfo = entry->secinfo;
   asection *sec = secinfo->sec;
@@ -306,7 +308,12 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
       len = -off & (entry->alignment - 1);
       if (len != 0)
        {
-         if (bfd_bwrite (pad, len, abfd) != len)
+         if (contents)
+           {
+             memcpy (contents + offset, pad, len);
+             offset += len;
+           }
+         else if (bfd_bwrite (pad, len, abfd) != len)
            goto err;
          off += len;
        }
@@ -314,7 +321,12 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
       str = entry->root.string;
       len = entry->len;
 
-      if (bfd_bwrite (str, len, abfd) != len)
+      if (contents)
+       {
+         memcpy (contents + offset, str, len);
+         offset += len;
+       }
+      else if (bfd_bwrite (str, len, abfd) != len)
        goto err;
 
       off += len;
@@ -322,9 +334,13 @@ sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry)
 
   /* Trailing alignment needed?  */
   off = sec->size - off;
-  if (off != 0
-      && bfd_bwrite (pad, off, abfd) != off)
-    goto err;
+  if (off != 0)
+    {
+      if (contents)
+       memcpy (contents + offset, pad, off);
+      else if (bfd_bwrite (pad, off, abfd) != off)
+       goto err;
+    }
 
   if (pad != NULL)
     free (pad);
@@ -785,6 +801,8 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
 {
   struct sec_merge_sec_info *secinfo;
   file_ptr pos;
+  unsigned char *contents;
+  Elf_Internal_Shdr *hdr;
 
   secinfo = (struct sec_merge_sec_info *) psecinfo;
 
@@ -795,11 +813,26 @@ _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
     return TRUE;
 
   /* FIXME: octets_per_byte.  */
-  pos = sec->output_section->filepos + sec->output_offset;
-  if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
-    return FALSE;
+  hdr = &elf_section_data (sec->output_section)->this_hdr;
+  if (hdr->sh_offset == (file_ptr) -1)
+    {
+      /* We must compress this section.  Write output to the
+        buffer.  */
+      contents = hdr->contents;
+      if ((sec->output_section->flags & SEC_ELF_COMPRESS) == 0
+         || contents == NULL)
+       abort ();
+    }
+  else
+    {
+      contents = NULL;
+      pos = sec->output_section->filepos + sec->output_offset;
+      if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
+       return FALSE;
+    }
 
-  if (! sec_merge_emit (output_bfd, secinfo->first_str))
+  if (! sec_merge_emit (output_bfd, secinfo->first_str, contents,
+                       sec->output_offset))
     return FALSE;
 
   return TRUE;
index 4a6f2e4f347350e5a3fe6509d68376d7cdba7678..d59a0e3014e547bed1f779c9bf80a6116fd9fade 100644 (file)
@@ -334,6 +334,10 @@ CODE_FRAGMENT
 .     executables or shared objects. This is for COFF only.  *}
 .#define SEC_COFF_SHARED 0x8000000
 .
+.  {* This section should be compressed.  This is for ELF linker
+.     internal use only.  *}
+.#define SEC_ELF_COMPRESS 0x8000000
+.
 .  {* When a section with this flag is being linked, then if the size of
 .     the input section is less than a page, it should not cross a page
 .     boundary.  If the size of the input section is one page or more,
index c90f98ce615e10e3e53fca62c3ab6a0aa2ccae4e..d42aa7575c719ad57da588262d6c2b5a8b2c3e68 100644 (file)
@@ -1,3 +1,7 @@
+2015-04-14  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * as.h (compressed_debug_section_type): Removed.
+
 2015-04-14  Nick Clifton  <nickc@redhat.com>
 
        * config/tc-rl78.h (TC_LINKRELAX_FIXUP): Define.
index e04cc0fa2bd958c0caee3e0ed2d479361652e1fd..6de319e839ce642d62c7499b3a1f3002fefdaac7 100644 (file)
--- a/gas/as.h
+++ b/gas/as.h
@@ -370,16 +370,6 @@ COMMON int flag_strip_local_absolute;
 /* True if we should generate a traditional format object file.  */
 COMMON int flag_traditional_format;
 
-/* Types of compressed debug sections.  We currently support zlib.  */
-enum compressed_debug_section_type
-{
-  COMPRESS_DEBUG_NONE = 0,
-  COMPRESS_DEBUG,
-  COMPRESS_DEBUG_ZLIB,
-  COMPRESS_DEBUG_GNU_ZLIB,
-  COMPRESS_DEBUG_GABI_ZLIB
-};
-
 /* Type of compressed debug sections we should generate.   */
 COMMON enum compressed_debug_section_type flag_compress_debug;
 
index 7d4919d1ef5401857303e07886c2d1bf8fe9fdc2..9afcc62c73f02e9162a21d43c4071c1cd7c339fb 100644 (file)
@@ -1,3 +1,7 @@
+2015-04-14  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * bfdlink.h (bfd_link_info): Add compress_debug.
+
 2015-04-14  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/pr17709
index 1b1582600a38f4f377ab09286fa15015b0d4d0dd..3989c60c5104fe29a362635c0c3afd913e990da5 100644 (file)
@@ -431,6 +431,9 @@ struct bfd_link_info
   /* Separator between archive and filename in linker script filespecs.  */
   char path_separator;
 
+  /* Compress DWARF debug sections.  */
+  enum compressed_debug_section_type compress_debug;
+
   /* Default stack size.  Zero means default (often zero itself), -1
      means explicitly zero-sized.  */
   bfd_signed_vma stacksize;
index 3e944feb8ed20ffead1d674b05da19a7b9b9ec51..bad213be3ea35dd3994d85908fb4c332f2da39e1 100644 (file)
@@ -1,3 +1,16 @@
+2015-04-14  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * ld.texinfo: Document --compress-debug-sections=.
+       * ldmain.c (main): Set BFD_COMPRESS on output_bfd if
+       COMPRESS_DEBUG is set.  Set BFD_COMPRESS_GABI on output_bfd
+       for COMPRESS_DEBUG_GABI_ZLIB.
+       * lexsup.c (elf_static_list_options): Add
+       --compress-debug-sections=.
+       * emultempl/elf32.em (OPTION_COMPRESS_DEBUG): New.
+       (xtra_long): Add "compress-debug-sections".
+       (gld${EMULATION_NAME}_handle_option): Handle
+       OPTION_COMPRESS_DEBUG.
+
 2015-04-14  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/pr17709
index 5db5a93c671bf6f51357d1eb98e70dbdf1799bf9..0802d763c91061f0d56b4a8d0d08633be47bed41 100644 (file)
@@ -2110,6 +2110,7 @@ fragment <<EOF
 #define OPTION_HASH_STYLE              (OPTION_EXCLUDE_LIBS + 1)
 #define OPTION_BUILD_ID                        (OPTION_HASH_STYLE + 1)
 #define OPTION_AUDIT                   (OPTION_BUILD_ID + 1)
+#define OPTION_COMPRESS_DEBUG          (OPTION_AUDIT + 1)
 
 static void
 gld${EMULATION_NAME}_add_options
@@ -2137,6 +2138,7 @@ EOF
 fi
 fragment <<EOF
     {"build-id", optional_argument, NULL, OPTION_BUILD_ID},
+    {"compress-debug-sections", required_argument, NULL, OPTION_COMPRESS_DEBUG},
 EOF
 if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
 fragment <<EOF
@@ -2186,6 +2188,19 @@ gld${EMULATION_NAME}_handle_option (int optc)
        emit_note_gnu_build_id = xstrdup (optarg);
       break;
 
+    case OPTION_COMPRESS_DEBUG:
+      if (strcasecmp (optarg, "none") == 0)
+       link_info.compress_debug = COMPRESS_DEBUG_NONE;
+      else if (strcasecmp (optarg, "zlib") == 0)
+       link_info.compress_debug = COMPRESS_DEBUG_ZLIB;
+      else if (strcasecmp (optarg, "zlib-gnu") == 0)
+       link_info.compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
+      else if (strcasecmp (optarg, "zlib-gabi") == 0)
+       link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+      else
+       einfo (_("%P%F: invalid --compress-debug-sections option: \`%s'\n"),
+              optarg);
+      break;
 EOF
 
 if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
index 4348c8812b4111ed5a61f2b3c1d46af13dbbb115..77c02d6f3d19fefed2dd9b639756bf6cb82f1be0 100644 (file)
@@ -2201,6 +2201,22 @@ new style GNU @code{.gnu.hash} section or @code{both} for both
 the classic ELF @code{.hash} and new style GNU @code{.gnu.hash}
 hash tables.  The default is @code{sysv}.
 
+@kindex --compress-debug-sections=none
+@kindex --compress-debug-sections=zlib
+@kindex --compress-debug-sections=zlib-gnu
+@kindex --compress-debug-sections=zlib-gabi
+@item --compress-debug-sections=none
+@itemx --compress-debug-sections=zlib
+@itemx --compress-debug-sections=zlib-gnu
+@itemx --compress-debug-sections=zlib-gabi
+On ELF platforms , these options control how DWARF debug sections are
+compressed using zlib.  @option{--compress-debug-sections=none} doesn't
+compress DWARF debug sections.  @option{--compress-debug-sections=zlib}
+and @option{--compress-debug-sections=zlib-gnu} compress DWARF debug
+sections and rename debug section names to begin with @samp{.zdebug}
+instead of @samp{.debug}.  @option{--compress-debug-sections=zlib-gabi}
+compresses DWARF debug sections with SHF_COMPRESSED from the ELF ABI.
+
 @kindex --reduce-memory-overheads
 @item --reduce-memory-overheads
 This option reduces memory requirements at ld runtime, at the expense of
index 2ecb92d00bf40a5a6396e870f6e211b6b8fa5f31..a7b72bd63f89f23a1107b64f8d1d9826a5251f33 100644 (file)
@@ -425,6 +425,13 @@ main (int argc, char **argv)
   else
     link_info.output_bfd->flags |= EXEC_P;
 
+  if ((link_info.compress_debug & COMPRESS_DEBUG))
+    {
+      link_info.output_bfd->flags |= BFD_COMPRESS;
+      if (link_info.compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
+       link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
+    }
+
   ldwrite ();
 
   if (config.map_file != NULL)
index 4a71ba41cb05e0a8df46bc49e39695e1643433ac..b618241f0d89bffc3d6cc235cd59215f6d9d03f6 100644 (file)
@@ -1722,6 +1722,9 @@ elf_static_list_options (FILE *file)
   fprintf (file, _("\
   --build-id[=STYLE]          Generate build ID note\n"));
   fprintf (file, _("\
+  --compress-debug-sections=[none|zlib|zlib-gnu|zlib-gabi]\n\
+                              Compress DWARF debug sections using zlib\n"));
+  fprintf (file, _("\
   -z common-page-size=SIZE    Set common page size to SIZE\n"));
   fprintf (file, _("\
   -z max-page-size=SIZE       Set maximum page size to SIZE\n"));
index c2ed134f240dc1f3bee3ca9f47d5305790abf7c2..54ae0aefc408b0c9d3d408f6d3896333a8dff795 100644 (file)
@@ -1,3 +1,16 @@
+2015-04-14  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * ld-elf/compress.exp (build_tests): Add tests for
+       --compress-debug-sections=.
+       (run_tests): Likewise.
+       Add additonal tests for --compress-debug-sections=.
+       * ld-elf/gabiend.rt: New file.
+       * ld-elf/gabinormal.rt: Likewise.
+       * ld-elf/gnubegin.rS: Likewise.
+       * ld-elf/gnunormal.rS: Likewise.
+       * ld-elf/zlibbegin.rS: Likewise.
+       * ld-elf/zlibnormal.rS: Likewise.
+
 2015-04-15  Alan Modra  <amodra@gmail.com>
 
        * ld-gc/pr18223.d: xfail tic6x.
index adb7fc2467f5b2e0a533241caba4e047d619ab50..e2448b9e103d48a2e4f7e8c9bd4ef646987abc16 100644 (file)
@@ -49,7 +49,8 @@ set build_tests {
    "-shared" "-fPIC -g -Wa,--compress-debug-sections"
    {foo.c} {} "libfoo.so"}
   {"Build libbar.so with compressed debug sections"
-   "-shared" "-fPIC -g -Wa,--compress-debug-sections"
+   "-shared -Wl,--compress-debug-sections=none"
+   "-fPIC -g -Wa,--compress-debug-sections"
    {begin.c end.c} {} "libbar.so"}
   {"Build libfoozlib.so with compressed debug sections with zlib-gabi"
    "-shared" "-fPIC -g -Wa,--compress-debug-sections=zlib-gabi"
@@ -57,6 +58,30 @@ set build_tests {
   {"Build libbarzlib.so with compressed debug sections with zlib-gabi"
    "-shared" "-fPIC -g -Wa,--compress-debug-sections=zlib-gabi"
    {begin.c end.c} {} "libbarzlib.so"}
+  {"Build libzlibfoo.so with zlib compressed debug sections"
+   "-shared -Wl,--compress-debug-sections=zlib"
+   "-fPIC -g -Wa,--compress-debug-sections=zlib"
+   {foo.c} {} "libzlibfoo.so"}
+  {"Build libgnufoo.so with zlib-gnu compressed debug sections"
+   "-shared -Wl,--compress-debug-sections=zlib-gnu"
+   "-fPIC -g -Wa,--compress-debug-sections=zlib-gnu"
+   {foo.c} {} "libgnufoo.so"}
+  {"Build libgabifoo.so with zlib-gabi compressed debug sections"
+   "-shared -Wl,--compress-debug-sections=zlib-gabi"
+   "-fPIC -g -Wa,--compress-debug-sections=zlib-gabi"
+   {foo.c} {} "libgabifoo.so"}
+  {"Build zlibbegin.o with zlib compressed debug sections"
+   "-r -nostdlib -Wl,--compress-debug-sections=zlib"
+   "-g -Wa,--compress-debug-sections=zlib"
+   {begin.c} {} "zlibbegin.o"}
+  {"Build gnubegin.o with zlib-gnu compressed debug sections"
+   "-r -nostdlib -Wl,--compress-debug-sections=zlib-gnu"
+   "-g -Wa,--compress-debug-sections=zlib-gnu"
+   {begin.c} {} "gnubegin.o"}
+  {"Build gabiend.o with zlib-gabi compressed debug sections"
+   "-r -nostdlib -Wl,--compress-debug-sections=zlib-gabi"
+   "-g -Wa,--compress-debug-sections=zlib-gnu"
+   {end.c} {} "gabiend.o"}
 }
 
 set run_tests {
@@ -66,6 +91,15 @@ set run_tests {
     {"Run normal with libfoo.so with compressed debug sections with zlib-gabi"
      "tmpdir/begin.o tmpdir/libfoozlib.so tmpdir/end.o" ""
      {main.c} "normal" "normal.out" "-Wa,--compress-debug-sections=zlib-gabi"}
+    {"Run zlibnormal with libzlibfoo.so with zlib compressed debug sections"
+     "tmpdir/begin.o tmpdir/libzlibfoo.so tmpdir/end.o --compress-debug-sections=zlib" ""
+     {main.c} "zlibnormal" "normal.out" "-Wa,--compress-debug-sections=zlib"}
+    {"Run gnunormal with libgnufoo.so with zlib-gnu compressed debug sections"
+     "tmpdir/gnubegin.o tmpdir/libgnufoo.so tmpdir/end.o --compress-debug-sections=zlib-gnu" ""
+     {main.c} "gnunormal" "normal.out" "-Wa,--compress-debug-sections=zlib-gnu"}
+    {"Run gabinormal with libgabifoo.so with zlib-gabi compressed debug sections"
+     "tmpdir/zlibbegin.o tmpdir/libgabifoo.so tmpdir/gabiend.o --compress-debug-sections=zlib-gabi" ""
+     {main.c} "gabinormal" "normal.out" "-Wa,--compress-debug-sections=zlib-gabi"}
 }
 
 run_cc_link_tests $build_tests
@@ -79,3 +113,134 @@ if { [catch {exec cmp tmpdir/libfoo.so tmpdir/libfoozlib.so}] } then {
 } else {
     pass "$test_name"
 }
+
+global READELF
+
+set test_name "Link -r with zlib compressed debug output"
+set test zlibbegin
+send_log "$READELF -S -W tmpdir/$test.o > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -S -W tmpdir/$test.o" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rS] } then {
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+
+set test_name "Link -r with zlib-gnu compressed debug output"
+set test gnubegin
+send_log "$READELF -S -W tmpdir/$test.o > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -S -W tmpdir/$test.o" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rS] } then {
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+
+set test_name "Link -r with zlib-gabi compressed debug output"
+set test gabiend
+send_log "$READELF -t -W tmpdir/$test.o > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -t -W tmpdir/$test.o" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rt] } then {
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+
+set test_name "Link with zlib compressed debug output"
+set test normal
+send_log "$READELF -w tmpdir/$test > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -w tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+
+set test_name "Link with zlib compressed debug output"
+set test zlibnormal
+send_log "$READELF -w tmpdir/$test | sed -e \"s/.zdebug_/.debug_/\" > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -w tmpdir/$test | sed -e \"s/.zdebug_/.debug_/\"" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+if { [catch {exec cmp tmpdir/normal.out tmpdir/$test.out}] } then {
+    send_log "tmpdir/normal.out tmpdir/$test.out differ.\n"
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+send_log "$READELF -S -W tmpdir/$test' > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -S -W tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rS] } then {
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+
+set test_name "Link with zlib-gnu compressed debug output"
+set test gnunormal
+send_log "$READELF -w tmpdir/$test | sed -e \"s/.zdebug_/.debug_/\" > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -w tmpdir/$test | sed -e \"s/.zdebug_/.debug_/\"" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+if { [catch {exec cmp tmpdir/normal.out tmpdir/$test.out}] } then {
+    send_log "tmpdir/normal.out tmpdir/$test.out differ.\n"
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+send_log "$READELF -S -W tmpdir/$test' > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -S -W tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rS] } then {
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+
+set test gabinormal
+set test_name "Link with zlib-gabi compressed debug output"
+send_log "$READELF -w tmpdir/$test > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -w tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+if { [catch {exec cmp tmpdir/normal.out tmpdir/$test.out}] } then {
+    send_log "tmpdir/normal.out tmpdir/$test.out differ.\n"
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+send_log "$READELF -t -W tmpdir/$test > tmpdir/$test.out\n"
+set got [remote_exec host "$READELF -t -W tmpdir/$test" "" "/dev/null" "tmpdir/$test.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    send_log "$got\n"
+    unresolved "$test_name"
+}
+if { [regexp_diff tmpdir/$test.out $srcdir/$subdir/$test.rt] } then {
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
diff --git a/ld/testsuite/ld-elf/gabiend.rt b/ld/testsuite/ld-elf/gabiend.rt
new file mode 100644 (file)
index 0000000..23bc36c
--- /dev/null
@@ -0,0 +1,4 @@
+#...
+ +\[[0-9a-f]+\]: .*COMPRESSED
+ +ZLIB, [0-9a-f]+, 1
+#pass
diff --git a/ld/testsuite/ld-elf/gabinormal.rt b/ld/testsuite/ld-elf/gabinormal.rt
new file mode 100644 (file)
index 0000000..23bc36c
--- /dev/null
@@ -0,0 +1,4 @@
+#...
+ +\[[0-9a-f]+\]: .*COMPRESSED
+ +ZLIB, [0-9a-f]+, 1
+#pass
diff --git a/ld/testsuite/ld-elf/gnubegin.rS b/ld/testsuite/ld-elf/gnubegin.rS
new file mode 100644 (file)
index 0000000..54de24c
--- /dev/null
@@ -0,0 +1,3 @@
+#...
+ +\[[ 0-9]+\] .zdebug_.* +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ [0-9a-f]+ +0 +0 +1
+#pass
diff --git a/ld/testsuite/ld-elf/gnunormal.rS b/ld/testsuite/ld-elf/gnunormal.rS
new file mode 100644 (file)
index 0000000..54de24c
--- /dev/null
@@ -0,0 +1,3 @@
+#...
+ +\[[ 0-9]+\] .zdebug_.* +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ [0-9a-f]+ +0 +0 +1
+#pass
diff --git a/ld/testsuite/ld-elf/zlibbegin.rS b/ld/testsuite/ld-elf/zlibbegin.rS
new file mode 100644 (file)
index 0000000..54de24c
--- /dev/null
@@ -0,0 +1,3 @@
+#...
+ +\[[ 0-9]+\] .zdebug_.* +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ [0-9a-f]+ +0 +0 +1
+#pass
diff --git a/ld/testsuite/ld-elf/zlibnormal.rS b/ld/testsuite/ld-elf/zlibnormal.rS
new file mode 100644 (file)
index 0000000..54de24c
--- /dev/null
@@ -0,0 +1,3 @@
+#...
+ +\[[ 0-9]+\] .zdebug_.* +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ [0-9a-f]+ +0 +0 +1
+#pass