diff options
-rw-r--r-- | .travis.yml | 7 | ||||
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | README.md (renamed from README) | 42 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | flake.lock | 28 | ||||
-rw-r--r-- | flake.nix | 41 | ||||
-rw-r--r-- | patchelf.1 | 8 | ||||
-rw-r--r-- | patchelf.spec.in | 4 | ||||
-rw-r--r-- | release.nix | 67 | ||||
-rw-r--r-- | src/patchelf.cc | 112 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rwxr-xr-x | tests/force-rpath.sh | 39 | ||||
-rwxr-xr-x | tests/output-flag.sh | 38 |
13 files changed, 308 insertions, 88 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e112de4 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: cpp +dist: xenial +script: + - ./bootstrap.sh + - ./configure + - make + - cd tests && make check diff --git a/Makefile.am b/Makefile.am index aa0d513..188f898 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = src tests -EXTRA_DIST = COPYING README patchelf.spec version $(man1_MANS) +EXTRA_DIST = COPYING README.md patchelf.spec version $(man1_MANS) man1_MANS = patchelf.1 -doc_DATA = README +doc_DATA = README.md @@ -1,4 +1,4 @@ -PatchELF is a simple utility for modifing existing ELF executables and +PatchELF is a simple utility for modifying existing ELF executables and libraries. In particular, it can do the following: * Change the dynamic loader ("ELF interpreter") of executables: @@ -47,13 +47,26 @@ libraries. In particular, it can do the following: This option can be give multiple times. +* Change SONAME of a dynamic library: -AUTHOR + $ patchelf --set-soname libnewname.so.3.4.5 path/to/libmylibrary.so.1.2.3 -Copyright 2004-2016 Eelco Dolstra <eelco.dolstra@logicblox.com>. +## INSTALLING -LICENSE +You can download a pre-compiled binary from the releases or compile it by yourself: + + ./bootstrap.sh + ./configure + make + sudo make install + +## AUTHOR + +Copyright 2004-2019 Eelco Dolstra <edolstra@gmail.com>. + + +## LICENSE This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -69,12 +82,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. -HOMEPAGE +## HOMEPAGE -http://nixos.org/patchelf.html +https://nixos.org/patchelf.html -BUGS +## BUGS The `strip' command from binutils generated broken executables when applied to the output of patchelf (if `--set-rpath' or @@ -83,7 +96,19 @@ This appears to be a bug in binutils (http://bugs.strategoxt.org/browse/NIXPKGS-85). -RELEASE HISTORY +## RELEASE HISTORY + +0.10 (March 28, 2019): + +* Many bug fixes. Please refer to the Git commit log: + + https://github.com/NixOS/patchelf/commits/master + + This release has contributions from Adam Trhoň, Benjamin Hipple, + Bernardo Ramos, Bjørn Forsman, Domen Kožar, Eelco Dolstra, Ezra + Cooper, Felipe Sateler, Jakub Wilk, James Le Cuirot, Karl Millar, + Linus Heckemann, Nathaniel J. Smith, Richard Purdie, Stanislav + Markevich and Tuomas Tynkkynen. 0.9 (February 29, 2016): @@ -155,4 +180,3 @@ RELEASE HISTORY 0.1 (October 11, 2005): * Initial release. - diff --git a/configure.ac b/configure.ac index d08a006..c2e5e98 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ AC_ARG_WITH([page-size], ) if test "$PAGESIZE" = auto; then - if type -p getconf &>/dev/null; then + if command -v getconf >/dev/null; then PAGESIZE=$(getconf PAGESIZE || getconf PAGE_SIZE) fi if test "$PAGESIZE" = auto -o -z "$PAGESIZE"; then diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..5d516b4 --- /dev/null +++ b/flake.lock @@ -0,0 +1,28 @@ +{ + "nodes": { + "nixpkgs": { + "info": { + "lastModified": 1590140420, + "narHash": "sha256-ozgGYyqGHoEKvgL00r6G0ht+ODXHuhpfW37IYxAda0A=" + }, + "locked": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "48723f48ab92381f0afd50143f38e45cf3080405", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-20.03", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 5 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..5ba87db --- /dev/null +++ b/flake.nix @@ -0,0 +1,41 @@ +{ + description = "A tool for modifying ELF executables and libraries"; + + inputs.nixpkgs.url = "nixpkgs/nixos-20.03"; + + outputs = { self, nixpkgs }: + + let + supportedSystems = [ "x86_64-linux" "i686-linux" "aarch64-linux" ]; + forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system); + in + + rec { + + overlay = final: prev: { + + patchelf-new = final.stdenv.mkDerivation { + name = "patchelf-${hydraJobs.tarball.version}"; + src = "${hydraJobs.tarball}/tarballs/*.tar.bz2"; + }; + + }; + + hydraJobs = import ./release.nix { + patchelfSrc = self; + nixpkgs = nixpkgs; + }; + + checks = forAllSystems (system: { + build = hydraJobs.build.${system}; + }); + + defaultPackage = forAllSystems (system: + (import nixpkgs { + inherit system; + overlays = [ self.overlay ]; + }).patchelf-new + ); + + }; +} @@ -10,6 +10,7 @@ patchelf - Modify ELF files .I OPTION .B .I FILE +.SM ... .B .SH DESCRIPTION @@ -20,7 +21,7 @@ of executables and change the RPATH of executables and libraries. .SH OPTIONS -The single option given operates on a given FILE, editing in place. +The single option given operates on each FILE, editing in place. .IP "--page-size SIZE" Uses the given page size instead of the default. @@ -75,13 +76,16 @@ Replaces a declared dependency on a dynamic library with another one (DT_NEEDED) This option can be give multiple times. .IP "--remove-needed LIBRARY" -Removes a declared depency on LIBRARY (DT_NEEDED entry). This +Removes a declared dependency on LIBRARY (DT_NEEDED entry). This option can be given multiple times. .IP "--no-default-lib" Marks the object that the search for dependencies of this object will ignore any default library search paths. +.IP "--output FILE" +Set the output file name. If not specified, the input will be modified in place. + .IP --debug Prints details of the changes made to the input file. diff --git a/patchelf.spec.in b/patchelf.spec.in index a361554..5569026 100644 --- a/patchelf.spec.in +++ b/patchelf.spec.in @@ -12,7 +12,7 @@ Prefix: /usr %description -PatchELF is a simple utility for modifing existing ELF executables and +PatchELF is a simple utility for modifying existing ELF executables and libraries. It can change the dynamic loader ("ELF interpreter") of executables and change the RPATH of executables and libraries. @@ -34,5 +34,5 @@ rm -rf $RPM_BUILD_ROOT %files %{_bindir}/patchelf -%doc %{_docdir}/patchelf/README +%doc %{_docdir}/patchelf/README.md %{_mandir}/man1/patchelf.1.gz diff --git a/release.nix b/release.nix index 1b6c67c..2cf9181 100644 --- a/release.nix +++ b/release.nix @@ -1,10 +1,11 @@ { patchelfSrc ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; } +, nixpkgs ? builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz , officialRelease ? false }: let - pkgs = import <nixpkgs> { }; + pkgs = import nixpkgs { system = builtins.currentSystem or "x86_64-linux"; }; jobs = rec { @@ -13,13 +14,19 @@ let tarball = pkgs.releaseTools.sourceTarball rec { name = "patchelf-tarball"; - version = builtins.readFile ./version + (if officialRelease then "" else "pre${toString patchelfSrc.revCount}_${patchelfSrc.shortRev}"); + version = builtins.readFile ./version + + (if officialRelease then "" else + "." + + ((if patchelfSrc ? lastModifiedDate + then builtins.substring 0 8 patchelfSrc.lastModifiedDate + else toString patchelfSrc.revCount or 0) + + "." + patchelfSrc.shortRev)); versionSuffix = ""; # obsolete src = patchelfSrc; preAutoconf = "echo ${version} > version"; postDist = '' - cp README $out/ - echo "doc readme $out/README" >> $out/nix-support/hydra-build-products + cp README.md $out/ + echo "doc readme $out/README.md" >> $out/nix-support/hydra-build-products ''; }; @@ -32,39 +39,27 @@ let }; - build = pkgs.lib.genAttrs [ "x86_64-linux" "i686-linux" /* "x86_64-freebsd" "i686-freebsd" "x86_64-darwin" "i686-solaris" "i686-cygwin" */ ] (system: + build = pkgs.lib.genAttrs [ "x86_64-linux" "i686-linux" "aarch64-linux" /* "x86_64-freebsd" "i686-freebsd" "x86_64-darwin" "i686-solaris" "i686-cygwin" */ ] (system: - with import <nixpkgs> { inherit system; }; + with import nixpkgs { inherit system; }; releaseTools.nixBuild { name = "patchelf"; src = tarball; doCheck = !stdenv.isDarwin && system != "i686-cygwin" && system != "i686-solaris"; buildInputs = lib.optionals stdenv.isLinux [ acl attr ]; - isReproducible = true; + isReproducible = system != "aarch64-linux"; # ARM machines are still on Nix 1.11 }); + /* + rpm_fedora27x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora27x86_64); - rpm_fedora20i386 = makeRPM_i686 (diskImages: diskImages.fedora20i386); - rpm_fedora20x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora20x86_64); - rpm_fedora21i386 = makeRPM_i686 (diskImages: diskImages.fedora21i386); - rpm_fedora21x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora21x86_64); - rpm_fedora23i386 = makeRPM_i686 (diskImages: diskImages.fedora23i386); - rpm_fedora23x86_64 = makeRPM_x86_64 (diskImages: diskImages.fedora23x86_64); + deb_debian9i386 = makeDeb_i686 (diskImages: diskImages.debian9i386); + deb_debian9x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian9x86_64); - deb_debian7i386 = makeDeb_i686 (diskImages: diskImages.debian7i386); - deb_debian7x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian7x86_64); - deb_debian8i386 = makeDeb_i686 (diskImages: diskImages.debian8i386); - deb_debian8x86_64 = makeDeb_x86_64 (diskImages: diskImages.debian8x86_64); - - deb_ubuntu1404i386 = makeDeb_i686 (diskImages: diskImages.ubuntu1404i386); - deb_ubuntu1404x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu1404x86_64); - deb_ubuntu1410i386 = makeDeb_i686 (diskImages: diskImages.ubuntu1410i386); - deb_ubuntu1410x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu1410x86_64); - deb_ubuntu1504i386 = makeDeb_i686 (diskImages: diskImages.ubuntu1504i386); - deb_ubuntu1504x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu1504x86_64); - deb_ubuntu1510i386 = makeDeb_i686 (diskImages: diskImages.ubuntu1510i386); - deb_ubuntu1510x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu1510x86_64); + deb_ubuntu1804i386 = makeDeb_i686 (diskImages: diskImages.ubuntu1804i386); + deb_ubuntu1804x86_64 = makeDeb_x86_64 (diskImages: diskImages.ubuntu1804x86_64); + */ release = pkgs.releaseTools.aggregate @@ -73,15 +68,13 @@ let [ tarball build.x86_64-linux build.i686-linux - #build.x86_64-freebsd - #build.i686-freebsd - #build.x86_64-darwin - rpm_fedora23i386 - rpm_fedora23x86_64 - deb_debian8i386 - deb_debian8x86_64 - deb_ubuntu1510i386 - deb_ubuntu1510x86_64 + /* + rpm_fedora27x86_64 + deb_debian9i386 + deb_debian9x86_64 + deb_ubuntu1804i386 + deb_ubuntu1804x86_64 + */ ]; meta.description = "Release-critical builds"; }; @@ -95,7 +88,7 @@ let makeRPM = system: diskImageFun: - with import <nixpkgs> { inherit system; }; + with import nixpkgs { inherit system; }; releaseTools.rpmBuild rec { name = "patchelf-rpm"; @@ -111,7 +104,7 @@ let makeDeb = system: diskImageFun: - with import <nixpkgs> { inherit system; }; + with import nixpkgs { inherit system; }; releaseTools.debBuild { name = "patchelf-deb"; diff --git a/src/patchelf.cc b/src/patchelf.cc index e9d7ea5..cbf420d 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -24,6 +24,7 @@ #include <memory> #include <sstream> #include <limits> +#include <stdexcept> #include <cstdlib> #include <cstdio> @@ -44,7 +45,9 @@ static bool debugMode = false; static bool forceRPath = false; -static std::string fileName; +static std::vector<std::string> fileNames; +static std::string outputFileName; +static bool alwaysWrite = false; static int pageSize = PAGESIZE; typedef std::shared_ptr<std::vector<unsigned char>> FileContents; @@ -134,8 +137,11 @@ private: ElfFile * elfFile; bool operator ()(const Elf_Phdr & x, const Elf_Phdr & y) { - if (x.p_type == PT_PHDR) return true; + // A PHDR comes before everything else. if (y.p_type == PT_PHDR) return false; + if (x.p_type == PT_PHDR) return true; + + // Sort non-PHDRs by address. return elfFile->rdi(x.p_paddr) < elfFile->rdi(y.p_paddr); } }; @@ -328,7 +334,12 @@ static FileContents readFile(std::string fileName, int fd = open(fileName.c_str(), O_RDONLY); if (fd == -1) throw SysError(fmt("opening '", fileName, "'")); - if ((size_t) read(fd, contents->data(), size) != size) + size_t bytesRead = 0; + ssize_t portion; + while ((portion = read(fd, contents->data() + bytesRead, size - bytesRead)) > 0) + bytesRead += portion; + + if (bytesRead != size) throw SysError(fmt("reading '", fileName, "'")); close(fd); @@ -393,10 +404,13 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fileContents) error("wrong ELF type"); if ((size_t) (rdi(hdr->e_phoff) + rdi(hdr->e_phnum) * rdi(hdr->e_phentsize)) > fileContents->size()) - error("missing program headers"); + 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 ((size_t) (rdi(hdr->e_shoff) + rdi(hdr->e_shnum) * rdi(hdr->e_shentsize)) > fileContents->size()) - error("missing section headers"); + error("section header table out of bounds"); if (rdi(hdr->e_phentsize) != sizeof(Elf_Phdr)) error("program headers have wrong size"); @@ -463,7 +477,7 @@ void ElfFile<ElfFileParamNames>::sortShdrs() /* Sort the sections by offset. */ CompShdr comp; comp.elfFile = this; - sort(shdrs.begin(), shdrs.end(), comp); + sort(shdrs.begin() + 1, shdrs.end(), comp); /* Restore the sh_link mappings. */ for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) @@ -485,11 +499,18 @@ void ElfFile<ElfFileParamNames>::sortShdrs() static void writeFile(std::string fileName, FileContents contents) { - int fd = open(fileName.c_str(), O_TRUNC | O_WRONLY); + debug("writing %s\n", fileName.c_str()); + + int fd = open(fileName.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0777); if (fd == -1) error("open"); - if (write(fd, contents->data(), contents->size()) != (off_t) contents->size()) + size_t bytesWritten = 0; + ssize_t portion; + while ((portion = write(fd, contents->data() + bytesWritten, contents->size() - bytesWritten)) > 0) + bytesWritten += portion; + + if (bytesWritten != contents->size()) error("write"); if (close(fd) != 0) @@ -558,8 +579,12 @@ template<ElfFileParams> Elf_Shdr & ElfFile<ElfFileParamNames>::findSection(const SectionName & sectionName) { Elf_Shdr * shdr = findSection2(sectionName); - if (!shdr) - error("cannot find section '" + sectionName + "'"); + if (!shdr) { + std::string extraMsg = ""; + if (sectionName == ".interp" || sectionName == ".dynamic" || sectionName == ".dynstr") + extraMsg = ". The input file is most likely statically linked"; + error("cannot find section '" + sectionName + "'" + extraMsg); + } return *shdr; } @@ -621,7 +646,8 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff, for (auto & i : replacedSections) { std::string sectionName = i.first; Elf_Shdr & shdr = findSection(sectionName); - memset(contents + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size)); + if (shdr.sh_type != SHT_NOBITS) + memset(contents + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size)); } for (auto & i : replacedSections) { @@ -1231,7 +1257,17 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, } - if (std::string(rpath ? rpath : "") == newRPath) return; + if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */ + dynRPath->d_tag = DT_RUNPATH; + dynRunPath = dynRPath; + dynRPath = 0; + } else if (forceRPath && dynRunPath) { /* convert DT_RUNPATH to DT_RPATH */ + dynRunPath->d_tag = DT_RPATH; + dynRPath = dynRunPath; + dynRunPath = 0; + } else if (std::string(rpath ? rpath : "") == newRPath) { + return; + } changed = true; @@ -1245,15 +1281,6 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, debug("new rpath is '%s'\n", newRPath.c_str()); - if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */ - dynRPath->d_tag = DT_RUNPATH; - dynRunPath = dynRPath; - dynRPath = 0; - } - - if (forceRPath && dynRPath && dynRunPath) { /* convert DT_RUNPATH to DT_RPATH */ - dynRunPath->d_tag = DT_IGNORE; - } if (newRPath.size() <= rpathSize) { strcpy(rpath, newRPath.c_str()); @@ -1461,6 +1488,7 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs) wri(newDyn.d_tag, DT_NEEDED); wri(newDyn.d_un.d_val, j); setSubstr(newDynamic, i * sizeof(Elf_Dyn), std::string((char *) &newDyn, sizeof(Elf_Dyn))); + i++; } changed = true; @@ -1542,7 +1570,7 @@ static bool printNeeded = false; static bool noDefaultLib = false; template<class ElfFile> -static void patchElf2(ElfFile && elfFile) +static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, std::string fileName) { if (printInterpreter) printf("%s\n", elfFile.getInterpreter().c_str()); @@ -1578,23 +1606,29 @@ static void patchElf2(ElfFile && elfFile) if (elfFile.isChanged()){ elfFile.rewriteSections(); writeFile(fileName, elfFile.fileContents); + } else if (alwaysWrite) { + debug("not modified, but alwaysWrite=true\n"); + writeFile(fileName, fileContents); } } static void patchElf() { - if (!printInterpreter && !printRPath && !printSoname && !printNeeded) - debug("patching ELF file '%s'\n", fileName.c_str()); + for (auto fileName : fileNames) { + if (!printInterpreter && !printRPath && !printSoname && !printNeeded) + debug("patching ELF file '%s'\n", fileName.c_str()); - debug("Kernel page size is %u bytes\n", getPageSize()); + debug("Kernel page size is %u bytes\n", getPageSize()); - auto fileContents = readFile(fileName); + auto fileContents = readFile(fileName); + 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>(fileContents)); - else - patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed>(fileContents)); + if (getElfType(fileContents).is32Bit) + patchElf2(ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed>(fileContents), fileContents, outputFileName2); + else + patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed>(fileContents), fileContents, outputFileName2); + } } @@ -1617,9 +1651,10 @@ void showHelp(const std::string & progName) [--replace-needed LIBRARY NEW_LIBRARY]\n\ [--print-needed]\n\ [--no-default-lib]\n\ + [--output FILE]\n\ [--debug]\n\ [--version]\n\ - FILENAME\n", progName.c_str()); + FILENAME...\n", progName.c_str()); } @@ -1703,6 +1738,11 @@ int mainWrapped(int argc, char * * argv) neededLibsToReplace[ argv[i+1] ] = argv[i+2]; i += 2; } + else if (arg == "--output") { + if (++i == argc) error("missing argument"); + outputFileName = argv[i]; + alwaysWrite = true; + } else if (arg == "--debug") { debugMode = true; } @@ -1717,11 +1757,15 @@ int mainWrapped(int argc, char * * argv) printf(PACKAGE_STRING "\n"); return 0; } - else break; + else { + fileNames.push_back(arg); + } } - if (i == argc) error("missing filename"); - fileName = argv[i]; + if (fileNames.empty()) error("missing filename"); + + if (!outputFileName.empty() && fileNames.size() != 1) + error("--output option only allowed with single input file"); patchElf(); diff --git a/tests/Makefile.am b/tests/Makefile.am index 32218e8..96339b3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -21,7 +21,9 @@ no_rpath_arch_TESTS = \ src_TESTS = \ plain-fail.sh plain-run.sh shrink-rpath.sh set-interpreter-short.sh \ set-interpreter-long.sh set-rpath.sh no-rpath.sh big-dynstr.sh \ - set-rpath-library.sh soname.sh shrink-rpath-with-allowed-prefixes.sh + set-rpath-library.sh soname.sh shrink-rpath-with-allowed-prefixes.sh \ + force-rpath.sh \ + output-flag.sh build_TESTS = \ $(no_rpath_arch_TESTS) diff --git a/tests/force-rpath.sh b/tests/force-rpath.sh new file mode 100755 index 0000000..9256905 --- /dev/null +++ b/tests/force-rpath.sh @@ -0,0 +1,39 @@ +#! /bin/sh -e +SCRATCH=scratch/$(basename $0 .sh) + +rm -rf ${SCRATCH} +mkdir -p ${SCRATCH} + +SCRATCHFILE=${SCRATCH}/libfoo.so +cp libfoo.so $SCRATCHFILE + +doit() { + echo patchelf $* + ../src/patchelf $* $SCRATCHFILE +} + +expect() { + out=$(echo $(objdump -x $SCRATCHFILE | grep PATH)) + + if [ "$out" != "$*" ]; then + echo "Expected '$*' but got '$out'" + exit 1 + fi +} + +doit --remove-rpath +expect +doit --set-rpath foo +expect RUNPATH foo +doit --force-rpath --set-rpath foo +expect RPATH foo +doit --force-rpath --set-rpath bar +expect RPATH bar +doit --remove-rpath +expect +doit --force-rpath --set-rpath foo +expect RPATH foo +doit --set-rpath foo +expect RUNPATH foo +doit --set-rpath bar +expect RUNPATH bar diff --git a/tests/output-flag.sh b/tests/output-flag.sh new file mode 100755 index 0000000..5da26b5 --- /dev/null +++ b/tests/output-flag.sh @@ -0,0 +1,38 @@ +#! /bin/sh -e +SCRATCH=scratch/$(basename $0 .sh) + +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/ + +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 +# 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 + +if test "$(uname)" = FreeBSD; then + export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB +fi + +exitCode=0 +(cd ${SCRATCH} && ./main2) || exitCode=$? + +if test "$exitCode" != 46; then + echo "bad exit code!" + exit 1 +fi + +exitCode=0 +(cd ${SCRATCH} && ./main3) || exitCode=$? + +if test "$exitCode" != 46; then + echo "bad exit code!" + exit 1 +fi |