1.5. Использование стека
Каждая программа имеет область памяти, называемую стеком. Стек используется для передачи параметров в процедуры и для хранения локальных данных процедур. Как известно, стек – это область памяти, при работе с которой необходимо соблюдать определённые правила, а именно: данные, которые попали в стек первыми, извлекаются оттуда последними. С другой стороны, если программе выделена некоторая память, то нет никаких физических ограничений на чтение и запись. Как же совмещаются два этих противоречивых принципа?
Пусть у нас есть функция f1, которая вызывает функцию f2, а функция f2, в свою очередь, вызывает функцию f3. При вызове функции f1 ей отводится определённое место в стеке под локальные данные. Это место отводится путём вычитания из регистра ESP значения, равного размеру требуемой памяти. Минимальный размер отводимой памяти равен 4 байтам, т.е. даже если процедуре требуется 1 байт, она должна занять 4 байта.
Функция f1 выполняет некоторые действия, после чего вызывает функцию f2. Функция f2 также отводит себе место в стеке, вычитая некоторое значение из регистра ESP. При этом локальные данные функций f1 и f2 размещаются в разных областях памяти. Далее функция f2 вызывает функцию f3, которая также отводит себе место в стеке. Функция f3 других функций не вызывает и при завершении работы должна освободить место в стеке, прибавив к регистру ESP значение, которые было вычтено при вызове функции. Если функция f3 не восстановит значение регистра ESP, то функция f2, продолжив работу, будет обращаться не к своим данным, т.к. она ищет их, основываясь на значении регистра ESP. Аналогично функция f2 должна при выходе восстановить значение регистра ESP, которое было до её вызова.
Таким образом, на уровне процедур необходимо соблюдать правила работы со стеком – процедура, которая заняла место в стеке последней, должна освобождать его первой. При несоблюдении этого правила, программа будет работать некорректно. Но каждая процедура может обращаться к своей области стека произвольным образом. Если бы мы были вынуждены соблюдать правила работы со стеком внутри каждой процедуры, пришлось бы перекладывать данные из стека в другую область памяти, а это было бы крайне неудобно и чрезвычайно замедлило бы выполнение программы.
Каждая программа имеет область данных, где размещаются глобальные переменные. Почему же локальные данные хранятся именно в стеке? Это делается для уменьшения объёма памяти занимаемого программой. Если программа будет последовательно вызывать несколько процедур, то в каждый момент времени будет отведено место только под данные одной процедуры, т.к. стек занимается и освобождается. Область данных существует всё время работы программы. Если бы локальные данные размещались в области данных, пришлось бы отводить место под локальные данные для всех процедур программы.
Локальные данные автоматически не инициализируются. Если в вышеприведённом примере функция f2 после функции f3 вызовет функцию f4, то функция f4 займёт в стеке место, которое до этого было занято функцией f3, таким образом, функции f4 «в наследство» достанутся данные функции f3. Поэтому каждая процедура обязательно должна заботиться об инициализации своих локальных данных.
Do'stlaringiz bilan baham: |