2013-04-10 4 views
1

При программировании (например, в C) в стеке хранится много переменных. Стек представляет собой структуру данных FIFO, и мы можем выставлять только верхнее значение стека.Как получить переменную, которая хранится в стеке?

скажем, у меня есть 100 переменных, хранящихся в стеке, и я хочу получить значение одного из них, которое не находится в верхней части стека. Как это получить? Включает ли операционная система все переменные, которые являются более новыми в стеке, до получения требуемой переменной, а затем выталкивать все из них обратно? Или существует ли другой способ, которым операционная система может приближаться к переменной внутри стека?

Благодаря

+0

Зачем вы хотите это сделать? Возможно, есть еще одно, лучшее решение вашей проблемы. – Mikkel

+0

Это, по крайней мере, LIFO, в C. –

ответ

2

Стек, используемый в таких языках, как C, не является типичным LIFO. Он называется стеком, потому что он используется в аналогично для LIFO: при вызове процедуры в стек помещается новый кадр. Кадр обычно содержит локальные переменные и информацию о бухгалтерском учете, например, где можно вернуться. Точно так же, когда процедура возвращается, ее фрейм сбрасывается со стека.

В этом нет ничего волшебного. Компилятор (а не операционная система) выделяет регистр, который будет использоваться как stack pointer - назовем его SP. По соглашению, SP указывает на ячейку памяти следующего свободного стека слова:

+----------------+ (high address) 
| argument 0 | 
+----------------+ 
| argument 1 | 
+----------------+ 
| return address | 
+----------------+ 
| local 0  | 
+----------------+ 
| local 1  | 
+----------------+     +----+  
| free slot | <-------------- | SP | 
+----------------+ (low address) +----+ 

протолкнуть значение в стек, мы делаем что-то вроде этого (в псевдо-сборки):

STORE [SP], 42 ; store the value 42 at the address where SP points 
SUB SP, 1  ; move down (the stack grows down!) to the next stack location 

В тех случаях, когда обозначение [SP] считывается как «содержимое ячейки памяти, к которой относится SP пунктов». Некоторые архитектуры, в частности x86, предоставляют команду push, которая выполняет как хранение, так и вычитание. Чтобы поместить (и отбросить) n верхние значения в стеке, мы просто добавляем n в SP *.

Теперь предположим, что мы хотим получить доступ к полем local 0 выше. Достаточно легко, если наш CPU имеет режим адресации base+offset! Предположим, SP указывает на свободный слот, как на картинке выше.

LOAD R0, [SP+2] ; load "local 0" into register R0 

Обратите внимание, как мы не Лопните local 0 из стека первых, потому что мы можем ссылаться на любое поле, используя его смещение от указателя стека.

В зависимости от архитектуры компилятора и машины может быть другой регистр, указывающий на область между локалями и аргументами (или около того). Этот регистр, обычно называемый frame pointer, остается фиксированным, когда указатель стека перемещается.

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

* Для простоты я предположил, что размер машинного слова 1 байт, поэтому мы вычитаем 1 из SP. На 32-битной машине нажатие слова на стек означает вычитание (по крайней мере) четырех байтов.

+0

действительно полезно, спасибо! – user1439691

2

I. Операционная система не делает ничего напрямую с переменными.

II. Не думайте о стеке как физическом стеке (причина этого слишком проста: это не одно). К элементам стека можно обращаться напрямую, а компилятор генерирует код, который делает это. Google "относительная адресация указателя стека".

Смежные вопросы