2828#include < string>
2929#include < unordered_map>
3030#include < unordered_set>
31+ #include < variant>
3132#include < vector>
3233
3334#include < cassert>
@@ -1852,6 +1853,87 @@ void ElfFile<ElfFileParamNames>::noDefaultLib()
18521853 changed = true ;
18531854}
18541855
1856+ template <ElfFileParams>
1857+ void ElfFile<ElfFileParamNames>::cleanStrTab()
1858+ {
1859+ std::unordered_map<std::string, unsigned > requiredStrs2Idx {{" " ,0 }};
1860+
1861+ // A collection of pointers to the fields that refer to str indices
1862+ // and a pointer to the new index value to be calculated
1863+ using StrIndexPtr = std::variant<Elf32_Word*, Elf64_Xword*>;
1864+ std::vector<std::pair<StrIndexPtr, unsigned *>> strRefs;
1865+
1866+ auto & strTabHdr = findSectionHeader (" .dynstr" );
1867+ auto strTab = getSectionSpan<char >(strTabHdr);
1868+
1869+ // Utility to collect a string index field from any table
1870+ auto collect = [&] (auto & idx) {
1871+ auto [it, _] = requiredStrs2Idx.emplace (&strTab[rdi (idx)], 0 );
1872+ strRefs.emplace_back (&idx, &it->second );
1873+ };
1874+
1875+ // Iterate on tables known to store references to .dynstr
1876+ for (auto & sym : tryGetSectionSpan<Elf_Sym>(" .dynsym" ))
1877+ collect (sym.st_name );
1878+
1879+ for (auto & dyn : tryGetSectionSpan<Elf_Dyn>(" .dynamic" ))
1880+ switch (rdi (dyn.d_tag ))
1881+ {
1882+ case DT_NEEDED:
1883+ case DT_SONAME:
1884+ case DT_RPATH:
1885+ case DT_RUNPATH: collect (dyn.d_un .d_val );
1886+ default :;
1887+ }
1888+
1889+ if (auto verdHdr = tryFindSectionHeader (" .gnu.version_d" ))
1890+ {
1891+ // Only collect fields if they use the strtab we are cleaning
1892+ if (&shdrs.at (rdi (verdHdr->get ().sh_link )) == &strTabHdr)
1893+ forAll_ElfVer (getSectionSpan<Elf_Verdef>(*verdHdr),
1894+ [] (auto & vd) {},
1895+ [&] (auto & vda) { collect (vda.vda_name ); }
1896+ );
1897+ }
1898+
1899+ if (auto vernHdr = tryFindSectionHeader (" .gnu.version_r" ))
1900+ {
1901+ // Only collect fields if they use the strtab we are cleaning
1902+ if (&shdrs.at (rdi (vernHdr->get ().sh_link )) == &strTabHdr)
1903+ forAll_ElfVer (getSectionSpan<Elf_Verneed>(*vernHdr),
1904+ [&] (auto & vn) { collect (vn.vn_file ); },
1905+ [&] (auto & vna) { collect (vna.vna_name ); }
1906+ );
1907+ }
1908+
1909+ // Iterate on all required strings calculating the new position
1910+ size_t curIdx = 1 ;
1911+ for (auto & [str,idx] : requiredStrs2Idx)
1912+ {
1913+ idx = curIdx;
1914+ curIdx += str.size ()+1 ;
1915+ }
1916+
1917+ // Add required strings to the new dynstr section
1918+ auto & newStrSec = replaceSection (" .dynstr" , curIdx);
1919+ for (auto & [str,idx] : requiredStrs2Idx)
1920+ std::copy (str.begin (), str.end ()+1 , newStrSec.begin ()+idx);
1921+
1922+ // Iterate on all fields on all tables setting the new index value
1923+ for (auto & [oldIndexPtr, newIdxPtr_] : strRefs)
1924+ {
1925+ auto newIdxPtr = newIdxPtr_; // Some compilers complain about
1926+ // capturing structured bindings
1927+ std::visit (
1928+ [&] (auto * ptr) { wri (*ptr, *newIdxPtr); },
1929+ oldIndexPtr
1930+ );
1931+ }
1932+
1933+ changed = true ;
1934+ this ->rewriteSections ();
1935+ }
1936+
18551937template <ElfFileParams>
18561938void ElfFile<ElfFileParamNames>::addDebugTag()
18571939{
@@ -2223,6 +2305,7 @@ static bool removeRPath = false;
22232305static bool setRPath = false ;
22242306static bool addRPath = false ;
22252307static bool addDebugTag = false ;
2308+ static bool cleanStrTab = false ;
22262309static bool renameDynamicSymbols = false ;
22272310static bool printRPath = false ;
22282311static std::string newRPath;
@@ -2294,6 +2377,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
22942377 if (renameDynamicSymbols)
22952378 elfFile.renameDynamicSymbols (symbolsToRename);
22962379
2380+ if (cleanStrTab)
2381+ elfFile.cleanStrTab ();
2382+
22972383 if (elfFile.isChanged ()){
22982384 writeFile (fileName, elfFile.fileContents );
22992385 } else if (alwaysWrite) {
@@ -2313,9 +2399,9 @@ static void patchElf()
23132399 const std::string & outputFileName2 = outputFileName.empty () ? fileName : outputFileName;
23142400
23152401 if (getElfType (fileContents).is32Bit )
2316- 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);
2402+ 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);
23172403 else
2318- 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);
2404+ 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);
23192405 }
23202406}
23212407
@@ -2489,6 +2575,9 @@ int mainWrapped(int argc, char * * argv)
24892575 else if (arg == " --add-debug-tag" ) {
24902576 addDebugTag = true ;
24912577 }
2578+ else if (arg == " --clean-strtab" ) {
2579+ cleanStrTab = true ;
2580+ }
24922581 else if (arg == " --rename-dynamic-symbols" ) {
24932582 renameDynamicSymbols = true ;
24942583 if (++i == argc) error (" missing argument" );
0 commit comments