123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- // compressed_output.cc -- manage compressed debug sections for gold
- // Copyright (C) 2007-2015 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"
- #include <zlib.h>
- #include "parameters.h"
- #include "options.h"
- #include "compressed_output.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.
- // It also writes a header before COMPRESSED_DATA: 4 bytes saying
- // "ZLIB", and 8 bytes indicating the uncompressed size, in big-endian
- // order.
- static bool
- zlib_compress(int header_size,
- const unsigned char* uncompressed_data,
- unsigned long uncompressed_size,
- unsigned char** compressed_data,
- unsigned long* compressed_size)
- {
- *compressed_size = uncompressed_size + uncompressed_size / 1000 + 128;
- *compressed_data = new unsigned char[*compressed_size + header_size];
- int compress_level;
- if (parameters->options().optimize() >= 1)
- compress_level = 9;
- else
- compress_level = 1;
- int rc = compress2(reinterpret_cast<Bytef*>(*compressed_data) + header_size,
- compressed_size,
- reinterpret_cast<const Bytef*>(uncompressed_data),
- uncompressed_size,
- compress_level);
- if (rc == Z_OK)
- {
- *compressed_size += header_size;
- return true;
- }
- else
- {
- delete[] *compressed_data;
- *compressed_data = NULL;
- return false;
- }
- }
- // Decompress COMPRESSED_DATA of size COMPRESSED_SIZE, into a buffer
- // UNCOMPRESSED_DATA of size UNCOMPRESSED_SIZE. Returns TRUE if it
- // decompressed successfully, false if it failed. The buffer, of
- // appropriate size, is provided by the caller, and is typically part
- // of the memory-mapped output file.
- static bool
- zlib_decompress(const unsigned char* compressed_data,
- unsigned long compressed_size,
- unsigned char* uncompressed_data,
- unsigned long uncompressed_size)
- {
- z_stream strm;
- int rc;
- /* It is possible the section consists of several compressed
- buffers concatenated together, so we uncompress in a loop. */
- strm.zalloc = NULL;
- strm.zfree = NULL;
- strm.opaque = NULL;
- strm.avail_in = compressed_size;
- strm.next_in = const_cast<Bytef*>(compressed_data);
- strm.avail_out = uncompressed_size;
- rc = inflateInit(&strm);
- while (strm.avail_in > 0)
- {
- if (rc != Z_OK)
- return false;
- strm.next_out = ((Bytef*) uncompressed_data
- + (uncompressed_size - strm.avail_out));
- rc = inflate(&strm, Z_FINISH);
- if (rc != Z_STREAM_END)
- return false;
- rc = inflateReset(&strm);
- }
- rc = inflateEnd(&strm);
- if (rc != Z_OK || strm.avail_out != 0)
- return false;
- return true;
- }
- // Read the compression header of a compressed debug section and return
- // the uncompressed size.
- uint64_t
- get_uncompressed_size(const unsigned char* compressed_data,
- section_size_type compressed_size)
- {
- const unsigned int zlib_header_size = 12;
- /* Verify the compression header. Currently, we support only zlib
- compression, so it should be "ZLIB" followed by the uncompressed
- section size, 8 bytes in big-endian order. */
- if (compressed_size >= zlib_header_size
- && strncmp(reinterpret_cast<const char*>(compressed_data),
- "ZLIB", 4) == 0)
- return elfcpp::Swap_unaligned<64, true>::readval(compressed_data + 4);
- return -1ULL;
- }
- // Decompress a compressed debug section directly into the output file.
- bool
- decompress_input_section(const unsigned char* compressed_data,
- unsigned long compressed_size,
- unsigned char* uncompressed_data,
- unsigned long uncompressed_size,
- int size,
- bool big_endian,
- elfcpp::Elf_Xword sh_flags)
- {
- if ((sh_flags & elfcpp::SHF_COMPRESSED) != 0)
- {
- unsigned int compression_header_size;
- if (size == 32)
- {
- compression_header_size = elfcpp::Elf_sizes<32>::chdr_size;
- if (big_endian)
- {
- elfcpp::Chdr<32, true> chdr(compressed_data);
- if (chdr.get_ch_type() != elfcpp::ELFCOMPRESS_ZLIB)
- return false;
- }
- else
- {
- elfcpp::Chdr<32, false> chdr(compressed_data);
- if (chdr.get_ch_type() != elfcpp::ELFCOMPRESS_ZLIB)
- return false;
- }
- }
- else if (size == 64)
- {
- compression_header_size = elfcpp::Elf_sizes<64>::chdr_size;
- if (big_endian)
- {
- elfcpp::Chdr<64, true> chdr(compressed_data);
- if (chdr.get_ch_type() != elfcpp::ELFCOMPRESS_ZLIB)
- return false;
- }
- else
- {
- elfcpp::Chdr<64, false> chdr(compressed_data);
- if (chdr.get_ch_type() != elfcpp::ELFCOMPRESS_ZLIB)
- return false;
- }
- }
- else
- gold_unreachable();
- return zlib_decompress(compressed_data + compression_header_size,
- compressed_size - compression_header_size,
- uncompressed_data,
- uncompressed_size);
- }
- const unsigned int zlib_header_size = 12;
- /* Verify the compression header. Currently, we support only zlib
- compression, so it should be "ZLIB" followed by the uncompressed
- section size, 8 bytes in big-endian order. */
- if (compressed_size >= zlib_header_size
- && strncmp(reinterpret_cast<const char*>(compressed_data),
- "ZLIB", 4) == 0)
- {
- unsigned long uncompressed_size_check =
- elfcpp::Swap_unaligned<64, true>::readval(compressed_data + 4);
- gold_assert(uncompressed_size_check == uncompressed_size);
- return zlib_decompress(compressed_data + zlib_header_size,
- compressed_size - zlib_header_size,
- uncompressed_data,
- uncompressed_size);
- }
- return false;
- }
- // Class Output_compressed_section.
- // Set the final data size of a compressed section. This is where
- // we actually compress the section data.
- void
- Output_compressed_section::set_final_data_size()
- {
- off_t uncompressed_size = this->postprocessing_buffer_size();
- // (Try to) compress the data.
- unsigned long compressed_size;
- unsigned char* uncompressed_data = this->postprocessing_buffer();
- // At this point the contents of all regular input sections will
- // have been copied into the postprocessing buffer, and relocations
- // will have been applied. Now we need to copy in the contents of
- // anything other than a regular input section.
- this->write_to_postprocessing_buffer();
- bool success = false;
- enum { none, gnu_zlib, gabi_zlib } compress;
- int compression_header_size = 12;
- const int size = parameters->target().get_size();
- if (strcmp(this->options_->compress_debug_sections(), "zlib-gnu") == 0)
- compress = gnu_zlib;
- else if (strcmp(this->options_->compress_debug_sections(), "zlib-gabi") == 0
- || strcmp(this->options_->compress_debug_sections(), "zlib") == 0)
- {
- compress = gabi_zlib;
- if (size == 32)
- compression_header_size = elfcpp::Elf_sizes<32>::chdr_size;
- else if (size == 64)
- compression_header_size = elfcpp::Elf_sizes<64>::chdr_size;
- else
- gold_unreachable();
- }
- else
- compress = none;
- if (compress != none)
- success = zlib_compress(compression_header_size, uncompressed_data,
- uncompressed_size, &this->data_,
- &compressed_size);
- if (success)
- {
- elfcpp::Elf_Xword flags = this->flags();
- if (compress == gabi_zlib)
- {
- // Set the SHF_COMPRESSED bit.
- flags |= elfcpp::SHF_COMPRESSED;
- const bool is_big_endian = parameters->target().is_big_endian();
- uint64_t addralign = this->addralign();
- if (size == 32)
- {
- if (is_big_endian)
- {
- elfcpp::Chdr_write<32, true> chdr(this->data_);
- chdr.put_ch_type(elfcpp::ELFCOMPRESS_ZLIB);
- chdr.put_ch_size(uncompressed_size);
- chdr.put_ch_addralign(addralign);
- }
- else
- {
- elfcpp::Chdr_write<32, false> chdr(this->data_);
- chdr.put_ch_type(elfcpp::ELFCOMPRESS_ZLIB);
- chdr.put_ch_size(uncompressed_size);
- chdr.put_ch_addralign(addralign);
- }
- }
- else if (size == 64)
- {
- if (is_big_endian)
- {
- elfcpp::Chdr_write<64, true> chdr(this->data_);
- chdr.put_ch_type(elfcpp::ELFCOMPRESS_ZLIB);
- chdr.put_ch_size(uncompressed_size);
- chdr.put_ch_addralign(addralign);
- }
- else
- {
- elfcpp::Chdr_write<64, false> chdr(this->data_);
- chdr.put_ch_type(elfcpp::ELFCOMPRESS_ZLIB);
- chdr.put_ch_size(uncompressed_size);
- chdr.put_ch_addralign(addralign);
- }
- }
- else
- gold_unreachable();
- }
- else
- {
- // Write out the zlib header.
- memcpy(this->data_, "ZLIB", 4);
- elfcpp::Swap_unaligned<64, true>::writeval(this->data_ + 4,
- uncompressed_size);
- // This converts .debug_foo to .zdebug_foo
- this->new_section_name_ = std::string(".z") + (this->name() + 1);
- this->set_name(this->new_section_name_.c_str());
- }
- this->set_flags(flags);
- this->set_data_size(compressed_size);
- }
- else
- {
- gold_warning(_("not compressing section data: zlib error"));
- gold_assert(this->data_ == NULL);
- this->set_data_size(uncompressed_size);
- }
- }
- // Write out a compressed section. If we couldn't compress, we just
- // write it out as normal, uncompressed data.
- void
- Output_compressed_section::do_write(Output_file* of)
- {
- off_t offset = this->offset();
- off_t data_size = this->data_size();
- unsigned char* view = of->get_output_view(offset, data_size);
- if (this->data_ == NULL)
- memcpy(view, this->postprocessing_buffer(), data_size);
- else
- memcpy(view, this->data_, data_size);
- of->write_output_view(offset, data_size, view);
- }
- } // End namespace gold.
|