add --clear-symbol-version

This sets the versym entry for a given symbol to 1.
This commit is contained in:
David McFarland
2020-08-10 15:38:34 -03:00
parent 61bc101769
commit 51a3d5b5ff

View File

@@ -57,8 +57,8 @@ static int forcedPageSize = -1;
typedef std::shared_ptr<std::vector<unsigned char>> 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<std::string> splitColonDelimitedString(const char * s)
@@ -215,6 +215,8 @@ public:
void noDefaultLib();
void clearSymbolVersions(const std::set<std::string> & syms);
private:
/* Convert an integer in big or little endian representation (as
@@ -1675,6 +1677,33 @@ void ElfFile<ElfFileParamNames>::noDefaultLib()
changed = true;
}
template<ElfFileParams>
void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string> & 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<std::string> neededLibsToRemove;
static std::map<std::string, std::string> neededLibsToReplace;
static std::set<std::string> neededLibsToAdd;
static std::set<std::string> 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<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed>(fileContents), fileContents, outputFileName2);
patchElf2(ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed, Elf32_Versym>(fileContents), fileContents, outputFileName2);
else
patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed>(fileContents), fileContents, outputFileName2);
patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, Elf64_Versym>(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];