Hello, I have troubles understanding the interpretation of $ORIGIN on OpenBSD. I'm switching to OpenBSD from Linux, so I may be biased in my assumptions.
I built a program (python in this example) with the following ld parameters: -Wl,origin,z -Wl,rpath,'$ORIGIN/../lib' I can then check that the proper attributes were set on the binary: $ readelf -d python ... 0x0000000000000001 (NEEDED) Shared library: [libpython2.7.so.1.0] ... 0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../lib] ... 0x000000006ffffffb (FLAGS_1) Flags: ORIGIN On the filesystem, everything is also correct, say I have: - The python binary located in ~/bin/python - The python library located in ~/lib/libpython2.7.so.1.0 Now if I run python using its absolute or relative path, everything works fine. However when I add python to my $PATH, and call it by name (just "python"), the loader complains it cannot find libpython2.7.so.1.0. e.g. with python in my $PATH: $ python python: can't load library 'libpython2.7.so.1.0' That won't work, while: $ $(which python) or $ ~/bin/python or $ /home/.../bin/python These will work. Strangely, if I cd to the directory where python is located, then I can issue just "python" and it will work. e.g: $ cd ~/bin $ python It seems to me that $ORIGIN is interpreted as a relative path from the elf file when calling it with an absolute path, or relative to the path of the caller when using $PATH. I did not expect this behavior, as "man ld.so" states: > When resolving dependencies for the loaded objects, ld-elf.so.1 may be > allowed to translate dynamic token strings in rpath and soname by setting > -z origin option of the static linker ld(1). The following strings are > recognized now: > $ORIGIN Translated to the full path of the loaded object. Am I doing something wrong here, or is expected behavior? I've spent some time digging libexec/ld.so/resolve.c for an explanation (I'm on -current snapshots from Dec 3 2015, last week). It's not an easy lecture for a newcomer, so please forgive me if what I say below is complete garbage. Here is what I found: 1) My elf binary is loaded and ends up in _dl_finalize_object() 2) My binary has RPATH and FLAGS_1 to ORIGIN, so _dl_origin_subst() is called if (object->dyn.rpath) { object->rpath = _dl_split_path(object->dyn.rpath); if ((object->obj_flags & DF_1_ORIGIN) && _dl_trust) _dl_origin_subst(object); } 3) _dl_origin_subst() retrieves the original path of the elf object, and applies $ORIGIN interpolation if necessary if (_dl_origin_path(object, origin_path) != 0) return; /* perform path substitutions on each segment of rpath */ for (pp = object->rpath; *pp != NULL; pp++) { _dl_origin_subst_path(object, origin_path, pp); } 4) _dl_origin_subst_path() will use origin_path in case of $ORIGIN, so back to _dl_origin_path() to understand what is used. case SUBST_ORIGIN: value = origin_path; break; 5) _dl_origin_path() just uses _dl_realpath(_dl_dirname()) on the elf object. 6) _dl_dirname() will return "." if the path provided does not contain a '/' 7) _dl_realpath() will prepend the CWD to this. These last steps seems odd to me. Why is the CWD used here, when what we really want is the directory containing the binary of the currently running process (i.e. /proc/self/exe on linux). Just my guess, I don't really know what I'm talking about. Anyway, explanations greatly appreciated! And again, please forgive me if all that is just me doing stupid things.