Ошибка связывания с objcopy --redefine-syms - PullRequest
0 голосов
/ 23 января 2019

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 правильно переименовывает символ.
  • Имя символа не изменилось в размере.
  • НО загрузчик игнорирует его во время загрузки.

Что за история здесь?

1 Ответ

0 голосов
/ 29 января 2019

ПОЧЕМУ? Что за история здесь?

objcopy -redefine-syms будет переопределять только символы отладки в таблицах символов .symtab и .strtab, а не символы в таблицах символов .dynsym и .dynstr, которые используются для динамической загрузки.

Если вы изучите библиотеку, созданную с помощью objcopy с помощью nm -D или readelf -s, вы увидите, что имя, используемое динамическим загрузчиком, по-прежнему _ZN3foq3barEii или с nm -DC, foq::bar(int, int).

Итак, вот что происходит.

Наиболее официальные ссылки, которые я смог найти, свидетельствующие о том, что objcopy не может использоваться для обновления динамических символов, - это неназначенная запись bugzilla с 2010 года:

Ошибка 11386 - objcopy должен иметь возможность обновлять динамическую видимость символов

И мой собственный запрос в официальном binutils списке рассылки:

Переопределение динамических символов


Как примечание, я не думаю, что есть инструмент для переопределения динамических символов (правильно), но я могу ошибаться.

Проект 2015 года cjacker / elfhash , похоже, делает попытку. Я попробовал это, и похоже, что он на самом деле переименовал имя динамического символа - но загрузка .so впоследствии не удалась, и вместо него использовался оригинальный символ libs.

% elfhash -f _ZN3foq3barEii -t _ZN3foo3barEii libmyfoq.so
% mv libmyfoq.so libmyfoo.so
% LD_DEBUG=bindings LD_DEBUG_OUTPUT=ld_debug.log LD_PRELOAD=./libmyfoo.so ./fooapp
ERROR: ld.so: object './libmyfoo.so' from LD_PRELOAD cannot be preloaded (cannot change memory protections): ignored.
...