Работа со стеком

Среда выполнения С/С++ используется run-time стек для хранения автоматических (локальных) переменных и адресов возврата. Необходимо помнить, что этот стек размещается в памяти данных и не имеет ничего общего со стеком программного секвенсора (PC Stack), используемого при программировании ADSP SHARC-процессоров на низком уровне.

Как и любой run-time стек, он растет в сторону младших адресов памяти. Для понимания работы стека вспомним понятие кадра стека: это фрагмент стека, используемый для хранения информации о текущем контексте С/С++ программы (локальных переменных, временных переменных компилятора, фактических параметрах вызова следующей функции).

Для работы со стеком используются два указателя:

- указатель стека, содержащий адрес вершины стека – верхней (т.е. расположенной по наибольшему адресу) незаполненной ячейки стека (в отличие от Intel-процессоров указатель run-time стека ADSP указывает на первую свободную ячейку);

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

Кадр стека для функции можно определить следующим образом:

Адреса Хранимое значение Когда помещается/выталкивается
Младшие адреса Сохраненный указатель на кадр "текущей" функции Автоматически при выполнении стандартного кода для вызова/возврата "вложенной" функции из "текущей" (только если есть вызов "вложенной" функции)
  Параметры вызова "вложенной" функции Вручную программистом (комплятором), только если есть вызов "вложенной" функции
Стек растет Локальные переменные "текущей" функции Вручную программистом (компилятором), если есть локальные параметры. Можно поменять местами с сохраняемыми регистрами
  Сохраненные регистры Call Preserved Вручную программистом (компилятором), если Scratch-регистров недостаточно. Можно поменять местами с локальными параметрами
Старшие адреса Адрес возврата в вызывающую подпрограмму Автоматически при выполнении стандартного кода вызова/возврата "текущей" функции из "вызывающей"

При генерации кода для вызова функции компилятор cc21k формирует код, выполняющий следующую последовательность действий (аналогичную должен формировать программист при вызове из программ на ассемблере любых функций, но обязательно при вызове функций C/C++):

- загрузка регистра r2 значением указателя кадра: r2 = i6;

- установка указателя кадра i6 на вершину стека: i6 = i7;

- использование задержанного перехода (db) для передачи управления вызываемой функции;

- во время выполнения первой инструкции, находящейся в конвейере до перехода, проталкивание в стек прежнего указателя кадра, находящегося в регистре r2;

- во время выполнения второй инструкции, находящейся в конвейере до перехода, проталкивание в стек адреса возврата (регистр pc).

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

cjump my_function (DB);

dm(i7, m7) = r2;

dm(i7, m7) = pc;

При генерации кода для выхода из функции компилятор формируется следующую последовательность действий:

- выталкивание адреса возврата из стека и загрузка его в регистр i12;

- использование задержанного перехода для возврата управления в вызывающую подпрограмму и перехода и адресу (i12+1);

- восстановление указателя стека вызывающей функции в регистре i7 путем установки равным указателю стека кадра (регистр i6) во время выполнения первой отложенной инструкции при переходе;

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

В системе команд процессора есть специальная инструкция rframe, автоматизирующая выполнение последних двух шагов:

i12 = dm(-1, i6);

jump (m14, i12) (DB);

nop;

rframe;

Действие приведенных фрагментов кода при вызове и возврате из подпрограмм проиллюстрировано на рисунке___.

Рис.___. Работа со стеком при использовании команд cjump и rframe

На рисунке ___. приведен пример структуры стека для вызова функции.

Рис.___. Структура стека при вызове функции


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: