aboutsummaryrefslogtreecommitdiff
path: root/notes/libc_support.txt
blob: b8317f1175555e78bd979ba7e34b154f52bc4496 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

Detecting the default/host libc
-------------------------------
Method 0:
Check using #ifdef at compile-time
- Problem: musl cannot be detected this way, so a fallback is required.

The easiest way to do this is probably at *runtime*.

Method 1:
Just check at list of hard-coded libc's, and if there's only one
available, it can be selected.
- Problem: it's unreliable (the libc might be missing and/or
  cross-compilation libc's might confuse the compiler)

Method 1b:
Use dlopen to figure out the libc.
* dlopen("libxxx.so", RTLD_NOLOAD) will return NULL if absent.
  That can be used for probing.
* dlopen(NULL, ???) will return a handle to the main executable.
  That can be used with dlinfo to get the "link map" which in
  turn contains the mapping libraries.
  (there's also dl_iterate_phdr, which is simpler, but not standardized)
- Problem: Neither of these ways will work from a static binary.

Method 2:
Check process mappings or similar.
Can do getauxval(AT_BASE) to get the base address of ldso/rtld.
- Problem 1: Doesn't work with dynamic linking. Need to fall back to method 1
  in that case.
- Problem 2: It's a non-standard glibc extension.
  (but apparently it is also available in /proc/pid/auxv)
- Problem 3: It's a non-standard Linux thing.
- This can also be used to get the "platform", AT_PLATFORM

Method 3: (best?)
List the symlinks in /proc/self/map_files and check for a known libc.
- Problem 1: It's probably Linux-specific.
- Problem 2: /proc might not be mapped

Method 4:
Read PT_INTERP from /proc/self/exe.
- Problem 1: /proc might not be mapped

Method 5:
Read PT_INTERP from /bin/true.
- Problem: Will fail on a multiarch system where the compiler is running
  as the "non-main" arch.

Method 6:
Check files in /etc:  ld.so.cache, ld.so.conf, ld-musl* ...

However, I don't think there's any portable way of using method 2, so
this means that musl cannot be reliably detected at all (since it also
lacks #defines). Maybe it could be the default if nothing else can be
detected, though.

Alternative solutions
---------------------

* Fall back to system linker if libc cannot be detected
* Have a configuration file, and let the user specify the default target.
* Trial an error! Try to build and then run some executable
  (could give false positives if binfmt (on Linux) or
   Linux emulation (on BSD) is enabled).