Функционални разговори, част 2 (стека и призоваващи конвенции)

В първата част сте научили основите на повикване функции на механизма, което се разглежда, от гледна точка на генерирания код. В същото време научихте за двата регистъра, които се използват x86 процесори семейство - регистъра на ЕПИ (показалеца на обучение) и ESP регистър (стека показалка). Във втората част ще научите малко повече за стека и нейната важна роля в механизма на извиквания на функции. Освен това, ще научите за две от най-популярните разговори конвенции [призовават конвенции] в програмирането Windows / C.

Стек - местоположение на паметта (в рамките на разпределените четири гигабайта), в който потокът може да съхранява данните, необходими за упражняване. По-специално, стека могат да се съхраняват местните променливи, използвани от вашия код, временните променливи, използвани от компилатора, аргументи на функция и т.н. Stack поведение прилича на поведението на тесте карти [купчина от карти], по този начин той получава своето име. Това означава, че когато поставите обекти в стека, те са винаги на върха му, а когато изтриете обект от купа, винаги можете да се премахне най-горния обект. От техническа гледна точка този метод на достъп до данните, се нарича LIFO (Last първа изходяща - продължи, първа изходяща).

Както е обяснено в първата част, системата предоставя купчина от всяка нишка. Чрез стак подразбиране е 1 MB, но тя може да бъде заменена със стойността, съдържаща се в процеса на глава изображение [процес "стойност на изображението глава]. Размерът на комин също може да бъде определен в CreateThread на повикване () или _beginthreadex ().

Процесорът трябва винаги да знаят къде на върха на стека. Местоположението му регистър определя ESP. EIP регистър стойност очевидно не може да се променя. ESP стойност регистър не само може да се променя от процесора имплицитно, но и това може да се промени чрез изрично инструкции.


Как параметрите се подават на функцията?


Как функция се получава параметри?

По този начин, при въвеждане на функция за кодиране има всичко, което той трябва да изпълни.


Разговори конвенции [Calling конвенции]

Сега тя ще бъде подходящо да се обмисли обажда конвенции. Свикването - е протокол за предаване на аргументи на функция. С други думи, това е споразумение между призванието и нарича код. Смятан в темите "Как параметрите се подават на функцията?" и "Как работи функцията получава опциите?" - е този протокол, това е общото описание. Въпреки това, ако се занимават със софтуер на Microsoft, след това има допълнителни споразумения. Най-полезните от тях:

__cdecl
__stdcalll
thiscall

В тази статия, ние ще обсъдим на споразуменията и механизми __cdecl __stdcall и да научат как стека прилича и компилиран код във всеки един от тези случаи.

Детайлно описание __cdecl протокол може да бъде намерена тук. Особено важни са следните точки:

* Редът на преминаващите аргументи: от дясно на ляво
* Отговорност за целостта на стека: повикващия трябва да премахнете аргументите от стека


Процедурата за преминаване аргументи в протокола __cdecl

Процедурата за подаване на аргументи, за да опише начина, по който аргументите са поставени в стека от повикващия. В случай на __cdecl протокол ние говорим за реда на "право". Това е последният аргумент е поставен в стека, на първо място, следвана от аргумента, предпоследен, и така нататък, докато всички аргументи няма да се появят в стека. След като това бъде направено, конструкцията се изпълнява повикване, функцията за разговори.

Функционални разговори, част 2 (стека и призоваващи конвенции)

* Изграждане на проекта (Build решение елемент от менюто).
Натиснете F5, за да стартирате програмата под дебъгер. Изпълнението на програмата ще спре в 13-та линия.
* Натиснете Alt + 5. Се появява прозорец, показване на съдържанието на регистрите [Регистри Window].
* Натиснете Alt + 6. Появява се отвори прозорец, показващ съдържанието на паметта [Memory Watch Window].
* Отидете на линия 13, за да отворите контекстното меню и изберете Go To демонтаж.
* The Disassembler отново отворите контекстното меню и се уверете, че белязана от следните елементи:
- Покажи Адрес
- Покажи на изходния код
- Показване Код Bytes

Disassembler прозорец трябва да изглежда така:

Функционални разговори, част 2 (стека и призоваващи конвенции)

Функционални разговори, част 2 (стека и призоваващи конвенции)


Отговорността за целостта на __cdecl протокол стека

* Натиснете F5, за да стартирате програмата под дебъгер. Изпълнението на програмата ще спре в 13-та линия.
* Натиснете Alt + 5. Се появява прозорец, показване на съдържанието на регистрите [Регистри Window].
* Натиснете Alt + 6. Появява се отвори прозорец, показващ съдържанието на паметта [Memory Watch Window].
* Отидете на линия 13, за да отворите контекстното меню и изберете Go To демонтаж.
* The Disassembler отново отворите контекстното меню и се уверете, че белязана от следните елементи:
- Покажи Адрес
- Покажи на изходния код
- Показване Код Bytes

Disassembler прозорец трябва да изглежда така:

Функционални разговори, част 2 (стека и призоваващи конвенции)

* Не забравяйте, че това, което е стойност в регистъра ESP сега (не сте поставени аргументите в стека). В нашия пример, тази стойност е 0x12FF64. Първото нещо, което трябва да се случи веднага след инструкция за повикване - за възстановяване на ESP в значението, което се сетите. Натиснете F10, за да пропуснете блока с две инструкции тласък и се обадете на инструкции. След това погледнете в стойността на ESP.

Функционални разговори, част 2 (стека и призоваващи конвенции)

* В нашия пример ESP регистър ще бъде номер 0x12FF5C. Както можете да видите, че не е равна на първоначалната стойност. Поради това е необходимо да се възстанови целостта на стека. Сега погледнете реда с код, който в момента спира изпълнението. Тази линия
При извършване на това действие, ние се 12FF5Ch + 8h = 12FF64h - ние изискваме броя. По този начин, този низ възстановява целостта на комина, тъй като ESP се връща към първоначалната си стойност. Имайте предвид, че тази линия е собственост на обаждащия се, а не на т.нар. Тя е в протокола __cdecl нарича "призовава функция премахва аргументите от комина [Calling функция се появи на аргументите от купчината]". Въпреки, че това не е пряко използвани инструкции поп, все още резултатът е един и същ - ESP показалка получава предишната стойност.


Заключения относно Протокола от __cdecl

* Отговорността на призванието код за целостта на пакета означава, че ако кодът на разговори на различни места, наречена 100 функции, използвайки __cdecl протокол, тя за всеки един от тези разговори да изпълни допълнителен код за целостта на стека, дори и ако званието през цялото време една и съща функция , Така, количеството на генерираната кодова може да бъде увеличена.
* Тъй като отговорността за целостта на стека се основава на кода за разговори, __cdecl протокол ви позволява да създадете списък с аргумент променлива дължина. Когато се обадите функция с променлив брой аргументи, само на обаждащия се знае колко параметри са преминали към него. Следователно __cdecl протокол е много подходящ за такава ситуация.