Особливості FASM по організації підпрограм (Windows - додатка).
Є чотири макроінструкції для того, щоб викликати процедури з параметрами, переданими в стек, stdcall викликає безпосередньо процедуру зазначену першим параметром, використовуючи STDCALL угода про виклики. Інша частина параметрів передані макроінструкції, визначає параметри для процедури і зберігається в стеці в зворотному порядку. Макроінструкція invoke робить та ж саме, однак процедура викликається побічно, через покажчик, позначений першим параметром. Таким чином, invoke може використовуватися, щоб викликати процедури за допомогою покажчиків, визначених у таблицях імпорту. Цей рядок: invoke MessageBox,0, szText, szCaption, MB_OK є еквівалентної цією: stdcall [MessageBox],0, szText, szCaption, MB_OK і вони обидві перетворяться в цей код: push MB_OK push szCaption push szText push 0 call [MessageBox]. ccall і cinvoke походять на stdcall і invoke, але вони повинні використовуватися, щоб викликати процедури, що використовують З угоду про виклики, де стековый фрейм повинний бути відновлений зухвалою програмою. Щоб визначити процедуру, що використовує стік для параметрів і локальну перемінних, Ви повинні використовувати макроінструкцію ргос. У найпростішій формі вона повинна супроводжуватися назвою для процедури і потім іменами для всіх параметрів які потрібно, наприклад: ргос WindowProc, hwnd, wmsg, wparam, lparam Кома між назвою процедури і першим параметром є додатковою. Код процедури повинний випливати в наступних рядках, і закінчуватися макроінструкцією endp. Стековый фрейм встановлюється автоматично на вході в процедуру, регістр ЕВР використовується як підстава, при звертанні до параметрів, так що Ви повинні уникати використовувати цей регістр дпя інших ланцюгів. Назви, зазначені для параметрів використовуються, щоб визначити Евр-основаные мітки, що Ви можете використовувати, щоб звернутися до параметрів як до перемінного. Наприклад
mov eax, [hwnd] інструкції в процедурі, визначені як у вищезгаданому прикладі, є еквівалентом mov eax, [ebp+8]. Область видимості цих міток обмежена процедурою, так що Ви можете використовувати ті ж самі назви для інших ланцюгів поза даною процедурою. Тому що будь-які параметри містяться в стек як подвійні слова при виклику таких процедур, мітки для параметрів визначаються як подвійні дані слова за замовчуванням, однак Ви можете визначати розміри дпя параметрів за допомогою двокрапки й оператора розміру наступного за назвою параметра. Попередній приклад може бути перезаписаний, котрий є знову еквівалентним: proc WindowProc, hwnd: DWORD, wmsg: DWORD,\ wparam: DWORD, lparam: DWORD Якщо Ви визначаєте розмір менший чим подвійне слово, дана мітка звертається до молодшої частини цілого подвійного слова, збереженого в стеці. Якщо Ви, визначаєте більший розмір, подібно покажчикові з зчетвереного слова, два параметри розміром з подвійне слово будуть визначені, щоб містити це значення, але позначені як одна перемінна. Назва процедури може також супроводжуватися stdcall або ключовим словом, що визначить використовувана угода про виклики. Коли ніякий такий тип не визначений, значення за замовчуванням використовується, що є еквівалентним STDCALL. Також ключове слово uses може випливати, і після нього, список регістрів (розділених пробілами), що будуть автоматично збережені на вході в процедуру і відновлені на виході. У цьому випадку повинна бути кома між списком регістрів і першим параметром. Так що цілком показана інструкція процедури могла б виглядати в такий спосіб: proc WindowProc stdcall uses ebx esi edi, hwnd: DWORD, wmsg: DWORD, wparam: DWORD, lparam: DWORD Щоб повідомляти локальну перемінну, Ви можете використовувати макроінструкцію local, супроводжувану одним або більш оголошеннями, розділеними комами, кожне, що складається з назви для перемінної, супроводжуваною двокрапкою і типом перемінної — кожним зі стандартних типів (повинний бути у верхньому регістрі) або назвою структури даних. Наприклад:
local hDC: DWORD, rc: RECT Щоб повідомляти локальний масив, Ви повинні за назвою перемінної вказати розмір масиву, ув'язнений у квадратні дужки, наприклад: local str [256]: BYTE Інший спосіб визначати локальні перемінні полягає в тому, щоб оголосити них у блоці, початому з макроінструкції “locals” і закінченим “endl”, у цьому випадку, вони можуть бути визначені точно також як припустимі дані. Це оголошення — еквівалент приклада приведеного вище: locals hDC dd? re RECT endl Локальні перемінні можуть бути оголошені де-небудь у процедурі, з єдиним обмеженням, що вони повинні бути оголошені перш, ніж вони використовуються. Область видимості міток для перемінних, визначених як локальні обмежена внутрішньою частиною процедури, Ви можете використовувати ті ж самі імена для інших ланцюгів поза процедурою. Якщо Ви даєте небагато значень перемінним, оголошеним як локальні, макроінструкція генерує команди, що ініціалізують ці перемінні з заданими значеннями і поміщає них у ту ж саму позицію в процедурі, де це оголошення поміщене. ret поміщений де-небудь у процедурі, генерує заключний код, необхідний, щоб правильно вийти з процедури, відновлюючи стековый фрейм і регістри, використовувані процедурою. Якщо Ви повинні зробити інструкцію повернення з підпрограми, використовуйте мнемоніку retn або ret з числовим операндом, що також змушує це інтерпретуватися як єдина інструкція. Повне визначення процедури може виглядати в такий спосіб: proc WindowProc uses ebx esi edi, hwnd, wmsg, wparam, lparam local hDC: DWORD, rc: RECT ; тут ваш код ret endp
Читайте также: III. Особливості програмної реалізації протоколу XDSEP Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|