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

В голом металлическом проекте C / C ++ я использую GCC-рычажного встроен (в настоящее время самый последний 4.9-2015-q2).

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

Кроме того, я использую 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 и еще немного.

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

Изменить 2015-07-20:

  • Наконец, я решил свою основную проблему, что мне нужно построить весь свой проект с 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).

4

Решение

Это пример для выяснения ссылок на _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,

2

Другие решения

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

Этот код не может скомпилировать (намеренно) для 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();
}
2

Пераф использует собственный 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

Посмотрите на Крючки-для-таНос тоже

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

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

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

2