Что такое утилита Linux для искажения имени символа C++?

Я имею c++filt команда, чтобы разобрать символ, что инструмент, чтобы сделать противоположное и искажать имя символа?

Это было бы полезно, если бы я хотел позвонить dlsym() на искаженном имени функции C++. Я бы предпочел не жестко кодировать искажение имени в коде, поскольку оно может меняться со временем из-за новых версий компиляторов или новых марок компиляторов или в настоящее время из-за компиляции для нескольких платформ.

Есть ли программный способ получить строку, которая представляет функцию C++ во время выполнения, чтобы код не зависел от компилятора? Один из возможных способов сделать это - вызвать во время компиляции утилиту, которая выполняет искажение имени для используемого компилятора и вставляет соответствующее искаженное имя символа C++ в строку для dlsym() использовать.

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

5 ответов

Решение

Вы можете получить желаемое, посмотрев на таблицу символов.so, на которую вы смотрите: Кто-то другой уже ответил на это. Возвращает таблицу символов совместно используемой библиотеки.

Однако, если есть слишком много символов... это может не сработать.
Так что вот сумасшедшая идея. Пусть покупатель будет бдителен!

Потенциальным решением является:

  1. создайте файл с заглушкой с точно одним именем: имя, которое вы хотите: void myfunction() { }

  2. скомпилируйте этот файл (с -fPIC и -shared, чтобы это была динамическая библиотека)

  3. вызовите dlopen / dlsym для этого конкретного файла

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

  5. dlclose() чтобы освободить его (потерять заглушку из ваших символов)

  6. Откройте нужный файл с помощью dlopen

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

Это безумие.

Вот как g++ искажает имена. Вы можете реализовать эти правила искажения в своей программе.

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

Имя искажения зависит от конкретной реализации.

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

Имя искажения

Здесь есть таблица, которая может помочь вам, если вы хотите сделать это вручную

Если вы используете на илиARMтогда вы можете попробовать этот (ish)-лайнер:

      echo "<your-type> <your-name>(<your-parameters>) {}" \
| g++ -x c++ - -o - -S -w \
| grep '^_' \
| sed 's/:$//'

вызывает интерфейс для компилятора.
g++ -x c++говорит интерпретировать язык ввода как C++.
g++ -x c++ -говорит, чтобы получить ввод от (по конвейеру).
g++ -x c++ - -o -говорит вывести наstdout(ваш дисплей).
g++ -x c++ - -o - -Sговорит вывести ассемблер/язык ассемблера.
g++ -x c++ - -o - -S -wговорит отключить все предупреждения отcc1plusplus.

Это дает нам исходный ассемблерный код.

Дляx86(_64)илиARM(v7/v8)машины, искаженное имя в выходных данных сборки будет начинаться с начала строки с префиксом подчеркивания () (обычно_Z).

Примечательно, что никакие другие строки не будут начинаться таким образом, поэтому строки, начинающиеся с подчеркивания, гарантированно будут именем объекта кода.

grep '^_'говорит отфильтровать вывод только до строк, начинающихся с подчеркивания (_).

Теперь у нас есть искаженные имена (по одному в каждой строке — в зависимости от того, сколько вы echoизд. в ).

Однако все имена в сборке имеют суффикс двоеточия (). Мы можем удалить его с помощью Stream-EDitor,sed.

sed 's/:$//'говорит убрать двоеточие(:) в конце каждой строки.

Наконец, пара конкретных примеров, показывающих искажение, а затем разборку для использования в качестве справки (вывод из x86машина):

Пример 1:

      echo "int MyFunction(int x, char y) {}" \
| g++ -x c++ - -o - -S -w \
| grep '^_' \
| sed 's/:$//'
_Z10MyFunctionic       # This is the output from the command pipeline

c++filt _Z10MyFunctionic
MyFunction(int, char)  # This is the output from c++filt

Пример 2:

      echo \
"\
namespace YourSpace { int YourFunction(int, char); }
int YourSpace::YourFunction(int x, char y) {}
"\
| g++ -x c++ - -o - -S -w \
| grep '^_' \
| sed 's/:$//'
_ZN9YourSpace12YourFunctionEic      # This is the output from the command pipeline

c++filt _ZN9YourSpace12YourFunctionEic
YourSpace::YourFunction(int, char)  # This is the output from c++filt

Я изначально видел, как применитьg++кstdinв статье Romain Picard:
How To Mangle And Demangle A Method Name C++
Я думаю, что это хорошее чтение.

Надеюсь, это помогло вам.

Дополнительная информация:
Основной источник: GNU &amp;lt;libstdc++&amp;gt; Руководство: Глава 28, часть 3: Разборка

Более простой метод, чем первый опубликованный. Напишите небольшую программу на C++, например:

#include <stdlib.h>

extern int doit(const char *toto, bool is);

int main(int argc, char *argv[])
{
  exit(doit (argv[0], true));
}

Постройте это с

# g++ -S test.cpp

И извлечь имя символа из источника ассемблера

# cat test.s | grep call | grep doit | awk '{print $2}'

Ты получаешь:

rcoscali@srjlx0001:/tmp/TestC++$ cat test.s | grep call | grep doit | awk '{print $2}'
_Z4doitPKcb
rcoscali@srjlx0001:/tmp/TestC++$ 

doit символ искаженный _Z4doitPKcbИспользуйте компилятор, который вы планируете использовать, потому что каждый компилятор имеет свои собственные правила преобразования имен (как было сказано ранее от одного компилятора к другому, эти правила могут измениться).

Повеселись!

Другие вопросы по тегам