~raphi/patchelf

9079354d2b94050f38594b5fab5f764f73e4b7e0 — Raphael Robatsch 1 year, 5 months ago c2b419d replace-symbol
Add --replace-symbol flag
3 files changed, 78 insertions(+), 0 deletions(-)

M patchelf.1
M src/patchelf.cc
M src/patchelf.h
M patchelf.1 => patchelf.1 +5 -0
@@ 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.

M src/patchelf.cc => src/patchelf.cc +71 -0
@@ 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]));

M src/patchelf.h => src/patchelf.h +2 -0
@@ 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();