добавление -rpath,/usr/lib в параметры сборки разделяемой библиотеки вызывает segfault

У меня есть программа привет мир.

#include <stdio.h>
#include <stdlib.h>

int main()
{
    printf("hello world! \n");
    return 0;
}

Я добавляю -lmicroxml в сборку программы на этапе линковки, чтобы линковать библиотеку libmicroxml.so

когда я запускаю свою программу, я получаю ошибку сегментации. ошибка сегментации связана с нагрузкой на libmicroxml.so. здесь после выполнения моей программы helleo world:

 strace ./test
execve("./test", ["./test"], [/* 11 vars */]) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x777de000
stat("/etc/ld.so.cache", 0x7f944760)    = -1 ENOENT (No such file or directory)
open("/lib/libmicroxml.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/lib/libmicroxml.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/libmicroxml.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=4129, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x777dd000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0\4p\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 69632, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x777b3000
old_mmap(0x777b3000, 1572, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x777b3000
old_mmap(0x777c3000, 1648, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x777c3000
close(3)                                = 0
munmap(0x777dd000, 4096)                = 0
open("/lib/libgcc_s.so.1", O_RDONLY)    = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=78232, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x777dd000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0006\320\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 147456, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7778f000
old_mmap(0x7778f000, 76928, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x7778f000
old_mmap(0x777b2000, 408, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x13000) = 0x777b2000
close(3)                                = 0
munmap(0x777dd000, 4096)                = 0
open("/lib/libc.so.0", O_RDONLY)        = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=413076, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x777dd000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0\253`\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 503808, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x77714000
old_mmap(0x77714000, 405592, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x77714000
old_mmap(0x77787000, 7572, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x63000) = 0x77787000
old_mmap(0x77789000, 21036, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x77789000
close(3)                                = 0
munmap(0x777dd000, 4096)                = 0
open("/usr/lib/libgcc_s.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=169712, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x777dd000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0\307\220\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 237568, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x776da000
old_mmap(0x776da000, 169036, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x776da000
old_mmap(0x77713000, 1776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x29000) = 0x77713000
close(3)                                = 0
munmap(0x777dd000, 4096)                = 0
open("/usr/lib/libc.so.0", O_RDONLY)    = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=425968, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x777dd000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0\267`\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 516096, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7765c000
old_mmap(0x7765c000, 418924, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x7765c000
old_mmap(0x776d2000, 8176, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x66000) = 0x776d2000
old_mmap(0x776d4000, 21784, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x776d4000
close(3)                                = 0
munmap(0x777dd000, 4096)                = 0
open("/lib/libc.so.0", O_RDONLY)        = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=413076, ...}) = 0
close(3)                                = 0
stat("/lib/ld-uClibc.so.0", {st_mode=S_IFREG|0755, st_size=28976, ...}) = 0
open("/lib/libc.so.0", O_RDONLY)        = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=413076, ...}) = 0
close(3)                                = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x777dd000
set_thread_area(0x777e4440)             = 0
mprotect(0x77787000, 4096, PROT_READ)   = 0
mprotect(0x776d2000, 4096, PROT_READ)   = 0
mprotect(0x777da000, 4096, PROT_READ)   = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
Segmentation fault

В сборке библиотеки libmicroxml я обнаружил, что они используют DSOFLAGS=-Wl,-soname,libmicroxml.so.1,-rpath,/usr/lib -shared -fPIC в сборке библиотеки (на этапе компоновки).

Я удалил -rpath,/usr/lib из вариантов, поэтому новый DSOFLAGS=-Wl,-soname,libmicroxml.so.1 -shared -fPIC

Затем я пересобрал библиотеку, а затем запустил программу hello world, и ошибка сегментации исчезла.

Я строю с mips_gcc-4.6-linaro_uClibc-0.9.33.2

Эта проблема не воспроизводится с моим старым gcc mips_gcc-4.3.3+cs_uClibc-0.9.30.1

Может ли кто-нибудь объяснить, почему удаление -rpath,/usr/lib из параметров компоновки устраняет segfault при загрузке библиотеки?


person MOHAMED    schedule 11.10.2013    source источник
comment
<pedantic> main не возвращает int </pedantic>   -  person Kninnug    schedule 11.10.2013
comment
@Kninnug это не причина моей проблемы. в любом случае я добавил возврат к моей основной функции   -  person MOHAMED    schedule 11.10.2013
comment
каков результат поиска libmicroxml.so на вашем ПК?   -  person stdcall    schedule 13.10.2013
comment
@MOHAMED Убедитесь, что если вы укажете -rpath,/usr/lib, что у вас есть файлы или библиотеки для загрузки оттуда, и файлы существуют, stackoverflow.com/questions/6562403/ (Мир и процветание для Туниса)   -  person Mehdi Karamosly    schedule 19.10.2013


Ответы (2)


Судя по трассировке, ваша программа загружает разные двоичные файлы одних и тех же модулей, которые должны иметь одну и ту же версию:

/lib/libc.so.0 (размер: 413076 байт) по сравнению с /usr/lib/libc.so.0 (размер: 425968 байт).

/lib/libgcc_s.so.1 (размер: 78232 байта) по сравнению с /usr/lib/libgcc_s.so.1 (размер: 169712 байт).

Вероятно, это происходит из-за того, что когда вы используете -rpath в ссылке на модуль, вы заставляете его загружать модули из /usr/lib, но путь поиска по умолчанию, который использует ваша программа, — /lib (согласно документации dlopen по адресу http://tldp.org/HOWTO/Program-Library-HOWTO/dl-libraries.html).

Итак: Ваша программа загружает /usr/lib/libmicroxml.so.1 (обратите внимание, что она не смогла найти /lib/libmicroxml.so.1, хотя сначала искала этот путь). Затем он продолжает загружать требуемые модули (libgcc и libc) из /lib, и, наконец, поскольку libmicroxml требует загрузки этих модулей из /usr/lib (из-за предоставленных аргументов сборки), они также загружаются из этого пути.

Когда у вас есть две разные библиотеки с одинаковым именем и интерфейсом (поскольку они имеют одну и ту же версию), загруженные вместе, вы не можете знать, какая версия какой функции вызывается, и это может привести к несоответствиям.

Я думаю, вы можете решить это либо так, как вы это сделали, либо добавив тот же аргумент -rpath в сборку вашей программы.

Причина, по которой удаление -rpath решает эту проблему, заключается в том, что при загрузке необходимых модулей для libmicroxml загрузчик сначала ищет /lib в качестве первого каталога по умолчанию (поскольку другой каталог не был указан), и поскольку модули в этой папке уже загружены, конфликта нет.

В любом случае, ситуация с двумя разными двоичными файлами для одного и того же модуля с одной и той же версией на одном диске очень вредна для здоровья.

Что касается версии GCC, я могу только предположить, что правильная libc или libgcc использовалась (или даже устанавливалась) с предыдущим GCC и была заменена более новой GCC, но я не смог найти документацию, подтверждающую это.

person Asaf    schedule 13.10.2013

Ваш DSOFLAGS выглядит так:

DSOFLAGS=-Wl,-soname,libmicroxml.so.1,-rpath,/usr/lib -shared -fPIC

Вы пробовали компилировать так?

gcc -L/usr/lib -Wl,-rpath=/usr/lib -Wall -o test main.c -lmicroxml

Затем вы можете использовать эту строку, а также CC и CFLAGS в Makefile, чтобы упростить компиляцию, если вы можете скомпилировать ее таким образом. Есть еще несколько способов связать.

Полезная информация по этой ссылке.

person ciphermagi    schedule 19.10.2013