summaryrefslogtreecommitdiff
path: root/gas/write.c
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@google.com>2010-07-03 20:52:22 +0000
committerCary Coutant <ccoutant@google.com>2010-07-03 20:52:22 +0000
commitb0b499c4d40a6329b30f41cc40ac9c7880f74a62 (patch)
tree1f51b5c301bc54d17329b9bd1d5c926e3c7aaee6 /gas/write.c
parent868599c9ad52c88d280699558f6aaf1316f815e9 (diff)
downloadbinutils-redhat-b0b499c4d40a6329b30f41cc40ac9c7880f74a62.tar.gz
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.
Diffstat (limited to 'gas/write.c')
-rw-r--r--gas/write.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/gas/write.c b/gas/write.c
index a148b248d2..71ac63562c 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);
}