@@ -134,9 +134,20 @@ static bool canBeVersioned(const Symbol &sym) {
134
134
StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms () {
135
135
if (!demangledSyms) {
136
136
demangledSyms.emplace ();
137
+ std::string demangled;
137
138
for (Symbol *sym : symVector)
138
- if (canBeVersioned (*sym))
139
- (*demangledSyms)[demangleItanium (sym->getName ())].push_back (sym);
139
+ if (canBeVersioned (*sym)) {
140
+ StringRef name = sym->getName ();
141
+ size_t pos = name.find (' @' );
142
+ if (pos == std::string::npos)
143
+ demangled = demangleItanium (name);
144
+ else if (pos + 1 == name.size () || name[pos + 1 ] == ' @' )
145
+ demangled = demangleItanium (name.substr (0 , pos));
146
+ else
147
+ demangled =
148
+ (demangleItanium (name.substr (0 , pos)) + name.substr (pos)).str ();
149
+ (*demangledSyms)[demangled].push_back (sym);
150
+ }
140
151
}
141
152
return *demangledSyms;
142
153
}
@@ -150,19 +161,29 @@ std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion ver) {
150
161
return {};
151
162
}
152
163
153
- std::vector<Symbol *> SymbolTable::findAllByVersion (SymbolVersion ver) {
164
+ std::vector<Symbol *> SymbolTable::findAllByVersion (SymbolVersion ver,
165
+ bool includeNonDefault) {
154
166
std::vector<Symbol *> res;
155
167
SingleStringMatcher m (ver.name );
168
+ auto check = [&](StringRef name) {
169
+ size_t pos = name.find (' @' );
170
+ if (!includeNonDefault)
171
+ return pos == StringRef::npos;
172
+ return !(pos + 1 < name.size () && name[pos + 1 ] == ' @' );
173
+ };
156
174
157
175
if (ver.isExternCpp ) {
158
176
for (auto &p : getDemangledSyms ())
159
177
if (m.match (p.first ()))
160
- res.insert (res.end (), p.second .begin (), p.second .end ());
178
+ for (Symbol *sym : p.second )
179
+ if (check (sym->getName ()))
180
+ res.push_back (sym);
161
181
return res;
162
182
}
163
183
164
184
for (Symbol *sym : symVector)
165
- if (canBeVersioned (*sym) && m.match (sym->getName ()))
185
+ if (canBeVersioned (*sym) && check (sym->getName ()) &&
186
+ m.match (sym->getName ()))
166
187
res.push_back (sym);
167
188
return res;
168
189
}
@@ -172,7 +193,7 @@ void SymbolTable::handleDynamicList() {
172
193
for (SymbolVersion &ver : config->dynamicList ) {
173
194
std::vector<Symbol *> syms;
174
195
if (ver.hasWildcard )
175
- syms = findAllByVersion (ver);
196
+ syms = findAllByVersion (ver, /* includeNonDefault= */ true );
176
197
else
177
198
syms = findByVersion (ver);
178
199
@@ -181,21 +202,13 @@ void SymbolTable::handleDynamicList() {
181
202
}
182
203
}
183
204
184
- // Set symbol versions to symbols. This function handles patterns
185
- // containing no wildcard characters.
186
- void SymbolTable::assignExactVersion (SymbolVersion ver, uint16_t versionId,
187
- StringRef versionName) {
188
- if (ver.hasWildcard )
189
- return ;
190
-
205
+ // Set symbol versions to symbols. This function handles patterns containing no
206
+ // wildcard characters. Return false if no symbol definition matches ver.
207
+ bool SymbolTable::assignExactVersion (SymbolVersion ver, uint16_t versionId,
208
+ StringRef versionName,
209
+ bool includeNonDefault) {
191
210
// Get a list of symbols which we need to assign the version to.
192
211
std::vector<Symbol *> syms = findByVersion (ver);
193
- if (syms.empty ()) {
194
- if (!config->undefinedVersion )
195
- error (" version script assignment of '" + versionName + " ' to symbol '" +
196
- ver.name + " ' failed: symbol not defined" );
197
- return ;
198
- }
199
212
200
213
auto getName = [](uint16_t ver) -> std::string {
201
214
if (ver == VER_NDX_LOCAL)
@@ -207,10 +220,11 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
207
220
208
221
// Assign the version.
209
222
for (Symbol *sym : syms) {
210
- // Skip symbols containing version info because symbol versions
211
- // specified by symbol names take precedence over version scripts.
212
- // See parseSymbolVersion().
213
- if (sym->getName ().contains (' @' ))
223
+ // For a non-local versionId, skip symbols containing version info because
224
+ // symbol versions specified by symbol names take precedence over version
225
+ // scripts. See parseSymbolVersion().
226
+ if (!includeNonDefault && versionId != VER_NDX_LOCAL &&
227
+ sym->getName ().contains (' @' ))
214
228
continue ;
215
229
216
230
// If the version has not been assigned, verdefIndex is -1. Use an arbitrary
@@ -225,13 +239,15 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
225
239
warn (" attempt to reassign symbol '" + ver.name + " ' of " +
226
240
getName (sym->versionId ) + " to " + getName (versionId));
227
241
}
242
+ return !syms.empty ();
228
243
}
229
244
230
- void SymbolTable::assignWildcardVersion (SymbolVersion ver, uint16_t versionId) {
245
+ void SymbolTable::assignWildcardVersion (SymbolVersion ver, uint16_t versionId,
246
+ bool includeNonDefault) {
231
247
// Exact matching takes precedence over fuzzy matching,
232
248
// so we set a version to a symbol only if no version has been assigned
233
249
// to the symbol. This behavior is compatible with GNU.
234
- for (Symbol *sym : findAllByVersion (ver))
250
+ for (Symbol *sym : findAllByVersion (ver, includeNonDefault ))
235
251
if (sym->verdefIndex == UINT32_C (-1 )) {
236
252
sym->verdefIndex = 0 ;
237
253
sym->versionId = versionId;
@@ -244,26 +260,60 @@ void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId) {
244
260
// script file, the script does not actually define any symbol version,
245
261
// but just specifies symbols visibilities.
246
262
void SymbolTable::scanVersionScript () {
263
+ SmallString<128 > buf;
247
264
// First, we assign versions to exact matching symbols,
248
265
// i.e. version definitions not containing any glob meta-characters.
249
- for (VersionDefinition &v : config->versionDefinitions )
250
- for (SymbolVersion &pat : v.patterns )
251
- assignExactVersion (pat, v.id , v.name );
266
+ std::vector<Symbol *> syms;
267
+ for (VersionDefinition &v : config->versionDefinitions ) {
268
+ auto assignExact = [&](SymbolVersion pat, uint16_t id, StringRef ver) {
269
+ bool found =
270
+ assignExactVersion (pat, id, ver, /* includeNonDefault=*/ false );
271
+ buf.clear ();
272
+ found |= assignExactVersion ({(pat.name + " @" + v.name ).toStringRef (buf),
273
+ pat.isExternCpp , /* hasWildCard=*/ false },
274
+ id, ver, /* includeNonDefault=*/ true );
275
+ if (!found && !config->undefinedVersion )
276
+ errorOrWarn (" version script assignment of '" + ver + " ' to symbol '" +
277
+ pat.name + " ' failed: symbol not defined" );
278
+ };
279
+ for (SymbolVersion &pat : v.nonLocalPatterns )
280
+ if (!pat.hasWildcard )
281
+ assignExact (pat, v.id , v.name );
282
+ for (SymbolVersion pat : v.localPatterns )
283
+ if (!pat.hasWildcard )
284
+ assignExact (pat, VER_NDX_LOCAL, " local" );
285
+ }
252
286
253
287
// Next, assign versions to wildcards that are not "*". Note that because the
254
288
// last match takes precedence over previous matches, we iterate over the
255
289
// definitions in the reverse order.
256
- for (VersionDefinition &v : llvm::reverse (config->versionDefinitions ))
257
- for (SymbolVersion &pat : v.patterns )
290
+ auto assignWildcard = [&](SymbolVersion pat, uint16_t id, StringRef ver) {
291
+ assignWildcardVersion (pat, id, /* includeNonDefault=*/ false );
292
+ buf.clear ();
293
+ assignWildcardVersion ({(pat.name + " @" + ver).toStringRef (buf),
294
+ pat.isExternCpp , /* hasWildCard=*/ true },
295
+ id,
296
+ /* includeNonDefault=*/ true );
297
+ };
298
+ for (VersionDefinition &v : llvm::reverse (config->versionDefinitions )) {
299
+ for (SymbolVersion &pat : v.nonLocalPatterns )
258
300
if (pat.hasWildcard && pat.name != " *" )
259
- assignWildcardVersion (pat, v.id );
301
+ assignWildcard (pat, v.id , v.name );
302
+ for (SymbolVersion &pat : v.localPatterns )
303
+ if (pat.hasWildcard && pat.name != " *" )
304
+ assignWildcard (pat, VER_NDX_LOCAL, v.name );
305
+ }
260
306
261
307
// Then, assign versions to "*". In GNU linkers they have lower priority than
262
308
// other wildcards.
263
- for (VersionDefinition &v : config->versionDefinitions )
264
- for (SymbolVersion &pat : v.patterns )
309
+ for (VersionDefinition &v : config->versionDefinitions ) {
310
+ for (SymbolVersion &pat : v.nonLocalPatterns )
265
311
if (pat.hasWildcard && pat.name == " *" )
266
- assignWildcardVersion (pat, v.id );
312
+ assignWildcard (pat, v.id , v.name );
313
+ for (SymbolVersion &pat : v.localPatterns )
314
+ if (pat.hasWildcard && pat.name == " *" )
315
+ assignWildcard (pat, VER_NDX_LOCAL, v.name );
316
+ }
267
317
268
318
// Symbol themselves might know their versions because symbols
269
319
// can contain versions in the form of <name>@<version>.
0 commit comments