Как проверить, откуда ссылка на функцию

В чистом проекте C/C++ я использую gcc-arm-embedded (в настоящее время наиболее недавнее 4.9-2015-q2).

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

Кроме того, я использую FreeRtos с heap_4.c и, например, malloc() перенаправлено непосредственно на pvPortMalloc() следующим образом:

void* malloc(size_t s) {
    return pvPortMalloc(s);
}

Поэтому я не хочу, чтобы какие-либо части кода управления кучей набора инструментов находились в моем двоичном файле.

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

(Использование printf() здесь просто в качестве примера. В моем проекте у меня есть собственная реализация printf(), которая печатает напрямую в uart без использования stdio. Но есть и другие случаи, например, удаление информации о типах, …)

В настоящее время у меня сложилась ситуация, когда мой проект (который состоит примерно из 200 исходных файлов c и c++) хорошо компилируется без какой-либо ссылки на _malloc_r(), если я строю с gcc 4.8.

Но при сборке с gcc 4.9 я вижу нежелательные ссылки на _malloc_r и некоторые другие.

Может ли быть инструмент командной строки для анализа моего файла elf, чтобы узнать, откуда ссылаются на определенные функции?

Редактировать 20.07.2015:

  • Наконец, я решил основную проблему, заключающуюся в том, что мне нужно собрать весь проект с помощью gcc 4.9 без ссылок на _malloc_r внутри моего кода.
  • Некоторые ссылки я нашел, применив этот ответ.
  • Далее я узнаю, что есть __gnu_cxx::__snprintf_lite(), который ссылается на полноценный iostream, который мне не нужен в моем коде. Этот __gnu_cxx::__snprintf_lite() используется некоторыми исключениями реализации gcc stl (например, на которые ссылается __throw_out_of_range_fmt()). (Да, мой код использует std::map). Мой способ избавиться от iostream заключался в том, чтобы просто предоставить свой собственный __gnu_cxx::__snprintf_lite() следующим образом (имея собственный небольшой след vsnprintf):

    namespace __gnu_cxx {
        int __snprintf_lite(char* buf, size_t bufsize, const char* fmt, va_list ap) {
            return vsnprintf(buf, bufsize, fmt, ap);
        }
    }
    

    Это можно проверить, просмотрев исходники библиотеки gcc-4.9 (например, src/gcc/libstdc++-v3/src/c++11/snprintf_lite.cc).


person Joe    schedule 27.06.2015    source источник
comment
Возможно, компоновщик может сказать вам, можете ли вы предотвратить включение определения соответствующей функции (функций).   -  person Cheers and hth. - Alf    schedule 27.06.2015
comment
К сожалению, я не знаю имен всех функций, которые прямо или косвенно могут привести к ссылкам, например. _malloc_r.   -  person Joe    schedule 27.06.2015
comment
Вы можете использовать objdump -d для дизассемблирования всех исполняемых разделов и перенаправления вывода в файл и поиска в нем _malloc_r с помощью текстового редактора.   -  person 4566976    schedule 27.06.2015
comment
Взгляните на Hooks-for-Malloc gnu.org /software/libc/manual/html_node/Hooks-for-Malloc.html   -  person frhack    schedule 27.06.2015
comment
LD_PRELOAD stackoverflow.com/questions/2948448/   -  person frhack    schedule 27.06.2015


Ответы (3)


Это пример поиска ссылок на _exit в статически скомпилированной программе:

/* hello.c */
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    write(1, "Hello\n", 6);
    _exit(0);
}

Скомпилируйте это:

$ gcc hello.c -static -g

Узнать адрес _exit:

$ nm a.out | grep " _exit"
000000000040f760 T _exit

Дизассемблируйте с objdump -d -j .text, grep для адреса _exit, cut адрес из строки и соедините его с addr2line:

$ objdump -d -j .text a.out | grep 40f760 | cut -c 1-8 | addr2line -e a.out -f
oom
dl-tls.o:?
main
/home/m/hello.c:8
__run_exit_handlers
??:?
??
??:0
_Exit
??:?
_dl_non_dynamic_init
??:?
abort
??:?
do_lookup_x
dl-lookup.o:?
_dl_relocate_object
??:?
_dl_signal_error
??:?
dl_open_worker
dl-open.o:?
_dl_close_worker.part.0
dl-close.o:?
_dl_start_profile
??:?

Результат:

Функции oom, main, __run_exit_handlers, ... ссылаются на функцию _exit.

person 4566976    schedule 27.06.2015
comment
Я думаю, это ведет в правильном направлении. Не могли бы вы указать причину oom аргумента addr2line? - person Joe; 28.06.2015
comment
@Joe oom является частью вывода addr2line. Это static функция (из memory) в библиотеке dl, которая вызывает _exit. - person 4566976; 28.06.2015
comment
Что ж, используя этот подход, я узнаю, что на _malloc_r ссылаются __ssprint_r и __submore; На сам __ssprint_r ссылается что-то с именем St?! На __submore ссылается _sungetc_r, на который также ссылается St. В этот момент я застрял в попытках проследить цепочку ссылок до своего собственного кода. - person Joe; 28.06.2015
comment
Следуя адресу этого St, вручную проверяя вывод objdump, я вижу, что на него ссылается __ssvfscanf_r, на который ссылается sscanf, на который ссылается _ZSt14__convert_to_vIeEvPKcRT_RSt12_Ios_IostateRKPi (void std::__convert_to_v<long double>(char const*, long double&, std::_Ios_Iostate&, int* const&)), что приводит меня к некоторым материалам, связанным с шаблонами iostream. - person Joe; 28.06.2015
comment
После некоторого изучения моего кода я обнаружил, что есть несколько разных косвенных ссылок на _malloc_r (в моем конкретном случае). Некоторые из них я нашел, используя этот подход (например, localtime() и mktime() ссылаются на _malloc_r косвенно (через mktime_tzset_unlocked_tzset_unlocked_r_malloc_r) при сборке с помощью gcc-arm 4.9); еще один хит, я описал в своем вопросе - person Joe; 02.07.2015

Я не уверен, правильно ли я вас понял, но, похоже, вы хотите избежать использования некоторых специфических функций в своем проекте. Как насчет того, чтобы просто отравить идентификаторы функций?

Этот код не скомпилируется (намеренно) для printf:

#define printf FORBIDDEN

int main(int argc, char *argv[]) {
  printf("Test");
}

со следующей ошибкой:

Untitled.cpp:11:3: error: no matching function for call to 'FORBIDDEN'
  printf("Test");
  ^~~~~~
Untitled.cpp:3:16: note: expanded from macro 'printf'
#define printf FORBIDDEN
               ^~~~~~~~~

Так что порядок объявления и переопределения не имеет значения. Вам не нужно знать все функции, которые вызывают запрещенные функции:

#define printf FORBIDDEN

// this in included file:
void otherfunc() {
  printf("I fail.");
}
// eof included file

int main(int argc, char *argv[]) {
  otherfunc();
}
person Kuba Wyrostek    schedule 27.06.2015
comment
Этот подход приводит к тому, что я должен вести черный список всех запрещенных функций. Кроме того, он отравляет все printf ключевые слова в коде, даже такую ​​возможную разрешенную OutStream::printf реализацию. - person Joe; 27.06.2015

Peraphs, использующие пользовательский malloc.h, где вы можете отменить или переопределить _malloc_r

Что-то подобное:

extern _PTR malloc _PARAMS ((size_t));
#ifdef __CYGWIN__
#undef _malloc_r
#define _malloc_r(r, s) malloc (s)
#else
extern _PTR _malloc_r _PARAMS ((struct _reent *, size_t));
#endif

Взгляните на Hooks-for-Malloc тоже

Библиотека GNU C позволяет вам изменять поведение malloc, realloc и free, указывая соответствующие функции ловушек. Вы можете использовать эти хуки, например, для отладки программ, использующих динамическое выделение памяти.

Переменные ловушки объявлены в malloc.h.

Еще один намек на использование LD_PRELOAD Что такое трюк LD_PRELOAD?

person frhack    schedule 27.06.2015
comment
Да, ИМХО, LD_PRELOAD на голом железе не получится. - person Joe; 27.06.2015
comment
О хуках malloc: _malloc_c() — это просто пример. Иногда я также наблюдал нежелательные ссылки, например. _write() или какие-то другие (не связанные со stdio) нежелательные функции. - person Joe; 27.06.2015
comment
-flto не поможет, потому что на нежелательный _malloc_r() действительно ссылаются (косвенно, например, через sprintf или что-то еще), и мне нужно найти место виновного кода в моих источниках. - person Joe; 28.06.2015