28
28
#include < string>
29
29
#include < unordered_map>
30
30
#include < unordered_set>
31
+ #include < variant>
31
32
#include < vector>
32
33
33
34
#include < cassert>
@@ -1852,6 +1853,87 @@ void ElfFile<ElfFileParamNames>::noDefaultLib()
1852
1853
changed = true ;
1853
1854
}
1854
1855
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
+
1855
1937
template <ElfFileParams>
1856
1938
void ElfFile<ElfFileParamNames>::addDebugTag()
1857
1939
{
@@ -2223,6 +2305,7 @@ static bool removeRPath = false;
2223
2305
static bool setRPath = false ;
2224
2306
static bool addRPath = false ;
2225
2307
static bool addDebugTag = false ;
2308
+ static bool cleanStrTab = false ;
2226
2309
static bool renameDynamicSymbols = false ;
2227
2310
static bool printRPath = false ;
2228
2311
static std::string newRPath;
@@ -2294,6 +2377,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
2294
2377
if (renameDynamicSymbols)
2295
2378
elfFile.renameDynamicSymbols (symbolsToRename);
2296
2379
2380
+ if (cleanStrTab)
2381
+ elfFile.cleanStrTab ();
2382
+
2297
2383
if (elfFile.isChanged ()){
2298
2384
writeFile (fileName, elfFile.fileContents );
2299
2385
} else if (alwaysWrite) {
@@ -2313,9 +2399,9 @@ static void patchElf()
2313
2399
const std::string & outputFileName2 = outputFileName.empty () ? fileName : outputFileName;
2314
2400
2315
2401
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);
2317
2403
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);
2319
2405
}
2320
2406
}
2321
2407
@@ -2489,6 +2575,9 @@ int mainWrapped(int argc, char * * argv)
2489
2575
else if (arg == " --add-debug-tag" ) {
2490
2576
addDebugTag = true ;
2491
2577
}
2578
+ else if (arg == " --clean-strtab" ) {
2579
+ cleanStrTab = true ;
2580
+ }
2492
2581
else if (arg == " --rename-dynamic-symbols" ) {
2493
2582
renameDynamicSymbols = true ;
2494
2583
if (++i == argc) error (" missing argument" );
0 commit comments