Проверка использования стека во время компиляции - PullRequest
29 голосов
/ 24 сентября 2008

Есть ли способ узнать и вывести размер стека, необходимый функции во время компиляции в C? Вот что я хотел бы знать:

Давайте возьмем некоторую функцию:

void foo(int a) {
    char c[5];
    char * s;
    //do something
    return;
}

При компиляции этой функции я хотел бы знать, сколько стекового пространства она будет использовать, когда она вызывается. Это может быть полезно для обнаружения объявления в стеке структуры, скрывающей большой буфер.

Я ищу что-нибудь, что напечатало бы что-то вроде этого:

файл foo.c: функция использует стек foo n байт

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

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

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

Ответы [ 7 ]

10 голосов
/ 12 января 2009

Код ядра Linux работает в стеке 4K на x86. Следовательно они заботятся. Чтобы проверить это, они написали сценарий perl, который вы можете найти в виде scripts / checkstack.pl в недавнем tar-архиве ядра (у 2.6.25 есть). Он работает на выходе objdump, документация по использованию находится в первоначальном комментарии.

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

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

Кстати, с помощью objdump из проекта mingw и ActivePerl, или с помощью Cygwin вы сможете сделать это также в Windows, а также в двоичных файлах, полученных другими компиляторами.

8 голосов
/ 24 сентября 2008

StackAnlyser, похоже, проверяет сам исполняемый код и некоторую информацию об отладке. То, что описывает этот ответ , это то, что я ищу, анализатор стека для меня выглядит излишним.

Что-то похожее на то, что существует для ADA, было бы хорошо. Посмотрите на эту страницу руководства из руководства по комарам:

22.2 Анализ использования статического стека

Модуль, скомпилированный с -fstack-using, сгенерирует дополнительный файл, который определяет максимальный объем используемого стека для каждой функции. Файл имеет то же базовое имя, что и целевой объектный файл с расширением .su. Каждая строка этого файла состоит из трех полей:

* The name of the function.
* A number of bytes.
* One or more qualifiers: static, dynamic, bounded. 

Второе поле соответствует размеру известной части функционального кадра.

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

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

3 голосов
/ 24 сентября 2008

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

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

Конечно, нельзя гарантировать, что ответ будет точным на 100%, так как компилятор может выполнять различные виды оптимизации, такие как заполнение, помещение переменных в регистры или полное удаление ненужных переменных. Но любой ответ, который он дает, должен быть как минимум хорошей оценкой.

Я сделал быстрый поиск в Google и нашел StackAnalyzer , но я предполагаю, что другие инструменты статического анализа кода имеют аналогичные возможности.

Если вы хотите получить 100% точную цифру, вам придется посмотреть на вывод компилятора или проверить его во время выполнения (как предложил Ральф в его ответ )

1 голос
/ 24 сентября 2008

Не совсем "время компиляции", но я бы сделал это как шаг после сборки:

  • позвольте компоновщику создать файл карты для вас
  • для каждой функции в файле карты прочитайте соответствующую часть исполняемого файла и проанализируйте пролог функции.

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

Для реализации этого вам необходимо:

  • сможет анализировать файл карты
  • понять формат исполняемого файла
  • знать, как может выглядеть пролог функции, и уметь «декодировать» его

Насколько легко или сложно это будет зависеть от вашей целевой платформы. (Встроенный? Какая архитектура процессора? Какой компилятор?)

Все это определенно можно сделать в x86 / Win32, но если вы никогда не делали ничего подобного и вам приходилось создавать все это с нуля, может пройти несколько дней, прежде чем вы закончите и что-то заработаете.

1 голос
/ 24 сентября 2008

Предполагая, что вы находитесь на встроенной платформе, вы можете обнаружить, что ваш набор инструментов имеет на это шанс. Хорошие коммерческие встроенные компиляторы (такие как, например, компилятор Arm / Keil) часто выдают отчеты об использовании стека.

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

1 голос
/ 24 сентября 2008

Только компилятор мог бы знать, так как это парень, который собирает все ваши вещи вместе. Вам нужно взглянуть на сгенерированную сборку и увидеть, сколько места зарезервировано в преамбуле, но это не учитывает такие вещи, как alloca, которые делают свое дело во время выполнения.

0 голосов
/ 24 сентября 2008

Не в общем. Проблема остановки в теоретической информатике предполагает, что вы даже не можете предсказать, остановится ли общая программа на заданном входе. Расчет стека, используемого для запуска программы в целом, был бы еще более сложным. Итак: нет. Может быть, в особых случаях.

Допустим, у вас есть рекурсивная функция, уровень рекурсии которой зависит от ввода, который может иметь произвольную длину, и вам уже не повезло.

...