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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
|
// stringpool.h -- a string pool 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.
#include <string>
#include <list>
#ifndef GOLD_STRINGPOOL_H
#define GOLD_STRINGPOOL_H
namespace gold
{
class Output_file;
// A Stringpool is a pool of unique strings. It provides the
// following features:
// Every string in the pool is unique. Thus, if you have two strings
// in the Stringpool, you can compare them for equality by using
// pointer comparison rather than string comparison.
// There is a key associated with every string in the pool. If you
// add strings to the Stringpool in the same order, then the key for
// each string will always be the same for any run of the linker.
// This is not true of the string pointers themselves, as they may
// change due to address space randomization. Some parts of the
// linker (e.g., the symbol table) use the key value instead of the
// string pointer so that repeated runs of the linker will generate
// precisely the same output.
// When you add a string to a Stringpool, Stringpool will optionally
// make a copy of it. Thus there is no requirement to keep a copy
// elsewhere.
// A Stringpool can be turned into a string table, a sequential series
// of null terminated strings. The first string may optionally be a
// single zero byte, as required for SHT_STRTAB sections. This
// conversion is only permitted after all strings have been added to
// the Stringpool. After doing this conversion, you can ask for the
// offset of any string in the stringpool in the string table, and you
// can write the resulting string table to an output file.
// When a Stringpool is turned into a string table, then as an
// optimization it will reuse string suffixes to avoid duplicating
// strings. That is, given the strings "abc" and "bc", only the
// string "abc" will be stored, and "bc" will be represented by an
// offset into the middle of the string "abc".
// Stringpools are implemented in terms of Stringpool_template, which
// is generalized on the type of character used for the strings. Most
// uses will want the Stringpool type which uses char. Other cases
// are used for merging wide string constants.
template<typename Stringpool_char>
class Stringpool_template
{
public:
// The type of a key into the stringpool. As described above, a key
// value will always be the same during any run of the linker. Zero
// is never a valid key value.
typedef size_t Key;
// Create a Stringpool.
Stringpool_template();
~Stringpool_template();
// Clear all the data from the stringpool.
void
clear();
// Hint to the stringpool class that you intend to insert n additional
// elements. The stringpool class can use this info however it likes;
// in practice it will resize its internal hashtables to make room.
void
reserve(unsigned int n);
// Indicate that we should not reserve offset 0 to hold the empty
// string when converting the stringpool to a string table. This
// should not be called for a proper ELF SHT_STRTAB section.
void
set_no_zero_null()
{ this->zero_null_ = false; }
// Add the string S to the pool. This returns a canonical permanent
// pointer to the string in the pool. If COPY is true, the string
// is copied into permanent storage. If PKEY is not NULL, this sets
// *PKEY to the key for the string.
const Stringpool_char*
add(const Stringpool_char* s, bool copy, Key* pkey);
// Add the prefix of length LEN of string S to the pool.
const Stringpool_char*
add_prefix(const Stringpool_char* s, size_t len, Key* pkey);
// If the string S is present in the pool, return the canonical
// string pointer. Otherwise, return NULL. If PKEY is not NULL,
// set *PKEY to the key.
const Stringpool_char*
find(const Stringpool_char* s, Key* pkey) const;
// Turn the stringpool into a string table: determine the offsets of
// all the strings. After this is called, no more strings may be
// added to the stringpool.
void
set_string_offsets();
// Get the offset of the string S in the string table. This returns
// the offset in bytes, not in units of Stringpool_char. This may
// only be called after set_string_offsets has been called.
section_offset_type
get_offset(const Stringpool_char* s) const;
// Get the offset of the string S in the string table.
section_offset_type
get_offset(const std::basic_string<Stringpool_char>& s) const
{ return this->get_offset(s.c_str()); }
// Get the size of the string table. This returns the number of
// bytes, not in units of Stringpool_char.
section_size_type
get_strtab_size() const
{
gold_assert(this->strtab_size_ != 0);
return this->strtab_size_;
}
// Write the string table into the output file at the specified
// offset.
void
write(Output_file*, off_t offset);
// Write the string table into the specified buffer, of the
// specified size. buffer_size should be at least
// get_strtab_size().
void
write_to_buffer(unsigned char* buffer, section_size_type buffer_size);
// Dump statistical information to stderr.
void
print_stats(const char*) const;
private:
Stringpool_template(const Stringpool_template&);
Stringpool_template& operator=(const Stringpool_template&);
// Return the length of a string in units of Stringpool_char.
static size_t
string_length(const Stringpool_char*);
// Return whether two strings are equal.
static bool
string_equal(const Stringpool_char*, const Stringpool_char*);
// Compute a hash code for a string. LENGTH is the length of the
// string in characters.
static size_t
string_hash(const Stringpool_char*, size_t length);
// We store the actual data in a list of these buffers.
struct Stringdata
{
// Length of data in buffer.
size_t len;
// Allocated size of buffer.
size_t alc;
// Buffer index.
unsigned int index;
// Buffer.
char data[1];
};
// Copy a string into the buffers, returning a canonical string.
const Stringpool_char*
add_string(const Stringpool_char*, size_t, Key*);
// Return whether s1 is a suffix of s2.
static bool
is_suffix(const Stringpool_char* s1, size_t len1,
const Stringpool_char* s2, size_t len2);
// The hash table key includes the string, the length of the string,
// and the hash code for the string. We put the hash code
// explicitly into the key so that we can do a find()/insert()
// sequence without having to recompute the hash. Computing the
// hash code is a significant user of CPU time in the linker.
struct Hashkey
{
const Stringpool_char* string;
// Length is in characters, not bytes.
size_t length;
size_t hash_code;
// This goes in an STL container, so we need a default
// constructor.
Hashkey()
: string(NULL), length(0), hash_code(0)
{ }
// Note that these constructors are relatively expensive, because
// they compute the hash code.
Hashkey(const Stringpool_char* s)
: string(s), length(string_length(s)), hash_code(string_hash(s, length))
{ }
Hashkey(const Stringpool_char* s, size_t len)
: string(s), length(len), hash_code(string_hash(s, len))
{ }
};
// Hash function. This is trivial, since we have already computed
// the hash.
struct Stringpool_hash
{
size_t
operator()(const Hashkey& hk) const
{ return hk.hash_code; }
};
// Equality comparison function for hash table.
struct Stringpool_eq
{
bool
operator()(const Hashkey&, const Hashkey&) const;
};
// The hash table is a map from strings to a pair of Key and string
// table offsets. We only use the offsets if we turn this into an
// string table section.
typedef std::pair<Key, section_offset_type> Hashval;
typedef Unordered_map<Hashkey, Hashval, Stringpool_hash,
Stringpool_eq> String_set_type;
// Comparison routine used when sorting into a string table.
typedef typename String_set_type::iterator Stringpool_sort_info;
struct Stringpool_sort_comparison
{
bool
operator()(const Stringpool_sort_info&, const Stringpool_sort_info&) const;
};
// List of Stringdata structures.
typedef std::list<Stringdata*> Stringdata_list;
// Mapping from const char* to namepool entry.
String_set_type string_set_;
// List of buffers.
Stringdata_list strings_;
// Size of string table.
section_size_type strtab_size_;
// Next Stringdata index.
unsigned int next_index_;
// Next key value for a string we don't copy.
int next_uncopied_key_;
// Whether to reserve offset 0 to hold the null string.
bool zero_null_;
};
// The most common type of Stringpool.
typedef Stringpool_template<char> Stringpool;
} // End namespace gold.
#endif // !defined(GOLD_STRINGPOOL_H)
|