Переопределение malloc / free со статическим связыванием имеет многократную ошибку определения - PullRequest
7 голосов
/ 07 апреля 2011

В последнее время моя компания хочет обновить компилятор с gcc-3.4 до gcc-4.5.Однако машина нашего клиента может не иметь обновленной libstdc++.so, поэтому мы хотим статически связать наш двоичный файл.

Нашей программе необходимо настроить malloc()/free() для очень высокой производительности.

Я изменил make-файл, добавил -static во время компоновки и получил следующее сообщение об ошибке:

/usr/lib64/libc.a(malloc.o)(.text+0x18c0): In function `free':
: multiple definition of `free'
../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o)(.text+0x3430): first defined here
/usr/bin/ld: Warning: size of symbol `free' changed from 271 in ../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o) to 255 in /usr/lib64/libc.a(malloc.o)
/usr/lib64/libc.a(malloc.o)(.text+0x3970): In function `malloc':
: multiple definition of `malloc'
../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o)(.text+0x29c0): first defined here
/usr/bin/ld: Warning: size of symbol `malloc' changed from 281 in ../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o) to 461 in /usr/lib64/libc.a(malloc.o)
/usr/lib64/libc.a(malloc.o)(.text+0x4050): In function `realloc':
: multiple definition of `realloc'
../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o)(.text+0x3e80): first defined here
/usr/bin/ld: Warning: size of symbol `realloc' changed from 335 in ../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o) to 927 in /usr/lib64/libc.a(malloc.o)

Хорошо, это разумно, поскольку libc.a уже имеет malloc()/free().

Но что меня смущает, так это то, что при динамическом линковании нет ошибок.Я искал и нашел этот вопрос: Как переопределить malloc () в Linux для использования в C ++ new .В ответе говорится, что компоновщик по-разному относится к файлу библиотеки (.a) и объектному файлу (.o).Теперь я знаю причину, по которой ошибка возникает при статическом связывании, а не при динамическом.

Однако я попробовал решение, описанное в этом ответе, заменил библиотечный файл на объектный файл напрямую, но разницы нет.Я все еще получил ошибку связывания множественного определения.Я также попробовал -static-libgcc (потому что я не знаю, что делать, я просто попробовал все, что видел на gcc man-странице), но это тоже не помогает.

Мне не нужно использоватьстатическое связывание.Я просто хочу решить проблему с версией libstdc++.so.Будем благодарны за любые предложения.

Заранее спасибо.

edit: Извините, я не прояснил себя.Использование #define malloc ... может не помочь здесь.Так как наша программа на C ++.Идиома #define может воздействовать только на функцию malloc()/free().Но наша программа активно использует new/delete для выделения / освобождения памяти.Все равно спасибо: D

Ответы [ 6 ]

5 голосов
/ 10 апреля 2011

Если вашей главной заботой является наличие libstdc ++. Поэтому в целевой системе, то почему бы просто не распространить более новую версию этого вместе с вашим приложением?

Я думаю, что статическое связывание в любом случае не является хорошим решением, компиляция проекта становится намного сложнее, и если вы сами используете общие объекты (например, при использовании собственных плагинов), тогда статическое связывание просто перестанет работать, поскольку отдельная копия статической библиотеки должна быть связана с каждым ваших двоичных файлов, исполняемых файлов и тому подобного. И можете ли вы представить, что произойдет, если в одной и той же программе будет несколько экземпляров глобальных переменных, блокировок и т. Д. При загрузке? Я скажу вам: вылетает.

Так что не статическая ссылка, скопируйте libstdc ++. Так в личный каталог (я не знаю, где установлено ваше приложение, но если у него есть личный префикс, это довольно просто, используйте $ prefix / lib).

Затем либо установите LD_LIBRARY_PATH, либо используйте -rpath для кодирования пути в двоичном файле, чтобы компоновщик его нашел. Конечно, это означает, что все библиотеки, с которыми вы ссылаетесь и которые могут использовать libstdc ++, также должны распространяться вместе с вашим приложением.

Но по размеру, это примерно то же самое, со статической связью, вы бы также носили этот код.

3 голосов
/ 10 апреля 2011

Вы можете использовать динамическое связывание с rpath . Смотрите "man ld" и "man ld.so".

Расширение $ ORIGIN может быть полезным: свяжите каждый .so, который вам нужен, в тот же каталог, что и программа (или подкаталог), и используйте «-rpath $ ORIGIN» или «-rpath, $ ORIGIN / lib» при компоновке с лд.

Многие программы используют этот подход для объединения своих собственных библиотек.

Другой способ - использовать скрипт .sh для установки LD_LIBRARY_PATH, а затем вызвать настоящую программу (скачайте бинарный файл firefox и посмотрите на run-mozilla.sh). Однако LD_LIBRARY_PATH просочится в подпроцессы. Так что он не такой чистый, но, вероятно, более переносимый для систем без GNU.

2 голосов
/ 07 апреля 2011

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

например

void* myProject_malloc(...)
void myProject_free()

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

#define malloc(x) myProject_malloc(x)
#define free() myProject_free()

Если вы не хотите использовать стандартную библиотеку, вы должны использовать опцию gcc: "-nostdlib". Но если вы сделаете это, вы не сможете использовать любую другую функцию стандартной библиотеки.

1 голос
/ 10 апреля 2011

Использование может использовать GNU malloc Hooks , если вы используете GNU libc.Я не очень доволен дизайном этого API, поэтому я не рекомендую использовать его.

Вы можете попробовать исправить libc.Удалите весь код в malloc/ и замените его своей реализацией.

Используя ту же идею, вы можете попытаться взять libc.a, удалить все файлы .o, содержащие malloc и друзей (это должны быть в основном все файлы .o, соответствующие malloc/*.c) и перепаковать libc.a с вашей реализацией.

0 голосов
/ 10 апреля 2011

Если вам нужно сделать это только для C ++, вы можете переопределить операторы new, delete, new [], delete [].См. 18.6.1 «Распределение и освобождение хранилища»

  void* operator new(std::size_t size);
  [...]
  void operator delete(void* ptr);

«Заменяемый: программа на C ++ может определить функцию с этой сигнатурой функции, которая заменяет версию по умолчанию, определенную стандартной библиотекой C ++.»

Однако я не знаю, работает ли он со статической связью (не знаю, как она реализована).

0 голосов
/ 07 апреля 2011

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

#define malloc myMalloc
#define free myFree
...