diff options
author | Jörg Thalheim <Mic92@users.noreply.github.com> | 2022-09-28 11:44:58 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-28 11:44:58 +0200 |
commit | 683e41d340aea90822bb5e202eeac15688234a51 (patch) | |
tree | 30de9dda2ee652e40c34eb1c4ead7587fe57db17 | |
parent | 7281d999e95d6730d1d08fc7517c15e27ddfb65f (diff) | |
parent | 5faf4534366826350654db8d65cba81e50387519 (diff) | |
download | patchelf-683e41d340aea90822bb5e202eeac15688234a51.tar.gz |
Merge pull request #381 from crystax/master
Add --print-os-abi and --set-os-abi options
-rw-r--r-- | patchelf.1 | 10 | ||||
-rw-r--r-- | src/patchelf.cc | 95 | ||||
-rw-r--r-- | src/patchelf.h | 4 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rwxr-xr-x | tests/change-abi.sh | 44 |
5 files changed, 154 insertions, 0 deletions
@@ -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 |