Перейти к содержанию
    

Отследить переменные на стеке.

Как можно знать по каким адресам расположаться локальные переменные на стеке при вхождении в функцию? Или это в принципе невозможно?

Изменено пользователем haker_fox
Исправил опечатку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Например, с помощью оператора получения адреса переменной "&". Можно определить относительные адреса в стеке с помощью изучения ассемблерного кода функции. Всё зависит от целей и задач, которые вы не сформулировали.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, jenya7 сказал:

расположаться

Что сделаютЬ?

1 час назад, jenya7 сказал:

на стаке

А чего сразу не "на стацке"?

 

Надеюсь, вы понимаете, что в общем случае при каждом входе в функцию эти адреса будут разные?

Что-то мне подсказывает, что вы снова закатываете Солнце вручную и пытаетесь реализовать va_arg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 1/4/2023 at 9:41 AM, Сергей Борщ said:

Надеюсь, вы понимаете, что в общем случае при каждом входе в функцию эти адреса будут разные?

Что-то мне подсказывает, что вы снова закатываете Солнце вручную и пытаетесь реализовать va_arg

разные? почему? что поменялось между входами?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, jenya7 сказал:

что поменялось между входами?

Вы действительно не понимаете или издеваетесь?

void a()
{
   int i;
   printf("addr = %p\n", &i);
}

void b()
{
   volatile int ii = 0;
   a();
}

void test()
{
    a();
    b();
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 1/4/2023 at 9:48 AM, Сергей Борщ said:

Вы действительно не понимаете или издеваетесь?

void a()
{
   int i;
   printf("addr = %p\n", &i);
}

void b()
{
   volatile int ii = 0;
   a();
}

void test()
{
    a();
    b();
}

ну и? тут статика, не вижу почему адреса должны измениться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Потому что при первом вызове функции a() стек условно пустой, а при втором вызове на стеке уже лежит переменная ii из функции b(). Что вы понимаете под понятием "статика" - мне неведомо.

Ну погоняйте этот код под отладчиком до пониамния, что ли. Я пас.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему "стацк" выдает разные адреса для переменных одной ф-ции? Да потому, что в первый раз фукнция вызвалась из main, когда "стацк" находился почти в его начале, а во второй раз эта же функция вызвалась из функции Foo, которая была вызвана из другой ф-ции OtherFoo, и "стацк" для вашей фукнции сместился уже подальше от его начала, потому как на "стацке" лежат "стацки" этих двух функций.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 1/4/2023 at 9:53 AM, Сергей Борщ said:

Потому что при первом вызове функции a() стек условно пустой, а при втором вызове на стеке уже лежит переменная ii из функции b().

Ну погоняйте этот код под отладчиком до пониамния, что ли. Я пас.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 1/4/2023 at 9:02 AM, makc said:

Например, с помощью оператора получения адреса переменной "&". Можно определить относительные адреса в стеке с помощью изучения ассемблерного кода функции. Всё зависит от целей и задач, которые вы не сформулировали.

очень непонятный баг. я получаю данные в буфер. периодически (раз в 163 секунды) данные принимают мусорные значения.

void buffcpy_cont(uint16_t *DataBuffer, uint16_t dataPtr, uint16_t lenght)
{
}

void save_data(uint16_t* DataBuffer, uint16_t command)
{
}

uint16_t check_new_message(void)
{
    uint16_t l_uiDataBuffer[32];
    uint16_t l_uiTempDataP = 0, l_uiDataSize = 0;

    buffcpy_cont(l_uiDataBuffer, l_uiTempDataP, l_uiDataSize);

    save_data(l_uiDataBuffer, l_uiCommandWord);
}

чттоб понять где ломаются данные я посылаю нулевые данные и поставил ловушки

void buffcpy_cont(uint16_t *DataBuffer, uint16_t dataPtr, uint16_t lenght)
{
}

void save_data(uint16_t* DataBuffer, uint16_t command)
{
   //trap 2
    if (DataBuffer[15] != 0)
      lock=1;
}

uint16_t check_new_message(void)
{
    uint16_t l_uiDataBuffer[32];
    uint16_t l_uiTempDataP = 0, l_uiDataSize = 0;

    buffcpy_cont(l_uiDataBuffer, l_uiTempDataP, l_uiDataSize);
  
    //trap 1
    if (l_uiDataBuffer[15] != 0)
      lock=1;

    save_data(l_uiDataBuffer, l_uiCommandWord);
}

срабатывает вторая ловушка. то есть данные ломаются при передаче буфера в функцию save_data.  я сделал буфер l_uiDataBuffer глобальным и проблема исчезла. но от меня требуют объяснений.

 

что интересно - посылка данных каждые 160 милисек - 163s/160ms = 1024 - как раз размер стака. может конечно просто совпадение.

 

ещё дополнение - система давно работает в лабораторных условиях но там её гоняют в режиме stress test - посылки данных каждые 20 милисек. проблема проявилась в полевых условиях - при посылках каждые 160 милисек.

Изменено пользователем jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Иллюстрирую поведение стека при вызовах функций:

Вначале код находится в main, а указатель вершины стека находится в его начале:

 

Спойлер

937490282_2023-01-04141323.thumb.png.1c3d6619d3868882763d44e6a7b3841d.png

 

Понятно, да?

Теперь вызываем из main функцию Test, указатель стека смещается на шаг назад (под шагом имею ввиду совокупность данных, располагаемых в стеке фукнции):

 

Спойлер

137883039_2023-01-04141426.thumb.png.51e94f667ef9737b07d8b2275d844a5f.png

 

Видите, где лежат переменные a, b, c? Запомнили? При выходе из фукнции Test указатель стека вернется в первоначальное положение:

 

Спойлер

84381692_2023-01-04141524.thumb.png.549b1b3152cfeb3ac78aae466c15e0c4.png

 

Теперь вызовем из main функцию OtherFoo(): указатель стека сместится на шаг назад, на те адреса, которые принадлежали ранее вызывавшейся функции Test, они будут ПЕРЕЗАПИСАНЫ переменными функции OtherFoo!

 

Спойлер

1255946743_2023-01-04141609.thumb.png.5f25e2bfd5f7fcd3db072b6fc78ecf5c.png

 

Видите - там, где раньше лежало значение 00000001 от фукнции Test, теперь помещено значение 000001F4.

Затем из OtherFoo вызывается функция Foo, и только уже из нее вызовется наша Test. Смотрите теперь ГДЕ будут лежать переменные a, b, 😄

1860831552_2023-01-04141854.thumb.png.43432df20ec0d60aa4c41c45fd8c1259.png

Узрели? Переменные те же самые, функция та же самая, но адреса на "стацке" этих переменных - уже, черт возьми, другие.

Понятно теперь как работает стек?

И самое важное из этого следствие: нельзя возвращать из функции адреса локальных нестатичных переменных, которые лежат в стеке функции, потому как при выходе из функции эти данные перестают быть актуальными и могут быть затерты другими функциями, в том числе и вызываемыми из возникшего в этот момент ПРЕРЫВАНИЯ! 

Если хотите, чтобы локальные переменные в фукнции сохраняли свою актуальность после выхода из функции, вы должны эти переменные объявить как static, тогда они будут расположены не на "стацке", а в другой области памяти и не будут затерты.

 

 

 

Изменено пользователем Variant99

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 1/4/2023 at 10:28 AM, Variant99 said:

 

И самое важное из этого следствие: нельзя возвращать из функции адреса локальных нестатичных переменных, которые лежат в стеке функции, потому как при выходе из функции эти данные перестают быть актуальными и могут быть затерты другими функциями, в том числе и вызываемыми из возникшего в этот момент ПРЕРЫВАНИЯ! 

Если хотите, чтобы локальные переменные в фукнции сохраняли свою актуальность после выхода из функции, вы должны эти переменные объявить как static, тогда они будут расположены не на "стацке", а в другой области памяти и не будут затерты.

 

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

buffcpy_cont(l_uiDataBuffer, l_uiTempDataP, l_uiDataSize);

//тут прерывание

save_data(l_uiDataBuffer, l_uiCommandWord);

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Когда произойдёт прерывание - неизвестно. На то оно и прерывание, чтобы прерывать работу в любое время в любом месте. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...