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,87 @@ 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 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
+
1906
1988
template <ElfFileParams>
1907
1989
void ElfFile<ElfFileParamNames>::addDebugTag()
1908
1990
{
@@ -2271,6 +2353,7 @@ static bool removeRPath = false;
2271
2353
static bool setRPath = false ;
2272
2354
static bool addRPath = false ;
2273
2355
static bool addDebugTag = false ;
2356
+ static bool cleanStrTab = false ;
2274
2357
static bool renameDynamicSymbols = false ;
2275
2358
static bool printRPath = false ;
2276
2359
static std::string newRPath;
@@ -2342,6 +2425,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
2342
2425
if (renameDynamicSymbols)
2343
2426
elfFile.renameDynamicSymbols (symbolsToRename);
2344
2427
2428
+ if (cleanStrTab)
2429
+ elfFile.cleanStrTab ();
2430
+
2345
2431
if (elfFile.isChanged ()){
2346
2432
writeFile (fileName, elfFile.fileContents );
2347
2433
} else if (alwaysWrite) {
@@ -2361,9 +2447,9 @@ static void patchElf()
2361
2447
const std::string & outputFileName2 = outputFileName.empty () ? fileName : outputFileName;
2362
2448
2363
2449
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);
2365
2451
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);
2367
2453
}
2368
2454
}
2369
2455
@@ -2406,6 +2492,7 @@ static void showHelp(const std::string & progName)
2406
2492
[--clear-execstack]\n \
2407
2493
[--set-execstack]\n \
2408
2494
[--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 \
2409
2496
[--output FILE]\n \
2410
2497
[--debug]\n \
2411
2498
[--version]\n \
@@ -2537,6 +2624,9 @@ static int mainWrapped(int argc, char * * argv)
2537
2624
else if (arg == " --add-debug-tag" ) {
2538
2625
addDebugTag = true ;
2539
2626
}
2627
+ else if (arg == " --clean-strtab" ) {
2628
+ cleanStrTab = true ;
2629
+ }
2540
2630
else if (arg == " --rename-dynamic-symbols" ) {
2541
2631
renameDynamicSymbols = true ;
2542
2632
if (++i == argc) error (" missing argument" );
0 commit comments