Почему параметры функции помещаются в стек вызовов раньше, чем адрес возврата? - PullRequest
9 голосов
/ 12 февраля 2012

С http://en.wikipedia.org/wiki/Stack_pointer#Structure

enter image description here

Мне интересно, почему адрес возврата функции находится над параметрами этой функции?

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

Каковы причины предпочтения реализации, показанной на диаграмме выше?

Ответы [ 2 ]

6 голосов
/ 12 февраля 2012

Адрес возврата обычно передается машинной командой call, которая [в наборе команд на родном языке ], в то время как параметры и переменные передаются несколькими машинными командами - которые создает компилятор.

Таким образом, адрес возврата - это последнее, что нажимает вызывающий , и перед чем-либо [локальными переменными], нажимаемым вызывающим.

Все параметры передаются перед адресом возврата, поскольку переход к фактической функции и вставка адреса возврата в стек выполняется в одной и той же машинной команде .

Кроме того, другая причина заключается в том, что вызывающим является тот, кто выделяет пространство в стеке для параметров. Это также должен быть [вызывающий объект], который очищает его.

1 голос
/ 12 февраля 2012

Причина проста: аргументы функции помещаются в стек вызывающей функцией (единственной, которая может это сделать, потому что только она обладает необходимой информацией; в конце концов, весь смысл в том, чтобы передать этоинформация для вызываемой функции).Адрес возврата помещается в стек с помощью механизма вызова функции.Функция вызывается после вызывающая функция установила параметры, потому что после вызова выполняется вызываемая функция, а не вызывающая.

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

Также обратите внимание, что это не зависит от вопроса о том, кто очищает параметры.В принципе, вызываемая функция может вызывать деструкторы вызова аргументов, даже если физически они лежат в кадре стека вызывающей стороны.Кроме того, многие процессоры (включая x86) имеют инструкции, которые автоматически возвращают дополнительное пространство над адресом возврата при возврате (например, компиляторы Pascal обычно делают это, потому что в Pascal нет очистки после возврата памяти, и, по крайней мере, дляПроцессоры того времени было более эффективно очищать с помощью этой инструкции процессора (я понятия не имею, верно ли это для современных процессоров). Однако C не использовал этот механизм из-за списков аргументов переменной длины:этот механизм неприменим, потому что вам нужно знать во время компиляции, сколько дополнительного пространства нужно освободить, а K & R C не требуется предварительно объявлять функции с переменными значениями (C89 делает, но лишь немногие, если какие-либо компиляторы используют это в силусовместимости со старым кодом), поэтому вызывающая функция не могла узнать, следует ли очищать аргументы, если она не должна делать это всегда.

...