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,88 @@ 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 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+
19061989template <ElfFileParams>
19071990void ElfFile<ElfFileParamNames>::addDebugTag()
19081991{
@@ -2271,6 +2354,7 @@ static bool removeRPath = false;
22712354static bool setRPath = false ;
22722355static bool addRPath = false ;
22732356static bool addDebugTag = false ;
2357+ static bool cleanStrTab = false ;
22742358static bool renameDynamicSymbols = false ;
22752359static bool printRPath = false ;
22762360static std::string newRPath;
@@ -2342,6 +2426,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
23422426 if (renameDynamicSymbols)
23432427 elfFile.renameDynamicSymbols (symbolsToRename);
23442428
2429+ if (cleanStrTab)
2430+ elfFile.cleanStrTab ();
2431+
23452432 if (elfFile.isChanged ()){
23462433 writeFile (fileName, elfFile.fileContents );
23472434 } else if (alwaysWrite) {
@@ -2361,9 +2448,9 @@ static void patchElf()
23612448 const std::string & outputFileName2 = outputFileName.empty () ? fileName : outputFileName;
23622449
23632450 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);
23652452 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);
23672454 }
23682455}
23692456
@@ -2406,6 +2493,7 @@ static void showHelp(const std::string & progName)
24062493 [--clear-execstack]\n \
24072494 [--set-execstack]\n \
24082495 [--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 \
24092497 [--output FILE]\n \
24102498 [--debug]\n \
24112499 [--version]\n \
@@ -2537,6 +2625,9 @@ static int mainWrapped(int argc, char * * argv)
25372625 else if (arg == " --add-debug-tag" ) {
25382626 addDebugTag = true ;
25392627 }
2628+ else if (arg == " --clean-strtab" ) {
2629+ cleanStrTab = true ;
2630+ }
25402631 else if (arg == " --rename-dynamic-symbols" ) {
25412632 renameDynamicSymbols = true ;
25422633 if (++i == argc) error (" missing argument" );
0 commit comments