29
29
#include < string_view>
30
30
#include < unordered_map>
31
31
#include < unordered_set>
32
+ #include < variant>
32
33
#include < vector>
33
34
34
35
#include < cassert>
@@ -1903,6 +1904,88 @@ void ElfFile<ElfFileParamNames>::noDefaultLib()
1903
1904
changed = true ;
1904
1905
}
1905
1906
1907
+ template <ElfFileParams>
1908
+ void ElfFile<ElfFileParamNames>::cleanStrTab()
1909
+ {
1910
+ std::unordered_map<std::string, unsigned > requiredStrs2Idx {{" " ,0 }};
1911
+
1912
+ // A collection of pairs, each containing:
1913
+ // - a pointer to the field that refer to str indices
1914
+ // - a pointer to the new index in `requiredStrs2Idx`
1915
+ using StrIndexPtr = std::variant<Elf32_Word*, Elf64_Xword*>;
1916
+ std::vector<std::pair<StrIndexPtr, unsigned *>> strRefs;
1917
+
1918
+ auto & strTabHdr = findSectionHeader (" .dynstr" );
1919
+ auto strTab = getSectionSpan<char >(strTabHdr);
1920
+
1921
+ // Utility to collect a string index field from any table
1922
+ auto collect = [&] (auto & idx) {
1923
+ auto [it, _] = requiredStrs2Idx.emplace (&strTab[rdi (idx)], 0 );
1924
+ strRefs.emplace_back (&idx, &it->second );
1925
+ };
1926
+
1927
+ // Iterate on tables known to store references to .dynstr
1928
+ for (auto & sym : tryGetSectionSpan<Elf_Sym>(" .dynsym" ))
1929
+ collect (sym.st_name );
1930
+
1931
+ for (auto & dyn : tryGetSectionSpan<Elf_Dyn>(" .dynamic" ))
1932
+ switch (rdi (dyn.d_tag ))
1933
+ {
1934
+ case DT_NEEDED:
1935
+ case DT_SONAME:
1936
+ case DT_RPATH:
1937
+ case DT_RUNPATH: collect (dyn.d_un .d_val );
1938
+ default :;
1939
+ }
1940
+
1941
+ if (auto verdHdr = tryFindSectionHeader (" .gnu.version_d" ))
1942
+ {
1943
+ // Only collect fields if they use the strtab we are cleaning
1944
+ if (&shdrs.at (rdi (verdHdr->get ().sh_link )) == &strTabHdr)
1945
+ forAll_ElfVer (getSectionSpan<Elf_Verdef>(*verdHdr),
1946
+ [] (auto & /* vd*/ ) {},
1947
+ [&] (auto & vda) { collect (vda.vda_name ); }
1948
+ );
1949
+ }
1950
+
1951
+ if (auto vernHdr = tryFindSectionHeader (" .gnu.version_r" ))
1952
+ {
1953
+ // Only collect fields if they use the strtab we are cleaning
1954
+ if (&shdrs.at (rdi (vernHdr->get ().sh_link )) == &strTabHdr)
1955
+ forAll_ElfVer (getSectionSpan<Elf_Verneed>(*vernHdr),
1956
+ [&] (auto & vn) { collect (vn.vn_file ); },
1957
+ [&] (auto & vna) { collect (vna.vna_name ); }
1958
+ );
1959
+ }
1960
+
1961
+ // Iterate on all required strings calculating the new position
1962
+ size_t curIdx = 1 ;
1963
+ for (auto & [str,idx] : requiredStrs2Idx)
1964
+ {
1965
+ idx = curIdx;
1966
+ curIdx += str.size () + /* null terminator*/ 1 ;
1967
+ }
1968
+
1969
+ // Add required strings to the new dynstr section
1970
+ auto & newStrSec = replaceSection (" .dynstr" , curIdx);
1971
+ for (auto & [str,idx] : requiredStrs2Idx)
1972
+ std::copy (str.begin (), str.end ()+1 , &newStrSec[idx]);
1973
+
1974
+ // Iterate on all fields on all tables setting the new index value
1975
+ for (auto & [oldIndexPtr, newIdxPtr_] : strRefs)
1976
+ {
1977
+ auto newIdxPtr = newIdxPtr_; // Some compilers complain about
1978
+ // capturing structured bindings
1979
+ std::visit (
1980
+ [&] (auto * ptr) { wri (*ptr, *newIdxPtr); },
1981
+ oldIndexPtr
1982
+ );
1983
+ }
1984
+
1985
+ changed = true ;
1986
+ this ->rewriteSections ();
1987
+ }
1988
+
1906
1989
template <ElfFileParams>
1907
1990
void ElfFile<ElfFileParamNames>::addDebugTag()
1908
1991
{
@@ -2271,6 +2354,7 @@ static bool removeRPath = false;
2271
2354
static bool setRPath = false ;
2272
2355
static bool addRPath = false ;
2273
2356
static bool addDebugTag = false ;
2357
+ static bool cleanStrTab = false ;
2274
2358
static bool renameDynamicSymbols = false ;
2275
2359
static bool printRPath = false ;
2276
2360
static std::string newRPath;
@@ -2342,6 +2426,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
2342
2426
if (renameDynamicSymbols)
2343
2427
elfFile.renameDynamicSymbols (symbolsToRename);
2344
2428
2429
+ if (cleanStrTab)
2430
+ elfFile.cleanStrTab ();
2431
+
2345
2432
if (elfFile.isChanged ()){
2346
2433
writeFile (fileName, elfFile.fileContents );
2347
2434
} else if (alwaysWrite) {
@@ -2361,9 +2448,9 @@ static void patchElf()
2361
2448
const std::string & outputFileName2 = outputFileName.empty () ? fileName : outputFileName;
2362
2449
2363
2450
if (getElfType (fileContents).is32Bit )
2364
- patchElf2 (ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed, Elf32_Versym , Elf32_Rel, Elf32_Rela, 32 >(fileContents), fileContents, outputFileName2);
2451
+ patchElf2 (ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Versym, Elf32_Verdef, Elf32_Verdaux, Elf32_Verneed, Elf32_Vernaux , Elf32_Rel, Elf32_Rela, 32 >(fileContents), fileContents, outputFileName2);
2365
2452
else
2366
- patchElf2 (ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, Elf64_Versym , Elf64_Rel, Elf64_Rela, 64 >(fileContents), fileContents, outputFileName2);
2453
+ patchElf2 (ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Versym, Elf64_Verdef, Elf64_Verdaux, Elf64_Verneed, Elf64_Vernaux , Elf64_Rel, Elf64_Rela, 64 >(fileContents), fileContents, outputFileName2);
2367
2454
}
2368
2455
}
2369
2456
@@ -2406,6 +2493,7 @@ static void showHelp(const std::string & progName)
2406
2493
[--clear-execstack]\n \
2407
2494
[--set-execstack]\n \
2408
2495
[--rename-dynamic-symbols NAME_MAP_FILE]\t Renames dynamic symbols. The map file should contain two symbols (old_name new_name) per line\n \
2496
+ [--clean-strtab]\n \
2409
2497
[--output FILE]\n \
2410
2498
[--debug]\n \
2411
2499
[--version]\n \
@@ -2537,6 +2625,9 @@ static int mainWrapped(int argc, char * * argv)
2537
2625
else if (arg == " --add-debug-tag" ) {
2538
2626
addDebugTag = true ;
2539
2627
}
2628
+ else if (arg == " --clean-strtab" ) {
2629
+ cleanStrTab = true ;
2630
+ }
2540
2631
else if (arg == " --rename-dynamic-symbols" ) {
2541
2632
renameDynamicSymbols = true ;
2542
2633
if (++i == argc) error (" missing argument" );
0 commit comments