@@ -2215,6 +2215,130 @@ void ElfFile<ElfFileParamNames>::renameDynamicSymbols(const std::unordered_map<s
2215
2215
this ->rewriteSections ();
2216
2216
}
2217
2217
2218
+ template <ElfFileParams>
2219
+ void ElfFile<ElfFileParamNames>::removeNeededVersion(const std::map<std::string, std::set<std::string>> & verMap)
2220
+ {
2221
+ if (verMap.empty ()) return ;
2222
+
2223
+ auto idxVersionR = getSectionIndex (" .gnu.version_r" );
2224
+ if (!idxVersionR) {
2225
+ error (" no .gnu.version_r section found\n " );
2226
+ return ;
2227
+ }
2228
+ auto & shdrVersionR = shdrs.at (idxVersionR);
2229
+ Elf_Shdr & shdrVersionRStrings = shdrs.at (rdi (shdrVersionR.sh_link ));
2230
+
2231
+ auto spanVersyms = tryGetSectionSpan<Elf_Versym>(" .gnu.version" );
2232
+
2233
+ size_t verNeedNum = rdi (shdrVersionR.sh_info );
2234
+ std::set<size_t > removedVersionIds;
2235
+
2236
+ // file names and versions here
2237
+ char * verStrTab = (char *) fileContents->data () + rdi (shdrVersionRStrings.sh_offset );
2238
+
2239
+ debug (" found .gnu.version_r with %i entries\n " , verNeedNum);
2240
+
2241
+ auto vn = (Elf_Verneed *)(fileContents->data () + rdi (shdrVersionR.sh_offset ));
2242
+ Elf_Verneed * prevVn = nullptr ;
2243
+ for (size_t i = 0 ; i < verNeedNum; ++i) {
2244
+ char * file = verStrTab + rdi (vn->vn_file );
2245
+
2246
+ if (verMap.count (file)) {
2247
+ size_t verNauxNum = rdi (vn->vn_cnt );
2248
+ size_t newVerNauxNum = 0 ;
2249
+
2250
+ auto va = (follow<Elf_Vernaux>(vn, rdi (vn->vn_aux )));
2251
+ Elf_Vernaux * prevVa = nullptr ;
2252
+
2253
+ auto & versions = verMap.at (file);
2254
+
2255
+ for (size_t j = 0 ; j < verNauxNum; ++j) {
2256
+ char * name = verStrTab + rdi (va->vna_name );
2257
+
2258
+ auto version = rdi (va->vna_other );
2259
+ off_t next = rdi (va->vna_next );
2260
+ if (versions.count (name)) {
2261
+ debug (" removing symbol %s with version %d in entry %s\n " , name, version, file);
2262
+ // 1 for unversioned symbol
2263
+ removedVersionIds.insert (version);
2264
+
2265
+ if (prevVa) {
2266
+ wri (prevVa->vna_next , next ? rdi (prevVa->vna_next ) + next : 0 );
2267
+ } else {
2268
+ wri (vn->vn_aux , next ? rdi (vn->vn_aux ) + next : 0 );
2269
+ }
2270
+ changed = true ;
2271
+
2272
+ auto nextVa = follow<Elf_Vernaux>(va, next);
2273
+ // remove the version data
2274
+ memset (va, 0 , sizeof (Elf_Vernaux));
2275
+ va = nextVa;
2276
+ } else {
2277
+ debug (" keeping symbol %s with version %d in entry %s\n " , name, version, file);
2278
+ ++newVerNauxNum;
2279
+ prevVa = va;
2280
+ va = follow<Elf_Vernaux>(va, next);
2281
+ }
2282
+ }
2283
+
2284
+ off_t next = rdi (vn->vn_next );
2285
+ // there are versions left
2286
+ if (prevVa) {
2287
+ wri (vn->vn_cnt , newVerNauxNum);
2288
+ prevVn = vn;
2289
+ vn = follow<Elf_Verneed>(vn, next);
2290
+ } else {
2291
+ // remove entire file entry
2292
+ if (prevVn) {
2293
+ wri (prevVn->vn_next , next ? rdi (prevVn->vn_next ) + next : 0 );
2294
+ } else {
2295
+ // there are file entries left
2296
+ if (next) {
2297
+ wri (shdrVersionR.sh_offset , rdi (shdrVersionR.sh_offset ) + next);
2298
+ } else {
2299
+ // FIXME: remove entire section?
2300
+ wri (shdrVersionR.sh_offset , 0 );
2301
+ wri (shdrVersionR.sh_size , 0 );
2302
+ }
2303
+ }
2304
+ wri (shdrVersionR.sh_info , rdi (shdrVersionR.sh_info ) - 1 );
2305
+
2306
+ Elf_Verneed * nextVn = follow<Elf_Verneed>(vn, next);
2307
+ memset (vn, 0 , sizeof (Elf_Verneed));
2308
+ vn = nextVn;
2309
+ }
2310
+ } else {
2311
+ off_t next = rdi (vn->vn_next );
2312
+ prevVn = vn;
2313
+ vn = follow<Elf_Verneed>(vn, next);
2314
+ }
2315
+ }
2316
+ // virtual address and file offset need to be the same for .gnu.version_r
2317
+ shdrVersionR.sh_addr = shdrVersionR.sh_offset ;
2318
+
2319
+ if (auto shdrDynamic = tryFindSectionHeader (" .dynamic" )) {
2320
+ auto dyn = (Elf_Dyn *)(fileContents->data () + rdi (shdrDynamic->get ().sh_offset ));
2321
+
2322
+ // keep DT_VERNEED and DT_VERNEEDNUM in sync, DT_VERNEEDNUM handled by rewriteHeaders
2323
+ for ( ; rdi (dyn->d_tag ) != DT_NULL; dyn++) {
2324
+ if (rdi (dyn->d_tag ) == DT_VERNEEDNUM) {
2325
+ dyn->d_un .d_val = shdrVersionR.sh_info ;
2326
+ }
2327
+ }
2328
+ }
2329
+
2330
+ if (spanVersyms) {
2331
+ for (auto & versym : spanVersyms) {
2332
+ if (removedVersionIds.count (versym)) {
2333
+ wri (versym, 1 );
2334
+ }
2335
+ }
2336
+ }
2337
+
2338
+ debug (" remaining entries in .gnu.version_r: %i\n " , rdi (shdrVersionR.sh_info ));
2339
+ this ->rewriteSections (true );
2340
+ }
2341
+
2218
2342
template <ElfFileParams>
2219
2343
void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string> & syms)
2220
2344
{
@@ -2376,6 +2500,7 @@ static bool addDebugTag = false;
2376
2500
static bool renameDynamicSymbols = false ;
2377
2501
static bool printRPath = false ;
2378
2502
static std::string newRPath;
2503
+ static std::map<std::string, std::set<std::string>> neededVersionsToRemove;
2379
2504
static std::set<std::string> neededLibsToRemove;
2380
2505
static std::map<std::string, std::string> neededLibsToReplace;
2381
2506
static std::set<std::string> neededLibsToAdd;
@@ -2430,6 +2555,7 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
2430
2555
2431
2556
if (printNeeded) elfFile.printNeededLibs ();
2432
2557
2558
+ elfFile.removeNeededVersion (neededVersionsToRemove);
2433
2559
elfFile.removeNeeded (neededLibsToRemove);
2434
2560
elfFile.replaceNeeded (neededLibsToReplace);
2435
2561
elfFile.addNeeded (neededLibsToAdd);
@@ -2505,6 +2631,7 @@ static void showHelp(const std::string & progName)
2505
2631
[--clear-symbol-version SYMBOL]\n \
2506
2632
[--add-debug-tag]\n \
2507
2633
[--print-execstack]\t\t Prints whether the object requests an executable stack\n \
2634
+ [--remove-needed-version LIBRARY VERSION_SYMBOL]\n \
2508
2635
[--clear-execstack]\n \
2509
2636
[--set-execstack]\n \
2510
2637
[--rename-dynamic-symbols NAME_MAP_FILE]\t Renames dynamic symbols. The map file should contain two symbols (old_name new_name) per line\n \
@@ -2613,6 +2740,11 @@ static int mainWrapped(int argc, char * * argv)
2613
2740
neededLibsToReplace[ argv[i+1 ] ] = argv[i+2 ];
2614
2741
i += 2 ;
2615
2742
}
2743
+ else if (arg == " --remove-needed-version" ) {
2744
+ if (i+2 >= argc) error (" missing argument(s)" );
2745
+ neededVersionsToRemove[ argv[i+1 ] ].insert (resolveArgument (argv[i+2 ]));
2746
+ i += 2 ;
2747
+ }
2616
2748
else if (arg == " --clear-symbol-version" ) {
2617
2749
if (++i == argc) error (" missing argument" );
2618
2750
symbolsToClearVersion.insert (resolveArgument (argv[i]));
0 commit comments