diff --git a/src/patchelf.cc b/src/patchelf.cc index 68daae2..5ae1aef 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -57,8 +57,8 @@ static int forcedPageSize = -1; typedef std::shared_ptr> FileContents; -#define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym, class Elf_Verneed -#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed +#define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym, class Elf_Verneed, class Elf_Versym +#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed, Elf_Versym static std::vector splitColonDelimitedString(const char * s) @@ -215,6 +215,8 @@ public: void noDefaultLib(); + void clearSymbolVersions(const std::set & syms); + private: /* Convert an integer in big or little endian representation (as @@ -1675,6 +1677,33 @@ void ElfFile::noDefaultLib() changed = true; } +template +void ElfFile::clearSymbolVersions(const std::set & syms) +{ + if (syms.empty()) return; + + auto shdrDynStr = findSection(".dynstr"); + auto shdrDynsym = findSection(".dynsym"); + auto shdrVersym = findSection(".gnu.version"); + + char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset); + Elf_Sym * dynsyms = (Elf_Sym *) (contents + rdi(shdrDynsym.sh_offset)); + Elf_Versym * versyms = (Elf_Versym *) (contents + rdi(shdrVersym.sh_offset)); + size_t count = rdi(shdrDynsym.sh_size) / sizeof(Elf_Sym); + + if (count != rdi(shdrVersym.sh_size) / sizeof(Elf_Versym)) + error("versym size mismatch"); + + for (size_t i = 0; i < count; i++) { + auto dynsym = dynsyms[i]; + auto name = strTab + rdi(dynsym.st_name); + if (syms.find(name) != syms.end()) { + debug("clearing symbol version for %s\n", name); + wri(versyms[i], 1); + } + } + changed = true; +} static bool printInterpreter = false; static bool printSoname = false; @@ -1690,6 +1719,7 @@ static std::string newRPath; static std::set neededLibsToRemove; static std::map neededLibsToReplace; static std::set neededLibsToAdd; +static std::set symbolsToClearVersion; static bool printNeeded = false; static bool noDefaultLib = false; @@ -1723,6 +1753,7 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, std elfFile.removeNeeded(neededLibsToRemove); elfFile.replaceNeeded(neededLibsToReplace); elfFile.addNeeded(neededLibsToAdd); + elfFile.clearSymbolVersions(symbolsToClearVersion); if (noDefaultLib) elfFile.noDefaultLib(); @@ -1747,9 +1778,9 @@ static void patchElf() std::string outputFileName2 = outputFileName.empty() ? fileName : outputFileName; if (getElfType(fileContents).is32Bit) - patchElf2(ElfFile(fileContents), fileContents, outputFileName2); + patchElf2(ElfFile(fileContents), fileContents, outputFileName2); else - patchElf2(ElfFile(fileContents), fileContents, outputFileName2); + patchElf2(ElfFile(fileContents), fileContents, outputFileName2); } } @@ -1773,6 +1804,7 @@ void showHelp(const std::string & progName) [--replace-needed LIBRARY NEW_LIBRARY]\n\ [--print-needed]\n\ [--no-default-lib]\n\ + [--clear-symbol-version SYMBOL]\n\ [--output FILE]\n\ [--debug]\n\ [--version]\n\ @@ -1860,6 +1892,10 @@ int mainWrapped(int argc, char * * argv) neededLibsToReplace[ argv[i+1] ] = argv[i+2]; i += 2; } + else if (arg == "--clear-symbol-version") { + if (++i == argc) error("missing argument"); + symbolsToClearVersion.insert(argv[i]); + } else if (arg == "--output") { if (++i == argc) error("missing argument"); outputFileName = argv[i];