9

I have been trying to compile openssl 1.0.0g with the following rpath:

$ORIGIN/../lib64

Everytime I readelf -d apps/openssl, I am getting results like the following depending on what escaping variation I tried:

\RIGIN/../lib64
RIGIN/../lib64
ORIGIN/../lib64

I want to setup my rpath without using external tools like chrpath. Is it at all possible? I will basically accept anything that does not involve using external tools like chrpath (though I would already be done with that).

Ideally, I would like to do it by passing options on the command line (any form of -Wl,-rpath,$ORIGIN/../lib64).

I don't mind editing the generated Makefile, which is what I have been trying last. If only I could get it to print a stupid dollar sign!!! I tried modifying LIBRPATH under the BUILDENV= block with no luck. My best results so far:

LIBRPATH=$$'ORIGIN/../lib64 # result: /../lib64
LIBRPATH=$$$$'ORIGIN/../lib64 # result: 12345<pid>/../lib64 

I have read various rpath related questions and tried various escaping and quoting tricks but nothing worked so far!

jww
  • 97,681
  • 90
  • 411
  • 885
Philippe A.
  • 2,885
  • 2
  • 28
  • 37
  • Also see [A description of RPATH $ORIGIN LD_LIBRARY_PATH and portable linux binaries](https://enchildfone.wordpress.com/2010/03/23/a-description-of-rpath-origin-ld_library_path-and-portable-linux-binaries/). The article basically says, *to hell with this stupid escaping rules in makefiles and linker scripts*. The article uses `XORIGIN`, and then uses `chrpath` after the binary is built to change `XORIGIN` to `$ORIGIN` – jww Nov 07 '18 at 17:39
  • So, I know this question is nearly a decade old, but it as yet has no accepted answer. And I think I've managed to come up with the best answer of the ones proposed here. It requires no complex escaping or post-build tasks with `chrpath`. Perhaps you could consider accepting it, as I believe it would definitely have solved your issue, though I admit it was many years too late. – acm May 19 '21 at 20:30

5 Answers5

8

In your makefile try:

-Wl,-rpath,${ORIGIN}/../lib64

I am assuming that the ORIGIN is a shell variable.

EDIT

I have just found an answer to your question (better late then never): You need to prevent make from interpolating variables, to do that you need to use $$ (double dolar sign):

-Wl,-rpath,'$$ORIGIN/../lib64'

I know that it works because I have tested it with my own application, enjoy :)

sirgeorge
  • 6,331
  • 1
  • 28
  • 33
  • It is not and that's part of the whole issue. I need the litteral string '$ORIGIN/../lib64' to be written in the executable. There must be no substitution of any kind. – Philippe A. Feb 22 '12 at 17:43
  • Can you please clarify what version of openssl you were using and what line of the Makefile you have changed? – Philippe A. Apr 15 '14 at 17:51
  • OpenSSL has a `Makefile.org` and a bunch of recursive makefiles. And they don't honor `CFLAGS`, `LDFLAGS`, etc. So *"In your makefile try..."* is *not* as easy as it sounds. – jww May 07 '15 at 16:49
2

I went the chrpath way. http://enchildfone.wordpress.com/2010/03/23/a-description-of-rpath-origin-ld_library_path-and-portable-linux-binaries/

It is quite complicated to counter shell expansion of `$$ORIGIN`` in openssl. Sooner or later, it gets expanded because of the dollar sign. If you really want to go this way, you can do it. I have found the following to work with openssl 1.0.1g on Linux. In Makefile.shared, look for this line:

DO_GNU_APP=LDFLAGS="$(CFLAGS) -Wl,-rpath,$(LIBRPATH)"

Replace it with the following. This quoting-fu neutralize the expansion of $. The double $$ is the way to get a single dollar sign in makefiles.

DO_GNU_APP=LDFLAGS="$(CFLAGS) -Wl,-rpath,'"'$$'"ORIGIN/../lib64'"

After compiling:

readelf -d apps/openssl | grep RPATH
 0x000000000000000f (RPATH)              Library rpath: ['$ORIGIN/../lib64']
Philippe A.
  • 2,885
  • 2
  • 28
  • 37
  • `DO_GNU_APP=LDFLAGS ...` - I *think* this will allow `libssl.so` to still load the wrong `libcrypto.so`. – jww May 07 '15 at 16:50
  • ***Plus One***... you managed to get a relative RPATH *with* a shell variable. Does `ldd` honor the shell variable? Does it expand? I'm going to bookmark this question because I've never seen that before.... – jww May 07 '15 at 16:56
  • $ORIGIN is a special ldd token. A badly chosen one if you ask me, because the dollar sign is a special character that gets expanded by shells, if not by makefiles. This is why is it so complicated to stick $ORIGIN into the executable. It is saner to use chrpath. This kind of relative rpath makes your openssl location independent and allows you to maintain multiple versions in different locations. – Philippe A. Dec 14 '16 at 15:02
1

OK I spent several hours fighting with this same issue and trying all manner of crazy escaping, at one point I was up to eight $ signs, at which point I decided that there must be another way.

In fact, it appears that there is, at least with GNU ld.

Instead of -Wl,-rpath,\\$$$\$\$\$$$\$\\\\$ORIGIN or some other elder-god-invoking monstrosity, just do this:

echo '-rpath=$ORIGIN/../lib64' > rpathorigin
./config -Wl,@$(pwd)/rpathorigin ...

I don't see that ld.gold documents the @ flag, and I have no idea about, say, lld. But if you are using GCC and it is invoking BFD ld, the above may just work for you.

Of course, the actual path used with origin should be customized as needed, and I have no opinion on ./config vs ./Configure. But using the response file trick seems to entirely sidestep the shell/make escaping nightmare.

acm
  • 12,183
  • 5
  • 39
  • 68
  • To provide some context on why I didn't just use `chrpath` as the other answer suggested, `chrpath` isn't installed on the machine where I need to build OpenSSL, and I don't have root on the system in order to install it. I didn't want to wait for an admin to install it for me, so I found this workaround instead. And sure, I could have built `chrpath` from source, but I was actually having difficulty finding a canonical source for the code. Lots of broken links. – acm Apr 25 '21 at 14:31
  • Escapeception, the final recursion. – Mavaddat Javid Nov 09 '21 at 06:41
0

I don't mind editing the generated Makefile, which is what I have been trying last...

I'm not sure you can set it with a shell variable and relative path. I don't think ldd expands the $ORIGIN in $ORIGIN/../lib64. In this case, I think you need to use ldconfig to add $ORIGIN/../lib64 to the library search paths. See finding ldd search path on Server Fault for more details.

Since I'm not sure, I'll provide the instructions anyway. You don't need to change the Makefiles. As a matter of fact, I did not have any luck doing so in the past because things get overwritten, and other things like CFLAGS and LDFLAGS get ignored.

Also see Build OpenSSL with RPATH? Your question and the cited question are different question that converge on similar answers (no duplicates between them). But it provides the OpenSSL dev's position on RPATHs. It was a private email, so I shared the relevant details rather than the whole message.

If you manage to embed $ORIGIN/../lib64 in the ELF section and it works, then please report back. Below, I am using /usr/local/ssl/lib for my RPATH. You should substitute $ORIGIN/../lib64 for /usr/local/ssl/lib.


OpenSSL supports RPATH's out of the box for BSD targets (but not others). From Configure:

# Unlike other OSes (like Solaris, Linux, Tru64, IRIX) BSD run-time
# linkers (tested OpenBSD, NetBSD and FreeBSD) "demand" RPATH set on
# .so objects. Apparently application RPATH is not global and does
# not apply to .so linked with other .so. Problem manifests itself
# when libssl.so fails to load libcrypto.so. One can argue that we
# should engrave this into Makefile.shared rules or into BSD-* config
# lines above. Meanwhile let's try to be cautious and pass -rpath to
# linker only when --prefix is not /usr.
if ($target =~ /^BSD\-/)
    {
    $shared_ldflag.=" -Wl,-rpath,\$(LIBRPATH)" if ($prefix !~ m|^/usr[/]*$|);
    }

The easiest way to do it for OpenSSL 1.0.2 appears to be add it to linker flags during configuration

./config -Wl,-rpath=/usr/local/ssl/lib

You can also edit Configure line and hard code the rpath. For example, I am working on Debian x86_64. So I opened the file Configure in an editor, copied linux-x86_64, named it linux-x86_64-rpath, and made the following change to add the -rpath option:

"linux-x86_64-rpath",   "gcc:-m64 -DL_ENDIAN -O3 -Wall -Wl,-rpath=/usr/local/ssl/lib::
-D_REENTRANT::-Wl,-rpath=/usr/local/ssl/lib -ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:
${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",

Above, fields 2 and 6 were changed. They correspond to $cflag and $ldflag in OpenSSL's builds system.

Then, Configure with the new configuration:

$ ./Configure linux-x86_64-rpath shared no-ssl2 no-ssl3 no-comp \
    --openssldir=/usr/local/ssl enable-ec_nistp_64_gcc_128

Finally, after make, verify the settings stuck:

$ readelf -d ./libssl.so | grep -i rpath
 0x000000000000000f (RPATH)              Library rpath: [/usr/local/ssl/lib]
$ readelf -d ./libcrypto.so | grep -i rpath
 0x000000000000000f (RPATH)              Library rpath: [/usr/local/ssl/lib]
$ readelf -d ./apps/openssl | grep -i rpath 
 0x000000000000000f (RPATH)              Library rpath: [/usr/local/ssl/lib]

Once you perform make install, then ldd will produce expected results:

$ ldd /usr/local/ssl/lib/libssl.so
    linux-vdso.so.1 =>  (0x00007ffceff6c000)
    libcrypto.so.1.0.0 => /usr/local/ssl/lib/libcrypto.so.1.0.0 (0x00007ff5eff96000)
    ...

$ ldd /usr/local/ssl/bin/openssl 
    linux-vdso.so.1 =>  (0x00007ffc30d3a000)
    libssl.so.1.0.0 => /usr/local/ssl/lib/libssl.so.1.0.0 (0x00007f9e8372e000)
    libcrypto.so.1.0.0 => /usr/local/ssl/lib/libcrypto.so.1.0.0 (0x00007f9e832c0000)
    ...
Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
0

Don't ask me why but this worked for me in OpenSSL 1.1.1i in getting around the $ sign issue:

\$\$\$$ORIGIN

Example:

./Configure linux-x86_64 '-Wl,-rpath,\$\$\$$ORIGIN'

Alternatively, if this command line hack isn't congruent with you, you can always use chrpath after building as others have suggested:

./Configure linux-x86_64 '-Wl,-rpath,XORIGIN'
make depend
make all
chrpath -r "\$ORIGIN" libssl.so
Akyidrian
  • 1,055
  • 10
  • 21