I have recently started compiling my application using -rpath, but when I UPX my application it removes the -rpath so my binaries cannot find their libs.
I am using version 3.01 on a Linux binary.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Pleae give a concrete example of the bad behavior, running both the plain executable and the compressed executable under 'strace', with a "diff -u" of the two outputs from strace that shows the fault.
This example works for me:
#include <stdio.h>
int const x = { 1, 2, 3 }; /* Otherwise this program is too small to compress. */
The ambiguous success of your hello world test isnt very helpful, I think there are things above my level of knowledge going on behind the scenes there would could still make it work, so I created a better test that does not utilise a lib already installed on your system. I created a hello world lib, and had your hello world test use it, and it did exactly what I expected it to. The plain one worked perfectly, the upx one spit out:
./hello-upx: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory
I have uploaded the source to the hello world lib, the hello world app, along with the commands I use to compile them and my two straces in an archive at:
The "Wl,-R,'$ORIGIN/libtest'" results in an executable which suffers from a bug in ld-linux.so. ld-linux.so gives up when readlink("/proc/self/exe",,) fails, because ld-linux.so believes that /proc/self/exe is required to make "$ORIGIN" work. It _might_ be a workaround to invoke the executable using an absolute pathname such as $PWD/hello-plain instead of a relative pathname such as ./hello-plain. It _does_ work to specifiy an absolute pathname in the original "-Wl,-R". In any case, there are other reasons besides upx why the readlink might fail, and ld-linux.so should be more robust. ld-linux.so need not be the first thing to run in a new process.
The reason why readlink("/proc/self/exe",,) fails is because the upx runtime decompressor munmap()s all pages from the original compressed executable, leaving no evidence that the program was compressed. The Linux kernel detects this total unmapping, and removes the symlink for /proc/self/exe.
The upx runtime decompressor saves the initial value of readlink("/proc/self/exe",,) in a new environment variable whose name is "\ \ \ " . Also, on Linux 2.6.29 and later, the Linux kernel puts the pathname that was specified to execve() into the Elf32_auxv at slot AT_EXECFN; see <elf.h>. Also, on all Linux since at least 2.0.0 (over ten years ago), that pathname can be accessed as the string which follows the string of the last environment variable. In fact AT_EXECFN points to that string, and is merely a formal recognition of what has been available for many years.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
My purpose in using $ORIGIN is so that the executable can be double clicked on to run from any path, any folder, any system without having to use an install script, wrapper script, or a package system.
In this instance, simply not running UPX on the Linux build of my application is a more desirable solution than any others, though I wish it were otherwise.
Thank you for your replies.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have recently started compiling my application using -rpath, but when I UPX my application it removes the -rpath so my binaries cannot find their libs.
I am using version 3.01 on a Linux binary.
Pleae give a concrete example of the bad behavior, running both the plain executable and the compressed executable under 'strace', with a "diff -u" of the two outputs from strace that shows the fault.
This example works for me:
int const x = { 1, 2, 3 }; /* Otherwise this program is too small to compress. */
main()
{
printf("Hello world.\n");
return 0;
}
$ cp /lib/libc.so.6 .
$ gcc -o hello-plain hello.c -Wl,-rpath=$PWD
$ upx -o hello-upx ./hello
$ strace -o strace-plain.out ./hello-plain
$ strace -o strace-upx.out ./hello-upx
$ diff -u strace-plain.out strace-upx.out
…
open("$PWD/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\353\1\240:\0\0\0"…, 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1825560, …}) = 0
@@ -17,12 +31,12 @@
mmap(0x3aa0364000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x164000) = 0x3aa0364000
mmap(0x3aa0369000, 18536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3aa0369000
…
Notice that the "open(" uses the same path "$PWD/libc.so.6" in both cases, and not something in /lib .
The ambiguous success of your hello world test isnt very helpful, I think there are things above my level of knowledge going on behind the scenes there would could still make it work, so I created a better test that does not utilise a lib already installed on your system. I created a hello world lib, and had your hello world test use it, and it did exactly what I expected it to. The plain one worked perfectly, the upx one spit out:
./hello-upx: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory
I have uploaded the source to the hello world lib, the hello world app, along with the commands I use to compile them and my two straces in an archive at:
http://www.indiedevs.com/test/upxtest.tar.gz
I hope this will help.
gcc -o hello-plain hello.c -L ./libtest -lstdc++ -ltest -Wl,-R,'$ORIGIN/libtest'
The "Wl,-R,'$ORIGIN/libtest'" results in an executable which suffers from a bug in ld-linux.so. ld-linux.so gives up when readlink("/proc/self/exe",,) fails, because ld-linux.so believes that /proc/self/exe is required to make "$ORIGIN" work. It _might_ be a workaround to invoke the executable using an absolute pathname such as $PWD/hello-plain instead of a relative pathname such as ./hello-plain. It _does_ work to specifiy an absolute pathname in the original "-Wl,-R". In any case, there are other reasons besides upx why the readlink might fail, and ld-linux.so should be more robust. ld-linux.so need not be the first thing to run in a new process.
The reason why readlink("/proc/self/exe",,) fails is because the upx runtime decompressor munmap()s all pages from the original compressed executable, leaving no evidence that the program was compressed. The Linux kernel detects this total unmapping, and removes the symlink for /proc/self/exe.
The upx runtime decompressor saves the initial value of readlink("/proc/self/exe",,) in a new environment variable whose name is "\ \ \ " . Also, on Linux 2.6.29 and later, the Linux kernel puts the pathname that was specified to execve() into the Elf32_auxv at slot AT_EXECFN; see <elf.h>. Also, on all Linux since at least 2.0.0 (over ten years ago), that pathname can be accessed as the string which follows the string of the last environment variable. In fact AT_EXECFN points to that string, and is merely a formal recognition of what has been available for many years.
My purpose in using $ORIGIN is so that the executable can be double clicked on to run from any path, any folder, any system without having to use an install script, wrapper script, or a package system.
In this instance, simply not running UPX on the Linux build of my application is a more desirable solution than any others, though I wish it were otherwise.
Thank you for your replies.