2014-10-09 2 views
1

Насколько я понимаю, указатель стека указывает на «свободную» память в стеке, а «толкание» данных в стеке записывается в местоположение, указанное указателем стека, и увеличивает/уменьшает его.Не указывает ли указатель на фреймворк указателя стека?

Но нельзя ли использовать смещения от указателя рамки для достижения того же, сохраняя при этом регистр. Накладные расходы, связанные с добавлением смещений в указатель фрейма, в значительной степени совпадают с накладными расходами приращения и уменьшения указателя стека. Единственное преимущество, которое я вижу, - это доступ к данным из «верхней» (или нижней), будет быстрее, если это не операция push или pop, например. просто чтение или запись на этот адрес без увеличения/уменьшения. Но опять же, для таких операций потребуется один дополнительный цикл, используя указатель кадра, и будет использоваться один дополнительный регистр для общего использования.

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

+2

Предположим, что у вас есть только указатель кадра и вызывается подпрограмма. Как эта подпрограмма узнает, где начинается ее собственный кадр? Или что делать, если обработчик сигнала должен быть выполнен или что-то, что нужно знать о текущих ограничениях стека? На практике это указатель кадра, который опущен, а не указатель стека. – Jester

+0

@Jester - при вызове подпрограммы указатель кадра настраивается и затем восстанавливается в кадр местоположения вызова? Предел стека может быть также рассчитан с помощью указателя кадра, если FP + смещение доступа> размер стека вы уходите. –

+0

Только вызывающий пользователь знает размер кадра, и если он корректирует указатель кадра, он эффективно превращается в указатель стека. – Jester

ответ

4

Ну, да, и на самом деле общий для генераторов 64-разрядных кодов. Однако есть осложнения, которые не делают его универсальным. Жесткое требование состоит в том, что значение указателя стека известно во время компиляции, поэтому генератор кода может надежно генерировать смещение.Это не работает, если:

  • Язык исполнения обеспечивает нетривиальные гарантии выравнивания. В частности, проблема в 32-битном коде, когда фрейм стека содержит 8-байтовые переменные, например double. Доступ к неверно выровненной переменной очень дорог (x2, если он смещен на 4, x3, если он пересекает линию кеша L1) и может привести к недействительности гарантии модели памяти. Генератор кода обычно не может предполагать, что функция вводится с выровненным стеком, поэтому необходимо генерировать код в прологе функции, это может привести к уменьшению указателя стека на дополнительные 4 байта.

  • Язык исполнения обеспечивает способ для динамического распределения пространства стека. Очень часто и желательно, это очень дешевая и быстрая память. Примерами являются alloca() в CRT, массивы переменной длины в C99 +, ключевое слово stackalloc на языке C#.

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

2

Ваш вопрос должен быть: Является ли указатель кадра избыточным?

В большинстве случаев код можно писать только с использованием указателя стека и не использовать указатель на большинстве процессоров (некоторые процессоры, такие как x86 в 16-разрядном режиме, имеют ограничения на доступ к указателю стека, поэтому указатель кадра необходимо).

Один пример:

mov ebp, esp 
push esi 
mov eax, [ebp+4] 
push edi 
mov eax, [ebp+8] 

также может быть записана в виде:

push esi 
mov eax, [esp+8] 
push edi 
mov eax, [esp+16] 

некоторых особых случаях - как функция ALLOCA() - однако требуют использования обоих кадров и стек указателей.

указатель стека, однако, никогда не лишний:

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

Поскольку такие прерывания предполагают, что память ниже указателя стека свободна, было бы очень плохой идеей использовать память под указателем стека; если произойдет прерывание, чем память ниже указателя стека будет уничтожена!

На процессорах MIPS (например) это чистое соглашение, которое из регистров является указателем стека; вы также можете сказать, что R9 является указателем стека, и стек не находится по адресу R9, но по адресу R9 + 1234. В 64-битном соглашении вызова Sparc используется такое странное соглашение для указателя стека. Однако это требует, чтобы весь код (включая операционную систему и все прерывания) использовал одно и то же соглашение.

На процессорах x86 это невозможно, потому что сам процессор будет считать, что память под указателем стека свободна: инструкции PUSH и CALL будут записываться в память под указателем стека, а в случае прерывания самого ЦП будет хранить информацию по адресу, на который указывает указатель стека, без возможности изменить это поведение!

+0

Обратите внимание, что прерывания x86 в защищенном режиме обычно настраиваются для использования альтернативного стека, поэтому они не сжимают стек приложения. Это вдвойне относится к x86-64 sysv abi, где вы явно имеете красную зону размером 128 байт, доступную под указателем стека. – Jester

+0

@Jester: Это правильно - однако многие люди, работающие с кодом ассемблера, будут либо запускать код в реальном режиме, работать с драйверами устройств, которые работают на CPL 0, либо работать с более простыми микроконтроллерами (более дорогие также имеют два стека). Во всех трех случаях прерывания будут разделять стек с собственным кодом. –

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