2016-10-19 9 views
4

У меня есть приложение, которое работает на MCU на базе ARM Cortex-M и написано на языках C и C++. Я использую gcc и g++, чтобы скомпилировать его и хотел бы полностью отключить любое использование кучи.GCC: Как отключить использование кучи полностью на MCU?

В стартовом файле MCU размер кучи уже установлен равным 0. В дополнение к этому, я также хотел бы запретить любое случайное использование кучи в коде.

Другими словами, я хотел бы линкер (и/или компилятор), чтобы дать мне ошибку, когда malloc, calloc, free функции или new, new[], delete, используются delete[] операторы.

До сих пор я пробовал -nostdlib, который дает мне такие вопросы, как undefined reference to _start. Я также пробовал -nodefaultlibs, но я все еще не жалуюсь, когда пытаюсь позвонить malloc. Каков правильный способ сделать это?

Примечания:

  • Это приложение работает на «голый металл», нет никакой операционной системы.
  • Я также хотел бы избежать использования malloc в стороннем коде (специализированные библиотеки, стандартная библиотека, printf и т. Д.).
  • Я полностью в порядке, не используя части стандартных библиотек C/C++, для которых требуются динамические выделения памяти.
  • Я бы предпочел время компиляции, а не время выполнения.
+0

Вы всегда можете удалить кучу из памяти через скрипт линкера, но это не помешает таНос звонки. Единственный безопасный способ сделать код idiot-proof, вероятно, использовать статический анализатор, как, например, некоторые проверки MISRA. Но серьезно, почему у вас есть какой-либо код с использованием динамической памяти в вашем проекте? Как минимум, обзор кода легко обнаружит это. – Lundin

+0

Не видя целиком ваше приложение, получение окончательного ответа может быть невозможным. Даже простые функции C, такие как 'printf()' будут использовать 'malloc()'/'free()' внутренне. И с участием C++ вы, вероятно, не можете использовать * anything *, который полагается на библиотеку времени выполнения C++. Просто загрузка библиотеки времени выполнения C++, вероятно, широко использует кучу. Я бы рискнул сказать, что это должно быть требование приложения с самого начала дизайна, чтобы быть успешным. –

+0

Если у вас есть заголовок, видимый для всей программы, вы можете сделать какой-то взломать как # #define malloc (dummy) NULL; _Static_assert (0, «Err: использование динамической памяти») '. Не очень, но полностью портативен. – Lundin

ответ

3

Я не уверен, что это лучший путь, но вы можете использовать --wrap флаг ld (который может пройти через gcc с помощью -Wl).

Идея состоит в том, что --wrap позволяет запросить ld для перенаправления «реального» символа на ваш собственный; например, если вы делаете --wrap=malloc, то ld будет искать вашу функцию __wrap_malloc, которая будет вызываться вместо оригинала `malloc.

Теперь, если вы --wrap=mallocбез определения __wrap_malloc вы уйдете с ним, если никто не использует его, но если кто-то ссылается на malloc вы получите сообщение об ошибке, связывающую.

$ cat test-nomalloc.c 
#include <stdlib.h> 

int main() { 
#ifdef USE_MALLOC 
    malloc(10); 
#endif 
    return 0; 
} 
$ gcc test-nomalloc.c -Wl,--wrap=malloc 
$ gcc test-nomalloc.c -DUSE_MALLOC -Wl,--wrap=malloc 
/tmp/ccIEUu9v.o: In function `main': 
test-nomalloc.c:(.text+0xa): undefined reference to `__wrap_malloc' 
collect2: error: ld returned 1 exit status 

Для new вы можете использовать подогнанные имена _Znwm (operator new(unsigned long)) и _Znam (operator new[](unsigned long)), которые должны быть то, что каждый new должен спуститься в конце.

+0

Эй, это здорово. Кажется, что удаление стандартной библиотеки C++ из компоновщика позаботится о 'new' и' delete'. И ваше решение прекрасно заботится о «malloc» и его друзьях. Очень круто. – Venemo

+0

На самом деле, похоже, мне вообще не нужно беспокоиться о 'libstdC++', потому что он также использует 'malloc' под капотом. – Venemo

-1

(отправил в ответ, потому что он не будет соответствовать в комментарии)

Если ОС вы работаете поддерживает the use of LD_PRELOAD, этот код должен обнаружить попытки использовать кучу:

/* remove the LD_PRELOAD from the environment so it 
    doesn't kill any child process the app may spawn */ 
static void lib_init(void) __attribute__((constructor)); 
static void lib_init(void) 
{ 
    unsetenv("LD_PRELOAD"); 
} 

void *malloc(size_t bytes) 
{ 
    kill(getpid(), SIGSEGV); 
    return(NULL); 
} 

void *calloc(size_t n, size_t bytes) 
{ 
    kill(getpid(), SIGSEGV); 
    return(NULL); 
} 

void *realloc(void *ptr, size_t bytes) 
{ 
    kill(getpid(), SIGSEGV); 
    return(NULL); 
} 

void *valloc(size_t bytes) 
{ 
    kill(getpid(), SIGSEGV); 
    return(NULL); 
} 

void *memalign(size_t alignment, size_t bytes) 
{ 
    kill(getpid(), SIGSEGV); 
    return(NULL); 
} 

int posix_memalign(void **ptr, size_t alignment, size_t bytes) 
{ 
    *ptr = NULL; 
    kill(getpid(), SIGSEGV); 
    return(-1); 
} 

Предполагая, что new реализован с использованием malloc(), а delete реализован с использованием free(), который будет охватывать все использование кучи и предоставить вам основной файл со стеком трассировки, предполагая, что файлы ядра включены.

Добавьте соответствующие заголовки, компиляции файла:

gcc [-m32|-m64] -shared heapdetect.c -o heapdetect.so 

Запустить приложение:

LD_PRELOAD=/path/to/heapdetect.so /your/app/here args ... 
+0

К сожалению, приложение работает на голом металле, нет ОС. Я обновлю этот вопрос, чтобы отразить это. – Venemo

+0

@Venemo Вы можете скомпилировать статическую библиотеку: 'gcc -c heapdetect.c; ar rvs libheapdetect.a heapdetect.o' затем связывается с '-lheapdetect' таким образом, как он используется до' libc' и 'libstdC++', предполагая, что так вы связываете, и те имена библиотек, которые вы используете. Без ОС «kill» (getpid(), SIGSEGV), вероятно, тоже не сработает. –

+0

Да, это сработает, но это все-таки вещь вовремя, а не время компиляции. – Venemo