Розуміння кадру стека функціонального виклику в C / C ++?


19

Я намагаюся зрозуміти, як будуються кадри стека і які змінні (парами) підштовхуються до складання в якому порядку? Деякі результати пошуку показали, що компілятор C / C ++ приймає рішення на основі операцій, які виконуються в межах функції. Наприклад, якщо функція повинна була просто збільшити значення переданого int на 1 (аналогічно оператору ++) і повернути його, вона помістить усі параметри функції та локальні змінні в регістри.

Мені цікаво, які регістри використовуються для повернених або пропущених параметрів значення. Як повертаються посилання? Як компілятор вибирає між eax, ebx, ecx та edx?

Що мені потрібно знати, щоб зрозуміти, як регістри, стеки та посилання використовуються, будуються та знищуються під час викликів функцій?


це досить важко читати (стіна тексту). Ви б не хотіли відредагувати свою публікацію в кращій формі?
гнат

1
Це питання мені здається досить широким. Крім того, це не буде дуже платформою?
Казарк

Також було задано запитання щодо SO: stackoverflow.com/questions/16088040/…
Wayne Conrad

Відповіді:


11

Окрім того, що сказав Дірк, важливим використанням кадрів стека є збереження попередніх значень регістрів, щоб їх можна було відновити після виклику функції. Так, навіть у процесорах, де регістри використовуються для передачі параметрів, повернення значення та збереження адреси повернення, значення цих регістрів зберігаються на стеку перед викликом функції, щоб вони могли бути відновлені після виклику. Це дозволяє одній функції викликати іншу, не перезаписуючи власні параметри або забувши власну зворотну адресу.

Отже, виклик функції B з функції A в типовій "загальній" системі може включати такі кроки:

  • функція A:
    • пробіл для повернення значення
    • параметри натискання
    • натисніть зворотну адресу
  • перейти до функції В
  • функція B:
    • натисніть адресу попереднього кадру стека
    • Push значення регістрів, які використовує ця функція (щоб їх можна було відновити)
    • простір для локальних змінних
    • зробити необхідні обчислення
    • відновити регістри
    • відновити попередній кадр стека
    • збереження результату функції
    • перейти до зворотної адреси
  • функція A:
    • поп-параметри
    • поп повернути значення

Це аж ніяк не єдиний спосіб, коли функціонування викликів може працювати (і у мене може бути крок або два не в порядку), але це повинно дати вам уявлення про те, як стек використовується для того, щоб процесор міг працювати з вкладеними викликами функцій.


Що саме тут означає «штовхання»? Я поняття не маю, що з цього зробити.
Томаш Зато - Відновіть Моніку

2
@ TomášZato pushі popдві основні операції на стеці. Стек - це структура, що склалася останнім-першим, як стопка книг. Коли ви push, ви кладете новий об’єкт поверх стека; коли ви popберете предмет з верхньої частини стека. Вам не дозволяється вставляти або видаляти об’єкти посередині, ви можете працювати лише у верхній частині стека. Ви можете прочитати більше про стеки взагалі та про програму, зокрема, у Вікіпедії.
Калеб

11

Це залежить від використовуваної конвенції про виклик. Той, хто визначає конвенцію про закликання, може прийняти це рішення, як того хоче.

У найбільш поширеній конвенції про виклики на x86 регістри не використовуються для передачі параметрів; параметри висуваються на стек, починаючи з самого правого параметра. Повернене значення розміщується в eax і може використовувати edx, якщо йому потрібен додатковий простір. Посилання та покажчики повертаються у вигляді адреси в eax.


5

Якщо ви дуже добре розумієте стек, то зрозумієте, як працює пам'ять у програмі, і якщо ви розумієте, як працює пам'ять у програмі, ви зрозумієте, як зберігається функція в програмі, і якщо ви розумієте, як зберігається функція в програмі, ви зрозумієте, як працює рекурсивна функція і якщо ви розумієте, як працює рекурсивна функція, ви зрозумієте, як працює компілятор, і якщо ви зрозумієте, як працює компілятор, ваш розум буде працювати як компілятор, і ви легко налагодите будь-яку програму

Дозвольте мені пояснити, як працює стек:

Спочатку ви повинні знати, як зберігати функції в стеці:

Купа зберігає значення динамічного розподілу пам'яті. Значення автоматичного розподілу та видалення зберігання стека.

введіть тут опис зображення

Розберемося на прикладі:

def hello(x):
    if x==1:
        return "op"
    else:
        u=1
        e=12
        s=hello(x-1)
        e+=1
        print(s)
        print(x)
        u+=1
    return e

hello(4)

Тепер зрозумійте частини цієї програми:

введіть тут опис зображення

Тепер давайте подивимося, що таке стек і що таке стек:

введіть тут опис зображення

Виділення стека:

Запам’ятайте одне, якщо будь-яка функція отримає „повернення”, незалежно від того, завантажила вона всі його локальні змінні або що-небудь, воно негайно повернеться з стека, буде його рамка стека. Це означає, що коли будь-яка рекурсивна функція отримує базову умову, і ми ставимо повернення після базової умови, тому базова умова не чекатиме завантаження локальних змінних, які знаходяться в іншій частині програми, вона негайно поверне поточний кадр зі стека і тепер, якщо один кадр наступний кадр повернення знаходиться в записі активації. Дивіться це на практиці:

введіть тут опис зображення

Розподіл блоку:

Тому тепер, коли функція знайшла оператор return, вона видаляє поточний кадр із стека.

при поверненні зі стека значення повернеться у зворотному порядку, у якому вони були виділені в стеці.

введіть тут опис зображення

Це дуже короткий опис, і якщо ви хочете дізнатися більше про стек та подвійну рекурсію, прочитайте два повідомлення цього блогу:

Детальніше про стек крок за кроком

Більше про подвійну рекурсію крок за кроком зі стеком


3

Те, що ви шукаєте, називається Application Binary Interface - ABI.

Існує специфікація для кожного компілятора, який пише ABI.

Кожна платформа зазвичай вказує і ABI для того, щоб підтримувати сумісність між компіляторами. Наприклад, конвенції про виклики x86 визначають типові умови викликів для x86 та x86-64. Однак я б очікував більш офіційного документа, ніж вікіпедія.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.