Читайте также:
|
|
Поскольку аппаратный стек располагается в оперативной памяти, в нем можно размещать обычные переменные программы. Размещение локальных переменных в стеке обладает рядом преимуществ по сравнению со статическим размещением переменных в фиксированных ячейках оперативной памяти. Как уже говорилось выше, это позволяет организовывать рекурсию. Кроме того, в современных архитектурах принципиальное значение имеет поддержка параллельных процессов, работающих над общими статическими переменными. Это так называемые легковесные процессы, или нити (Thread), работающие параллельно в рамках одной программы. На использовании нитей, например, основана работа всех графических приложений в системе Microsoft Windows 32: одна нить обрабатывает сообщения графической системы (нажатия на клавиатуру и кнопки мыши, перерисовка окон, выборка команд из меню и т.п.), другие нити занимаются вычислениями, сетевым обменом, анимацией и т.п.
Различные нити работают параллельно над общими статическими данными, совершая таким образом некоторую совместную работу. При этом одна и та же подпрограмма может вызываться из разных нитей. В отличие от статических переменных, которые являются общими для всех нитей, для каждой нити выделяется свой отдельный стек. При использовании нитей очень важно, чтобы локальные переменные подпрограммы располагались в стеке. Иначе было бы невозможно параллельно вызывать одну и ту же подпрограмму из разных нитей: повторный вызов подпрограммы, уже работающей в рамках другой нити, разрушил бы статический набор локальных переменных этой подпрограммы. А при использовании стека наборы локальных данных одной и той же подпрограммы, вызываемой из разных нитей, различны, поскольку они располагаются в разных стеках. Таким образом, разные нити работают с разными наборами локальных переменных, не мешая друг другу.
Рассмотрим более подробно, как размещаются локальные переменные подпрограммы в стеке, на примере языка Си. В Си подпрограммы называются функциями. Функция может иметь аргументы и локальные переменные, т.е. переменные, существующие только в процессе выполнения функции. Рассмотрим для примера функцию ƒ, зависящую от двух входных аргументов x и y целого типа, в которой используются три локальные переменные a, b и c также целого типа. Функция возвращает целое значение.
int f(int x, int y) {
int a, b, c;
...
}
Пусть в некотором месте программы вызывается функция ƒ с аргументами x = 222, y = 333:
z = f(222, 333);
Вызывающая программа помещает фактические значения аргументов x и y функции ƒ в стек, при этом на вершине стека лежит первый аргумент функции, под ним — второй аргумент. Вызов функции транслируется в следующие команды:
push 333
push 222
call ƒ
Обратите внимание, что в стек сначала помещается второй аргумент функции, затем первый, в результате на вершине стека оказывается первый аргумент. При выполнении инструкции вызова call в стек помещается также адрес возврата.
В момент начала работы функции ƒ cтек имеет следующий вид:
адрес возврата | <=SP |
.... |
На вершине стека лежит адрес возврата, под ним — фактическое значение аргумента x, затем фактическое значение аргумента y.
Перед началом работы функция ƒ должна захватить в стеке область памяти под свои локальные переменные a, b, c. В языке Си принято следующее соглашение: адрес блока локальных переменных функции в момент ее работы помещается в специальный регистр процессора, который называется FP, от англ. Frame Pointer — указатель кадра. (В процессоре Intel 80386 роль указателя кадра выполняет регистр EBP.) В первую очередь функция ƒ сохраняет в стеке предыдущее значение регистра FP. Затем значение указателя стека копируется в регистр FP. После этого функция ƒ захватывает в стеке область памяти размером в 3 машинных слова под свои локальные переменные a, b, c. Для этого функция ƒ просто уменьшает значение регистра SP на 12 (три машинных слова равны двенадцати байтам). Таким образом, начало функции ƒ состоит из следующих команд:
push FP
FP:= SP
SP:= SP − 12
После захвата кадра локальных переменных стек выглядит следующим образом.
c | <=SP |
b | |
a | |
старое значение FP | <=FP |
адрес возврата | |
x=222 | |
y=333 | |
... |
Аргументы и локальные переменные функции ƒ адресуются относительно регистра FP. Так, аргумент x имеет адрес FP+8, аргумент y - адрес FP+12. Переменная a имеет адрес FP-4, переменная b - адрес FP-8, переменная c - адрес FP-12.
По окончании работы функция ƒ сначала увеличивает указатель стека на 12, удаляя таким образом из стека свои локальные переменные a, b, c. Затем старое значение FP извлекается из стека и помещается в FP (таким образом, регистр FP восстанавливает свое значение до вызова функции ƒ). После этого осуществляется возврат в вызывающую программу: адрес возврата снимается со стека и управление передается по адресу возврата. Результат функции ƒ передается через нулевой регистр.
R0:= результат функции
SP:= SP +12
pop FP
return
Вызывающая программа удаляет из стека фактические значения аргументов x и y, помещенные в стек перед вызовом функции ƒ.
Дата добавления: 2014-12-19; просмотров: 141 | Поможем написать вашу работу | Нарушение авторских прав |