2929#include < string_view>
3030#include < unordered_map>
3131#include < unordered_set>
32+ #include < variant>
3233#include < vector>
3334
3435#include < cassert>
@@ -1903,6 +1904,87 @@ void ElfFile<ElfFileParamNames>::noDefaultLib()
19031904 changed = true ;
19041905}
19051906
1907+ template <ElfFileParams>
1908+ void ElfFile<ElfFileParamNames>::cleanStrTab()
1909+ {
1910+ std::unordered_map<std::string, unsigned > requiredStrs2Idx {{" " ,0 }};
1911+
1912+ // A collection of pointers to the fields that refer to str indices
1913+ // and a pointer to the new index value to be calculated
1914+ using StrIndexPtr = std::variant<Elf32_Word*, Elf64_Xword*>;
1915+ std::vector<std::pair<StrIndexPtr, unsigned *>> strRefs;
1916+
1917+ auto & strTabHdr = findSectionHeader (" .dynstr" );
1918+ auto strTab = getSectionSpan<char >(strTabHdr);
1919+
1920+ // Utility to collect a string index field from any table
1921+ auto collect = [&] (auto & idx) {
1922+ auto [it, _] = requiredStrs2Idx.emplace (&strTab[rdi (idx)], 0 );
1923+ strRefs.emplace_back (&idx, &it->second );
1924+ };
1925+
1926+ // Iterate on tables known to store references to .dynstr
1927+ for (auto & sym : tryGetSectionSpan<Elf_Sym>(" .dynsym" ))
1928+ collect (sym.st_name );
1929+
1930+ for (auto & dyn : tryGetSectionSpan<Elf_Dyn>(" .dynamic" ))
1931+ switch (rdi (dyn.d_tag ))
1932+ {
1933+ case DT_NEEDED:
1934+ case DT_SONAME:
1935+ case DT_RPATH:
1936+ case DT_RUNPATH: collect (dyn.d_un .d_val );
1937+ default :;
1938+ }
1939+
1940+ if (auto verdHdr = tryFindSectionHeader (" .gnu.version_d" ))
1941+ {
1942+ // Only collect fields if they use the strtab we are cleaning
1943+ if (&shdrs.at (rdi (verdHdr->get ().sh_link )) == &strTabHdr)
1944+ forAll_ElfVer (getSectionSpan<Elf_Verdef>(*verdHdr),
1945+ [] (auto & /* vd*/ ) {},
1946+ [&] (auto & vda) { collect (vda.vda_name ); }
1947+ );
1948+ }
1949+
1950+ if (auto vernHdr = tryFindSectionHeader (" .gnu.version_r" ))
1951+ {
1952+ // Only collect fields if they use the strtab we are cleaning
1953+ if (&shdrs.at (rdi (vernHdr->get ().sh_link )) == &strTabHdr)
1954+ forAll_ElfVer (getSectionSpan<Elf_Verneed>(*vernHdr),
1955+ [&] (auto & vn) { collect (vn.vn_file ); },
1956+ [&] (auto & vna) { collect (vna.vna_name ); }
1957+ );
1958+ }
1959+
1960+ // Iterate on all required strings calculating the new position
1961+ size_t curIdx = 1 ;
1962+ for (auto & [str,idx] : requiredStrs2Idx)
1963+ {
1964+ idx = curIdx;
1965+ curIdx += str.size ()+1 ;
1966+ }
1967+
1968+ // Add required strings to the new dynstr section
1969+ auto & newStrSec = replaceSection (" .dynstr" , curIdx);
1970+ for (auto & [str,idx] : requiredStrs2Idx)
1971+ std::copy (str.begin (), str.end ()+1 , newStrSec.begin ()+idx);
1972+
1973+ // Iterate on all fields on all tables setting the new index value
1974+ for (auto & [oldIndexPtr, newIdxPtr_] : strRefs)
1975+ {
1976+ auto newIdxPtr = newIdxPtr_; // Some compilers complain about
1977+ // capturing structured bindings
1978+ std::visit (
1979+ [&] (auto * ptr) { wri (*ptr, *newIdxPtr); },
1980+ oldIndexPtr
1981+ );
1982+ }
1983+
1984+ changed = true ;
1985+ this ->rewriteSections ();
1986+ }
1987+
19061988template <ElfFileParams>
19071989void ElfFile<ElfFileParamNames>::addDebugTag()
19081990{
@@ -2271,6 +2353,7 @@ static bool removeRPath = false;
22712353static bool setRPath = false ;
22722354static bool addRPath = false ;
22732355static bool addDebugTag = false ;
2356+ static bool cleanStrTab = false ;
22742357static bool renameDynamicSymbols = false ;
22752358static bool printRPath = false ;
22762359static std::string newRPath;
@@ -2342,6 +2425,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
23422425 if (renameDynamicSymbols)
23432426 elfFile.renameDynamicSymbols (symbolsToRename);
23442427
2428+ if (cleanStrTab)
2429+ elfFile.cleanStrTab ();
2430+
23452431 if (elfFile.isChanged ()){
23462432 writeFile (fileName, elfFile.fileContents );
23472433 } else if (alwaysWrite) {
@@ -2361,9 +2447,9 @@ static void patchElf()
23612447 const std::string & outputFileName2 = outputFileName.empty () ? fileName : outputFileName;
23622448
23632449 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);
2450+ 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);
23652451 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);
2452+ 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);
23672453 }
23682454}
23692455
@@ -2406,6 +2492,7 @@ static void showHelp(const std::string & progName)
24062492 [--clear-execstack]\n \
24072493 [--set-execstack]\n \
24082494 [--rename-dynamic-symbols NAME_MAP_FILE]\t Renames dynamic symbols. The map file should contain two symbols (old_name new_name) per line\n \
2495+ [--clean-strtab]\n \
24092496 [--output FILE]\n \
24102497 [--debug]\n \
24112498 [--version]\n \
@@ -2537,6 +2624,9 @@ static int mainWrapped(int argc, char * * argv)
25372624 else if (arg == " --add-debug-tag" ) {
25382625 addDebugTag = true ;
25392626 }
2627+ else if (arg == " --clean-strtab" ) {
2628+ cleanStrTab = true ;
2629+ }
25402630 else if (arg == " --rename-dynamic-symbols" ) {
25412631 renameDynamicSymbols = true ;
25422632 if (++i == argc) error (" missing argument" );
0 commit comments