@@ 88,6 88,11 @@ option can be given multiple times.
.IP --print-needed
Prints all DT_NEEDED entries of the executable.
+.IP "--replace-symbol SYMBOL_ORIG SYMBOL_NEW"
+Replaces the name of a symbol with another one (.dynsym). The new symbol will
+not have a version associated with it.
+This option can be given multiple times.
+
.IP "--no-default-lib"
Marks the object so that the search for dependencies of this object will ignore any
default library search paths.
@@ 1638,6 1638,69 @@ void ElfFile<ElfFileParamNames>::printNeededLibs() // const
template<ElfFileParams>
+void ElfFile<ElfFileParamNames>::replaceSymbols(const std::map<std::string, std::string> & syms)
+{
+ if (syms.empty()) return;
+
+ auto shdrDynStr = findSectionHeader(".dynstr");
+ auto shdrDynSym = findSectionHeader(".dynsym");
+ auto shdrVersion = tryFindSectionHeader(".gnu.version");
+ char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset);
+
+ auto symStart = (Elf_Sym *)(fileContents->data() + rdi(shdrDynSym.sh_offset));
+ auto symCount = rdi(shdrDynSym.sh_size) / rdi(shdrDynSym.sh_entsize);
+ auto version = shdrVersion
+ ? (Elf_Versym *) (fileContents->data() + rdi(shdrVersion->get().sh_offset))
+ : nullptr;
+
+ unsigned int dynStrAddedBytes = 0;
+ std::unordered_map<std::string, Elf_Off> addedStrings;
+
+ for ( size_t symNum = 0; symNum < symCount; symNum++ ) {
+ auto sym = symStart + symNum;
+ char * name = strTab + rdi(sym->st_name);
+ auto i = syms.find(name);
+ if (i != syms.end() && name != i->second) {
+ auto replacement = i->second;
+
+ debug("replacing .dynsym entry '%s' with '%s'\n", name, replacement.c_str());
+
+ if (version) {
+ debug("setting version of symbol %d from %d to %d\n", symNum, version[symNum], VER_NDX_GLOBAL);
+ wri(version[symNum], VER_NDX_GLOBAL);
+ }
+
+ auto a = addedStrings.find(replacement);
+ // the same replacement string has already been added, reuse it
+ if (a != addedStrings.end()) {
+ wri(sym->st_name, a->second);
+ continue;
+ }
+
+ // technically, the string referred by d_val could be used otherwise, too (although unlikely)
+ // we'll therefore add a new string
+ debug("resizing .dynstr ...\n");
+
+ // relative location of the new string
+ Elf_Off strOffset = rdi(shdrDynStr.sh_size) + dynStrAddedBytes;
+ std::string & newDynStr = replaceSection(".dynstr",
+ strOffset + replacement.size() + 1);
+ setSubstr(newDynStr, strOffset, replacement + '\0');
+
+ wri(sym->st_name, strOffset);
+ addedStrings[replacement] = strOffset;
+
+ dynStrAddedBytes += replacement.size() + 1;
+
+ changed = true;
+ }
+ }
+
+ this->rewriteSections();
+}
+
+
+template<ElfFileParams>
void ElfFile<ElfFileParamNames>::noDefaultLib()
{
auto shdrDynamic = findSectionHeader(".dynamic");
@@ 1754,6 1817,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::map<std::string, std::string> symbolsToReplace;
static std::set<std::string> symbolsToClearVersion;
static bool printNeeded = false;
static bool noDefaultLib = false;
@@ 1790,6 1854,7 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
elfFile.removeNeeded(neededLibsToRemove);
elfFile.replaceNeeded(neededLibsToReplace);
elfFile.addNeeded(neededLibsToAdd);
+ elfFile.replaceSymbols(symbolsToReplace);
elfFile.clearSymbolVersions(symbolsToClearVersion);
if (noDefaultLib)
@@ 1852,6 1917,7 @@ void showHelp(const std::string & progName)
[--remove-needed LIBRARY]\n\
[--replace-needed LIBRARY NEW_LIBRARY]\n\
[--print-needed]\n\
+ [--replace-symbol SYMBOL OLD_SYMBOL]\n\
[--no-default-lib]\n\
[--no-sort]\t\tDo not sort program+section headers; useful for debugging patchelf.\n\
[--clear-symbol-version SYMBOL]\n\
@@ 1952,6 2018,11 @@ int mainWrapped(int argc, char * * argv)
neededLibsToReplace[ argv[i+1] ] = argv[i+2];
i += 2;
}
+ else if (arg == "--replace-symbol") {
+ if (i+2 >= argc) error("missing argument(s)");
+ symbolsToReplace[ argv[i+1] ] = argv[i+2];
+ i += 2;
+ }
else if (arg == "--clear-symbol-version") {
if (++i == argc) error("missing argument");
symbolsToClearVersion.insert(resolveArgument(argv[i]));
@@ 127,6 127,8 @@ public:
void replaceNeeded(const std::map<std::string, std::string> & libs);
+ void replaceSymbols(const std::map<std::string, std::string> & syms);
+
void printNeededLibs() /* should be const */;
void noDefaultLib();