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