summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Thalheim <Mic92@users.noreply.github.com>2022-09-28 11:44:58 +0200
committerGitHub <noreply@github.com>2022-09-28 11:44:58 +0200
commit683e41d340aea90822bb5e202eeac15688234a51 (patch)
tree30de9dda2ee652e40c34eb1c4ead7587fe57db17
parent7281d999e95d6730d1d08fc7517c15e27ddfb65f (diff)
parent5faf4534366826350654db8d65cba81e50387519 (diff)
downloadpatchelf-683e41d340aea90822bb5e202eeac15688234a51.tar.gz
Merge pull request #381 from crystax/master
Add --print-os-abi and --set-os-abi options
-rw-r--r--patchelf.110
-rw-r--r--src/patchelf.cc95
-rw-r--r--src/patchelf.h4
-rw-r--r--tests/Makefile.am1
-rwxr-xr-xtests/change-abi.sh44
5 files changed, 154 insertions, 0 deletions
diff --git a/patchelf.1 b/patchelf.1
index fdf16fd..7c8f402 100644
--- a/patchelf.1
+++ b/patchelf.1
@@ -36,6 +36,16 @@ INTERPRETER.
.IP --print-interpreter
Prints the ELF interpreter of the executable.
+.IP --print-os-abi
+Prints the OS ABI of the executable (EI_OSABI field of an ELF file).
+
+.IP "--set-os-abi ABI"
+Changes the OS ABI of the executable (EI_OSABI field of an ELF file).
+The ABI parameter is pretty flexible. For example, you can specify it
+as a "Linux", "linux", or even "lInUx" - all those names will set EI_OSABI
+field of the ELF header to the value "3", which corresponds to Linux OS ABI.
+The same applies to other ABI names - System V, FreeBSD, Solaris, etc.
+
.IP --print-soname
Prints DT_SONAME entry of .dynamic section.
Raises an error if DT_SONAME doesn't exist.
diff --git a/src/patchelf.cc b/src/patchelf.cc
index 49accae..505c980 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -86,6 +86,20 @@ static bool hasAllowedPrefix(const std::string & s, const std::vector<std::strin
return std::any_of(allowedPrefixes.begin(), allowedPrefixes.end(), [&](const std::string & i) { return !s.compare(0, i.size(), i); });
}
+static std::string trim(std::string s)
+{
+ s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); }));
+ s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end());
+
+ return s;
+}
+
+static std::string downcase(std::string s)
+{
+ std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::tolower(c); });
+ return s;
+}
+
/* !!! G++ creates broken code if this function is inlined, don't know
why... */
template<ElfFileParams>
@@ -1105,6 +1119,68 @@ std::string ElfFile<ElfFileParamNames>::getInterpreter()
}
template<ElfFileParams>
+void ElfFile<ElfFileParamNames>::modifyOsAbi(osAbiMode op, const std::string & newOsAbi)
+{
+ unsigned char abi = hdr()->e_ident[EI_OSABI];
+
+ if (op == printOsAbi) {
+ switch (abi) {
+ case 0: printf("System V\n"); break;
+ case 1: printf("HP-UX\n"); break;
+ case 2: printf("NetBSD\n"); break;
+ case 3: printf("Linux\n"); break;
+ case 4: printf("GNU Hurd\n"); break;
+ case 6: printf("Solaris\n"); break;
+ case 7: printf("AIX\n"); break;
+ case 8: printf("IRIX\n"); break;
+ case 9: printf("FreeBSD\n"); break;
+ case 10: printf("Tru64\n"); break;
+ case 12: printf("OpenBSD\n"); break;
+ case 13: printf("OpenVMS\n"); break;
+ default: printf("0x%02X\n", (unsigned int) abi);
+ }
+ return;
+ }
+
+ unsigned char newAbi;
+ std::string nabi = downcase(trim(newOsAbi));
+ if (nabi == "system v" || nabi == "system-v" || nabi == "sysv")
+ newAbi = 0;
+ else if (nabi == "hp-ux")
+ newAbi = 1;
+ else if (nabi == "netbsd")
+ newAbi = 2;
+ else if (nabi == "linux" || nabi == "gnu")
+ newAbi = 3;
+ else if (nabi == "gnu hurd" || nabi == "gnu-hurd" || nabi == "hurd")
+ newAbi = 4;
+ else if (nabi == "solaris")
+ newAbi = 6;
+ else if (nabi == "aix")
+ newAbi = 7;
+ else if (nabi == "irix")
+ newAbi = 8;
+ else if (nabi == "freebsd")
+ newAbi = 9;
+ else if (nabi == "tru64")
+ newAbi = 10;
+ else if (nabi == "openbsd")
+ newAbi = 12;
+ else if (nabi == "openvms")
+ newAbi = 13;
+ else
+ error("unrecognized OS ABI");
+
+ if (newAbi == abi) {
+ debug("current and requested OS ABIs are equal\n");
+ return;
+ }
+
+ hdr()->e_ident[EI_OSABI] = newAbi;
+ changed = true;
+}
+
+template<ElfFileParams>
void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string & newSoname)
{
if (rdi(hdr()->e_type) != ET_DYN) {
@@ -1739,6 +1815,9 @@ void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string>
}
static bool printInterpreter = false;
+static bool printOsAbi = false;
+static bool setOsAbi = false;
+static std::string newOsAbi;
static bool printSoname = false;
static bool setSoname = false;
static std::string newSoname;
@@ -1764,6 +1843,12 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
if (printInterpreter)
printf("%s\n", elfFile.getInterpreter().c_str());
+ if (printOsAbi)
+ elfFile.modifyOsAbi(elfFile.printOsAbi, "");
+
+ if (setOsAbi)
+ elfFile.modifyOsAbi(elfFile.replaceOsAbi, newOsAbi);
+
if (printSoname)
elfFile.modifySoname(elfFile.printSoname, "");
@@ -1839,6 +1924,8 @@ void showHelp(const std::string & progName)
[--set-interpreter FILENAME]\n\
[--page-size SIZE]\n\
[--print-interpreter]\n\
+ [--print-os-abi]\t\tPrints 'EI_OSABI' field of ELF header\n\
+ [--set-os-abi ABI]\t\tSets 'EI_OSABI' field of ELF header to ABI.\n\
[--print-soname]\t\tPrints 'DT_SONAME' entry of .dynamic section. Raises an error if DT_SONAME doesn't exist\n\
[--set-soname SONAME]\t\tSets 'DT_SONAME' entry to SONAME.\n\
[--set-rpath RPATH]\n\
@@ -1888,6 +1975,14 @@ int mainWrapped(int argc, char * * argv)
else if (arg == "--print-interpreter") {
printInterpreter = true;
}
+ else if (arg == "--print-os-abi") {
+ printOsAbi = true;
+ }
+ else if (arg == "--set-os-abi") {
+ if (++i == argc) error("missing argument");
+ setOsAbi = true;
+ newOsAbi = resolveArgument(argv[i]);
+ }
else if (arg == "--print-soname") {
printSoname = true;
}
diff --git a/src/patchelf.h b/src/patchelf.h
index 33ecfc3..2e2ac6d 100644
--- a/src/patchelf.h
+++ b/src/patchelf.h
@@ -109,6 +109,10 @@ public:
std::string getInterpreter();
+ typedef enum { printOsAbi, replaceOsAbi } osAbiMode;
+
+ void modifyOsAbi(osAbiMode op, const std::string & newOsAbi);
+
typedef enum { printSoname, replaceSoname } sonameMode;
void modifySoname(sonameMode op, const std::string & newSoname);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index bbea1ba..600639d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -33,6 +33,7 @@ src_TESTS = \
endianness.sh \
contiguous-note-sections.sh \
no-gnu-hash.sh \
+ change-abi.sh \
grow-file.sh \
no-dynamic-section.sh \
args-from-file.sh \
diff --git a/tests/change-abi.sh b/tests/change-abi.sh
new file mode 100755
index 0000000..26a151d
--- /dev/null
+++ b/tests/change-abi.sh
@@ -0,0 +1,44 @@
+#! /bin/sh -e
+
+SCRATCH=scratch/$(basename $0 .sh)
+
+rm -rf ${SCRATCH}
+mkdir -p ${SCRATCH}
+
+cp simple-pie ${SCRATCH}/simple-pie
+
+# Save the old OS ABI
+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
+}
+
+# Reset OS ABI to the saved one
+../src/patchelf --set-os-abi "$OLDABI" ${SCRATCH}/simple-pie
+
+# Verify we still can run the executable
+${SCRATCH}/simple-pie