From Craig Silverstein: Add support for compressing .debug_str section.
[deliverable/binutils-gdb.git] / gold / compressed_output.cc
CommitLineData
9a0910c3
ILT
1// compressed_output.cc -- manage compressed output sections for gold
2
3// Copyright 2007 Free Software Foundation, Inc.
4// Written by Ian Lance Taylor <iant@google.com>.
5
6// This file is part of gold.
7
8// This program is free software; you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation; either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU General Public License for more details.
17
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21// MA 02110-1301, USA.
22
23#include "gold.h"
24
25#ifdef HAVE_ZLIB_H
26#include <zlib.h>
27#endif
28
29#include "compressed_output.h"
30#include "parameters.h"
31
32namespace gold
33{
34
35// Compress UNCOMPRESSED_DATA of size UNCOMPRESSED_SIZE. Returns true
36// if it successfully compressed, false if it failed for any reason
37// (including not having zlib support in the library). If it returns
38// true, it allocates memory for the compressed data using new, and
39// sets *COMPRESSED_DATA and *COMPRESSED_SIZE to appropriate values.
40
41static bool
42zlib_compress(const char* uncompressed_data, unsigned long uncompressed_size,
43 char** compressed_data, unsigned long* compressed_size)
44{
45#ifndef HAVE_ZLIB_H
46 return false;
47#else
48 *compressed_size = uncompressed_size + uncompressed_size / 1000 + 128;
49 *compressed_data = new char[*compressed_size];
50
51 int compress_level;
52 if (parameters->optimization_level() >= 1)
53 compress_level = 9;
54 else
55 compress_level = 1;
56
57 int rc = compress2(reinterpret_cast<Bytef*>(*compressed_data),
58 compressed_size,
59 reinterpret_cast<const Bytef*>(uncompressed_data),
60 uncompressed_size,
61 compress_level);
62 if (rc == Z_OK)
63 return true;
64 else
65 {
66 delete[] *compressed_data;
67 *compressed_data = NULL;
68 return false;
69 }
70#endif // #ifdef HAVE_ZLIB_H
71}
72
73// After compressing an output section, we rename it from foo to
74// foo.zlib.nnnn, where nnnn is the uncompressed size of the section.
75
76static std::string
77zlib_compressed_suffix(unsigned long uncompressed_size)
78{
79 char size_string[64];
80 snprintf(size_string, sizeof(size_string), "%lu", uncompressed_size);
81 return std::string(".zlib.") + size_string;
82}
83
84// Class Output_compressed_section_data.
85
86// Add an input section. In this case, we just keep track of the sections.
87
88bool
89Output_compressed_section_data::do_add_input_section(Relobj* obj,
90 unsigned int shndx)
91{
92 this->objects_.push_back(Object_entry(obj, shndx));
93 return true;
94}
95
96// Set the final data size of a compressed section. This is where
97// we actually compress the section data.
98
99void
100Output_compressed_section_data::set_final_data_size()
101{
102 // FIXME: assert that relocations have already been applied.
103
104 off_t uncompressed_size = 0;
105 for (std::vector<Object_entry>::iterator it = this->objects_.begin();
106 it != this->objects_.end();
107 ++it)
108 {
109 it->contents
110 = it->object->section_contents(it->shndx, &it->length, false);
111 uncompressed_size += it->length;
112 }
113
114 // (Try to) compress the data.
115 unsigned long compressed_size;
116 char* uncompressed_data = new char[uncompressed_size];
117 off_t pos = 0;
118 for (std::vector<Object_entry>::const_iterator it = this->objects_.begin();
119 it != this->objects_.end();
120 ++it)
121 {
122 memcpy(uncompressed_data + pos,
123 reinterpret_cast<const char*>(it->contents),
124 it->length);
125 pos += it->length;
126 }
127
128 bool success = false;
129 if (options_.zlib_compress_debug_sections())
130 success = zlib_compress(uncompressed_data, uncompressed_size,
131 &this->data_, &compressed_size);
132 if (success)
133 {
134 delete[] uncompressed_data;
135 this->set_data_size(compressed_size);
136 this->new_section_name_ = zlib_compressed_suffix(uncompressed_size);
137 }
138 else
139 {
140 gold_warning(_("Not compressing section data: zlib error"));
141 gold_assert(this->data_ == NULL);
142 this->data_ = uncompressed_data;
143 this->set_data_size(uncompressed_size);
144 }
145}
146
147// Change the name of the output section to reflect it's compressed.
148// The layout routines call into this right before finalizing the
149// shstrtab.
150
151const char*
152Output_compressed_section_data::do_modified_output_section_name(
153 const char* name)
154{
155 // This mean we never compressed the data.
156 if (this->new_section_name_.empty())
157 return NULL;
158 this->new_section_name_ = std::string(name) + this->new_section_name_;
159 return this->new_section_name_.c_str();
160}
161
162// Write out a compressed section. If we couldn't compress, we just
163// write it out as normal, uncompressed data.
164
165void
166Output_compressed_section_data::do_write(Output_file* of)
167{
168 unsigned char* uview = of->get_output_view(this->offset(),
169 this->data_size());
170 char* view = reinterpret_cast<char*>(uview);
171 memcpy(view, this->data_, this->data_size());
172 of->write_output_view(this->offset(), this->data_size(), uview);
173}
174
175// Class Output_compressed_string.
176
177// Add an input section. We don't do anything special here.
178
179template<typename Char_type>
180bool
181Output_compressed_string<Char_type>::do_add_input_section(Relobj* object,
182 unsigned int shndx)
183{
184 return Output_merge_string<Char_type>::do_add_input_section(object, shndx);
185}
186
187// Set the final data size of a compressed section. This is where
188// we actually compress the section data.
189
190template<typename Char_type>
191void
192Output_compressed_string<Char_type>::set_final_data_size()
193{
194 // First let the superclass finalize all its data, then write it to
195 // a buffer.
196 unsigned long uncompressed_size = this->finalize_merged_data();
197 char* uncompressed_data = new char[uncompressed_size];
198 this->stringpool_to_buffer(uncompressed_data, uncompressed_size);
199
200 // (Try to) compress the data.
201 unsigned long compressed_size;
202 if (options_.zlib_compress_debug_sections()
203 && zlib_compress(uncompressed_data, uncompressed_size,
204 &this->compressed_data_, &compressed_size))
205 {
206 this->set_data_size(compressed_size);
207 // Save some memory.
208 this->clear_stringpool();
209 // We will be renaming the section to name.zlib.uncompressed_size.
210 this->new_section_name_ = zlib_compressed_suffix(uncompressed_size);
211 }
212 else
213 {
214 this->compressed_data_ = NULL;
215 this->set_data_size(uncompressed_size);
216 }
217
218 delete[] uncompressed_data;
219}
220
221// Change the name of the output section to reflect it's compressed.
222// The layout routines call into this right before finalizing the
223// shstrtab.
224
225template<typename Char_type>
226const char*
227Output_compressed_string<Char_type>::do_modified_output_section_name(
228 const char* name)
229{
230 // This mean we never compressed the data
231 if (this->new_section_name_.empty())
232 return NULL;
233 this->new_section_name_ = std::string(name) + this->new_section_name_;
234 return this->new_section_name_.c_str();
235}
236
237// Write out a compressed string section. If we couldn't compress,
238// we just write out the normal string section.
239
240template<typename Char_type>
241void
242Output_compressed_string<Char_type>::do_write(Output_file* of)
243{
244 if (this->compressed_data_ == NULL)
245 Output_merge_string<Char_type>::do_write(of);
246 else
247 {
248 unsigned char* uview = of->get_output_view(this->offset(),
249 this->data_size());
250 char* view = reinterpret_cast<char*>(uview);
251 memcpy(view, this->compressed_data_, this->data_size());
252 of->write_output_view(this->offset(), this->data_size(), uview);
253 }
254}
255
256// Instantiate the templates we need.
257
258template
259class Output_compressed_string<char>;
260
261template
262class Output_compressed_string<uint16_t>;
263
264template
265class Output_compressed_string<uint32_t>;
266
267} // End namespace gold.
This page took 0.032029 seconds and 4 git commands to generate.