-
-
Notifications
You must be signed in to change notification settings - Fork 14.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Link to libraries through absolute paths? #24844
Comments
Is it unambiguous, which library should be linked? Does ELF even allow this? |
Another possible issue is if |
http://www.skyfree.org/linux/references/ELF_Format.pdf not a canonical source as far as I can tell, but the "Shared Object Dependencies" section suggests so.
I don't think |
Yes, Hopefully we have that converted to use |
I whipped up a patch to patchelf to implement this in case anybody wants to try to see what breaks: https://github.com/dezgeg/patchelf/tree/abs |
One example that I can remember is scanner drivers (sane). For example on my system:
I have a |
But are the sane plugin |
@dezgeg True! That leaves us with |
Very interesting. I didn't know the loader can be so easily convinced to absolute path searches (without changing sonames). It would really be a significant change to basic nix(pkgs) principles, maybe worth of an RFC before we switch (but I'd favor more investigation+testing before RFC).
|
If I read the logic in glibc correctly, yes, loading libraries (by both |
That’s the current ratio of |
|
Yeah, exactly. Although I'm not sure your statistics for hits are correct though — It's possible that all of the |
On Darwin, all of our Nix library references are absolute by default, even though we do use rpath in some places. Just FYI for "prior art" 😄 |
No! Now I can't patent the technique ;-) |
I wrote a WIP patch for haskellPackages, using @dezgeg’s patch for It fails because of broken ELF binaries, though. Probably a bug in the patchelf |
FWIW this would break this hack for changing freetype behaviour — at least in its current form. It should of course still work using |
The primary approach for implementing this should probably be making libraries and executables link with the absolute paths from the get-go rather than patching them post-hoc, right? Does anyone know how this would be done? |
I experimented with that a few days in April; the GNU linker describes how it will skip search heuristics if it finds absolute paths in the ELF header. |
One advantage for a fixup-phase approach: it should work even on binary packages. (Though I personally don't consider that a significant pro.) |
It's certainly more versatile, but it still feels wrong: why compile something the wrong way then fix it rather than compiling it right in the first place? |
I understand that sentiment, but if our default linker doesn't allow it, we'd have to patch the linker to add this (optional) functionality, I guess, and that feels rather cumbersome to maintain. (not mentioning the additional complications if someone wants to use a different linker, etc.) Still, it's possible the other option won't turn out easy either. |
As for doing it w/o fixup, I think we can replace Shouldn't be too much trouble since we already have misc support for basically gathering all the "-L" paths and locating each library anyway. FWIW a quick look into this particular issue leads to these relevant discussions: catkin discussion Doing this with a fixup sounds good to me as well, maybe give both a try? EDIT: Absolute path for (Err I suppose this "only" happened because I also removed all "-L" switches.) |
I don't think passing absolute paths to |
@ben0x539 seems to for me? Here's a quick test: with import <nixpkgs> {};
rec {
foo = stdenv.mkDerivation {
name = "libfoo";
buildCommand = ''
echo "int foo() { return 5; }" >> foo.c
cc foo.c -o libfoo.so -shared
mkdir -p $out/lib
mv libfoo.so $out/lib
'';
};
main = stdenv.mkDerivation {
name = "abspath-test";
buildInputs = [ foo ];
buildCommand = ''
cat >>main.c <<EOF
#include <stdio.h>
int foo();
int main() {
printf("foo: %d\n", foo());
return 0;
}
EOF
cc main.c -o main -lfoo
mkdir -p $out/bin
mv main $out/bin/
'';
};
main-abs = stdenv.mkDerivation {
name = "abspath-test";
buildInputs = [ foo ];
buildCommand = ''
cat >>main.c <<EOF
#include <stdio.h>
int foo();
int main() {
printf("foo: %d\n", foo());
return 0;
}
EOF
cc main.c -o main ${foo}/lib/libfoo.so
mkdir -p $out/bin
mv main $out/bin/
'';
};
} $ nix-build -A main -o main
$ nix-build -A main-abs -o main-abs
$ readelf -d main/bin/main
Dynamic section at offset 0xde8 contains 25 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libfoo.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [/nix/store/nirdkvlp2wim11mh0fj0bbpmdq6m5rg4-abspath-test/lib64:/nix/store/nirdkvlp2wim11mh0fj0bbpmdq6m5rg4-abspath-test/lib:/nix/store/my9f454r82wy6jv3x7bvvpx6hffcahsj-gcc-5.4.0/libexec/gcc/x86_64-unknown-linux-gnu/5.4.0:/nix/store/h6np4yvv6j7qcp3ikh4gcgj49zgjsb7n-libfoo/lib:/nix/store/7crrmih8c52r8fbnqb933dxrsp44md93-glibc-2.25/lib:/nix/store/89bjrnjb8c9vvhzb92fz832x6fwg3kbj-gcc-5.4.0-lib/lib]
0x000000000000000c (INIT) 0x4006c8
0x000000000000000d (FINI) 0x4008a4
0x0000000000000019 (INIT_ARRAY) 0x600dd0
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x600dd8
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x0000000000000004 (HASH) 0x4002e0
0x0000000000000005 (STRTAB) 0x400410
0x0000000000000006 (SYMTAB) 0x400320
0x000000000000000a (STRSZ) 528 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x600fc8
0x0000000000000007 (RELA) 0x400668
0x0000000000000008 (RELASZ) 96 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW
0x000000006ffffffe (VERNEED) 0x400638
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x400620
0x0000000000000000 (NULL) 0x0
$ readelf -d main-abs/bin/main
Dynamic section at offset 0xde8 contains 25 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [/nix/store/h6np4yvv6j7qcp3ikh4gcgj49zgjsb7n-libfoo/lib/libfoo.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [/nix/store/2x61jy86dxzzyp88vah6hk1s0556bx1z-abspath-test/lib64:/nix/store/2x61jy86dxzzyp88vah6hk1s0556bx1z-abspath-test/lib:/nix/store/my9f454r82wy6jv3x7bvvpx6hffcahsj-gcc-5.4.0/libexec/gcc/x86_64-unknown-linux-gnu/5.4.0:/nix/store/h6np4yvv6j7qcp3ikh4gcgj49zgjsb7n-libfoo/lib:/nix/store/7crrmih8c52r8fbnqb933dxrsp44md93-glibc-2.25/lib:/nix/store/89bjrnjb8c9vvhzb92fz832x6fwg3kbj-gcc-5.4.0-lib/lib]
0x000000000000000c (INIT) 0x400700
0x000000000000000d (FINI) 0x4008e4
0x0000000000000019 (INIT_ARRAY) 0x600dd0
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x600dd8
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x0000000000000004 (HASH) 0x4002e0
0x0000000000000005 (STRTAB) 0x400410
0x0000000000000006 (SYMTAB) 0x400320
0x000000000000000a (STRSZ) 583 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x600fc8
0x0000000000000007 (RELA) 0x4006a0
0x0000000000000008 (RELASZ) 96 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW
0x000000006ffffffe (VERNEED) 0x400670
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x400658
0x0000000000000000 (NULL) 0x0 |
Exploring the idea of doing this by modifying ld-wrapper in this branch. YMMV, let's see if this gets an absolute-path-linked gcc :). I'd feel better if we had a fixup phase regardless, to either catch and abort if things aren't absolute or to handle cases missed for whatever reason. Currently I'm handling Or maybe just doing it all in the fixup phase would be simpler? (Especially if a fixup phase is used anyway...?) Update: branch currently gets mostly through gcc, but dies when it attempts to link against a shared object when Solving this with a fixup has the appeal of being straightforward to implement, and as @vcunat mentioned would work on pre-compiled binaries as well. |
... right, I was just using some random existing .so file and that had
the SONAME set, so it was linked by that rather than path. Whoops.
Thanks for clarifying!
…On Sat, 2017-06-24 at 10:36 -0700, Will Dietz wrote:
@ben0x539 seems to for me? Here's a quick test:
```
with import <nixpkgs> {};
rec {
foo = stdenv.mkDerivation {
name = "libfoo";
buildCommand = ''
echo "int foo() { return 5; }" >> foo.c
cc foo.c -o libfoo.so -shared
mkdir -p $out/lib
mv libfoo.so $out/lib
'';
};
main = stdenv.mkDerivation {
name = "abspath-test";
buildInputs = [ foo ];
buildCommand = ''
cat >>main.c <<EOF
#include <stdio.h>
int foo();
int main() {
printf("foo: %d\n", foo());
return 0;
}
EOF
cc main.c -o main -lfoo
mkdir -p $out/bin
mv main $out/bin/
'';
};
main-abs = stdenv.mkDerivation {
name = "abspath-test";
buildInputs = [ foo ];
buildCommand = ''
cat >>main.c <<EOF
#include <stdio.h>
int foo();
int main() {
printf("foo: %d\n", foo());
return 0;
}
EOF
cc main.c -o main ${foo}/lib/libfoo.so
mkdir -p $out/bin
mv main $out/bin/
'';
};
}
```
|
Somebody else should take a look at it first, I might have overlooked a flag with |
This comment has been minimized.
This comment has been minimized.
no, bad bot |
Why not apply @dezgeg 's |
iirc it had some bug that either crashed patchelf itself or caused the resulting executables to crash (can't remember which). That said, that is my preferred approach — the patch just needs fixing, which is what I'll have a look at doing (see #45105) unless someone else beats me to it. |
I'm working with a small loader without support for RPATH so I've tried patching Clang to resolve libraries to absolute paths before linking, but LLD somehow unresolves them to filenames. Even if it did work, patching during fixupPhase is still probably the most robust solution because there tools can distinguish between temporary paths and permanent store paths. EDIT: This behavior is stupid easy to patch in LLVM LLD: ehmry/llvm-project@796dbd9 |
This issue has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/genodepkgs-extending-nixpkgs-nixos-to-genode/8779/2 |
This issue has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/lots-of-libraries-cant-be-found/11670/2 |
BTW, replacing short library names with full paths across nixpkgs isn't feasible until this is fixed: NixOS/patchelf#244. |
I marked this as stale due to inactivity. → More info |
Definitely not stale. |
I like the absolute paths solution better because the loader caches duplicate dependency information every time they are included. But the loader cache is probably less effort to maintain than a new ELF format. Maybe the solution is to make a new loader cache format that allows recursive loading. |
NixOS/patchelf#357 implements this |
If this lands it would be huge. |
still relevant |
See also https://stoppels.ch/2022/08/04/stop-searching-for-shared-libraries.html for a simple(r) solution |
Using absolute paths in sonames was discussed above. I'm personally not convinced that we should use that (by default); I fear it would be much more trouble than worth. |
My system has a slow HD and it takes forever to open applications. I'm pretty sure it's due to this issue. So IMO it's worth the trouble to figure out some solution to the "stat storm". |
@Mathnerd314 I think we all agree that it would be great to fix it. It's just tricky :/ |
In the Spack package manager we now enable this feature under a config flag. |
This issue has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/tweag-nix-dev-update-40/23480/3 |
Issue description
echo
's dynamic section currently looks like this...Because we don't have any caching as far as I understand, this means that when echo is run, a whole lot of fairly superfluous system calls are made:
This issue is more pronounced for programs that link to lots of libraries, as the linker will go through the RPATH for each library linked to. As far as I understand it, the
DT_NEEDED
entries in the dynamic relocation section could contain absolute paths, which would reduce the amount of searching necessary. Additionally, this ties the library reference more closely to the derivation's build inputs.Any thoughts? I haven't got any hard data on the performance impact this has (though the fact that most distros use the ld.so.cache mechanism to speed up loading suggests that it is relevant at least in some contexts), or any idea what other consequences of using absolute paths would be, but having executable loading be O(n²) for the number of referenced store components just somewhat bothers me.
Technical details
The text was updated successfully, but these errors were encountered: