Commit | Line | Data |
---|---|---|
b8e6aad9 ILT |
1 | // merge.cc -- handle section merging for gold |
2 | ||
6cb15b7f ILT |
3 | // Copyright 2006, 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 | ||
b8e6aad9 ILT |
23 | #include "gold.h" |
24 | ||
25 | #include <cstdlib> | |
26 | ||
27 | #include "merge.h" | |
28 | ||
29 | namespace gold | |
30 | { | |
31 | ||
32 | // Sort the entries in a merge mapping. The key is an input object, a | |
33 | // section index in that object, and an offset in that section. | |
34 | ||
35 | bool | |
36 | Output_merge_base::Merge_key_less::operator()(const Merge_key& mk1, | |
37 | const Merge_key& mk2) const | |
38 | { | |
39 | // The order of different objects and different sections doesn't | |
40 | // matter. We want to get consistent results across links so we | |
41 | // don't use pointer comparison. | |
42 | if (mk1.object != mk2.object) | |
43 | return mk1.object->name() < mk2.object->name(); | |
44 | if (mk1.shndx != mk2.shndx) | |
45 | return mk1.shndx < mk2.shndx; | |
46 | return mk1.offset < mk2.offset; | |
47 | } | |
48 | ||
49 | // Add a mapping from an OFFSET in input section SHNDX in object | |
50 | // OBJECT to an OUTPUT_OFFSET in a merged output section. This | |
51 | // manages the mapping used to resolve relocations against merged | |
52 | // sections. | |
53 | ||
54 | void | |
55 | Output_merge_base::add_mapping(Relobj* object, unsigned int shndx, | |
56 | off_t offset, off_t output_offset) | |
57 | { | |
58 | Merge_key mk; | |
59 | mk.object = object; | |
60 | mk.shndx = shndx; | |
61 | mk.offset = offset; | |
62 | std::pair<Merge_map::iterator, bool> ins = | |
63 | this->merge_map_.insert(std::make_pair(mk, output_offset)); | |
64 | gold_assert(ins.second); | |
65 | } | |
66 | ||
67 | // Return the output address for an input address. The input address | |
68 | // is at offset OFFSET in section SHNDX in OBJECT. | |
69 | // OUTPUT_SECTION_ADDRESS is the address of the output section. If we | |
70 | // know the address, set *POUTPUT and return true. Otherwise return | |
71 | // false. | |
72 | ||
73 | bool | |
74 | Output_merge_base::do_output_address(const Relobj* object, unsigned int shndx, | |
75 | off_t offset, | |
76 | uint64_t output_section_address, | |
77 | uint64_t* poutput) const | |
78 | { | |
79 | gold_assert(output_section_address == this->address()); | |
80 | ||
81 | Merge_key mk; | |
82 | mk.object = object; | |
83 | mk.shndx = shndx; | |
84 | mk.offset = offset; | |
85 | Merge_map::const_iterator p = this->merge_map_.lower_bound(mk); | |
86 | ||
87 | // If MK is not in the map, lower_bound returns the next iterator | |
88 | // larger than it. | |
c077629b ILT |
89 | if (p == this->merge_map_.end() |
90 | || p->first.object != object | |
b8e6aad9 ILT |
91 | || p->first.shndx != shndx |
92 | || p->first.offset != offset) | |
93 | { | |
94 | if (p == this->merge_map_.begin()) | |
95 | return false; | |
96 | --p; | |
97 | } | |
98 | ||
99 | if (p->first.object != object || p->first.shndx != shndx) | |
100 | return false; | |
101 | ||
102 | // Any input section is fully mapped: we don't need to know the size | |
103 | // of the range starting at P->FIRST.OFFSET. | |
104 | *poutput = output_section_address + p->second + (offset - p->first.offset); | |
105 | return true; | |
106 | } | |
107 | ||
108 | // Compute the hash code for a fixed-size constant. | |
109 | ||
110 | size_t | |
111 | Output_merge_data::Merge_data_hash::operator()(Merge_data_key k) const | |
112 | { | |
113 | const unsigned char* p = this->pomd_->constant(k); | |
114 | uint64_t entsize = this->pomd_->entsize(); | |
115 | ||
116 | // Fowler/Noll/Vo (FNV) hash (type FNV-1a). | |
117 | if (sizeof(size_t) == 8) | |
118 | { | |
119 | size_t result = static_cast<size_t>(14695981039346656037ULL); | |
120 | for (uint64_t i = 0; i < entsize; ++i) | |
121 | { | |
122 | result &= (size_t) *p++; | |
123 | result *= 1099511628211ULL; | |
124 | } | |
125 | return result; | |
126 | } | |
127 | else | |
128 | { | |
129 | size_t result = 2166136261UL; | |
130 | for (uint64_t i = 0; i < entsize; ++i) | |
131 | { | |
132 | result ^= (size_t) *p++; | |
133 | result *= 16777619UL; | |
134 | } | |
135 | return result; | |
136 | } | |
137 | } | |
138 | ||
139 | // Return whether one hash table key equals another. | |
140 | ||
141 | bool | |
142 | Output_merge_data::Merge_data_eq::operator()(Merge_data_key k1, | |
143 | Merge_data_key k2) const | |
144 | { | |
145 | const unsigned char* p1 = this->pomd_->constant(k1); | |
146 | const unsigned char* p2 = this->pomd_->constant(k2); | |
147 | return memcmp(p1, p2, this->pomd_->entsize()) == 0; | |
148 | } | |
149 | ||
150 | // Add a constant to the end of the section contents. | |
151 | ||
152 | void | |
153 | Output_merge_data::add_constant(const unsigned char* p) | |
154 | { | |
155 | uint64_t entsize = this->entsize(); | |
156 | if (this->len_ + entsize > this->alc_) | |
157 | { | |
158 | if (this->alc_ == 0) | |
159 | this->alc_ = 128 * entsize; | |
160 | else | |
161 | this->alc_ *= 2; | |
162 | this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->alc_)); | |
163 | if (this->p_ == NULL) | |
164 | gold_fatal("out of memory", true); | |
165 | } | |
166 | ||
167 | memcpy(this->p_ + this->len_, p, entsize); | |
168 | this->len_ += entsize; | |
169 | } | |
170 | ||
171 | // Add the input section SHNDX in OBJECT to a merged output section | |
172 | // which holds fixed length constants. Return whether we were able to | |
173 | // handle the section; if not, it will be linked as usual without | |
174 | // constant merging. | |
175 | ||
176 | bool | |
177 | Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx) | |
178 | { | |
179 | off_t len; | |
9eb9fa57 | 180 | const unsigned char* p = object->section_contents(shndx, &len, false); |
b8e6aad9 ILT |
181 | |
182 | uint64_t entsize = this->entsize(); | |
183 | ||
184 | if (len % entsize != 0) | |
185 | return false; | |
186 | ||
187 | for (off_t i = 0; i < len; i += entsize, p += entsize) | |
188 | { | |
189 | // Add the constant to the section contents. If we find that it | |
190 | // is already in the hash table, we will remove it again. | |
191 | Merge_data_key k = this->len_; | |
192 | this->add_constant(p); | |
193 | ||
194 | std::pair<Merge_data_hashtable::iterator, bool> ins = | |
195 | this->hashtable_.insert(k); | |
196 | ||
197 | if (!ins.second) | |
198 | { | |
199 | // Key was already present. Remove the copy we just added. | |
200 | this->len_ -= entsize; | |
201 | k = *ins.first; | |
202 | } | |
203 | ||
204 | // Record the offset of this constant in the output section. | |
205 | this->add_mapping(object, shndx, i, k); | |
206 | } | |
207 | ||
208 | return true; | |
209 | } | |
210 | ||
211 | // Set the final data size in a merged output section with fixed size | |
212 | // constants. | |
213 | ||
214 | void | |
215 | Output_merge_data::do_set_address(uint64_t, off_t) | |
216 | { | |
217 | // Release the memory we don't need. | |
218 | this->p_ = static_cast<unsigned char*>(realloc(this->p_, this->len_)); | |
219 | gold_assert(this->p_ != NULL); | |
220 | this->set_data_size(this->len_); | |
221 | } | |
222 | ||
223 | // Write the data of a merged output section with fixed size constants | |
224 | // to the file. | |
225 | ||
226 | void | |
227 | Output_merge_data::do_write(Output_file* of) | |
228 | { | |
229 | of->write(this->offset(), this->p_, this->len_); | |
230 | } | |
231 | ||
b8e6aad9 ILT |
232 | // Add an input section to a merged string section. |
233 | ||
234 | template<typename Char_type> | |
235 | bool | |
236 | Output_merge_string<Char_type>::do_add_input_section(Relobj* object, | |
237 | unsigned int shndx) | |
238 | { | |
239 | off_t len; | |
9eb9fa57 | 240 | const unsigned char* pdata = object->section_contents(shndx, &len, false); |
b8e6aad9 ILT |
241 | |
242 | const Char_type* p = reinterpret_cast<const Char_type*>(pdata); | |
243 | ||
244 | if (len % sizeof(Char_type) != 0) | |
245 | { | |
246 | fprintf(stderr, | |
247 | _("%s: %s: mergeable string section length not multiple of " | |
248 | "character size\n"), | |
249 | program_name, object->name().c_str()); | |
250 | gold_exit(false); | |
251 | } | |
252 | len /= sizeof(Char_type); | |
253 | ||
254 | off_t i = 0; | |
255 | while (i < len) | |
256 | { | |
257 | off_t plen = 0; | |
258 | for (const Char_type* pl = p; *pl != 0; ++pl) | |
259 | { | |
260 | ++plen; | |
261 | if (i + plen >= len) | |
262 | { | |
263 | fprintf(stderr, | |
264 | _("%s: %s: entry in mergeable string section " | |
265 | "not null terminated\n"), | |
266 | program_name, object->name().c_str()); | |
267 | gold_exit(false); | |
268 | } | |
269 | } | |
270 | ||
271 | const Char_type* str = this->stringpool_.add(p, NULL); | |
272 | ||
42e3fe0d | 273 | this->merged_strings_.push_back(Merged_string(object, shndx, i, str)); |
b8e6aad9 ILT |
274 | |
275 | p += plen + 1; | |
276 | i += plen + 1; | |
277 | } | |
278 | ||
279 | return true; | |
280 | } | |
281 | ||
282 | // Set the final data size of a merged string section. This is where | |
283 | // we finalize the mappings from the input sections to the output | |
284 | // section. | |
285 | ||
286 | template<typename Char_type> | |
287 | void | |
288 | Output_merge_string<Char_type>::do_set_address(uint64_t, off_t) | |
289 | { | |
290 | this->stringpool_.set_string_offsets(); | |
291 | ||
42e3fe0d ILT |
292 | for (typename Merged_strings::const_iterator p = |
293 | this->merged_strings_.begin(); | |
294 | p != this->merged_strings_.end(); | |
b8e6aad9 | 295 | ++p) |
42e3fe0d ILT |
296 | this->add_mapping(p->object, p->shndx, p->offset, |
297 | this->stringpool_.get_offset(p->string)); | |
b8e6aad9 ILT |
298 | |
299 | this->set_data_size(this->stringpool_.get_strtab_size()); | |
300 | ||
301 | // Save some memory. | |
42e3fe0d | 302 | this->merged_strings_.clear(); |
b8e6aad9 ILT |
303 | } |
304 | ||
305 | // Write out a merged string section. | |
306 | ||
307 | template<typename Char_type> | |
308 | void | |
309 | Output_merge_string<Char_type>::do_write(Output_file* of) | |
310 | { | |
311 | this->stringpool_.write(of, this->offset()); | |
312 | } | |
313 | ||
314 | // Instantiate the templates we need. | |
315 | ||
316 | template | |
317 | class Output_merge_string<char>; | |
318 | ||
319 | template | |
320 | class Output_merge_string<uint16_t>; | |
321 | ||
322 | template | |
323 | class Output_merge_string<uint32_t>; | |
324 | ||
325 | } // End namespace gold. |