#c #assembly #arm #callstack #stack-size
#c #сборка #arm #callstack #размер стека
Вопрос:
Наша компания купила проприетарную функцию C: у нас есть скомпилированная библиотека ProcessData.a
и файл интерфейса для ее вызова:
# ProcessData.h
void ProcessData(char* pointer_to_data, int data_len);
Мы хотим использовать эту функцию на ARM
встроенном процессоре, и мы хотим знать, сколько места в стеке она может использовать.
Вопрос: как измерить использование стека произвольной функции?
До сих пор я пытался реализовать следующие вспомогательные функции:
static int* stackPointerBeforeCall;
void StartStackMeasurement(void) {
asm ("mov %0, sp" : "=r"(stackPointerBeforeCall));
// For some reason I can't overwrite values immediately below the
// stack pointer. I suspect a return address is placed there.
static int* pointer;
pointer = stackPointerBeforeCall - 4;
// Filling all unused stack space with a fixed constant
while (pointer != amp;_sstack) {
*pointer = 0xEEEEEEEE;
pointer--;
}
*pointer = 0xEEEEEEEE;
}
void FinishStackMeasurement(void) {
int* lastUnusedAddress = amp;_sstack;
while (*lastUnusedAddress == 0xEEEEEEEE) {
lastUnusedAddress ;
}
// Printing how many stack bytes a function has used
printf("STACK: %dn", (stackPointerBeforeCall-lastUnusedAddress)*sizeof(int));
}
А затем использовать их непосредственно перед и после вызова функции:
StartStackMeasurement();
ProcessData(array, sizeof(array));
FinishStackMeasurement();
Но это кажется опасным взломом — особенно та часть, где я вычитаю 4
из stackPointerBeforeCall
и перезаписываю все, что приведено ниже. Есть ли лучший способ?
Комментарии:
1. Хорошего способа сделать это нет, но может быть менее хакерский способ. Имеет ли встроенная среда, в которой вы запускаете этот код, защиту памяти? Есть ли у него потоки? Есть ли у него (устаревшие, но незаменимые) функции POSIX
getcontext
,makecontext
,setcontext
, иswapcontext
?2. Заполнение стека шаблоном и последующая его проверка — это обычный подход к проверке стека. Если указатель стека всегда указывает на значение, введенное последним, то вычитание 4 является правильным для 32-разрядной системы. (Я не проверял документацию для ARM.) Не зная подробностей о вашей ОС и / или доступных библиотеках, мы не знаем, существуют ли в вашей системе какие-либо специальные механизмы для проверки стека. Возможно, вам придется выполнить тест с разными входными данными, если использование стека зависит от данных. Подумайте о том, чтобы спросить создателя библиотеки о максимальном использовании стека.
3. Правильный способ сделать это — спросить поставщика.
4. Один очень хитрый способ — прочитать sp через ассемблер, заполнить все от sp до конца стека известной шестнадцатеричной последовательностью, 0xAA или такой. Затем проверьте, на сколько 0xAA изменилась функция. Не точная наука, а старый добрый трюк, используемый для определения максимального использования стека в системах с голым металлом.
5. Кстати, опубликованный код должен гарантировать, что
pointer
он не размещен в стеке, иначе он может решить уничтожить себя и заменить содержимое адресом 0xeeeeeeeeee 🙂 Лучшее решение для этогоstatic int* pointer; pointer = stackPointerBeforeCall - 4;
Ответ №1:
Скомпилируйте программу и проанализируйте сборку или машинный код для рассматриваемой функции. Многие функции используют стек статическим образом, и этот статический размер может быть обоснован анализом скомпилированного кода. Некоторые функции динамически выделяют пространство стека на основе некоторых вычислений, обычно связанных с некоторым входным параметром. В этих случаях вы увидите, что для выделения места в стеке используются разные инструкции, и вам придется вернуться к объяснению того, как может быть получен динамический размер стека.
Конечно, этот анализ пришлось бы переделать с обновлениями функции (библиотеки).
Ответ №2:
Вы можете использовать getrusage, который представляет собой функцию, которая позволяет вам использовать ресурсы вашего программного обеспечения, в частности ru_isrss
, которая
Целочисленное значение, выраженное таким же образом, которое представляет собой объем неразделенной памяти, используемой для стекового пространства
Затем вы можете сравнить его с использованием стека вашей программой с помощью имитированного вызова библиотеки.
Однако это будет работать только в том случае, если ваша система реализовала ru_isrss
(в отличие от Linux), в противном случае для поля будет установлено значение 0.