diff options
author | Ian Lance Taylor <iant@google.com> | 2007-11-30 00:35:27 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2007-11-30 00:35:27 +0000 |
commit | 9a0910c33e1a6962d475ee0a994fd1f5e446a888 (patch) | |
tree | f30e7b369cc05383699fbe4780ee0839b8dbcdde /gold/compressed_output.cc | |
parent | 71195202dfb59bb7b61b35dc4cc5d202fab12020 (diff) | |
download | binutils-9a0910c33e1a6962d475ee0a994fd1f5e446a888.zip binutils-9a0910c33e1a6962d475ee0a994fd1f5e446a888.tar.gz binutils-9a0910c33e1a6962d475ee0a994fd1f5e446a888.tar.bz2 |
From Craig Silverstein: Add support for compressing .debug_str section.
Diffstat (limited to 'gold/compressed_output.cc')
-rw-r--r-- | gold/compressed_output.cc | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/gold/compressed_output.cc b/gold/compressed_output.cc new file mode 100644 index 0000000..1006ac8 --- /dev/null +++ b/gold/compressed_output.cc @@ -0,0 +1,267 @@ +// compressed_output.cc -- manage compressed output sections for gold + +// Copyright 2007 Free Software Foundation, Inc. +// Written by Ian Lance Taylor <iant@google.com>. + +// This file is part of gold. + +// This program 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 of the License, or +// (at your option) any later version. + +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +#include "gold.h" + +#ifdef HAVE_ZLIB_H +#include <zlib.h> +#endif + +#include "compressed_output.h" +#include "parameters.h" + +namespace gold +{ + +// Compress UNCOMPRESSED_DATA of size UNCOMPRESSED_SIZE. Returns true +// if it successfully compressed, false if it failed for any reason +// (including not having zlib support in the library). If it returns +// true, it allocates memory for the compressed data using new, and +// sets *COMPRESSED_DATA and *COMPRESSED_SIZE to appropriate values. + +static bool +zlib_compress(const char* uncompressed_data, unsigned long uncompressed_size, + char** compressed_data, unsigned long* compressed_size) +{ +#ifndef HAVE_ZLIB_H + return false; +#else + *compressed_size = uncompressed_size + uncompressed_size / 1000 + 128; + *compressed_data = new char[*compressed_size]; + + int compress_level; + if (parameters->optimization_level() >= 1) + compress_level = 9; + else + compress_level = 1; + + int rc = compress2(reinterpret_cast<Bytef*>(*compressed_data), + compressed_size, + reinterpret_cast<const Bytef*>(uncompressed_data), + uncompressed_size, + compress_level); + if (rc == Z_OK) + return true; + else + { + delete[] *compressed_data; + *compressed_data = NULL; + return false; + } +#endif // #ifdef HAVE_ZLIB_H +} + +// After compressing an output section, we rename it from foo to +// foo.zlib.nnnn, where nnnn is the uncompressed size of the section. + +static std::string +zlib_compressed_suffix(unsigned long uncompressed_size) +{ + char size_string[64]; + snprintf(size_string, sizeof(size_string), "%lu", uncompressed_size); + return std::string(".zlib.") + size_string; +} + +// Class Output_compressed_section_data. + +// Add an input section. In this case, we just keep track of the sections. + +bool +Output_compressed_section_data::do_add_input_section(Relobj* obj, + unsigned int shndx) +{ + this->objects_.push_back(Object_entry(obj, shndx)); + return true; +} + +// Set the final data size of a compressed section. This is where +// we actually compress the section data. + +void +Output_compressed_section_data::set_final_data_size() +{ + // FIXME: assert that relocations have already been applied. + + off_t uncompressed_size = 0; + for (std::vector<Object_entry>::iterator it = this->objects_.begin(); + it != this->objects_.end(); + ++it) + { + it->contents + = it->object->section_contents(it->shndx, &it->length, false); + uncompressed_size += it->length; + } + + // (Try to) compress the data. + unsigned long compressed_size; + char* uncompressed_data = new char[uncompressed_size]; + off_t pos = 0; + for (std::vector<Object_entry>::const_iterator it = this->objects_.begin(); + it != this->objects_.end(); + ++it) + { + memcpy(uncompressed_data + pos, + reinterpret_cast<const char*>(it->contents), + it->length); + pos += it->length; + } + + bool success = false; + if (options_.zlib_compress_debug_sections()) + success = zlib_compress(uncompressed_data, uncompressed_size, + &this->data_, &compressed_size); + if (success) + { + delete[] uncompressed_data; + this->set_data_size(compressed_size); + this->new_section_name_ = zlib_compressed_suffix(uncompressed_size); + } + else + { + gold_warning(_("Not compressing section data: zlib error")); + gold_assert(this->data_ == NULL); + this->data_ = uncompressed_data; + this->set_data_size(uncompressed_size); + } +} + +// Change the name of the output section to reflect it's compressed. +// The layout routines call into this right before finalizing the +// shstrtab. + +const char* +Output_compressed_section_data::do_modified_output_section_name( + const char* name) +{ + // This mean we never compressed the data. + if (this->new_section_name_.empty()) + return NULL; + this->new_section_name_ = std::string(name) + this->new_section_name_; + return this->new_section_name_.c_str(); +} + +// Write out a compressed section. If we couldn't compress, we just +// write it out as normal, uncompressed data. + +void +Output_compressed_section_data::do_write(Output_file* of) +{ + unsigned char* uview = of->get_output_view(this->offset(), + this->data_size()); + char* view = reinterpret_cast<char*>(uview); + memcpy(view, this->data_, this->data_size()); + of->write_output_view(this->offset(), this->data_size(), uview); +} + +// Class Output_compressed_string. + +// Add an input section. We don't do anything special here. + +template<typename Char_type> +bool +Output_compressed_string<Char_type>::do_add_input_section(Relobj* object, + unsigned int shndx) +{ + return Output_merge_string<Char_type>::do_add_input_section(object, shndx); +} + +// Set the final data size of a compressed section. This is where +// we actually compress the section data. + +template<typename Char_type> +void +Output_compressed_string<Char_type>::set_final_data_size() +{ + // First let the superclass finalize all its data, then write it to + // a buffer. + unsigned long uncompressed_size = this->finalize_merged_data(); + char* uncompressed_data = new char[uncompressed_size]; + this->stringpool_to_buffer(uncompressed_data, uncompressed_size); + + // (Try to) compress the data. + unsigned long compressed_size; + if (options_.zlib_compress_debug_sections() + && zlib_compress(uncompressed_data, uncompressed_size, + &this->compressed_data_, &compressed_size)) + { + this->set_data_size(compressed_size); + // Save some memory. + this->clear_stringpool(); + // We will be renaming the section to name.zlib.uncompressed_size. + this->new_section_name_ = zlib_compressed_suffix(uncompressed_size); + } + else + { + this->compressed_data_ = NULL; + this->set_data_size(uncompressed_size); + } + + delete[] uncompressed_data; +} + +// Change the name of the output section to reflect it's compressed. +// The layout routines call into this right before finalizing the +// shstrtab. + +template<typename Char_type> +const char* +Output_compressed_string<Char_type>::do_modified_output_section_name( + const char* name) +{ + // This mean we never compressed the data + if (this->new_section_name_.empty()) + return NULL; + this->new_section_name_ = std::string(name) + this->new_section_name_; + return this->new_section_name_.c_str(); +} + +// Write out a compressed string section. If we couldn't compress, +// we just write out the normal string section. + +template<typename Char_type> +void +Output_compressed_string<Char_type>::do_write(Output_file* of) +{ + if (this->compressed_data_ == NULL) + Output_merge_string<Char_type>::do_write(of); + else + { + unsigned char* uview = of->get_output_view(this->offset(), + this->data_size()); + char* view = reinterpret_cast<char*>(uview); + memcpy(view, this->compressed_data_, this->data_size()); + of->write_output_view(this->offset(), this->data_size(), uview); + } +} + +// Instantiate the templates we need. + +template +class Output_compressed_string<char>; + +template +class Output_compressed_string<uint16_t>; + +template +class Output_compressed_string<uint32_t>; + +} // End namespace gold. |