summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBreno Rodrigues GuimarĂ£es <brenorg@gmail.com>2023-02-23 22:07:41 -0300
committerGitHub <noreply@github.com>2023-02-23 22:07:41 -0300
commit70a477a252420c3f6a2e8e8d4c63d557df4b7f46 (patch)
treea68dce23c94fe6250b8f3dc3c7ab8ada895e4d84
parentafca68f86aa021c5cb991bb810db71eb6af89155 (diff)
parent69a7ae54d27513d7553b4d8bd77ade017e674e22 (diff)
downloadpatchelf-70a477a252420c3f6a2e8e8d4c63d557df4b7f46.tar.gz
Merge branch 'NixOS:master' into breno.457
-rw-r--r--.github/workflows/publish.yml2
-rw-r--r--patchelf.18
-rw-r--r--src/Makefile.am2
-rw-r--r--src/patchelf.cc416
-rw-r--r--src/patchelf.h153
-rw-r--r--tests/Makefile.am23
-rwxr-xr-xtests/add-debug-tag.sh14
-rwxr-xr-xtests/add-rpath.sh25
-rwxr-xr-xtests/args-from-file.sh20
-rwxr-xr-xtests/big-dynstr.sh25
-rwxr-xr-xtests/build-id.sh2
-rwxr-xr-xtests/change-abi.sh45
-rwxr-xr-xtests/contiguous-note-sections.sh4
-rwxr-xr-xtests/empty-note.sh10
-rwxr-xr-xtests/endianness.sh14
-rwxr-xr-xtests/force-rpath.sh28
-rwxr-xr-xtests/grow-file.sh14
-rwxr-xr-xtests/invalid-elf.sh4
-rwxr-xr-xtests/no-gnu-hash.sh12
-rwxr-xr-xtests/no-rpath-pie-powerpc.sh2
-rwxr-xr-xtests/no-rpath-prebuild.sh22
-rwxr-xr-xtests/no-rpath.sh16
-rwxr-xr-xtests/output-flag.sh29
-rwxr-xr-xtests/phdr-corruption.sh4
-rwxr-xr-xtests/plain-needed.sh8
-rwxr-xr-xtests/rename-dynamic-symbols.sh84
-rwxr-xr-xtests/replace-add-needed.sh24
-rwxr-xr-xtests/replace-needed.sh17
-rwxr-xr-xtests/set-empty-rpath.sh12
-rwxr-xr-xtests/set-interpreter-long.sh18
-rwxr-xr-xtests/set-interpreter-short.sh12
-rwxr-xr-xtests/set-rpath-library.sh34
-rwxr-xr-xtests/set-rpath-rel-map.sh27
-rwxr-xr-xtests/set-rpath.sh25
-rwxr-xr-xtests/shrink-rpath-with-allowed-prefixes.sh42
-rwxr-xr-xtests/shrink-rpath.sh16
-rwxr-xr-xtests/soname.sh18
-rwxr-xr-xtests/too-many-strtab.sh12
38 files changed, 881 insertions, 362 deletions
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index c180417..f330171 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -47,7 +47,7 @@ jobs:
needs: [build_windows]
runs-on: windows-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: patchelf
diff --git a/patchelf.1 b/patchelf.1
index 3d46f1f..6a8a94e 100644
--- a/patchelf.1
+++ b/patchelf.1
@@ -123,6 +123,14 @@ Clears the executable flag of the GNU_STACK program header, or adds a new header
.IP "--set-execstack"
Sets the executable flag of the GNU_STACK program header, or adds a new header.
+.IP "--rename-dynamic-symbols NAME_MAP_FILE"
+Renames dynamic symbols. The name map file should contain lines
+with the old and the new name separated by spaces like this:
+
+old_name new_name
+
+Symbol names do not contain version specifier that are also shown in the output of the nm -D command from binutils. So instead of the name write@GLIBC_2.2.5 it is just write.
+
.IP "--output FILE"
Set the output file name. If not specified, the input will be modified in place.
diff --git a/src/Makefile.am b/src/Makefile.am
index fa0a9cc..93e92d8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
-AM_CXXFLAGS = -Wall -std=c++17 -D_FILE_OFFSET_BITS=64
+AM_CXXFLAGS = -Wall -Wextra -Wcast-qual -std=c++17 -D_FILE_OFFSET_BITS=64
if WITH_ASAN
AM_CXXFLAGS += -fsanitize=address -fsanitize-address-use-after-scope
diff --git a/src/patchelf.cc b/src/patchelf.cc
index 0c1fbe8..5dd320d 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -17,16 +17,19 @@
*/
#include <algorithm>
+#include <fstream>
#include <limits>
#include <map>
#include <memory>
+#include <optional>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
+#include <string_view>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
-#include <optional>
#include <cassert>
#include <cerrno>
@@ -69,14 +72,18 @@ static int forcedPageSize = -1;
#define EM_LOONGARCH 258
#endif
-
-static std::vector<std::string> splitColonDelimitedString(const char * s)
+[[nodiscard]] static std::vector<std::string> splitColonDelimitedString(std::string_view s)
{
- std::string item;
std::vector<std::string> parts;
- std::stringstream ss(s);
- while (std::getline(ss, item, ':'))
- parts.push_back(item);
+
+ size_t pos;
+ while ((pos = s.find(':')) != std::string_view::npos) {
+ parts.emplace_back(s.substr(0, pos));
+ s = s.substr(pos + 1);
+ }
+
+ if (!s.empty())
+ parts.emplace_back(s);
return parts;
}
@@ -104,7 +111,7 @@ static std::string downcase(std::string s)
why... */
template<ElfFileParams>
template<class I>
-I ElfFile<ElfFileParamNames>::rdi(I i) const
+constexpr I ElfFile<ElfFileParamNames>::rdi(I i) const noexcept
{
I r = 0;
if (littleEndian) {
@@ -131,7 +138,7 @@ static void debug(const char * format, ...)
}
-void fmt2(std::ostringstream & out)
+static void fmt2([[maybe_unused]] std::ostringstream & out)
{
}
@@ -162,7 +169,7 @@ struct SysError : std::runtime_error
{ }
};
-__attribute__((noreturn)) static void error(const std::string & msg)
+[[noreturn]] static void error(const std::string & msg)
{
if (errno)
throw SysError(msg);
@@ -191,11 +198,11 @@ static FileContents readFile(const std::string & fileName,
while ((portion = read(fd, contents->data() + bytesRead, size - bytesRead)) > 0)
bytesRead += portion;
+ close(fd);
+
if (bytesRead != size)
throw SysError(fmt("reading '", fileName, "'"));
- close(fd);
-
return contents;
}
@@ -207,10 +214,10 @@ struct ElfType
};
-ElfType getElfType(const FileContents & fileContents)
+[[nodiscard]] static ElfType getElfType(const FileContents & fileContents)
{
/* Check the ELF header for basic validity. */
- if (fileContents->size() < static_cast<off_t>(sizeof(Elf32_Ehdr)))
+ if (fileContents->size() < sizeof(Elf32_Ehdr))
error("missing ELF header");
auto contents = fileContents->data();
@@ -231,14 +238,32 @@ ElfType getElfType(const FileContents & fileContents)
}
-static void checkPointer(const FileContents & contents, void * p, unsigned int size)
+static void checkPointer(const FileContents & contents, const void * p, size_t size)
{
- auto q = static_cast<unsigned char *>(p);
- if (!(q >= contents->data() && q + size <= contents->data() + contents->size()))
+ if (p < contents->data() || size > contents->size() || p > contents->data() + contents->size() - size)
error("data region extends past file end");
}
+static void checkOffset(const FileContents & contents, size_t offset, size_t size)
+{
+ size_t end;
+
+ if (offset > contents->size()
+ || size > contents->size()
+ || __builtin_add_overflow(offset, size, &end)
+ || end > contents->size())
+ error("data offset extends past file end");
+}
+
+
+static std::string extractString(const FileContents & contents, size_t offset, size_t size)
+{
+ checkOffset(contents, offset, size);
+ return { reinterpret_cast<const char *>(contents->data()) + offset, size };
+}
+
+
template<ElfFileParams>
ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
: fileContents(fContents)
@@ -255,14 +280,34 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
if (rdi(hdr()->e_type) != ET_EXEC && rdi(hdr()->e_type) != ET_DYN)
error("wrong ELF type");
- if (rdi(hdr()->e_phoff) + rdi(hdr()->e_phnum) * rdi(hdr()->e_phentsize) > fileContents->size())
- error("program header table out of bounds");
+ {
+ auto ph_offset = rdi(hdr()->e_phoff);
+ auto ph_num = rdi(hdr()->e_phnum);
+ auto ph_entsize = rdi(hdr()->e_phentsize);
+ size_t ph_size, ph_end;
+
+ if (__builtin_mul_overflow(ph_num, ph_entsize, &ph_size)
+ || __builtin_add_overflow(ph_offset, ph_size, &ph_end)
+ || ph_end > fileContents->size()) {
+ error("program header table out of bounds");
+ }
+ }
if (rdi(hdr()->e_shnum) == 0)
error("no section headers. The input file is probably a statically linked, self-decompressing binary");
- if (rdi(hdr()->e_shoff) + rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize) > fileContents->size())
- error("section header table out of bounds");
+ {
+ auto sh_offset = rdi(hdr()->e_shoff);
+ auto sh_num = rdi(hdr()->e_shnum);
+ auto sh_entsize = rdi(hdr()->e_shentsize);
+ size_t sh_size, sh_end;
+
+ if (__builtin_mul_overflow(sh_num, sh_entsize, &sh_size)
+ || __builtin_add_overflow(sh_offset, sh_size, &sh_end)
+ || sh_end > fileContents->size()) {
+ error("section header table out of bounds");
+ }
+ }
if (rdi(hdr()->e_phentsize) != sizeof(Elf_Phdr))
error("program headers have wrong size");
@@ -286,12 +331,15 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
/* Get the section header string table section (".shstrtab"). Its
index in the section header table is given by e_shstrndx field
of the ELF header. */
- unsigned int shstrtabIndex = rdi(hdr()->e_shstrndx);
+ auto shstrtabIndex = rdi(hdr()->e_shstrndx);
if (shstrtabIndex >= shdrs.size())
error("string table index out of bounds");
- unsigned int shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size);
- char * shstrtab = (char * ) fileContents->data() + rdi(shdrs[shstrtabIndex].sh_offset);
+ auto shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size);
+ size_t shstrtabptr;
+ if (__builtin_add_overflow(reinterpret_cast<size_t>(fileContents->data()), rdi(shdrs[shstrtabIndex].sh_offset), &shstrtabptr))
+ error("string table overflow");
+ const char *shstrtab = reinterpret_cast<const char *>(shstrtabptr);
checkPointer(fileContents, shstrtab, shstrtabSize);
if (shstrtabSize == 0)
@@ -309,7 +357,7 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
template<ElfFileParams>
-unsigned int ElfFile<ElfFileParamNames>::getPageSize() const
+unsigned int ElfFile<ElfFileParamNames>::getPageSize() const noexcept
{
if (forcedPageSize > 0)
return forcedPageSize;
@@ -431,6 +479,8 @@ static void writeFile(const std::string & fileName, const FileContents & content
static uint64_t roundUp(uint64_t n, uint64_t m)
{
+ if (n == 0)
+ return m;
return ((n - 1) / m + 1) * m;
}
@@ -531,7 +581,7 @@ std::string ElfFile<ElfFileParamNames>::getSectionName(const Elf_Shdr & shdr) co
template<ElfFileParams>
-Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sectionName)
+const Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sectionName) const
{
auto shdr = tryFindSectionHeader(sectionName);
if (!shdr) {
@@ -545,7 +595,7 @@ Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sec
template<ElfFileParams>
-std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::tryFindSectionHeader(const SectionName & sectionName)
+std::optional<std::reference_wrapper<const Elf_Shdr>> ElfFile<ElfFileParamNames>::tryFindSectionHeader(const SectionName & sectionName) const
{
auto i = getSectionIndex(sectionName);
if (i)
@@ -553,9 +603,30 @@ std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::tryF
return {};
}
+template<ElfFileParams>
+template<class T>
+span<T> ElfFile<ElfFileParamNames>::getSectionSpan(const Elf_Shdr & shdr) const
+{
+ return span((T*)(fileContents->data() + rdi(shdr.sh_offset)), rdi(shdr.sh_size)/sizeof(T));
+}
+
+template<ElfFileParams>
+template<class T>
+span<T> ElfFile<ElfFileParamNames>::getSectionSpan(const SectionName & sectionName)
+{
+ return getSectionSpan<T>(findSectionHeader(sectionName));
+}
template<ElfFileParams>
-unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName)
+template<class T>
+span<T> ElfFile<ElfFileParamNames>::tryGetSectionSpan(const SectionName & sectionName)
+{
+ auto shdrOpt = tryFindSectionHeader(sectionName);
+ return shdrOpt ? getSectionSpan<T>(*shdrOpt) : span<T>();
+}
+
+template<ElfFileParams>
+unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName) const
{
for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
if (getSectionName(shdrs.at(i)) == sectionName) return i;
@@ -579,7 +650,7 @@ std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sec
s = std::string(i->second);
} else {
auto shdr = findSectionHeader(sectionName);
- s = std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size));
+ s = extractString(fileContents, rdi(shdr.sh_offset), rdi(shdr.sh_size));
}
s.resize(size);
@@ -598,7 +669,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
clobbering previously written new section contents. */
for (auto & i : replacedSections) {
const std::string & sectionName = i.first;
- Elf_Shdr & shdr = findSectionHeader(sectionName);
+ const Elf_Shdr & shdr = findSectionHeader(sectionName);
if (rdi(shdr.sh_type) != SHT_NOBITS)
memset(fileContents->data() + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size));
}
@@ -617,7 +688,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
debug("rewriting section '%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n",
sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i->second.size());
- memcpy(fileContents->data() + curOff, (unsigned char *) i->second.c_str(),
+ memcpy(fileContents->data() + curOff, i->second.c_str(),
i->second.size());
/* Update the section header for this section. */
@@ -1215,10 +1286,13 @@ static void setSubstr(std::string & s, unsigned int pos, const std::string & t)
template<ElfFileParams>
-std::string ElfFile<ElfFileParamNames>::getInterpreter()
+std::string ElfFile<ElfFileParamNames>::getInterpreter() const
{
auto shdr = findSectionHeader(".interp");
- return std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size) - 1);
+ auto size = rdi(shdr.sh_size);
+ if (size > 0)
+ size--;
+ return extractString(fileContents, rdi(shdr.sh_offset), size);
}
template<ElfFileParams>
@@ -1341,7 +1415,7 @@ void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string &
std::string & newDynamic = replaceSection(".dynamic", rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
unsigned int idx = 0;
- for (; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++);
+ for (; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++);
debug("DT_NULL index is %d\n", idx);
/* Shift all entries down by one. */
@@ -1497,7 +1571,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
case rpPrint: {
printf("%s\n", rpath ? rpath : "");
return;
- };
+ }
case rpRemove: {
if (!rpath) {
debug("no RPATH to delete\n");
@@ -1510,7 +1584,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
if (!rpath) {
debug("no RPATH to shrink\n");
return;
- ;}
+ }
newRPath = shrinkRPath(rpath, neededLibs, allowedRpathPrefixes);
break;
}
@@ -1576,7 +1650,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
unsigned int idx = 0;
- for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
+ for ( ; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
debug("DT_NULL index is %d\n", idx);
/* Shift all entries down by one. */
@@ -1778,7 +1852,7 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn) * libs.size());
unsigned int idx = 0;
- for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
+ for ( ; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
debug("DT_NULL index is %d\n", idx);
/* Shift all entries down by the number of new entries. */
@@ -1801,13 +1875,13 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
}
template<ElfFileParams>
-void ElfFile<ElfFileParamNames>::printNeededLibs() // const
+void ElfFile<ElfFileParamNames>::printNeededLibs() const
{
const auto shdrDynamic = findSectionHeader(".dynamic");
const auto shdrDynStr = findSectionHeader(".dynstr");
- const char *strTab = (char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
+ const char *strTab = (const char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
- const Elf_Dyn *dyn = (Elf_Dyn *) (fileContents->data() + rdi(shdrDynamic.sh_offset));
+ const Elf_Dyn *dyn = (const Elf_Dyn *) (fileContents->data() + rdi(shdrDynamic.sh_offset));
for (; rdi(dyn->d_tag) != DT_NULL; dyn++) {
if (rdi(dyn->d_tag) == DT_NEEDED) {
@@ -1840,7 +1914,7 @@ void ElfFile<ElfFileParamNames>::noDefaultLib()
rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
unsigned int idx = 0;
- for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
+ for ( ; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
debug("DT_NULL index is %d\n", idx);
/* Shift all entries down by one. */
@@ -1873,7 +1947,7 @@ void ElfFile<ElfFileParamNames>::addDebugTag()
rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
unsigned int idx = 0;
- for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
+ for ( ; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
debug("DT_NULL index is %d\n", idx);
/* Shift all entries down by one. */
@@ -1890,6 +1964,220 @@ void ElfFile<ElfFileParamNames>::addDebugTag()
changed = true;
}
+static uint32_t gnuHash(std::string_view name) {
+ uint32_t h = 5381;
+ for (uint8_t c : name)
+ h = ((h << 5) + h) + c;
+ return h;
+}
+
+template<ElfFileParams>
+auto ElfFile<ElfFileParamNames>::parseGnuHashTable(span<char> sectionData) -> GnuHashTable
+{
+ auto hdr = (typename GnuHashTable::Header*)sectionData.begin();
+ auto bloomFilters = span((typename GnuHashTable::BloomWord*)(hdr+1), rdi(hdr->maskwords));
+ auto buckets = span((uint32_t*)bloomFilters.end(), rdi(hdr->numBuckets));
+ auto table = span(buckets.end(), ((uint32_t*)sectionData.end()) - buckets.end());
+ return GnuHashTable{*hdr, bloomFilters, buckets, table};
+}
+
+template<ElfFileParams>
+void ElfFile<ElfFileParamNames>::rebuildGnuHashTable(span<char> strTab, span<Elf_Sym> dynsyms)
+{
+ auto sectionData = tryGetSectionSpan<char>(".gnu.hash");
+ if (!sectionData)
+ return;
+
+ auto ght = parseGnuHashTable(sectionData);
+
+ // We can't trust the value of symndx when the hash table is empty
+ if (ght.m_table.size() == 0)
+ return;
+
+ // The hash table includes only a subset of dynsyms
+ auto firstSymIdx = rdi(ght.m_hdr.symndx);
+ dynsyms = span(&dynsyms[firstSymIdx], dynsyms.end());
+
+ // Only use the range of symbol versions that will be changed
+ auto versyms = tryGetSectionSpan<Elf_Versym>(".gnu.version");
+ if (versyms)
+ versyms = span(&versyms[firstSymIdx], versyms.end());
+
+ struct Entry
+ {
+ uint32_t hash, bucketIdx, originalPos;
+ };
+
+ std::vector<Entry> entries;
+ entries.reserve(dynsyms.size());
+
+ uint32_t pos = 0; // Track the original position of the symbol in the table
+ for (auto& sym : dynsyms)
+ {
+ Entry e;
+ e.hash = gnuHash(&strTab[rdi(sym.st_name)]);
+ e.bucketIdx = e.hash % ght.m_buckets.size();
+ e.originalPos = pos++;
+ entries.push_back(e);
+ }
+
+ // Sort the entries based on the buckets. This is a requirement for gnu hash table to work
+ std::sort(entries.begin(), entries.end(), [&] (auto& l, auto& r) {
+ return l.bucketIdx < r.bucketIdx;
+ });
+
+ // Create a map of old positions to new positions after sorting
+ std::vector<uint32_t> old2new(entries.size());
+ for (size_t i = 0; i < entries.size(); ++i)
+ old2new[entries[i].originalPos] = i;
+
+ // Update the symbol table with the new order and
+ // all tables that refer to symbols through indexes in the symbol table
+ auto reorderSpan = [] (auto dst, auto& old2new)
+ {
+ std::vector tmp(dst.begin(), dst.end());
+ for (size_t i = 0; i < tmp.size(); ++i)
+ dst[old2new[i]] = tmp[i];
+ };
+
+ reorderSpan(dynsyms, old2new);
+ if (versyms)
+ reorderSpan(versyms, old2new);
+
+ auto remapSymbolId = [&old2new, firstSymIdx] (auto& oldSymIdx)
+ {
+ return oldSymIdx >= firstSymIdx ? old2new[oldSymIdx - firstSymIdx] + firstSymIdx
+ : oldSymIdx;
+ };
+
+ for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
+ {
+ auto& shdr = shdrs.at(i);
+ auto shtype = rdi(shdr.sh_type);
+ if (shtype == SHT_REL)
+ changeRelocTableSymIds<Elf_Rel>(shdr, remapSymbolId);
+ else if (shtype == SHT_RELA)
+ changeRelocTableSymIds<Elf_Rela>(shdr, remapSymbolId);
+ }
+
+ // Update bloom filters
+ std::fill(ght.m_bloomFilters.begin(), ght.m_bloomFilters.end(), 0);
+ for (size_t i = 0; i < entries.size(); ++i)
+ {
+ auto h = entries[i].hash;
+ size_t idx = (h / ElfClass) % ght.m_bloomFilters.size();
+ auto val = rdi(ght.m_bloomFilters[idx]);
+ val |= uint64_t(1) << (h % ElfClass);
+ val |= uint64_t(1) << ((h >> rdi(ght.m_hdr.shift2)) % ElfClass);
+ wri(ght.m_bloomFilters[idx], val);
+ }
+
+ // Fill buckets
+ std::fill(ght.m_buckets.begin(), ght.m_buckets.end(), 0);
+ for (size_t i = 0; i < entries.size(); ++i)
+ {
+ auto symBucketIdx = entries[i].bucketIdx;
+ if (!ght.m_buckets[symBucketIdx])
+ wri(ght.m_buckets[symBucketIdx], i + firstSymIdx);
+ }
+
+ // Fill hash table
+ for (size_t i = 0; i < entries.size(); ++i)
+ {
+ auto& n = entries[i];
+ bool isLast = (i == entries.size() - 1) || (n.bucketIdx != entries[i+1].bucketIdx);
+ // Add hash with first bit indicating end of chain
+ wri(ght.m_table[i], isLast ? (n.hash | 1) : (n.hash & ~1));
+ }
+}
+
+static uint32_t sysvHash(std::string_view name) {
+ uint32_t h = 0;
+ for (uint8_t c : name)
+ {
+ h = (h << 4) + c;
+ uint32_t g = h & 0xf0000000;
+ if (g != 0)
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ return h;
+}
+
+template<ElfFileParams>
+auto ElfFile<ElfFileParamNames>::parseHashTable(span<char> sectionData) -> HashTable
+{
+ auto hdr = (typename HashTable::Header*)sectionData.begin();
+ auto buckets = span((uint32_t*)(hdr+1), rdi(hdr->numBuckets));
+ auto table = span(buckets.end(), ((uint32_t*)sectionData.end()) - buckets.end());
+ return HashTable{*hdr, buckets, table};
+}
+
+template<ElfFileParams>
+void ElfFile<ElfFileParamNames>::rebuildHashTable(span<char> strTab, span<Elf_Sym> dynsyms)
+{
+ auto sectionData = tryGetSectionSpan<char>(".hash");
+ if (!sectionData)
+ return;
+
+ auto ht = parseHashTable(sectionData);
+
+ std::fill(ht.m_buckets.begin(), ht.m_buckets.end(), 0);
+ std::fill(ht.m_chain.begin(), ht.m_chain.end(), 0);
+
+ // The hash table includes only a subset of dynsyms
+ auto firstSymIdx = dynsyms.size() - ht.m_chain.size();
+ dynsyms = span(&dynsyms[firstSymIdx], dynsyms.end());
+
+ for (auto& sym : dynsyms)
+ {
+ auto name = &strTab[rdi(sym.st_name)];
+ uint32_t i = &sym - dynsyms.begin();
+ uint32_t hash = sysvHash(name) % ht.m_buckets.size();
+ wri(ht.m_chain[i], rdi(ht.m_buckets[hash]));
+ wri(ht.m_buckets[hash], i);
+ }
+}
+
+template<ElfFileParams>
+void ElfFile<ElfFileParamNames>::renameDynamicSymbols(const std::unordered_map<std::string_view, std::string>& remap)
+{
+ auto dynsyms = getSectionSpan<Elf_Sym>(".dynsym");
+ auto strTab = getSectionSpan<char>(".dynstr");
+
+ std::vector<char> extraStrings;
+ extraStrings.reserve(remap.size() * 30); // Just an estimate
+ for (auto& dynsym : dynsyms)
+ {
+ std::string_view name = &strTab[rdi(dynsym.st_name)];
+ auto it = remap.find(name);
+ if (it != remap.end())
+ {
+ wri(dynsym.st_name, strTab.size() + extraStrings.size());
+ auto& newName = it->second;
+ debug("renaming dynamic symbol %s to %s\n", name.data(), it->second.c_str());
+ extraStrings.insert(extraStrings.end(), newName.begin(), newName.end() + 1);
+ changed = true;
+ } else {
+ debug("skip renaming dynamic symbol %sn", name.data());
+ }
+ }
+
+ if (changed)
+ {
+ auto newStrTabSize = strTab.size() + extraStrings.size();
+ auto& newSec = replaceSection(".dynstr", newStrTabSize);
+ auto newStrTabSpan = span(newSec.data(), newStrTabSize);
+
+ std::copy(extraStrings.begin(), extraStrings.end(), &newStrTabSpan[strTab.size()]);
+
+ rebuildGnuHashTable(newStrTabSpan, dynsyms);
+ rebuildHashTable(newStrTabSpan, dynsyms);
+ }
+
+ this->rewriteSections();
+}
+
template<ElfFileParams>
void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string> & syms)
{
@@ -2012,12 +2300,15 @@ static bool removeRPath = false;
static bool setRPath = false;
static bool addRPath = false;
static bool addDebugTag = false;
+static bool renameDynamicSymbols = false;
static bool printRPath = false;
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 std::unordered_map<std::string_view, std::string> symbolsToRename;
+static std::unordered_set<std::string> symbolsToRenameKeys;
static bool printNeeded = false;
static bool noDefaultLib = false;
static bool printExecstack = false;
@@ -2077,6 +2368,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
if (addDebugTag)
elfFile.addDebugTag();
+ if (renameDynamicSymbols)
+ elfFile.renameDynamicSymbols(symbolsToRename);
+
if (elfFile.isChanged()){
writeFile(fileName, elfFile.fileContents);
} else if (alwaysWrite) {
@@ -2096,13 +2390,13 @@ static void patchElf()
const 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, Elf32_Versym>(fileContents), fileContents, outputFileName2);
+ patchElf2(ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed, Elf32_Versym, Elf32_Rel, Elf32_Rela, 32>(fileContents), fileContents, outputFileName2);
else
- patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, Elf64_Versym>(fileContents), fileContents, outputFileName2);
+ patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, Elf64_Versym, Elf64_Rel, Elf64_Rela, 64>(fileContents), fileContents, outputFileName2);
}
}
-std::string resolveArgument(const char *arg) {
+[[nodiscard]] static std::string resolveArgument(const char *arg) {
if (strlen(arg) > 0 && arg[0] == '@') {
FileContents cnts = readFile(arg + 1);
return std::string((char *)cnts->data(), cnts->size());
@@ -2112,7 +2406,7 @@ std::string resolveArgument(const char *arg) {
}
-void showHelp(const std::string & progName)
+static void showHelp(const std::string & progName)
{
fprintf(stderr, "syntax: %s\n\
[--set-interpreter FILENAME]\n\
@@ -2140,6 +2434,7 @@ void showHelp(const std::string & progName)
[--print-execstack]\t\tPrints whether the object requests an executable stack\n\
[--clear-execstack]\n\
[--set-execstack]\n\
+ [--rename-dynamic-symbols NAME_MAP_FILE]\tRenames dynamic symbols. The map file should contain two symbols (old_name new_name) per line\n\
[--output FILE]\n\
[--debug]\n\
[--version]\n\
@@ -2147,7 +2442,7 @@ void showHelp(const std::string & progName)
}
-int mainWrapped(int argc, char * * argv)
+static int mainWrapped(int argc, char * * argv)
{
if (argc <= 1) {
showHelp(argv[0]);
@@ -2271,6 +2566,31 @@ int mainWrapped(int argc, char * * argv)
else if (arg == "--add-debug-tag") {
addDebugTag = true;
}
+ else if (arg == "--rename-dynamic-symbols") {
+ renameDynamicSymbols = true;
+ if (++i == argc) error("missing argument");
+
+ const char* fname = argv[i];
+ std::ifstream infile(fname);
+ if (!infile) error(fmt("Cannot open map file ", fname));
+
+ std::string line, from, to;
+ size_t lineCount = 1;
+ while (std::getline(infile, line))
+ {
+ std::istringstream iss(line);
+ if (!(iss >> from))
+ break;
+ if (!(iss >> to))
+ error(fmt(fname, ":", lineCount, ": Map file line is missing the second element"));
+ if (symbolsToRenameKeys.count(from))
+ error(fmt(fname, ":", lineCount, ": Name '", from, "' appears twice in the map file"));
+ if (from.find('@') != std::string_view::npos || to.find('@') != std::string_view::npos)
+ error(fmt(fname, ":", lineCount, ": Name pair contains version tag: ", from, " ", to));
+ lineCount++;
+ symbolsToRename[*symbolsToRenameKeys.insert(from).first] = to;
+ }
+ }
else if (arg == "--help" || arg == "-h" ) {
showHelp(argv[0]);
return 0;
diff --git a/src/patchelf.h b/src/patchelf.h
index c3096ff..9fab18c 100644
--- a/src/patchelf.h
+++ b/src/patchelf.h
@@ -1,7 +1,37 @@
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "elf.h"
+
using FileContents = std::shared_ptr<std::vector<unsigned char>>;
-#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
+#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, class Elf_Rel, class Elf_Rela, unsigned ElfClass
+#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed, Elf_Versym, Elf_Rel, Elf_Rela, ElfClass
+
+template<class T>
+struct span
+{
+ explicit span(T* d = {}, size_t l = {}) : data(d), len(l) {}
+ span(T* from, T* to) : data(from), len(to-from) { assert(from <= to); }
+ T& operator[](std::size_t i) { checkRange(i); return data[i]; }
+ T* begin() { return data; }
+ T* end() { return data + len; }
+ auto size() const { return len; }
+ explicit operator bool() const { return size() > 0; }
+
+private:
+ void checkRange(std::size_t i) {
+ if (i >= size()) throw std::out_of_range("error: Span access out of range.");
+ }
+
+ T* data;
+ size_t len;
+};
template<ElfFileParams>
class ElfFile
@@ -30,14 +60,14 @@ private:
/* Align on 4 or 8 bytes boundaries on 32- or 64-bit platforms
respectively. */
- size_t sectionAlignment = sizeof(Elf_Off);
+ static constexpr size_t sectionAlignment = sizeof(Elf_Off);
std::vector<SectionName> sectionsByOldIndex;
public:
explicit ElfFile(FileContents fileContents);
- bool isChanged()
+ [[nodiscard]] bool isChanged() const noexcept
{
return changed;
}
@@ -46,8 +76,8 @@ private:
struct CompPhdr
{
- ElfFile * elfFile;
- bool operator ()(const Elf_Phdr & x, const Elf_Phdr & y)
+ const ElfFile * elfFile;
+ bool operator ()(const Elf_Phdr & x, const Elf_Phdr & y) const noexcept
{
// A PHDR comes before everything else.
if (elfFile->rdi(y.p_type) == PT_PHDR) return false;
@@ -58,39 +88,39 @@ private:
}
};
- friend struct CompPhdr;
-
void sortPhdrs();
struct CompShdr
{
- ElfFile * elfFile;
- bool operator ()(const Elf_Shdr & x, const Elf_Shdr & y)
+ const ElfFile * elfFile;
+ bool operator ()(const Elf_Shdr & x, const Elf_Shdr & y) const noexcept
{
return elfFile->rdi(x.sh_offset) < elfFile->rdi(y.sh_offset);
}
};
- friend struct CompShdr;
-
- unsigned int getPageSize() const;
+ [[nodiscard]] unsigned int getPageSize() const noexcept;
void sortShdrs();
void shiftFile(unsigned int extraPages, size_t sizeOffset, size_t extraBytes);
- std::string getSectionName(const Elf_Shdr & shdr) const;
+ [[nodiscard]] std::string getSectionName(const Elf_Shdr & shdr) const;
+
+ const Elf_Shdr & findSectionHeader(const SectionName & sectionName) const;
- Elf_Shdr & findSectionHeader(const SectionName & sectionName);
+ [[nodiscard]] std::optional<std::reference_wrapper<const Elf_Shdr>> tryFindSectionHeader(const SectionName & sectionName) const;
- std::optional<std::reference_wrapper<Elf_Shdr>> tryFindSectionHeader(const SectionName & sectionName);
+ template<class T> span<T> getSectionSpan(const Elf_Shdr & shdr) const;
+ template<class T> span<T> getSectionSpan(const SectionName & sectionName);
+ template<class T> span<T> tryGetSectionSpan(const SectionName & sectionName);
- unsigned int getSectionIndex(const SectionName & sectionName);
+ [[nodiscard]] unsigned int getSectionIndex(const SectionName & sectionName) const;
std::string & replaceSection(const SectionName & sectionName,
unsigned int size);
- bool haveReplacedSection(const SectionName & sectionName) const;
+ [[nodiscard]] bool haveReplacedSection(const SectionName & sectionName) const;
void writeReplacedSections(Elf_Off & curOff,
Elf_Addr startAddr, Elf_Off startOffset);
@@ -107,7 +137,7 @@ public:
void rewriteSections(bool force = false);
- std::string getInterpreter();
+ [[nodiscard]] std::string getInterpreter() const;
typedef enum { printOsAbi, replaceOsAbi } osAbiMode;
@@ -131,12 +161,14 @@ public:
void replaceNeeded(const std::map<std::string, std::string> & libs);
- void printNeededLibs() /* should be const */;
+ void printNeededLibs() const;
void noDefaultLib();
void addDebugTag();
+ void renameDynamicSymbols(const std::unordered_map<std::string_view, std::string>&);
+
void clearSymbolVersions(const std::set<std::string> & syms);
enum class ExecstackMode { print, set, clear };
@@ -144,26 +176,89 @@ public:
void modifyExecstack(ExecstackMode op);
private:
+ struct GnuHashTable {
+ using BloomWord = Elf_Addr;
+ struct Header {
+ uint32_t numBuckets, symndx, maskwords, shift2;
+ } m_hdr;
+ span<BloomWord> m_bloomFilters;
+ span<uint32_t> m_buckets, m_table;
+ };
+ GnuHashTable parseGnuHashTable(span<char> gh);
+
+ struct HashTable {
+ struct Header {
+ uint32_t numBuckets, nchain;
+ } m_hdr;
+ span<uint32_t> m_buckets, m_chain;
+ };
+ HashTable parseHashTable(span<char> gh);
+
+ void rebuildGnuHashTable(span<char> strTab, span<Elf_Sym> dynsyms);
+ void rebuildHashTable(span<char> strTab, span<Elf_Sym> dynsyms);
+
+ using Elf_Rel_Info = decltype(Elf_Rel::r_info);
+
+ uint32_t rel_getSymId(const Elf_Rel_Info& info) const
+ {
+ if constexpr (std::is_same_v<Elf_Rel, Elf64_Rel>)
+ return ELF64_R_SYM(info);
+ else
+ return ELF32_R_SYM(info);
+ }
+
+ Elf_Rel_Info rel_setSymId(Elf_Rel_Info info, uint32_t id) const
+ {
+ if constexpr (std::is_same_v<Elf_Rel, Elf64_Rel>)
+ {
+ constexpr Elf_Rel_Info idmask = (~Elf_Rel_Info()) << 32;
+ info = (info & ~idmask) | (Elf_Rel_Info(id) << 32);
+ }
+ else
+ {
+ constexpr Elf_Rel_Info idmask = (~Elf_Rel_Info()) << 8;
+ info = (info & ~idmask) | (Elf_Rel_Info(id) << 8);
+ }
+ return info;
+ }
+
+ template<class ElfRelType, class RemapFn>
+ void changeRelocTableSymIds(const Elf_Shdr& shdr, RemapFn&& old2newSymId)
+ {
+ static_assert(std::is_same_v<ElfRelType, Elf_Rel> || std::is_same_v<ElfRelType, Elf_Rela>);
+
+ for (auto& r : getSectionSpan<ElfRelType>(shdr))
+ {
+ auto info = rdi(r.r_info);
+ auto oldSymIdx = rel_getSymId(info);
+ auto newSymIdx = old2newSymId(oldSymIdx);
+ if (newSymIdx != oldSymIdx)
+ wri(r.r_info, rel_setSymId(info, newSymIdx));
+ }
+ }
/* Convert an integer in big or little endian representation (as
specified by the ELF header) to this platform's integer
representation. */
template<class I>
- I rdi(I i) const;
+ constexpr I rdi(I i) const noexcept;
/* Convert back to the ELF representation. */
- template<class I>
- I wri(I & t, unsigned long long i) const
+ template<class I, class U>
+ constexpr inline I wri(I & t, U i) const
{
- t = rdi((I) i);
- return i;
+ I val = static_cast<I>(i);
+ if (static_cast<U>(val) != i)
+ throw std::runtime_error { "value truncation" };
+ t = rdi(val);
+ return val;
}
- Elf_Ehdr *hdr() {
- return (Elf_Ehdr *)fileContents->data();
+ [[nodiscard]] Elf_Ehdr *hdr() noexcept {
+ return reinterpret_cast<Elf_Ehdr *>(fileContents->data());
}
- const Elf_Ehdr *hdr() const {
- return (const Elf_Ehdr *)fileContents->data();
+ [[nodiscard]] const Elf_Ehdr *hdr() const noexcept {
+ return reinterpret_cast<const Elf_Ehdr *>(fileContents->data());
}
};
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b8c97dc..55a8f75 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -46,7 +46,9 @@ src_TESTS = \
repeated-updates.sh \
empty-note.sh \
print-execstack.sh \
- modify-execstack.sh
+ modify-execstack.sh \
+ rename-dynamic-symbols.sh \
+ empty-note.sh
build_TESTS = \
$(no_rpath_arch_TESTS)
@@ -117,7 +119,7 @@ check_DATA = libbig-dynstr.debug
# - with libtool, it is difficult to control options
# - with libtool, it is not possible to compile convenience *dynamic* libraries :-(
check_PROGRAMS += libfoo.so libfoo-scoped.so libbar.so libbar-scoped.so libsimple.so libsimple-execstack.so libbuildid.so libtoomanystrtab.so \
- phdr-corruption.so
+ phdr-corruption.so many-syms-main libmany-syms.so
libbuildid_so_SOURCES = simple.c
libbuildid_so_LDFLAGS = $(LDFLAGS_sharedlib) -Wl,--build-id
@@ -148,6 +150,14 @@ too_many_strtab_SOURCES = too-many-strtab.c too-many-strtab2.s
libtoomanystrtab_so_SOURCES = too-many-strtab.c too-many-strtab2.s
libtoomanystrtab_so_LDFLAGS = $(LDFLAGS_sharedlib)
+many_syms_main_SOURCES = many-syms-main.c
+many_syms_main_LDFLAGS = $(LDFLAGS_local)
+many_syms_main_LDADD = -lmany-syms $(AM_LDADD)
+many_syms_main_DEPENDENCIES = libmany-syms.so
+many_syms_main_CFLAGS = -pie
+libmany_syms_so_SOURCES = many-syms.c
+libmany_syms_so_LDFLAGS = $(LDFLAGS_sharedlib)
+
no_rpath_SOURCES = no-rpath.c
# no -fpic for no-rpath.o
no_rpath_CFLAGS =
@@ -159,3 +169,12 @@ contiguous_note_sections_CFLAGS = -pie
phdr_corruption_so_SOURCES = void.c phdr-corruption.ld
phdr_corruption_so_LDFLAGS = -nostdlib -shared -Wl,-T$(srcdir)/phdr-corruption.ld
phdr_corruption_so_CFLAGS =
+
+many-syms.c:
+ i=1; while [ $$i -le 2000 ]; do echo "void f$$i() {};"; i=$$(($$i + 1)); done > $@
+
+many-syms-main.c:
+ echo "int main() {" > $@
+ i=1; while [ $$i -le 2000 ]; do echo "void f$$i(); f$$i();"; i=$$(($$i + 1)); done >> $@
+ echo "}" >> $@
+
diff --git a/tests/add-debug-tag.sh b/tests/add-debug-tag.sh
index 4fbbfa4..37bf957 100755
--- a/tests/add-debug-tag.sh
+++ b/tests/add-debug-tag.sh
@@ -1,14 +1,14 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
READELF=${READELF:-readelf}
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp libsimple.so ${SCRATCH}/
+cp libsimple.so "${SCRATCH}"/
# check there is no DT_DEBUG tag
-debugTag=$($READELF -d ${SCRATCH}/libsimple.so)
+debugTag=$($READELF -d "${SCRATCH}/libsimple.so")
echo ".dynamic before: $debugTag"
if echo "$debugTag" | grep -q DEBUG; then
echo "failed --add-debug-tag test. Expected no line with (DEBUG), got: $debugTag"
@@ -16,10 +16,10 @@ if echo "$debugTag" | grep -q DEBUG; then
fi
# set DT_DEBUG
-../src/patchelf --add-debug-tag ${SCRATCH}/libsimple.so
+../src/patchelf --add-debug-tag "${SCRATCH}/libsimple.so"
# check there is DT_DEBUG tag
-debugTag=$($READELF -d ${SCRATCH}/libsimple.so)
+debugTag=$($READELF -d "${SCRATCH}/libsimple.so")
echo ".dynamic before: $debugTag"
if ! echo "$debugTag" | grep -q DEBUG; then
echo "failed --add-debug-tag test. Expected line with (DEBUG), got: $debugTag"
diff --git a/tests/add-rpath.sh b/tests/add-rpath.sh
index 3368708..1f9f7f9 100755
--- a/tests/add-rpath.sh
+++ b/tests/add-rpath.sh
@@ -1,24 +1,25 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-mkdir -p ${SCRATCH}/libsA
-mkdir -p ${SCRATCH}/libsB
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+mkdir -p "${SCRATCH}/libsA"
+mkdir -p "${SCRATCH}/libsB"
-cp main ${SCRATCH}/
-cp libfoo.so ${SCRATCH}/libsA/
-cp libbar.so ${SCRATCH}/libsB/
+cp main "${SCRATCH}"/
+cp libfoo.so "${SCRATCH}/libsA/"
+cp libbar.so "${SCRATCH}/libsB/"
-../src/patchelf --force-rpath --add-rpath $(pwd)/${SCRATCH}/libsA ${SCRATCH}/main
-../src/patchelf --force-rpath --add-rpath $(pwd)/${SCRATCH}/libsB ${SCRATCH}/main
+../src/patchelf --force-rpath --add-rpath "$(pwd)/${SCRATCH}/libsA" "${SCRATCH}/main"
+../src/patchelf --force-rpath --add-rpath "$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main"
if test "$(uname)" = FreeBSD; then
- export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB
+ LD_LIBRARY_PATH="$(pwd)/${SCRATCH}/libsB"
+ export LD_LIBRARY_PATH
fi
exitCode=0
-(cd ${SCRATCH} && ./main) || exitCode=$?
+(cd "${SCRATCH}" && ./main) || exitCode=$?
if test "$exitCode" != 46; then
echo "bad exit code!"
diff --git a/tests/args-from-file.sh b/tests/args-from-file.sh
index c0d1a54..107031e 100755
--- a/tests/args-from-file.sh
+++ b/tests/args-from-file.sh
@@ -1,16 +1,16 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp main ${SCRATCH}/
-RANDOM_PATH=$(pwd)/${SCRATCH}/$RANDOM
-echo -n ${RANDOM_PATH} >> ${SCRATCH}/add-rpath
+cp main "${SCRATCH}"/
+SOME_PATH=$(pwd)/${SCRATCH}/some-path
+printf "%s" "$SOME_PATH" >> "${SCRATCH}"/add-rpath
-! ../src/patchelf --print-rpath ${SCRATCH}/main | grep $RANDOM_PATH
-../src/patchelf --add-rpath @${SCRATCH}/add-rpath ${SCRATCH}/main
-../src/patchelf --print-rpath ${SCRATCH}/main | grep $RANDOM_PATH
+ ../src/patchelf --print-rpath "${SCRATCH}"/main | grep "$SOME_PATH" && exit 1
+../src/patchelf --add-rpath @"${SCRATCH}"/add-rpath "${SCRATCH}"/main
+../src/patchelf --print-rpath "${SCRATCH}"/main | grep "$SOME_PATH"
# should print error message and fail
-../src/patchelf --set-rpath @${SCRATCH}/does-not-exist ${SCRATCH}/main 2>&1 | grep "getting info about"
+../src/patchelf --set-rpath @"${SCRATCH}"/does-not-exist "${SCRATCH}"/main 2>&1 | grep "getting info about"
diff --git a/tests/big-dynstr.sh b/tests/big-dynstr.sh
index 19adad1..89c5355 100755
--- a/tests/big-dynstr.sh
+++ b/tests/big-dynstr.sh
@@ -1,25 +1,26 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-mkdir -p ${SCRATCH}/libsA
-mkdir -p ${SCRATCH}/libsB
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+mkdir -p "${SCRATCH}/libsA"
+mkdir -p "${SCRATCH}/libsB"
-cp big-dynstr ${SCRATCH}/
-cp libfoo.so ${SCRATCH}/libsA/
-cp libbar.so ${SCRATCH}/libsB/
+cp big-dynstr "${SCRATCH}/"
+cp libfoo.so "${SCRATCH}/libsA/"
+cp libbar.so "${SCRATCH}/libsB/"
-oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/big-dynstr)
+oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/big-dynstr")
if test -z "$oldRPath"; then oldRPath="/oops"; fi
-../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/big-dynstr
+../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/big-dynstr"
if test "$(uname)" = FreeBSD; then
- export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB
+ LD_LIBRARY_PATH="$(pwd)/${SCRATCH}/libsB"
+ export LD_LIBRARY_PATH
fi
exitCode=0
-cd ${SCRATCH} && ./big-dynstr || exitCode=$?
+cd "${SCRATCH}" && ./big-dynstr || exitCode=$?
if test "$exitCode" != 46; then
echo "bad exit code!"
diff --git a/tests/build-id.sh b/tests/build-id.sh
index dc44a7a..c9bf712 100755
--- a/tests/build-id.sh
+++ b/tests/build-id.sh
@@ -1,5 +1,5 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
READELF=${READELF:-readelf}
rm -rf "${SCRATCH}"
diff --git a/tests/change-abi.sh b/tests/change-abi.sh
index 26a151d..03c5f9b 100755
--- a/tests/change-abi.sh
+++ b/tests/change-abi.sh
@@ -1,44 +1,29 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp simple-pie ${SCRATCH}/simple-pie
+cp simple-pie "${SCRATCH}/simple-pie"
# Save the old OS ABI
-OLDABI=`../src/patchelf --print-os-abi ${SCRATCH}/simple-pie`
+OLDABI=$(../src/patchelf --print-os-abi "${SCRATCH}/simple-pie")
# Ensure it's not empty
test -n "$OLDABI"
# Change OS ABI and verify it has been changed
-{
- echo "System V"
- echo "HP-UX"
- echo "NetBSD"
- echo "Linux"
- echo "GNU Hurd"
- echo "Solaris"
- echo "AIX"
- echo "IRIX"
- echo "FreeBSD"
- echo "Tru64"
- echo "OpenBSD"
- echo "OpenVMS"
-} | {
- while IFS="\n" read ABI; do
- echo "Set OS ABI to '$ABI'..."
- ../src/patchelf --set-os-abi "$ABI" ${SCRATCH}/simple-pie
-
- echo "Check is OS ABI is '$ABI'..."
- NEWABI=`../src/patchelf --print-os-abi ${SCRATCH}/simple-pie`
- test "$NEWABI" = "$ABI"
- done
-}
+for ABI in "System V" "HP-UX" "NetBSD" "Linux" "GNU Hurd" "Solaris" "AIX" "IRIX" "FreeBSD" "Tru64" "OpenBSD" "OpenVMS"; do
+ echo "Set OS ABI to '$ABI'..."
+ ../src/patchelf --set-os-abi "$ABI" "${SCRATCH}/simple-pie"
+
+ echo "Check is OS ABI is '$ABI'..."
+ NEWABI=$(../src/patchelf --print-os-abi "${SCRATCH}/simple-pie")
+ test "$NEWABI" = "$ABI"
+done
# Reset OS ABI to the saved one
-../src/patchelf --set-os-abi "$OLDABI" ${SCRATCH}/simple-pie
+../src/patchelf --set-os-abi "$OLDABI" "${SCRATCH}/simple-pie"
# Verify we still can run the executable
-${SCRATCH}/simple-pie
+"${SCRATCH}/simple-pie"
diff --git a/tests/contiguous-note-sections.sh b/tests/contiguous-note-sections.sh
index 65abf0c..aa1f84a 100755
--- a/tests/contiguous-note-sections.sh
+++ b/tests/contiguous-note-sections.sh
@@ -1,6 +1,6 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
rm -rf "${SCRATCH}"
mkdir -p "${SCRATCH}"
@@ -10,4 +10,4 @@ cp contiguous-note-sections "${SCRATCH}/"
# Running --set-interpreter on this binary should not produce the following
# error:
# patchelf: cannot normalize PT_NOTE segment: non-contiguous SHT_NOTE sections
-../src/patchelf --set-interpreter ld-linux-x86-64.so.2 ${SCRATCH}/contiguous-note-sections
+../src/patchelf --set-interpreter ld-linux-x86-64.so.2 "${SCRATCH}/contiguous-note-sections"
diff --git a/tests/empty-note.sh b/tests/empty-note.sh
index c127d8c..57656fb 100755
--- a/tests/empty-note.sh
+++ b/tests/empty-note.sh
@@ -1,12 +1,12 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-cp $(dirname $(readlink -f $0))/empty-note ${SCRATCH}/
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+cp "$(dirname "$(readlink -f "$0")")/empty-note" "${SCRATCH}/"
# Running --set-interpreter on this binary should not produce the following
# error:
# patchelf: cannot normalize PT_NOTE segment: non-contiguous SHT_NOTE sections
-../src/patchelf --set-interpreter ld-linux-x86-64.so.2 ${SCRATCH}/empty-note
+../src/patchelf --set-interpreter ld-linux-x86-64.so.2 "${SCRATCH}/empty-note"
diff --git a/tests/endianness.sh b/tests/endianness.sh
index 4f84a08..fc2994b 100755
--- a/tests/endianness.sh
+++ b/tests/endianness.sh
@@ -1,23 +1,23 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
PATCHELF="../src/patchelf"
for arch in ppc64 ppc64le; do
- rm -rf ${SCRATCH}
- mkdir -p ${SCRATCH}
+ rm -rf "${SCRATCH}"
+ mkdir -p "${SCRATCH}"
- cp ${srcdir}/endianness/${arch}/main ${srcdir}/endianness/${arch}/libtest.so ${SCRATCH}/
+ cp "${srcdir}/endianness/${arch}/main" "${srcdir}/endianness/${arch}/libtest.so" "${SCRATCH}/"
rpath="${PWD}/${SCRATCH}"
# set rpath to scratch dir
- ${PATCHELF} --output ${SCRATCH}/main-rpath --set-rpath $rpath ${SCRATCH}/main
+ ${PATCHELF} --output "${SCRATCH}/main-rpath" --set-rpath "$rpath" "${SCRATCH}/main"
# attempt to shrink rpath, should not result in empty rpath
- ${PATCHELF} --output ${SCRATCH}/main-shrunk --shrink-rpath --debug ${SCRATCH}/main-rpath
+ ${PATCHELF} --output "${SCRATCH}/main-shrunk" --shrink-rpath --debug "${SCRATCH}/main-rpath"
# check whether rpath is still present
- if ! ${PATCHELF} --print-rpath ${SCRATCH}/main-shrunk | grep -q "$rpath"; then
+ if ! ${PATCHELF} --print-rpath "${SCRATCH}/main-shrunk" | grep -q "$rpath"; then
echo "rpath was removed for ${arch}"
exit 1
fi
diff --git a/tests/force-rpath.sh b/tests/force-rpath.sh
index c9b9a5d..a673f20 100755
--- a/tests/force-rpath.sh
+++ b/tests/force-rpath.sh
@@ -1,29 +1,33 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
OBJDUMP=${OBJDUMP:-objdump}
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
SCRATCHFILE=${SCRATCH}/libfoo.so
-cp libfoo.so $SCRATCHFILE
+cp libfoo.so "$SCRATCHFILE"
doit() {
- echo patchelf $*
- ../src/patchelf $* $SCRATCHFILE
+ set +x
+ ../src/patchelf "$@" "$SCRATCHFILE"
+ set -x
}
expect() {
- out=$(echo $($OBJDUMP -x $SCRATCHFILE | grep PATH))
+ out=$("$OBJDUMP" -x "$SCRATCHFILE" | grep PATH || true)
- if [ "$out" != "$*" ]; then
- echo "Expected '$*' but got '$out'"
- exit 1
- fi
+ for i in $out; do
+ if [ "$i" != "$1" ]; then
+ echo "Expected '$*' but got '$out'"
+ exit 1
+ fi
+ shift
+ done
}
doit --remove-rpath
-expect
+expect ""
doit --set-rpath foo
expect RUNPATH foo
doit --force-rpath --set-rpath foo
diff --git a/tests/grow-file.sh b/tests/grow-file.sh
index 4c405df..ec5957d 100755
--- a/tests/grow-file.sh
+++ b/tests/grow-file.sh
@@ -1,16 +1,16 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp simple-pie ${SCRATCH}/simple-pie
+cp simple-pie "${SCRATCH}/simple-pie"
# Add a 40MB rpath
-tr -cd 'a-z0-9' < /dev/urandom | dd count=40 bs=1000000 > ${SCRATCH}/foo.bin
+tr -cd 'a-z0-9' < /dev/urandom | dd count=40 bs=1000000 > "${SCRATCH}/foo.bin"
# Grow the file
-../src/patchelf --add-rpath @${SCRATCH}/foo.bin ${SCRATCH}/simple-pie
+../src/patchelf --add-rpath @"${SCRATCH}/foo.bin" "${SCRATCH}/simple-pie"
# Make sure we can still run it
-${SCRATCH}/simple-pie
+"${SCRATCH}/simple-pie"
diff --git a/tests/invalid-elf.sh b/tests/invalid-elf.sh
index 0f020e8..c124501 100755
--- a/tests/invalid-elf.sh
+++ b/tests/invalid-elf.sh
@@ -6,12 +6,12 @@
# by a signal. This works because the exit code of processes that were
# killed by a signal is 128 plus the signal number.
killed_by_signal() {
- [ $1 -ge 128 ]
+ [ "$1" -ge 128 ]
}
# The directory containing all our input files.
-TEST_DIR=$(dirname $(readlink -f $0))/invalid-elf
+TEST_DIR=$(dirname "$(readlink -f "$0")")/invalid-elf
# Each test case is listed here. The names should roughly indicate
# what makes the given ELF file invalid.
diff --git a/tests/no-gnu-hash.sh b/tests/no-gnu-hash.sh
index 0ce93f4..b12542e 100755
--- a/tests/no-gnu-hash.sh
+++ b/tests/no-gnu-hash.sh
@@ -1,14 +1,14 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
STRIP=${STRIP:-strip}
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp simple ${SCRATCH}/
+cp simple "${SCRATCH}/"
-${STRIP} --remove-section=.gnu.hash ${SCRATCH}/simple
+${STRIP} --remove-section=.gnu.hash "${SCRATCH}/simple"
# Check if patchelf handles binaries with GNU_HASH in dynamic section but
# without .gnu.hash section
-../src/patchelf --set-interpreter /oops ${SCRATCH}/simple
+../src/patchelf --set-interpreter /oops "${SCRATCH}/simple"
diff --git a/tests/no-rpath-pie-powerpc.sh b/tests/no-rpath-pie-powerpc.sh
index b469f9b..963797c 100755
--- a/tests/no-rpath-pie-powerpc.sh
+++ b/tests/no-rpath-pie-powerpc.sh
@@ -30,7 +30,7 @@ fi
# Tests for powerpc PIE endianness regressions
readelfData=$(${READELF} -l ${SCRATCH}/no-rpath 2>&1)
-if [ $(echo "$readelfData" | grep --count "PHDR") != 1 ]; then
+if [ $(echo "$readelfData" | grep "PHDR" | wc -l) != 1 ]; then
# Triggered if PHDR errors appear on stderr
echo "Unexpected number of occurences of PHDR in readelf results"
exit 1
diff --git a/tests/no-rpath-prebuild.sh b/tests/no-rpath-prebuild.sh
index c58cf8e..143c55c 100755
--- a/tests/no-rpath-prebuild.sh
+++ b/tests/no-rpath-prebuild.sh
@@ -4,35 +4,35 @@ ARCH="$1"
PAGESIZE=4096
if [ -z "$ARCH" ]; then
- ARCH=$(basename $0 .sh | sed -e 's/^no-rpath-//')
+ ARCH=$(basename "$0" .sh | sed -e 's/^no-rpath-//')
fi
SCRATCH=scratch/no-rpath-$ARCH
-if [ -z "$ARCH" ] || [ $ARCH = prebuild ] ; then
+if [ -z "$ARCH" ] || [ "$ARCH" = prebuild ] ; then
echo "Architecture required"
exit 1
fi
no_rpath_bin="${srcdir}/no-rpath-prebuild/no-rpath-$ARCH"
-if [ ! -f $no_rpath_bin ]; then
+if [ ! -f "$no_rpath_bin" ]; then
echo "no 'no-rpath' binary for '$ARCH' in '${srcdir}/no-rpath-prebuild'"
exit 1
fi
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp $no_rpath_bin ${SCRATCH}/no-rpath
+cp "$no_rpath_bin" "${SCRATCH}"/no-rpath
-oldRPath=$(../src/patchelf --page-size ${PAGESIZE} --print-rpath ${SCRATCH}/no-rpath)
+oldRPath=$(../src/patchelf --page-size "${PAGESIZE}" --print-rpath "${SCRATCH}/no-rpath")
if test -n "$oldRPath"; then exit 1; fi
-../src/patchelf --page-size ${PAGESIZE} \
- --set-interpreter "$(../src/patchelf --page-size ${PAGESIZE} --print-interpreter ../src/patchelf)" \
- --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx ${SCRATCH}/no-rpath
+../src/patchelf --page-size "${PAGESIZE}" \
+ --set-interpreter "$(../src/patchelf --page-size "${PAGESIZE}" --print-interpreter ../src/patchelf)" \
+ --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx "${SCRATCH}"/no-rpath
-newRPath=$(../src/patchelf --page-size ${PAGESIZE} --print-rpath ${SCRATCH}/no-rpath)
+newRPath=$(../src/patchelf --page-size "${PAGESIZE}" --print-rpath "${SCRATCH}/no-rpath")
if ! echo "$newRPath" | grep -q '/foo:/bar'; then
echo "incomplete RPATH"
exit 1
diff --git a/tests/no-rpath.sh b/tests/no-rpath.sh
index 3efa7f1..7fe0372 100755
--- a/tests/no-rpath.sh
+++ b/tests/no-rpath.sh
@@ -1,21 +1,21 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp no-rpath ${SCRATCH}/
+cp no-rpath "${SCRATCH}/"
-oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/no-rpath)
+oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/no-rpath")
if test -n "$oldRPath"; then exit 1; fi
../src/patchelf \
--set-interpreter "$(../src/patchelf --print-interpreter ../src/patchelf)" \
- --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx ${SCRATCH}/no-rpath
+ --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx "${SCRATCH}/no-rpath"
-newRPath=$(../src/patchelf --print-rpath ${SCRATCH}/no-rpath)
+newRPath=$(../src/patchelf --print-rpath "${SCRATCH}/no-rpath")
if ! echo "$newRPath" | grep -q '/foo:/bar'; then
echo "incomplete RPATH"
exit 1
fi
-cd ${SCRATCH} && ./no-rpath
+cd "${SCRATCH}" && ./no-rpath
diff --git a/tests/output-flag.sh b/tests/output-flag.sh
index 5da26b5..26e8782 100755
--- a/tests/output-flag.sh
+++ b/tests/output-flag.sh
@@ -1,28 +1,29 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-mkdir -p ${SCRATCH}/libsA
-mkdir -p ${SCRATCH}/libsB
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+mkdir -p "${SCRATCH}/libsA"
+mkdir -p "${SCRATCH}/libsB"
-cp main ${SCRATCH}/
-cp libfoo.so ${SCRATCH}/libsA/
-cp libbar.so ${SCRATCH}/libsB/
+cp main "${SCRATCH}"/
+cp libfoo.so "${SCRATCH}/libsA/"
+cp libbar.so "${SCRATCH}/libsB/"
-oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main)
+oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/main")
if test -z "$oldRPath"; then oldRPath="/oops"; fi
-../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main --output ${SCRATCH}/main2
+../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main" --output "${SCRATCH}/main2"
# make sure it copies even when there is nothing to do (because rpath is already set)
-../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main2 --output ${SCRATCH}/main3
+../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main2" --output "${SCRATCH}/main3"
if test "$(uname)" = FreeBSD; then
- export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB
+ LD_LIBRARY_PATH="$(pwd)/${SCRATCH}/libsB"
+ export LD_LIBRARY_PATH
fi
exitCode=0
-(cd ${SCRATCH} && ./main2) || exitCode=$?
+(cd "${SCRATCH}" && ./main2) || exitCode=$?
if test "$exitCode" != 46; then
echo "bad exit code!"
@@ -30,7 +31,7 @@ if test "$exitCode" != 46; then
fi
exitCode=0
-(cd ${SCRATCH} && ./main3) || exitCode=$?
+(cd "${SCRATCH}" && ./main3) || exitCode=$?
if test "$exitCode" != 46; then
echo "bad exit code!"
diff --git a/tests/phdr-corruption.sh b/tests/phdr-corruption.sh
index 1e62101..4f6e901 100755
--- a/tests/phdr-corruption.sh
+++ b/tests/phdr-corruption.sh
@@ -2,7 +2,7 @@
PATCHELF="../src/patchelf"
SONAME="phdr-corruption.so"
-SCRATCH="scratch/$(basename $0 .sh)"
+SCRATCH="scratch/$(basename "$0" .sh)"
SCRATCH_SO="${SCRATCH}/${SONAME}"
READELF=${READELF:-readelf}
@@ -15,7 +15,7 @@ cp "${SONAME}" "${SCRATCH}"
# Check for PT_PHDR entry VirtAddr corruption
readelfData=$(${READELF} -l "${SCRATCH_SO}" 2>&1)
-if [ $(echo "$readelfData" | grep --count "PHDR") != 1 ]; then
+if [ "$(echo "$readelfData" | grep "PHDR" | wc -l)" != 1 ]; then
# Triggered if PHDR errors appear on stderr
echo "ERROR: Unexpected number of occurences of PHDR in readelf results!"
exit 1
diff --git a/tests/plain-needed.sh b/tests/plain-needed.sh
index 8967303..e44293b 100755
--- a/tests/plain-needed.sh
+++ b/tests/plain-needed.sh
@@ -1,14 +1,14 @@
#! /bin/sh
set -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
MAIN_ELF="${SCRATCH}/main"
PATCHELF="../src/patchelf"
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-cp main ${SCRATCH}/
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+cp main "${SCRATCH}"/
echo "Confirming main requires libfoo"
${PATCHELF} --print-needed "${MAIN_ELF}" | grep -q libfoo.so
diff --git a/tests/rename-dynamic-symbols.sh b/tests/rename-dynamic-symbols.sh
new file mode 100755
index 0000000..6fabb33
--- /dev/null
+++ b/tests/rename-dynamic-symbols.sh
@@ -0,0 +1,84 @@
+#!/bin/sh -e
+SCRATCH=scratch/$(basename $0 .sh)
+PATCHELF=$(readlink -f "../src/patchelf")
+
+rm -rf ${SCRATCH}
+mkdir -p ${SCRATCH}
+
+full_main_name="${PWD}/many-syms-main"
+full_lib_name="${PWD}/libmany-syms.so"
+chmod -w $full_lib_name $full_main_name
+
+suffix="_special_suffix"
+
+cd ${SCRATCH}
+
+###############################################################################
+# Test that all symbols in the dynamic symbol table will have the expected
+# names after renaming.
+# Also test that if we rename all symbols back, the symbols are as expected
+###############################################################################
+
+list_symbols() {
+ nm -D $@ | awk '{ print $NF }' | sed '/^ *$/d'
+}
+
+list_symbols $full_lib_name | cut -d@ -f1 | sort -u | awk "{printf \"%s %s${suffix}\n\",\$1,\$1}" > map
+list_symbols $full_lib_name | cut -d@ -f1 | sort -u | awk "{printf \"%s${suffix} %s\n\",\$1,\$1}" > rmap
+
+${PATCHELF} --rename-dynamic-symbols map --output libmapped.so $full_lib_name
+${PATCHELF} --rename-dynamic-symbols rmap --output libreversed.so libmapped.so
+
+list_symbols $full_lib_name | sort > orig_syms
+list_symbols libmapped.so | sort > map_syms
+list_symbols libreversed.so | sort > rev_syms
+
+diff orig_syms rev_syms > diff_orig_syms_rev_syms || exit 1
+
+# Renamed symbols that match version numbers will be printed with version instead of them being ommited
+# CXXABI10 is printed as CXXABI10
+# but CXXABI10_renamed is printed as CXXABI10_renamed@@CXXABI10
+# awk is used to remove these cases so that we can match the "mapped" symbols to original symbols
+sed "s/${suffix}//" map_syms | awk -F @ '{ if ($1 == $2 || $1 == $3) { print $1; } else { print $0; }}' | sort > map_syms_r
+diff orig_syms map_syms_r > diff_orig_syms_map_syms_r || exit 1
+
+###############################################################################
+# Check the relocation tables after renaming
+###############################################################################
+
+print_relocation_table() {
+ readelf -W -r $1 | awk '{ printf "%s\n",$5 }' | cut -f1 -d@
+}
+
+print_relocation_table $full_lib_name > orig_rel
+print_relocation_table libmapped.so > map_rel
+print_relocation_table libreversed.so > rev_rel
+
+diff orig_rel rev_rel > diff_orig_rel_rev_rel || exit 1
+sed "s/${suffix}//" map_rel > map_rel_r
+diff orig_rel map_rel_r > diff_orig_rel_map_rel_r || exit 1
+
+###############################################################################
+# Test that the hash table is correctly updated.
+# For this to work, we need to rename symbols and actually use the library
+# Here we:
+# 1. Create a map from all symbols in libstdc++.so as "sym sym_special_suffix"
+# 2. Copy Patchelf and all of its transitive library dependencies into a new directory
+# 3. Rename symbols in Patchelf and all dependencies according to the map
+# 4. Run patchelf with the modified dependencies
+###############################################################################
+
+echo "# Create the map"
+list_symbols --defined-only $full_lib_name | cut -d@ -f1 | sort -u | awk "{printf \"%s %s${suffix}\n\",\$1,\$1}" > map
+
+echo "# Copy all dependencies"
+mkdir env
+cd env
+cp $full_lib_name $full_main_name .
+
+echo "# Apply renaming"
+chmod +w *
+${PATCHELF} --rename-dynamic-symbols ../map *
+
+echo "# Run the patched tool and libraries"
+env LD_BIND_NOW=1 LD_LIBRARY_PATH=${PWD} ./many-syms-main
diff --git a/tests/replace-add-needed.sh b/tests/replace-add-needed.sh
index e2cb255..701cb95 100755
--- a/tests/replace-add-needed.sh
+++ b/tests/replace-add-needed.sh
@@ -1,15 +1,15 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
PATCHELF=$(readlink -f "../src/patchelf")
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp simple ${SCRATCH}/
-cp libfoo.so ${SCRATCH}/
-cp libbar.so ${SCRATCH}/
+cp simple "${SCRATCH}"/
+cp libfoo.so "${SCRATCH}"/
+cp libbar.so "${SCRATCH}"/
-cd ${SCRATCH}
+cd "${SCRATCH}"
libcldd=$(ldd ./simple | awk '/ => / { print $3 }' | grep -E "(libc(-[0-9.]*)*.so|ld-musl)")
@@ -22,11 +22,11 @@ ${PATCHELF} --add-needed libbar.so ./simple
# Make the NEEDED in libfoo the same as simple
# This is a current "bug" in musl
# https://www.openwall.com/lists/musl/2021/12/21/1
-${PATCHELF} --replace-needed libbar.so $(readlink -f ./libbar.so) ./libfoo.so
+${PATCHELF} --replace-needed libbar.so "$(readlink -f ./libbar.so)" ./libfoo.so
-${PATCHELF} --replace-needed libc.so.6 ${libcldd} \
- --replace-needed libbar.so $(readlink -f ./libbar.so) \
- --add-needed $(readlink -f ./libfoo.so) \
+${PATCHELF} --replace-needed libc.so.6 "${libcldd}" \
+ --replace-needed libbar.so "$(readlink -f ./libbar.so)" \
+ --add-needed "$(readlink -f ./libfoo.so)" \
./simple
exitCode=0
@@ -35,4 +35,4 @@ exitCode=0
if test "$exitCode" != 0; then
ldd ./simple
exit 1
-fi \ No newline at end of file
+fi
diff --git a/tests/replace-needed.sh b/tests/replace-needed.sh
index 0a5581c..6099d93 100755
--- a/tests/replace-needed.sh
+++ b/tests/replace-needed.sh
@@ -1,21 +1,20 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-oldNeeded=$(../src/patchelf --print-needed big-dynstr)
oldLibc=$(../src/patchelf --print-needed big-dynstr | grep -v 'foo\.so')
-../src/patchelf --output ${SCRATCH}/big-needed --replace-needed ${oldLibc} long_long_very_long_libc.so.6 --replace-needed libfoo.so lf.so big-dynstr
+../src/patchelf --output "${SCRATCH}/big-needed" --replace-needed "${oldLibc}" long_long_very_long_libc.so.6 --replace-needed libfoo.so lf.so big-dynstr
-if [ -z "$(../src/patchelf --print-needed ${SCRATCH}/big-needed | grep -Fx "long_long_very_long_libc.so.6")" ]; then
+if ! ../src/patchelf --print-needed "${SCRATCH}/big-needed" | grep -Fxq "long_long_very_long_libc.so.6"; then
echo "library long_long_very_long_libc.so.6 not found as NEEDED"
- ../src/patchelf --print-needed ${SCRATCH}/big-needed
+ ../src/patchelf --print-needed "${SCRATCH}/big-needed"
exit 1
fi
-if [ -z "$(../src/patchelf --print-needed ${SCRATCH}/big-needed | grep -Fx "lf.so")" ]; then
+if ! ../src/patchelf --print-needed "${SCRATCH}/big-needed" | grep -Fxq "lf.so"; then
echo "library lf.so not found as NEEDED"
- ../src/patchelf --print-needed ${SCRATCH}/big-needed
+ ../src/patchelf --print-needed "${SCRATCH}/big-needed"
exit 1
fi
diff --git a/tests/set-empty-rpath.sh b/tests/set-empty-rpath.sh
index de846a2..b640822 100755
--- a/tests/set-empty-rpath.sh
+++ b/tests/set-empty-rpath.sh
@@ -1,11 +1,11 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp simple ${SCRATCH}/simple
+cp simple "${SCRATCH}"/simple
-../src/patchelf --force-rpath --set-rpath "" ${SCRATCH}/simple
+../src/patchelf --force-rpath --set-rpath "" "${SCRATCH}/simple"
-${SCRATCH}/simple
+"${SCRATCH}"/simple
diff --git a/tests/set-interpreter-long.sh b/tests/set-interpreter-long.sh
index 058ccd2..f1e0d2f 100755
--- a/tests/set-interpreter-long.sh
+++ b/tests/set-interpreter-long.sh
@@ -1,5 +1,5 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
./simple
@@ -11,24 +11,24 @@ if test "$(uname)" = Linux; then
"$oldInterpreter" ./simple
fi
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-newInterpreter=$(pwd)/${SCRATCH}/iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
-cp simple ${SCRATCH}/
-../src/patchelf --set-interpreter "$newInterpreter" ${SCRATCH}/simple
+newInterpreter="$(pwd)/${SCRATCH}/iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
+cp simple "${SCRATCH}/"
+../src/patchelf --set-interpreter "$newInterpreter" "${SCRATCH}/simple"
echo "running with missing interpreter..."
-if ${SCRATCH}/simple; then
+if "${SCRATCH}"/simple; then
echo "simple works, but it shouldn't"
exit 1
fi
echo "running with new interpreter..."
ln -s "$oldInterpreter" "$newInterpreter"
-${SCRATCH}/simple
+"${SCRATCH}"/simple
if test "$(uname)" = Linux; then
echo "running with explicit interpreter..."
- "$oldInterpreter" ${SCRATCH}/simple
+ "$oldInterpreter" "${SCRATCH}/simple"
fi
diff --git a/tests/set-interpreter-short.sh b/tests/set-interpreter-short.sh
index 2c9f4eb..69746da 100755
--- a/tests/set-interpreter-short.sh
+++ b/tests/set-interpreter-short.sh
@@ -1,19 +1,19 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
./simple
oldInterpreter=$(../src/patchelf --print-interpreter ./simple)
echo "current interpreter is $oldInterpreter"
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp simple ${SCRATCH}/
-../src/patchelf --set-interpreter /oops ${SCRATCH}/simple
+cp simple "${SCRATCH}"/
+../src/patchelf --set-interpreter /oops "${SCRATCH}/simple"
echo "running with missing interpreter..."
-if ${SCRATCH}/simple; then
+if "${SCRATCH}/simple"; then
echo "simple works, but it shouldn't"
exit 1
fi
diff --git a/tests/set-rpath-library.sh b/tests/set-rpath-library.sh
index a5c8ca7..55661a1 100755
--- a/tests/set-rpath-library.sh
+++ b/tests/set-rpath-library.sh
@@ -1,40 +1,40 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
if test "$(uname)" = FreeBSD; then
echo "skipping on FreeBSD"
exit 0
fi
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-mkdir -p ${SCRATCH}/libsA
-mkdir -p ${SCRATCH}/libsB
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+mkdir -p "${SCRATCH}/libsA"
+mkdir -p "${SCRATCH}/libsB"
-cp main-scoped ${SCRATCH}/
-cp libfoo-scoped.so ${SCRATCH}/libsA/
-cp libbar-scoped.so ${SCRATCH}/libsB/
+cp main-scoped "${SCRATCH}/"
+cp libfoo-scoped.so "${SCRATCH}/libsA/"
+cp libbar-scoped.so "${SCRATCH}/libsB/"
-oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main-scoped)
+oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}"/main-scoped)
if test -z "$oldRPath"; then oldRPath="/oops"; fi
-../src/patchelf --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main-scoped
+../src/patchelf --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main-scoped"
# "main" contains libbar in its RUNPATH, but that's ignored when
# resolving libfoo. So libfoo won't find libbar and this will fail.
exitCode=0
-(cd ${SCRATCH} && ./main-scoped) || exitCode=$?
+(cd "${SCRATCH}" && ./main-scoped) || exitCode=$?
if test "$exitCode" = 46; then
echo "expected failure"
fi
# So set an RUNPATH on libfoo as well.
-oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/libsA/libfoo-scoped.so)
+oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/libsA/libfoo-scoped.so")
if test -z "$oldRPath"; then oldRPath="/oops"; fi
-../src/patchelf --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/libsA/libfoo-scoped.so
+../src/patchelf --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/libsA/libfoo-scoped.so"
exitCode=0
-(cd ${SCRATCH} && ./main-scoped) || exitCode=$?
+(cd "${SCRATCH}" && ./main-scoped) || exitCode=$?
if test "$exitCode" != 46; then
echo "bad exit code!"
@@ -42,15 +42,15 @@ if test "$exitCode" != 46; then
fi
# Remove the libbar PATH from main using --shrink-rpath.
-../src/patchelf --shrink-rpath ${SCRATCH}/main-scoped
-if ../src/patchelf --print-rpath ${SCRATCH}/main-scoped | grep /libsB; then
+../src/patchelf --shrink-rpath "${SCRATCH}/main-scoped"
+if ../src/patchelf --print-rpath "${SCRATCH}/main-scoped" | grep /libsB; then
echo "shrink failed"
exit 1
fi
# And it should still run.
exitCode=0
-(cd ${SCRATCH} && ./main-scoped) || exitCode=$?
+(cd "${SCRATCH}" && ./main-scoped) || exitCode=$?
if test "$exitCode" != 46; then
echo "bad exit code!"
diff --git a/tests/set-rpath-rel-map.sh b/tests/set-rpath-rel-map.sh
index 48bc361..2f890f2 100755
--- a/tests/set-rpath-rel-map.sh
+++ b/tests/set-rpath-rel-map.sh
@@ -1,6 +1,6 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
OBJDUMP=${OBJDUMP:-objdump}
OBJCOPY=${OBJCOPY:-objcopy}
@@ -9,29 +9,30 @@ if ! $OBJDUMP -p main | grep -q MIPS_RLD_MAP_REL; then
exit 0
fi
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-mkdir -p ${SCRATCH}/libsA
-mkdir -p ${SCRATCH}/libsB
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+mkdir -p "${SCRATCH}/libsA"
+mkdir -p "${SCRATCH}/libsB"
-cp main ${SCRATCH}/
-cp libfoo.so ${SCRATCH}/libsA/
-cp libbar.so ${SCRATCH}/libsB/
+cp main "${SCRATCH}/"
+cp libfoo.so "${SCRATCH}/libsA/"
+cp libbar.so "${SCRATCH}/libsB/"
# break the main executable by removing .rld_map section
-${OBJCOPY} --remove-section .rld_map ${SCRATCH}/main
+${OBJCOPY} --remove-section .rld_map "${SCRATCH}/main"
-oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main)
+oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/main")
if test -z "$oldRPath"; then oldRPath="/oops"; fi
-../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main
+../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main"
if test "$(uname)" = FreeBSD; then
- export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB
+ LD_LIBRARY_PATH=$(pwd)/"${SCRATCH}"/libsB
+ export LD_LIBRARY_PATH
fi
exitCode=0
-(cd ${SCRATCH} && ./main) || exitCode=$?
+(cd "${SCRATCH}" && ./main) || exitCode=$?
if test "$exitCode" != 46; then
echo "bad exit code!"
diff --git a/tests/set-rpath.sh b/tests/set-rpath.sh
index 90452f9..565582a 100755
--- a/tests/set-rpath.sh
+++ b/tests/set-rpath.sh
@@ -1,25 +1,26 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-mkdir -p ${SCRATCH}/libsA
-mkdir -p ${SCRATCH}/libsB
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+mkdir -p "${SCRATCH}"/libsA
+mkdir -p "${SCRATCH}"/libsB
-cp main ${SCRATCH}/
-cp libfoo.so ${SCRATCH}/libsA/
-cp libbar.so ${SCRATCH}/libsB/
+cp main "${SCRATCH}"/
+cp libfoo.so "${SCRATCH}/libsA/"
+cp libbar.so "${SCRATCH}/libsB/"
-oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main)
+oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/main")
if test -z "$oldRPath"; then oldRPath="/oops"; fi
-../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main
+../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main"
if test "$(uname)" = FreeBSD; then
- export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB
+ LD_LIBRARY_PATH="$(pwd)/${SCRATCH}/libsB"
+ export LD_LIBRARY_PATH
fi
exitCode=0
-(cd ${SCRATCH} && ./main) || exitCode=$?
+(cd "${SCRATCH}" && ./main) || exitCode=$?
if test "$exitCode" != 46; then
echo "bad exit code!"
diff --git a/tests/shrink-rpath-with-allowed-prefixes.sh b/tests/shrink-rpath-with-allowed-prefixes.sh
index db24da2..aca8d06 100755
--- a/tests/shrink-rpath-with-allowed-prefixes.sh
+++ b/tests/shrink-rpath-with-allowed-prefixes.sh
@@ -1,47 +1,47 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-mkdir -p ${SCRATCH}/libsA
-mkdir -p ${SCRATCH}/libsB
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+mkdir -p "${SCRATCH}/libsA"
+mkdir -p "${SCRATCH}/libsB"
-cp main ${SCRATCH}/
-cp libfoo.so libbar.so ${SCRATCH}/libsA/
-cp libfoo.so libbar.so ${SCRATCH}/libsB/
+cp main "${SCRATCH}"/
+cp libfoo.so libbar.so "${SCRATCH}/libsA/"
+cp libfoo.so libbar.so "${SCRATCH}/libsB/"
-oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main)
+oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/main")
if test -z "$oldRPath"; then oldRPath="/oops"; fi
pathA="$(pwd)/${SCRATCH}/libsA"
pathB="$(pwd)/${SCRATCH}/libsB"
-../src/patchelf --force-rpath --set-rpath $oldRPath:$pathA:$pathB ${SCRATCH}/main
+../src/patchelf --force-rpath --set-rpath "$oldRPath:$pathA:$pathB" "${SCRATCH}/main"
-cp ${SCRATCH}/main ${SCRATCH}/mainA
-cp ${SCRATCH}/main ${SCRATCH}/mainB
+cp "${SCRATCH}"/main "${SCRATCH}/mainA"
+cp "${SCRATCH}"/main "${SCRATCH}/mainB"
-../src/patchelf --shrink-rpath ${SCRATCH}/main
-../src/patchelf --shrink-rpath --allowed-rpath-prefixes $oldRPath:$pathA ${SCRATCH}/mainA
-../src/patchelf --shrink-rpath --allowed-rpath-prefixes $oldRPath:$pathB ${SCRATCH}/mainB
+../src/patchelf --shrink-rpath "${SCRATCH}/main"
+../src/patchelf --shrink-rpath --allowed-rpath-prefixes "$oldRPath:$pathA" "${SCRATCH}/mainA"
+../src/patchelf --shrink-rpath --allowed-rpath-prefixes "$oldRPath:$pathB" "${SCRATCH}/mainB"
check() {
exe=$1
mustContain=$2
mustNotContain=$3
- rpath=$(../src/patchelf --print-rpath $exe)
+ rpath=$(../src/patchelf --print-rpath "$exe")
echo "RPATH of $exe after: $rpath"
- if ! echo "$rpath" | grep -q $mustContain; then
+ if ! echo "$rpath" | grep -q "$mustContain"; then
echo "RPATH didn't contain '$mustContain' when it should have"
exit 1
fi
- if echo "$rpath" | grep -q $mustNotContain; then
+ if echo "$rpath" | grep -q "$mustNotContain"; then
echo "RPATH contained '$mustNotContain' when it shouldn't have"
exit 1
fi
}
-check ${SCRATCH}/main $pathA $pathB
-check ${SCRATCH}/mainA $pathA $pathB
-check ${SCRATCH}/mainB $pathB $pathA
+check "${SCRATCH}/main" "$pathA" "$pathB"
+check "${SCRATCH}/mainA" "$pathA" "$pathB"
+check "${SCRATCH}/mainB" "$pathB" "$pathA"
diff --git a/tests/shrink-rpath.sh b/tests/shrink-rpath.sh
index 3adc846..6944a44 100755
--- a/tests/shrink-rpath.sh
+++ b/tests/shrink-rpath.sh
@@ -1,5 +1,5 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
rpath=$(../src/patchelf --print-rpath ./libbar.so)
echo "RPATH before: $rpath"
@@ -8,22 +8,22 @@ if ! echo "$rpath" | grep -q /no-such-path; then
exit 1
fi
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
-cp libbar.so ${SCRATCH}/
-../src/patchelf --shrink-rpath ${SCRATCH}/libbar.so
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
+cp libbar.so "${SCRATCH}"/
+../src/patchelf --shrink-rpath "${SCRATCH}/libbar.so"
-rpath=$(../src/patchelf --print-rpath ${SCRATCH}/libbar.so)
+rpath=$(../src/patchelf --print-rpath "${SCRATCH}/libbar.so")
echo "RPATH after: $rpath"
if echo "$rpath" | grep -q /no-such-path; then
echo "RPATH not shrunk"
exit 1
fi
-cp libfoo.so ${SCRATCH}/
+cp libfoo.so "${SCRATCH}/"
exitCode=0
-cd ${SCRATCH} && LD_LIBRARY_PATH=. ../../main || exitCode=$?
+cd "${SCRATCH}" && LD_LIBRARY_PATH=. ../../main || exitCode=$?
if test "$exitCode" != 46; then
echo "bad exit code!"
diff --git a/tests/soname.sh b/tests/soname.sh
index 4a8fb96..683e481 100755
--- a/tests/soname.sh
+++ b/tests/soname.sh
@@ -1,29 +1,29 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp libsimple.so ${SCRATCH}/
+cp libsimple.so "${SCRATCH}/"
# set an initial DT_SONAME entry
-../src/patchelf --set-soname libsimple.so.1.0 ${SCRATCH}/libsimple.so
-newSoname=$(../src/patchelf --print-soname ${SCRATCH}/libsimple.so)
+../src/patchelf --set-soname libsimple.so.1.0 "${SCRATCH}/libsimple.so"
+newSoname=$(../src/patchelf --print-soname "${SCRATCH}/libsimple.so")
if test "$newSoname" != libsimple.so.1.0; then
echo "failed --set-soname test. Expected newSoname: libsimple.so.1.0, got: $newSoname"
exit 1
fi
# print DT_SONAME
-soname=$(../src/patchelf --print-soname ${SCRATCH}/libsimple.so)
+soname=$(../src/patchelf --print-soname "${SCRATCH}/libsimple.so")
if test "$soname" != libsimple.so.1.0; then
echo "failed --print-soname test. Expected soname: libsimple.so.1.0, got: $soname"
exit 1
fi
# replace DT_SONAME entry
-../src/patchelf --set-soname libsimple.so.1.1 ${SCRATCH}/libsimple.so
-newSoname=$(../src/patchelf --print-soname ${SCRATCH}/libsimple.so)
+../src/patchelf --set-soname libsimple.so.1.1 "${SCRATCH}/libsimple.so"
+newSoname=$(../src/patchelf --print-soname "${SCRATCH}/libsimple.so")
if test "$newSoname" != libsimple.so.1.1; then
echo "failed --set-soname test. Expected newSoname: libsimple.so.1.1, got: $newSoname"
exit 1
diff --git a/tests/too-many-strtab.sh b/tests/too-many-strtab.sh
index 3ef158f..96006a4 100755
--- a/tests/too-many-strtab.sh
+++ b/tests/too-many-strtab.sh
@@ -1,19 +1,19 @@
#! /bin/sh -e
-SCRATCH=scratch/$(basename $0 .sh)
+SCRATCH=scratch/$(basename "$0" .sh)
-rm -rf ${SCRATCH}
-mkdir -p ${SCRATCH}
+rm -rf "${SCRATCH}"
+mkdir -p "${SCRATCH}"
-cp libtoomanystrtab.so ${SCRATCH}/
+cp libtoomanystrtab.so "${SCRATCH}"/
# Set a RUNPATH on the library
-../src/patchelf --set-rpath '$ORIGIN' ${SCRATCH}/libtoomanystrtab.so
+../src/patchelf --set-rpath "\$ORIGIN" "${SCRATCH}/libtoomanystrtab.so"
# Check that patchelf is able to patch it again without crashing. Previously,
# it will wrongly identify the lib as a static object because there was no
# .dynamic section
exitCode=0
-(../src/patchelf --set-rpath '$ORIGIN' ${SCRATCH}/libtoomanystrtab.so) || exitCode=$?
+(../src/patchelf --set-rpath "\$ORIGIN" "${SCRATCH}/libtoomanystrtab.so") || exitCode=$?
if test "$exitCode" != 0; then
echo "bad exit code!"
exit 1