1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
|
// merge.h -- handle section merging for gold -*- C++ -*-
// Copyright 2006, 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.
#ifndef GOLD_MERGE_H
#define GOLD_MERGE_H
#include <climits>
#include "stringpool.h"
#include "output.h"
namespace gold
{
// This class manages mappings from input sections to offsets in an
// output section. This is used where input sections are merged. The
// actual data is stored in fields in Object.
class Merge_map
{
public:
Merge_map()
{ }
// Add a mapping for the bytes from OFFSET to OFFSET + LENGTH in the
// input section SHNDX in object OBJECT to OUTPUT_OFFSET in the
// output section. An OUTPUT_OFFSET of -1 means that the bytes are
// discarded.
void
add_mapping(Relobj* object, unsigned int shndx, off_t offset, off_t length,
off_t output_offset);
// Return the output offset for an input address. The input address
// is at offset OFFSET in section SHNDX in OBJECT. This sets
// *OUTPUT_OFFSET to the offset in the output section; this will be
// -1 if the bytes are not being copied to the output. This returns
// true if the mapping is known, false otherwise.
bool
get_output_offset(const Relobj* object, unsigned int shndx, off_t offset,
off_t *output_offset) const;
};
// A general class for SHF_MERGE data, to hold functions shared by
// fixed-size constant data and string data.
class Output_merge_base : public Output_section_data
{
public:
Output_merge_base(uint64_t entsize, uint64_t addralign)
: Output_section_data(addralign), merge_map_(), entsize_(entsize)
{ }
// Return the output offset for an input offset.
bool
do_output_offset(const Relobj* object, unsigned int shndx, off_t offset,
off_t* poutput) const;
protected:
// Return the entry size.
uint64_t
entsize() const
{ return this->entsize_; }
// Add a mapping from an OFFSET in input section SHNDX in object
// OBJECT to an OUTPUT_OFFSET in the output section.
void
add_mapping(Relobj* object, unsigned int shndx, off_t offset,
off_t length, off_t output_offset)
{
this->merge_map_.add_mapping(object, shndx, offset, length, output_offset);
}
private:
// A mapping from input object/section/offset to offset in output
// section.
Merge_map merge_map_;
// The entry size. For fixed-size constants, this is the size of
// the constants. For strings, this is the size of a character.
uint64_t entsize_;
};
// Handle SHF_MERGE sections with fixed-size constant data.
class Output_merge_data : public Output_merge_base
{
public:
Output_merge_data(uint64_t entsize, uint64_t addralign)
: Output_merge_base(entsize, addralign), p_(NULL), len_(0), alc_(0),
hashtable_(128, Merge_data_hash(this), Merge_data_eq(this))
{ }
// Add an input section.
bool
do_add_input_section(Relobj* object, unsigned int shndx);
// Set the final data size.
void
do_set_address(uint64_t, off_t);
// Write the data to the file.
void
do_write(Output_file*);
private:
// We build a hash table of the fixed-size constants. Each constant
// is stored as a pointer into the section data we are accumulating.
// A key in the hash table. This is an offset in the section
// contents we are building.
typedef off_t Merge_data_key;
// Compute the hash code. To do this we need a pointer back to the
// object holding the data.
class Merge_data_hash
{
public:
Merge_data_hash(const Output_merge_data* pomd)
: pomd_(pomd)
{ }
size_t
operator()(Merge_data_key) const;
private:
const Output_merge_data* pomd_;
};
friend class Merge_data_hash;
// Compare two entries in the hash table for equality. To do this
// we need a pointer back to the object holding the data. Note that
// we now have a pointer to the object stored in two places in the
// hash table. Fixing this would require specializing the hash
// table, which would be hard to do portably.
class Merge_data_eq
{
public:
Merge_data_eq(const Output_merge_data* pomd)
: pomd_(pomd)
{ }
bool
operator()(Merge_data_key k1, Merge_data_key k2) const;
private:
const Output_merge_data* pomd_;
};
friend class Merge_data_eq;
// The type of the hash table.
typedef Unordered_set<Merge_data_key, Merge_data_hash, Merge_data_eq>
Merge_data_hashtable;
// Given a hash table key, which is just an offset into the section
// data, return a pointer to the corresponding constant.
const unsigned char*
constant(Merge_data_key k) const
{
gold_assert(k >= 0 && k < this->len_);
return this->p_ + k;
}
// Add a constant to the output.
void
add_constant(const unsigned char*);
// The accumulated data.
unsigned char* p_;
// The length of the accumulated data.
off_t len_;
// The size of the allocated buffer.
size_t alc_;
// The hash table.
Merge_data_hashtable hashtable_;
};
// Handle SHF_MERGE sections with string data. This is a template
// based on the type of the characters in the string.
template<typename Char_type>
class Output_merge_string : public Output_merge_base
{
public:
Output_merge_string(uint64_t addralign)
: Output_merge_base(sizeof(Char_type), addralign), stringpool_(),
merged_strings_()
{
gold_assert(addralign <= sizeof(Char_type));
this->stringpool_.set_no_zero_null();
}
// Add an input section.
bool
do_add_input_section(Relobj* object, unsigned int shndx);
// Set the final data size.
void
do_set_address(uint64_t, off_t);
// Write the data to the file.
void
do_write(Output_file*);
private:
// As we see input sections, we build a mapping from object, section
// index and offset to strings.
struct Merged_string
{
// The input object where the string was found.
Relobj* object;
// The input section in the input object.
unsigned int shndx;
// The offset in the input section.
off_t offset;
// The string itself, a pointer into a Stringpool.
const Char_type* string;
// The length of the string in bytes, including the null terminator.
size_t length;
Merged_string(Relobj *objecta, unsigned int shndxa, off_t offseta,
const Char_type* stringa, size_t lengtha)
: object(objecta), shndx(shndxa), offset(offseta), string(stringa),
length(lengtha)
{ }
};
typedef std::vector<Merged_string> Merged_strings;
// As we see the strings, we add them to a Stringpool.
Stringpool_template<Char_type> stringpool_;
// Map from a location in an input object to an entry in the
// Stringpool.
Merged_strings merged_strings_;
};
} // End namespace gold.
#endif // !defined(GOLD_MERGE_H)
|