@@ -2245,6 +2245,49 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
2245
2245
return v;
2246
2246
}
2247
2247
2248
+ static void combineVersionedSymbol (Symbol &sym,
2249
+ DenseMap<Symbol *, Symbol *> &map) {
2250
+ const char *suffix1 = sym.getVersionSuffix ();
2251
+ if (suffix1[0 ] != ' @' || suffix1[1 ] == ' @' )
2252
+ return ;
2253
+
2254
+ // Check the existing symbol foo. We have two special cases to handle:
2255
+ //
2256
+ // * There is a definition of foo@v1 and foo@@v1.
2257
+ // * There is a definition of foo@v1 and foo.
2258
+ Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find (sym.getName ()));
2259
+ if (!sym2)
2260
+ return ;
2261
+ const char *suffix2 = sym2->getVersionSuffix ();
2262
+ if (suffix2[0 ] == ' @' && suffix2[1 ] == ' @' &&
2263
+ strcmp (suffix1 + 1 , suffix2 + 2 ) == 0 ) {
2264
+ // foo@v1 and foo@@v1 should be merged, so redirect foo@v1 to foo@@v1.
2265
+ map.try_emplace (&sym, sym2);
2266
+ // If both foo@v1 and foo@@v1 are defined and non-weak, report a
2267
+ // duplicate definition error.
2268
+ if (sym.isDefined ())
2269
+ sym2->checkDuplicate (cast<Defined>(sym));
2270
+ sym2->resolve (sym);
2271
+ // Eliminate foo@v1 from the symbol table.
2272
+ sym.symbolKind = Symbol::PlaceholderKind;
2273
+ sym.isUsedInRegularObj = false ;
2274
+ } else if (auto *sym1 = dyn_cast<Defined>(&sym)) {
2275
+ if (sym2->versionId > VER_NDX_GLOBAL
2276
+ ? config->versionDefinitions [sym2->versionId ].name == suffix1 + 1
2277
+ : sym1->section == sym2->section && sym1->value == sym2->value ) {
2278
+ // Due to an assembler design flaw, if foo is defined, .symver foo,
2279
+ // foo@v1 defines both foo and foo@v1. Unless foo is bound to a
2280
+ // different version, GNU ld makes foo@v1 canonical and eliminates
2281
+ // foo. Emulate its behavior, otherwise we would have foo or foo@@v1
2282
+ // beside foo@v1. foo@v1 and foo combining does not apply if they are
2283
+ // not defined in the same place.
2284
+ map.try_emplace (sym2, &sym);
2285
+ sym2->symbolKind = Symbol::PlaceholderKind;
2286
+ sym2->isUsedInRegularObj = false ;
2287
+ }
2288
+ }
2289
+ }
2290
+
2248
2291
// Do renaming for --wrap and foo@v1 by updating pointers to symbols.
2249
2292
//
2250
2293
// When this function is executed, only InputFiles and symbol table
@@ -2257,51 +2300,14 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
2257
2300
map[w.sym ] = w.wrap ;
2258
2301
map[w.real ] = w.sym ;
2259
2302
}
2260
- for (Symbol *sym : symtab->symbols ()) {
2261
- // Enumerate symbols with a non-default version (foo@v1). hasVersionSuffix
2262
- // filters out most symbols but is not sufficient.
2263
- if (!sym->hasVersionSuffix )
2264
- continue ;
2265
- const char *suffix1 = sym->getVersionSuffix ();
2266
- if (suffix1[0 ] != ' @' || suffix1[1 ] == ' @' )
2267
- continue ;
2268
2303
2269
- // Check the existing symbol foo. We have two special cases to handle:
2270
- //
2271
- // * There is a definition of foo@v1 and foo@@v1.
2272
- // * There is a definition of foo@v1 and foo.
2273
- Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find (sym->getName ()));
2274
- if (!sym2)
2275
- continue ;
2276
- const char *suffix2 = sym2->getVersionSuffix ();
2277
- if (suffix2[0 ] == ' @' && suffix2[1 ] == ' @' &&
2278
- strcmp (suffix1 + 1 , suffix2 + 2 ) == 0 ) {
2279
- // foo@v1 and foo@@v1 should be merged, so redirect foo@v1 to foo@@v1.
2280
- map.try_emplace (sym, sym2);
2281
- // If both foo@v1 and foo@@v1 are defined and non-weak, report a duplicate
2282
- // definition error.
2283
- if (sym->isDefined ())
2284
- sym2->checkDuplicate (cast<Defined>(*sym));
2285
- sym2->resolve (*sym);
2286
- // Eliminate foo@v1 from the symbol table.
2287
- sym->symbolKind = Symbol::PlaceholderKind;
2288
- sym->isUsedInRegularObj = false ;
2289
- } else if (auto *sym1 = dyn_cast<Defined>(sym)) {
2290
- if (sym2->versionId > VER_NDX_GLOBAL
2291
- ? config->versionDefinitions [sym2->versionId ].name == suffix1 + 1
2292
- : sym1->section == sym2->section && sym1->value == sym2->value ) {
2293
- // Due to an assembler design flaw, if foo is defined, .symver foo,
2294
- // foo@v1 defines both foo and foo@v1. Unless foo is bound to a
2295
- // different version, GNU ld makes foo@v1 canonical and eliminates foo.
2296
- // Emulate its behavior, otherwise we would have foo or foo@@v1 beside
2297
- // foo@v1. foo@v1 and foo combining does not apply if they are not
2298
- // defined in the same place.
2299
- map.try_emplace (sym2, sym);
2300
- sym2->symbolKind = Symbol::PlaceholderKind;
2301
- sym2->isUsedInRegularObj = false ;
2302
- }
2303
- }
2304
- }
2304
+ // If there are version definitions (versionDefinitions.size() > 2), enumerate
2305
+ // symbols with a non-default version (foo@v1) and check whether it should be
2306
+ // combined with foo or foo@@v1.
2307
+ if (config->versionDefinitions .size () > 2 )
2308
+ for (Symbol *sym : symtab->symbols ())
2309
+ if (sym->hasVersionSuffix )
2310
+ combineVersionedSymbol (*sym, map);
2305
2311
2306
2312
if (map.empty ())
2307
2313
return ;
0 commit comments