diff options
author | Rolf Eike Beer <eb@emlix.com> | 2020-09-17 10:26:49 +0200 |
---|---|---|
committer | Jörg Thalheim <joerg@thalheim.io> | 2021-11-27 11:06:49 +0100 |
commit | b02a14949f66175517a330ffdd5d803ba81e937d (patch) | |
tree | ff3f3c371f434493f4778510c440a8fe6ea2c842 /src/patchelf.cc | |
parent | b4cb6cac7844a112f3fbb1f64ffefd2624d0537e (diff) | |
download | patchelf-replace-lib.tar.gz |
avoid adding the same .dynstr entries multiple timesreplace-lib
This can happen especially if .gnu.version_r stores the strings in .dynstr, so
replacing the library names would add them twice to the same section. Keep a map
of what was already added and where, and simply reuse the old entries if they
are needed again.
Diffstat (limited to 'src/patchelf.cc')
-rw-r--r-- | src/patchelf.cc | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/src/patchelf.cc b/src/patchelf.cc index 6148abd..41fdde0 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -24,6 +24,7 @@ #include <sstream> #include <stdexcept> #include <string> +#include <unordered_map> #include <vector> #include <cassert> @@ -1584,6 +1585,7 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std:: unsigned int verNeedNum = 0; unsigned int dynStrAddedBytes = 0; + std::unordered_map<std::string, Elf_Off> addedStrings; for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { if (rdi(dyn->d_tag) == DT_NEEDED) { @@ -1594,15 +1596,25 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std:: debug("replacing DT_NEEDED entry '%s' with '%s'\n", name, replacement.c_str()); + auto a = addedStrings.find(replacement); + // the same replacement string has already been added, reuse it + if (a != addedStrings.end()) { + wri(dyn->d_un.d_val, 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", - rdi(shdrDynStr.sh_size) + replacement.size() + 1 + dynStrAddedBytes); - setSubstr(newDynStr, rdi(shdrDynStr.sh_size) + dynStrAddedBytes, replacement + '\0'); + strOffset + replacement.size() + 1); + setSubstr(newDynStr, strOffset, replacement + '\0'); - wri(dyn->d_un.d_val, rdi(shdrDynStr.sh_size) + dynStrAddedBytes); + wri(dyn->d_un.d_val, strOffset); + addedStrings[replacement] = strOffset; dynStrAddedBytes += replacement.size() + 1; @@ -1640,6 +1652,9 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std:: // added bytes into account. if (versionRStringsSName == ".dynstr") verStrAddedBytes += dynStrAddedBytes; + else + // otherwise the already added strings can't be reused + addedStrings.clear(); auto need = (Elf_Verneed *)(fileContents->data() + rdi(shdrVersionR.sh_offset)); while (verNeedNum > 0) { @@ -1649,15 +1664,24 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std:: auto replacement = i->second; debug("replacing .gnu.version_r entry '%s' with '%s'\n", file, replacement.c_str()); - debug("resizing string section %s ...\n", versionRStringsSName.c_str()); - std::string & newVerDynStr = replaceSection(versionRStringsSName, - rdi(shdrVersionRStrings.sh_size) + replacement.size() + 1 + verStrAddedBytes); - setSubstr(newVerDynStr, rdi(shdrVersionRStrings.sh_size) + verStrAddedBytes, replacement + '\0'); + auto a = addedStrings.find(replacement); + // the same replacement string has already been added, reuse it + if (a != addedStrings.end()) { + wri(need->vn_file, a->second); + } else { + debug("resizing string section %s ...\n", versionRStringsSName.c_str()); + + Elf_Off strOffset = rdi(shdrVersionRStrings.sh_size) + verStrAddedBytes; + std::string & newVerDynStr = replaceSection(versionRStringsSName, + strOffset + replacement.size() + 1); + setSubstr(newVerDynStr, strOffset, replacement + '\0'); - wri(need->vn_file, rdi(shdrVersionRStrings.sh_size) + verStrAddedBytes); + wri(need->vn_file, strOffset); + addedStrings[replacement] = strOffset; - verStrAddedBytes += replacement.size() + 1; + verStrAddedBytes += replacement.size() + 1; + } changed = true; } else { |