1001 * Предпосылки *
Сторонний поставщик C ++ предоставил исполняемый файл fooapp
, в котором используется общий объект libfoo.so
. Библиотека также поставляется с заголовком foo.hpp
, поэтому разработчики могут создавать другие приложения:
/* foo.hpp */
namespace foo {
void bar(int a, int b);
// More code below here <--- NOTE!!!
}
Пример успеха
Это стандартный рабочий процесс наложения функций LD_PRELOAD
.
Сначала я пишу свою собственную версию библиотеки myfoo.cpp
, которая точно отражает часть foo.hpp
:
/* myfoo.hpp */
# include <ofstream>
namespace foo {
void bar(int a, int b) {
std::cout << a << "," << b << std::endl;
}
// NOTHING below here <-- NOTE!!!
}
Затем я компилирую свою библиотеку в libmyfoo.so
и вижу следующее:
$ nm libfoo.so -C | fgrep bar
0000000000021fc0 T foo::bar(int, int)
$ nm libmyfoo.so -C | fgrep bar
0000000000010c30 T foo::bar(int, int)
$ LD_DEBUG=bindings LD_DEBUG_OUTPUT=ld_debug.log LD_PRELOAD=./libmyfoo.so fooapp
Успех! ld_debug.log
показывает привязку, как и ожидалось, и bar(...)
генерирует вывод на консоль.
Пример отказа
В примере с ошибкой я собираюсь (1) изменить один символ в myfoo.hpp
и (2) затем исправить этот символ в двоичном коде, используя objcopy
:
/* myfoo.hpp */
# include <ofstream>
namespace foq { // <-- NAME CHANGE!
void bar(int a, int b) {
std::cout << a << "," << b << std::endl;
}
// NOTHING below here <-- NOTE!!!
}
Когда я компилирую свою библиотеку в libmyfoq.so
, я вижу следующее:
$ nm libfoo.so -C | fgrep bar
0000000000021fc0 T foo::bar(int, int) # <-- Sames as before
$ nm libmyfoq.so -C | fgrep bar
0000000000010c30 T foq::bar(int, int) # <-- New name as expected
$ objcopy --redefine-syms=sym.map libmyfoq.so libmyfoo.so # <-- NEW STEP!
$ nm libmyfoo.so -C | fgrep bar
0000000000010c30 T foo::bar(int, int) # <-- SUCCESSful name update
$ LD_DEBUG=bindings LD_DEBUG_OUTPUT=ld_debug.log LD_PRELOAD=./libmyfoo.so fooapp
Ошибка! ld_debug.log
показывает NO привязку fooapp
символов к libmyfoo.so
.
(PS - Если вам интересно, sym.map
содержит отображение между искаженным именем foq::bar
и искаженным именем foo::bar
. Это можно увидеть, если вы уроните -C
из * Команда 1055 *. Подробнее см. man objcopy
.)
Почему?
В итоге:
objcopy
правильно переименовывает символ.
- Имя символа не изменилось в размере.
- НО загрузчик игнорирует его во время загрузки.
Что за история здесь?