diff --git a/src/patchelf.cc b/src/patchelf.cc index e824cbf9..8d4da8c5 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -18,29 +18,20 @@ #include #include -#include -#include -#include #include #include -#include #include -#include -#include - #include #include #include #include #include #include - #include #include #include #include -#include "elf.h" #include "patchelf.h" #ifndef PACKAGE_STRING @@ -1082,6 +1073,16 @@ std::string ElfFile::getInterpreter() template void ElfFile::modifySoname(sonameMode op, const std::string & newSoname) { + + bool soNameModified = false; + + Finally finally([&]() { + if (soNameModified) { + this->rewriteSections(); + changed = true; + } + }); + if (rdi(hdr()->e_type) != ET_DYN) { debug("this is not a dynamic library\n"); return; @@ -1149,17 +1150,24 @@ void ElfFile::modifySoname(sonameMode op, const std::string & setSubstr(newDynamic, 0, std::string((char *)&newDyn, sizeof(Elf_Dyn))); } - changed = true; - this->rewriteSections(); + soNameModified = true; } template void ElfFile::setInterpreter(const std::string & newInterpreter) { + bool interpreterChanged = false; + + Finally finally([&]() { + if (interpreterChanged) { + this->rewriteSections(); + changed = true; + } + }); + std::string & section = replaceSection(".interp", newInterpreter.size() + 1); setSubstr(section, 0, newInterpreter + '\0'); - changed = true; - this->rewriteSections(); + interpreterChanged = true; } @@ -1222,27 +1230,42 @@ std::string ElfFile::shrinkRPath(char* rpath, std::vector void ElfFile::removeRPath(Elf_Shdr & shdrDynamic) { + bool rpathChanged = false; + Finally finally([&]() { + if (rpathChanged) { + this->rewriteSections(); + changed = true; + } + }); + auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset)); Elf_Dyn * last = dyn; for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { if (rdi(dyn->d_tag) == DT_RPATH) { debug("removing DT_RPATH entry\n"); - changed = true; + rpathChanged = true; } else if (rdi(dyn->d_tag) == DT_RUNPATH) { debug("removing DT_RUNPATH entry\n"); - changed = true; + rpathChanged = true; } else { *last++ = *dyn; } } memset(last, 0, sizeof(Elf_Dyn) * (dyn - last)); - this->rewriteSections(); } template void ElfFile::modifyRPath(RPathOp op, const std::vector & allowedRpathPrefixes, std::string newRPath) { + bool rpathChanged = false; + Finally finally([&]() { + if (rpathChanged) { + this->rewriteSections(); + changed = true; + } + }); + auto shdrDynamic = findSectionHeader(".dynamic"); if (rdi(shdrDynamic.sh_type) == SHT_NOBITS) { @@ -1321,18 +1344,18 @@ void ElfFile::modifyRPath(RPathOp op, wri(dynRPath->d_tag, DT_RUNPATH); dynRunPath = dynRPath; dynRPath = nullptr; - changed = true; + rpathChanged = true; } else if (forceRPath && dynRunPath) { /* convert DT_RUNPATH to DT_RPATH */ wri(dynRunPath->d_tag, DT_RPATH); dynRPath = dynRunPath; dynRunPath = nullptr; - changed = true; + rpathChanged = true; } if (rpath && rpath == newRPath) { return; } - changed = true; + rpathChanged = true; /* Zero out the previous rpath to prevent retained dependencies in Nix. */ @@ -1383,7 +1406,6 @@ void ElfFile::modifyRPath(RPathOp op, newDyn.d_un.d_val = shdrDynStr.sh_size; setSubstr(newDynamic, 0, std::string((char *) &newDyn, sizeof(Elf_Dyn))); } - this->rewriteSections(); } @@ -1392,6 +1414,14 @@ void ElfFile::removeNeeded(const std::set & libs { if (libs.empty()) return; + bool neededChanged = false; + Finally finally([&]() { + if (neededChanged) { + this->rewriteSections(); + changed = true; + } + }); + auto shdrDynamic = findSectionHeader(".dynamic"); auto shdrDynStr = findSectionHeader(".dynstr"); char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset); @@ -1403,7 +1433,7 @@ void ElfFile::removeNeeded(const std::set & libs char * name = strTab + rdi(dyn->d_un.d_val); if (libs.count(name)) { debug("removing DT_NEEDED entry '%s'\n", name); - changed = true; + neededChanged = true; } else { debug("keeping DT_NEEDED entry '%s'\n", name); *last++ = *dyn; @@ -1422,6 +1452,14 @@ void ElfFile::replaceNeeded(const std::maprewriteSections(); + changed = true; + } + }); + auto shdrDynamic = findSectionHeader(".dynamic"); auto shdrDynStr = findSectionHeader(".dynstr"); char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset); @@ -1464,7 +1502,7 @@ void ElfFile::replaceNeeded(const std::map::replaceNeeded(const std::map::replaceNeeded(const std::maprewriteSections(); } template @@ -1547,6 +1583,14 @@ void ElfFile::addNeeded(const std::set & libs) { if (libs.empty()) return; + bool neededChanged = false; + Finally finally([&]() { + if (neededChanged) { + this->rewriteSections(); + changed = true; + } + }); + auto shdrDynamic = findSectionHeader(".dynamic"); auto shdrDynStr = findSectionHeader(".dynstr"); @@ -1589,9 +1633,7 @@ void ElfFile::addNeeded(const std::set & libs) i++; } - changed = true; - - this->rewriteSections(); + neededChanged = true; } template @@ -1615,6 +1657,14 @@ void ElfFile::printNeededLibs() // const template void ElfFile::noDefaultLib() { + bool defaultLibChanged = false; + Finally finally([&]() { + if (defaultLibChanged) { + this->rewriteSections(); + changed = true; + } + }); + auto shdrDynamic = findSectionHeader(".dynamic"); auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset)); @@ -1648,8 +1698,7 @@ void ElfFile::noDefaultLib() setSubstr(newDynamic, 0, std::string((char *) &newDyn, sizeof(Elf_Dyn))); } - this->rewriteSections(); - changed = true; + defaultLibChanged = true; } template @@ -1657,6 +1706,14 @@ void ElfFile::clearSymbolVersions(const std::set { if (syms.empty()) return; + bool symbolVersionsChanged = false; + Finally finally([&]() { + if (symbolVersionsChanged) { + this->rewriteSections(); + changed = true; + } + }); + auto shdrDynStr = findSectionHeader(".dynstr"); auto shdrDynsym = findSectionHeader(".dynsym"); auto shdrVersym = findSectionHeader(".gnu.version"); @@ -1677,8 +1734,7 @@ void ElfFile::clearSymbolVersions(const std::set wri(versyms[i], 1); } } - changed = true; - this->rewriteSections(); + symbolVersionsChanged = true; } static bool printInterpreter = false; diff --git a/src/patchelf.h b/src/patchelf.h index 93a0e5c2..9f249271 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -1,3 +1,15 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "elf.h" + using FileContents = std::shared_ptr>; #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 @@ -157,3 +169,15 @@ class ElfFile return (const Elf_Ehdr *)fileContents->data(); } }; + +/* A trivial class to run a function at the end of a scope. */ +class Finally +{ +private: + std::function fun; + +public: + Finally(std::function fun) : fun(fun) { } + ~Finally() { fun(); } +}; +