17
17
*/
18
18
19
19
#include < algorithm>
20
+ #include < fstream>
20
21
#include < limits>
21
22
#include < map>
22
23
#include < memory>
24
+ #include < optional>
23
25
#include < set>
24
26
#include < sstream>
25
27
#include < stdexcept>
26
28
#include < string>
27
29
#include < unordered_map>
30
+ #include < unordered_set>
28
31
#include < vector>
29
- #include < optional>
30
32
31
33
#include < cassert>
32
34
#include < cerrno>
@@ -553,6 +555,27 @@ std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::tryF
553
555
return {};
554
556
}
555
557
558
+ template <ElfFileParams>
559
+ template <class T >
560
+ span<T> ElfFile<ElfFileParamNames>::getSectionSpan(const Elf_Shdr & shdr) const
561
+ {
562
+ return span ((T*)(fileContents->data () + rdi (shdr.sh_offset )), rdi (shdr.sh_size )/sizeof (T));
563
+ }
564
+
565
+ template <ElfFileParams>
566
+ template <class T >
567
+ span<T> ElfFile<ElfFileParamNames>::getSectionSpan(const SectionName & sectionName)
568
+ {
569
+ return getSectionSpan<T>(findSectionHeader (sectionName));
570
+ }
571
+
572
+ template <ElfFileParams>
573
+ template <class T >
574
+ span<T> ElfFile<ElfFileParamNames>::tryGetSectionSpan(const SectionName & sectionName)
575
+ {
576
+ auto shdrOpt = tryFindSectionHeader (sectionName);
577
+ return shdrOpt ? getSectionSpan<T>(*shdrOpt) : span<T>();
578
+ }
556
579
557
580
template <ElfFileParams>
558
581
unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName)
@@ -1861,6 +1884,223 @@ void ElfFile<ElfFileParamNames>::addDebugTag()
1861
1884
changed = true ;
1862
1885
}
1863
1886
1887
+ static uint32_t gnuHash (std::string_view name) {
1888
+ uint32_t h = 5381 ;
1889
+ for (uint8_t c : name)
1890
+ h = ((h << 5 ) + h) + c;
1891
+ return h;
1892
+ }
1893
+
1894
+ template <ElfFileParams>
1895
+ auto ElfFile<ElfFileParamNames>::parseGnuHashTable(span<char > sectionData) -> GnuHashTable
1896
+ {
1897
+ auto hdr = (typename GnuHashTable::Header*)sectionData.begin ();
1898
+ auto bloomFilters = span ((typename GnuHashTable::BloomWord*)(hdr+1 ), rdi (hdr->maskwords ));
1899
+ auto buckets = span ((uint32_t *)bloomFilters.end (), rdi (hdr->numBuckets ));
1900
+ auto table = span (buckets.end (), ((uint32_t *)sectionData.end ()) - buckets.end ());
1901
+ return GnuHashTable{*hdr, bloomFilters, buckets, table};
1902
+ }
1903
+
1904
+ template <ElfFileParams>
1905
+ void ElfFile<ElfFileParamNames>::rebuildGnuHashTable(const char * strTab, span<Elf_Sym> dynsyms)
1906
+ {
1907
+ auto sectionData = tryGetSectionSpan<char >(" .gnu.hash" );
1908
+ if (!sectionData)
1909
+ return ;
1910
+
1911
+ auto ght = parseGnuHashTable (sectionData);
1912
+
1913
+ // We can't trust the value of symndx when the hash table is empty
1914
+ if (ght.m_table .size () == 0 )
1915
+ return ;
1916
+
1917
+ // The hash table includes only a subset of dynsyms
1918
+ auto firstSymIdx = rdi (ght.m_hdr .symndx );
1919
+ dynsyms = span (dynsyms.begin () + firstSymIdx, dynsyms.end ());
1920
+
1921
+ // Only use the range of symbol versions that will be changed
1922
+ auto versyms = tryGetSectionSpan<Elf_Versym>(" .gnu.version" );
1923
+ if (versyms)
1924
+ versyms = span (versyms.begin () + firstSymIdx, versyms.end ());
1925
+
1926
+ struct Entry
1927
+ {
1928
+ uint32_t hash, bucketIdx, originalPos;
1929
+ };
1930
+
1931
+ std::vector<Entry> entries;
1932
+ entries.reserve (dynsyms.size ());
1933
+
1934
+ uint32_t pos = 0 ; // Track the original position of the symbol in the table
1935
+ for (auto & sym : dynsyms)
1936
+ {
1937
+ Entry e;
1938
+ e.hash = gnuHash (strTab + rdi (sym.st_name ));
1939
+ e.bucketIdx = e.hash % ght.m_buckets .size ();
1940
+ e.originalPos = pos++;
1941
+ entries.push_back (e);
1942
+ }
1943
+
1944
+ // Sort the entries based on the buckets. This is a requirement for gnu hash table to work
1945
+ std::sort (entries.begin (), entries.end (), [&] (auto & l, auto & r) {
1946
+ return l.bucketIdx < r.bucketIdx ;
1947
+ });
1948
+
1949
+ // Create a map of old positions to new positions after sorting
1950
+ std::vector<uint32_t > old2new (entries.size ());
1951
+ for (size_t i = 0 ; i < entries.size (); ++i)
1952
+ old2new[entries[i].originalPos ] = i;
1953
+
1954
+ // Update the symbol table with the new order and
1955
+ // all tables that refer to symbols through indexes in the symbol table
1956
+ auto reorderSpan = [] (auto dst, auto & old2new)
1957
+ {
1958
+ std::vector tmp (dst.begin (), dst.end ());
1959
+ for (size_t i = 0 ; i < tmp.size (); ++i)
1960
+ dst[old2new[i]] = tmp[i];
1961
+ };
1962
+
1963
+ reorderSpan (dynsyms, old2new);
1964
+ if (versyms)
1965
+ reorderSpan (versyms, old2new);
1966
+
1967
+ auto fixRelocationTable = [&old2new, firstSymIdx, this ] <class ER > (auto & hdr)
1968
+ {
1969
+ auto rela = getSectionSpan<ER>(hdr);
1970
+ for (auto & r : rela)
1971
+ {
1972
+ auto info = rdi (r.r_info );
1973
+ auto oldSymIdx = rel_getSymId (info);
1974
+ if (oldSymIdx >= firstSymIdx)
1975
+ {
1976
+ auto newSymIdx = old2new[oldSymIdx - firstSymIdx] + firstSymIdx;
1977
+ if (newSymIdx != oldSymIdx)
1978
+ wri (r.r_info , rel_setSymId (info, newSymIdx));
1979
+ }
1980
+ }
1981
+ };
1982
+
1983
+ for (unsigned int i = 1 ; i < rdi (hdr ()->e_shnum ); ++i)
1984
+ {
1985
+ auto & shdr = shdrs.at (i);
1986
+ auto shtype = rdi (shdr.sh_type );
1987
+ if (shtype == SHT_REL)
1988
+ fixRelocationTable.template operator ()<Elf_Rel>(shdr);
1989
+ else if (shtype == SHT_RELA)
1990
+ fixRelocationTable.template operator ()<Elf_Rela>(shdr);
1991
+ }
1992
+
1993
+ // Update bloom filters
1994
+ std::fill (ght.m_bloomFilters .begin (), ght.m_bloomFilters .end (), 0 );
1995
+ for (size_t i = 0 ; i < entries.size (); ++i)
1996
+ {
1997
+ auto h = entries[i].hash ;
1998
+ size_t idx = (h / ElfClass) % ght.m_bloomFilters .size ();
1999
+ auto val = rdi (ght.m_bloomFilters [idx]);
2000
+ val |= uint64_t (1 ) << (h % ElfClass);
2001
+ val |= uint64_t (1 ) << ((h >> rdi (ght.m_hdr .shift2 )) % ElfClass);
2002
+ wri (ght.m_bloomFilters [idx], val);
2003
+ }
2004
+
2005
+ // Fill buckets
2006
+ std::fill (ght.m_buckets .begin (), ght.m_buckets .end (), 0 );
2007
+ for (size_t i = 0 ; i < entries.size (); ++i)
2008
+ {
2009
+ auto symBucketIdx = entries[i].bucketIdx ;
2010
+ if (!ght.m_buckets [symBucketIdx])
2011
+ wri (ght.m_buckets [symBucketIdx], i + firstSymIdx);
2012
+ }
2013
+
2014
+ // Fill hash table
2015
+ for (size_t i = 0 ; i < entries.size (); ++i)
2016
+ {
2017
+ auto & n = entries[i];
2018
+ bool isLast = (i == entries.size () - 1 ) || (n.bucketIdx != entries[i+1 ].bucketIdx );
2019
+ // Add hash with first bit indicating end of chain
2020
+ wri (ght.m_table [i], isLast ? (n.hash | 1 ) : (n.hash & ~1 ));
2021
+ }
2022
+ }
2023
+
2024
+ static uint32_t sysvHash (std::string_view name) {
2025
+ uint32_t h = 0 ;
2026
+ for (uint8_t c : name)
2027
+ {
2028
+ h = (h << 4 ) + c;
2029
+ uint32_t g = h & 0xf0000000 ;
2030
+ if (g != 0 )
2031
+ h ^= g >> 24 ;
2032
+ h &= ~g;
2033
+ }
2034
+ return h;
2035
+ }
2036
+
2037
+ template <ElfFileParams>
2038
+ auto ElfFile<ElfFileParamNames>::parseHashTable(span<char > sectionData) -> HashTable
2039
+ {
2040
+ auto hdr = (typename HashTable::Header*)sectionData.begin ();
2041
+ auto buckets = span ((uint32_t *)(hdr+1 ), rdi (hdr->numBuckets ));
2042
+ auto table = span (buckets.end (), ((uint32_t *)sectionData.end ()) - buckets.end ());
2043
+ return HashTable{*hdr, buckets, table};
2044
+ }
2045
+
2046
+ template <ElfFileParams>
2047
+ void ElfFile<ElfFileParamNames>::rebuildHashTable(const char * strTab, span<Elf_Sym> dynsyms)
2048
+ {
2049
+ auto sectionData = tryGetSectionSpan<char >(" .hash" );
2050
+ if (!sectionData)
2051
+ return ;
2052
+
2053
+ auto ht = parseHashTable (sectionData);
2054
+
2055
+ std::fill (ht.m_buckets .begin (), ht.m_buckets .end (), 0 );
2056
+ std::fill (ht.m_chain .begin (), ht.m_chain .end (), 0 );
2057
+
2058
+ auto symsToInsert = span (dynsyms.end () - ht.m_chain .size (), dynsyms.end ());
2059
+
2060
+ for (auto & sym : symsToInsert)
2061
+ {
2062
+ auto name = strTab + rdi (sym.st_name );
2063
+ uint32_t i = &sym - dynsyms.begin ();
2064
+ uint32_t hash = sysvHash (name) % ht.m_buckets .size ();
2065
+ wri (ht.m_chain [i], rdi (ht.m_buckets [hash]));
2066
+ wri (ht.m_buckets [hash], i);
2067
+ }
2068
+ }
2069
+
2070
+ template <ElfFileParams>
2071
+ void ElfFile<ElfFileParamNames>::renameDynamicSymbols(const std::unordered_map<std::string_view, std::string>& remap)
2072
+ {
2073
+ auto dynsyms = getSectionSpan<Elf_Sym>(" .dynsym" );
2074
+ auto strTab = getSectionSpan<char >(" .dynstr" );
2075
+
2076
+ std::vector<char > extraStrings;
2077
+ extraStrings.reserve (remap.size () * 30 ); // Just an estimate
2078
+ for (size_t i = 0 ; i < dynsyms.size (); i++)
2079
+ {
2080
+ auto & dynsym = dynsyms[i];
2081
+ std::string_view name = &strTab[rdi (dynsym.st_name )];
2082
+ auto it = remap.find (name);
2083
+ if (it != remap.end ())
2084
+ {
2085
+ wri (dynsym.st_name , strTab.size () + extraStrings.size ());
2086
+ auto & newName = it->second ;
2087
+ extraStrings.insert (extraStrings.end (), newName.data (), newName.data () + newName.size () + 1 );
2088
+ changed = true ;
2089
+ }
2090
+ }
2091
+
2092
+ if (changed)
2093
+ {
2094
+ auto & newSec = replaceSection (" .dynstr" , strTab.size () + extraStrings.size ());
2095
+ std::copy (extraStrings.begin (), extraStrings.end (), newSec.begin () + strTab.size ());
2096
+
2097
+ rebuildGnuHashTable (newSec.data (), dynsyms);
2098
+ rebuildHashTable (newSec.data (), dynsyms);
2099
+ }
2100
+
2101
+ this ->rewriteSections ();
2102
+ }
2103
+
1864
2104
template <ElfFileParams>
1865
2105
void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string> & syms)
1866
2106
{
@@ -1904,12 +2144,15 @@ static bool removeRPath = false;
1904
2144
static bool setRPath = false ;
1905
2145
static bool addRPath = false ;
1906
2146
static bool addDebugTag = false ;
2147
+ static bool renameDynamicSymbols = false ;
1907
2148
static bool printRPath = false ;
1908
2149
static std::string newRPath;
1909
2150
static std::set<std::string> neededLibsToRemove;
1910
2151
static std::map<std::string, std::string> neededLibsToReplace;
1911
2152
static std::set<std::string> neededLibsToAdd;
1912
2153
static std::set<std::string> symbolsToClearVersion;
2154
+ static std::unordered_map<std::string_view, std::string> symbolsToRename;
2155
+ static std::unordered_set<std::string> symbolsToRenameKeys;
1913
2156
static bool printNeeded = false ;
1914
2157
static bool noDefaultLib = false ;
1915
2158
@@ -1959,6 +2202,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
1959
2202
if (addDebugTag)
1960
2203
elfFile.addDebugTag ();
1961
2204
2205
+ if (renameDynamicSymbols)
2206
+ elfFile.renameDynamicSymbols (symbolsToRename);
2207
+
1962
2208
if (elfFile.isChanged ()){
1963
2209
writeFile (fileName, elfFile.fileContents );
1964
2210
} else if (alwaysWrite) {
@@ -1978,9 +2224,9 @@ static void patchElf()
1978
2224
const std::string & outputFileName2 = outputFileName.empty () ? fileName : outputFileName;
1979
2225
1980
2226
if (getElfType (fileContents).is32Bit )
1981
- patchElf2 (ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed, Elf32_Versym>(fileContents), fileContents, outputFileName2);
2227
+ 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);
1982
2228
else
1983
- patchElf2 (ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, Elf64_Versym>(fileContents), fileContents, outputFileName2);
2229
+ 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);
1984
2230
}
1985
2231
}
1986
2232
@@ -2019,6 +2265,7 @@ void showHelp(const std::string & progName)
2019
2265
[--no-sort]\t\t Do not sort program+section headers; useful for debugging patchelf.\n \
2020
2266
[--clear-symbol-version SYMBOL]\n \
2021
2267
[--add-debug-tag]\n \
2268
+ [--rename-dynamic-symbols NAME_MAP_FILE]\t Renames dynamic symbols. The name map file should contain two symbols (old_name new_name) per line\n \
2022
2269
[--output FILE]\n \
2023
2270
[--debug]\n \
2024
2271
[--version]\n \
@@ -2141,6 +2388,25 @@ int mainWrapped(int argc, char * * argv)
2141
2388
else if (arg == " --add-debug-tag" ) {
2142
2389
addDebugTag = true ;
2143
2390
}
2391
+ else if (arg == " --rename-dynamic-symbols" ) {
2392
+ renameDynamicSymbols = true ;
2393
+ if (++i == argc) error (" missing argument" );
2394
+
2395
+ std::ifstream infile (argv[i]);
2396
+ if (!infile) error (fmt (" Cannot open map file " , argv[i]));
2397
+
2398
+ std::string from, to;
2399
+ while (true )
2400
+ {
2401
+ if (!(infile >> from))
2402
+ break ;
2403
+ if (!(infile >> to))
2404
+ error (" Odd number of symbols in map file" );
2405
+ if (symbolsToRenameKeys.count (from))
2406
+ error (fmt (" Symbol appears twice in the map file: " , from.c_str ()));
2407
+ symbolsToRename[*symbolsToRenameKeys.insert (from).first ] = to;
2408
+ }
2409
+ }
2144
2410
else if (arg == " --help" || arg == " -h" ) {
2145
2411
showHelp (argv[0 ]);
2146
2412
return 0 ;
0 commit comments