Не очень понятно (для меня), почему ограничение ( libm.a + libc.so ) необходимо, поэтому оно пахнет как XY Проблема .
Согласно [RedHat.Bugzilla]: Ошибка 1433347 - glibc: Селективное статическое связывание libm.a завершается неудачно из-за неразрешенного символа _dl_x86_cpu_features (на который указывает @KamilCuk):
Это не поддерживается.
Вы бы смешали статический libm.a с будущими libc.so.6 и ld.so, и это нарушит взаимозависимости между базовыми библиотеками, которые образуют «реализацию среды выполнения C».
Либо вся реализация среды выполнения статически связана, либо ни одна из них не является статически связанной. Вы не можете связывать его части статически, а не другие, потому что каждая часть зависит от другой, чтобы сформировать полную реализацию. Математическая библиотека - не то, что можно статически связать, бывает, что у нас есть libm.a, но это деталь реализации.
Пожалуйста, используйте '-static' для всего приложения.
похоже, что это неподдерживаемая конфигурация. Это имеет смысл, но это также немного сбивает с толку: даже если libc и libm являются 2 отдельными файлами на диске (для каждой конфигурации: static , shared ), они являются частью одной библиотеки ( g libc ), поэтому:
- Это не ОК использовать половину статически построенной библиотеки, а другую половину как общий объект (некоторые вещи, которые приходят мне в голову: gcc -fPIC флаг, а также инициализация библиотеки)
- Конечно, в большинстве случаев библиотека состоит из одного файла , поэтому вышеупомянутый пункт не будет применяться (отсюда и путаница)
С самого начала я подозревал, что это некоторый код, который (обнаруживает и) использует (если присутствует) некоторые возможности CPU (скорее всего, для повышения скорости или точности), что:
- Используется только некоторыми (тригонометрическими) функциями (например, sin , cos , но not tanh ) - I Я просто догадываюсь здесь: на основе того, как вычисляются значения функции (например, ряд Тейлора )
- Это происходит только тогда, когда libc ( libm ) синхронизированы
Я использовал эту простую программу.
main.c
#include <stdio.h>
#include <math.h>
#if !defined(FUNC)
# define FUNC sqrt
#endif
int main() {
double val = 3.141592;
printf("func(%.06lf): %.06lf\n", val, FUNC(val));
return 0;
}
Ниже приведен ряд шагов, которые я выполнил при рассмотрении проблемы:
Окружающая среда:
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q056415996]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
[prompt]> uname -a
Linux cfati-ubtu16x64-0 4.15.0-51-generic #55~16.04.1-Ubuntu SMP Thu May 16 09:24:37 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
[prompt]> gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[prompt]> ldd --version
ldd (Ubuntu GLIBC 2.23-0ubuntu11) 2.23
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
[prompt]> ls
main.c
Случай, когда 2 библиотечные части ( libc и libm ) синхронизированы:
[prompt]> gcc -fPIC main.c -DFUNC=sin -o sin_static.out -static -lm
[prompt]> ll sin_static.out
-rwxrwxr-x 1 cfati cfati 1007744 Jun 13 20:08 sin_static.out
[prompt]> ldd sin_static.out
not a dynamic executable
[prompt]> ./sin_static.out
func(3.141592): 0.000001
[prompt]>
[prompt]> gcc -fPIC main.c -DFUNC=sin -o sin_mso.out -l:libm.so
[prompt]> ll sin_mso.out
-rwxrwxr-x 1 cfati cfati 8656 Jun 13 20:09 sin_mso.out
[prompt]> ldd sin_mso.out
linux-vdso.so.1 => (0x00007ffc80ddd000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f999636b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9995fa1000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9996674000)
[prompt]> ./sin_mso.out
func(3.141592): 0.000001
Все отлично работает в обоих случаях.
Переключиться на libm.a (для sin и tanh ):
[prompt]> gcc -fPIC main.c -DFUNC=sin -o sin_ma.out -l:libm.a
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libm.a(s_sin.o): In function `__cos':
(.text+0x3542): undefined reference to `_dl_x86_cpu_features'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libm.a(s_sin.o): In function `__sin':
(.text+0x3572): undefined reference to `_dl_x86_cpu_features'
collect2: error: ld returned 1 exit status
[prompt]> ll sin_ma.out
ls: cannot access 'sin_ma.out': No such file or directory
[prompt]>
[prompt]> gcc -fPIC main.c -DFUNC=tanh -o tanh_ma.out -l:libm.a
[prompt]> ll tanh_ma.out
-rwxrwxr-x 1 cfati cfati 12856 Jun 13 20:10 tanh_ma.out
[prompt]> ldd tanh_ma.out
linux-vdso.so.1 => (0x00007ffcfa531000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f124625c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1246626000)
[prompt]> ./tanh_ma.out
func(3.141592): 0.996272
Как видно:
- Для sin , компоновщик жаловался (даже без -fno-builtin )
- Для Тан все прошло хорошо
С этого момента я собираюсь сосредоточиться на случае, который не работает .
Поиграть немного с флагами компоновщика (man ld
( [die.linux]: ld (1) - Страница man Linux )):
[prompt]> gcc -fPIC main.c -DFUNC=sin -o sin_ma_undefined.out -l:libm.a -Wl,--warn-unresolved-symbols
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libm.a(s_sin.o): In function `__cos':
(.text+0x3542): warning: undefined reference to `_dl_x86_cpu_features'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libm.a(s_sin.o): In function `__sin':
(.text+0x3572): warning: undefined reference to `_dl_x86_cpu_features'
[prompt]> ll sin_ma_undefined.out
-rwxrwxr-x 1 cfati cfati 104088 Jun 13 20:10 sin_ma_undefined.out
[prompt]> ldd sin_ma_undefined.out
linux-vdso.so.1 => (0x00007fff984b0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f274ad00000)
/lib64/ld-linux-x86-64.so.2 (0x00007f274b0ca000)
[prompt]> ./sin_ma_undefined.out
Segmentation fault (core dumped)
Он прошел фазу соединения, но segfault ed во время выполнения (что было отчасти ожидаемо).
Обнаружено [Amper.Git]: с открытым исходным кодом / glibc - Добавить _dl_x86_cpu_features в rtld_global (обратите внимание, что нет из этого в официальный glibc : [GNU]: индекс / gnu / libc ). Там довольно тяжелые вещи. Я "одолжил" некоторые и сохранил их.
_dl_x86_cpu_features.c
#if defined(_DL_X86_CPU_FEATURES__WORKAROUND)
# define FEATURE_INDEX_MAX 1
enum {
COMMON_CPUID_INDEX_1 = 0,
COMMON_CPUID_INDEX_7,
COMMON_CPUID_INDEX_80000001, // for AMD
// Keep the following line at the end.
COMMON_CPUID_INDEX_MAX
};
struct cpu_features {
enum cpu_features_kind {
arch_kind_unknown = 0,
arch_kind_intel,
arch_kind_amd,
arch_kind_other
} kind;
int max_cpuid;
struct cpuid_registers {
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
} cpuid[COMMON_CPUID_INDEX_MAX];
unsigned int family;
unsigned int model;
unsigned int feature[FEATURE_INDEX_MAX];
};
struct cpu_features _dl_x86_cpu_features;
#endif
#include "_dl_x86_cpu_features.c"
также необходимо добавить в main.c :
[prompt]> gcc -fPIC main.c -DFUNC=sin -D_DL_X86_CPU_FEATURES__WORKAROUND -o sin_ma_workaround.out -l:libm.a
[prompt]> ll sin_ma_workaround.out
-rwxrwxr-x 1 cfati cfati 104088 Jun 13 20:13 sin_ma_workaround.out
[prompt]> ldd sin_ma_workaround.out
linux-vdso.so.1 => (0x00007fff17b6c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5a992e5000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5a996af000)
[prompt]> ./sin_ma_workaround.out
func(3.141592): 0.000001
Видимо, работает (по крайней мере, в моей среде) !!!
Хотя для меня это и помогло (и, вероятно, в вашем случае так будет), я все же считаю это обходным путем ( gainarie ), а Я неосознавая все последствия .
Итак, я советую придерживаться (любого из) рекомендуемых вариантов (с шага # 2. ).
Но было бы интересно посмотреть, как ведут себя другие компиляторы.