Погодження викликів

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до: навігація, пошук

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

  • місцем розташування параметрів і значень до повернення (в регістрах; у стеку; в обох)
  • порядком в якому передаються параметри (або частини одного параметра)
  • розподілом завдань з встановлення і очистки після виклику підпрограми між викликальною і викликаною підпрограмами
  • регістри які може прямо використовувати викликана підпрограма також іноді різняться

Різні мови програмування використовують різні погодження викликів і, таким чином, можуть виконуватися на різних платформах. Іноді це призводить до проблем коли спільно використовуються модулі написані із використанням різних мов, або коли викликається операційна система чи API з мови відмінної від тої на якій вона/він написан. Навіть програма, яка використовує одну мову програмування може використати декілька погоджень викилків, або вибраних компілятором з метою оптимізації, або вказаних програмістом.

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

Платформа x86[ред.ред. код]

Архітектура x86 підтримує багато погоджень викиликів. Через малу кількість регістрів, погодження викликів на x86 здебільшого передають аргументи через стек, в той час як значення до повернення (або вказівник на нього) передається в регістрі. Деякі погодження викликів передають в регістрах декілька перших аргументів, що може збільшити видатність для маленьких і листових часто викликаних підпрограм (тобто підпрограм, які не викликають інші підпрограми і, таким чином, не мають бути повторновикористовними).

Приклад виклику:

push eAX            ; передати зміст регістра
push byte[eBP+20]   ; передати деяку змінну в пам'яті (синтаксис FASM/TASM)
push 3              ; передати деяку константу
call calc           ; результат виконання знаходиться в eAX

Типова структура викликаної підпрограми: (деякі або всі (окрім ret) інструкції нижче можуть бути оптимізовані видаленням в простих підпрограмах)

calc:
 push eBP            ; зберегти старий вказівник кадра
 mov eBP,eSP         ; отримати новий вказівник кадра
 sub eSP,localsize   ; зарезервувати місце для локальних змінних
 .
 .                   ; виконати обчислення, залишити результат в AX
 .
 mov eSP,eBP         ; звільнити пам'ять локальних змінних
 pop eBP             ; відновити старий вказівник кадра
 ret paramsize       ; звільнити міце параметрів і повернутись

cdecl[ред.ред. код]

Cdecl- тип викликів, який походить з мови програмування C і використовується за замовчуванням в компіляторах С/С++ на архітектурі x86[1]. Параметри в підпрограму передаються через стек, куди поміщаються у зворотному порядку (справа наліво). 32-бітний результат повертається в регістрі процесора EAX. Чисткою стека займається зовнішня підпрограма.

pascal[ред.ред. код]

Тип викликів, що використовується в основному в мові програмування Pascal. Параметри в підпрограму поміщаються в стек в прямому порядку (зліва направо, тобто протилежно до Cdecl), чисткою стека займається внутрішня підпрограма (та що викликається за допомогою цього виклику). Цей тип викликів був поширений в наступних 16-розрядних інтерфейсах: OS/2 1.x, Microsoft Windows 3.x, і Borland Delphi версії 1.x.

stdcall[ред.ред. код]

stdcall - є стандартним типом виклику для Microsoft Win32 API [2] і Open Watcom C++. Являє собою своєрідний гібрид двох попередніх типів. Викликана підпрограма залишається відповідальною за очищення стека, але параметри поміщаються в стек у зворотному (справа-наліво, як і в cdecl). Регістри EAX, ECX, EDX призначені для використання в межах функції. Значення, що повертається, зберігається в регістрі ЕАХ.

fastcall[ред.ред. код]

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

Платформа AMD64(x86-64)[ред.ред. код]

Розробники платформи AMD64 значно розширили набір регістрів процесора. Це дозволило передавати використати як стандарт передачу параметрів в регістрах процесора. Зокрема, перші чотири цілочисельні параметри передаються в регістрах RCX, RDX, R8, R9. Наступні параметри, якщо такі є - через стек. Результат повертається в регістрі EAX. [3]

References[ред.ред. код]

  1. http://msdn.microsoft.com/en-us/library/zkwh89ks.aspx
  2. http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx
  3. http://msdn.microsoft.com/en-US/library/zthk2dkh%28v=vs.80%29.aspx