Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
л.р.1-12.СПРГ-1(40, укр).doc
Скачиваний:
5
Добавлен:
27.08.2019
Размер:
2.33 Mб
Скачать

3.3. Використання загальних перемінних у процедурах

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

  • При відносно великій кількості процедур обробки тих самих даних продуктивність процедури знижується. Припустимо, у процедурі мається масив чисел, що обробляється декількома процедурами. Щораз при звертанні до процедури інші програми змушені обчислювати якимсь образом адреси елементів масиву. Якщо використовується стек, а в переважній більшості випадків так воно і є, виникає необхідність звертання до стеку для одержання місця розташування елементів масиву в пам'яті. При відносно рідкому звертанні до процедури таких проблем може і не виникнути, але з ускладненням структури програми й алгоритмів обробки швидкодія додатки може знизитися.

  • При обробці тих самих даних різними процедурами структурируемость програми, що використовує асемблерні процедури, погіршується.

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

Надалі ми буде вживати терміни “загальна перемінна” і “глобальна перемінна” як синоніми. Для роботи з загальними перемінними в мові асемблера використовуються директиви public і extern. Директива public повідомляє перемінну або процедуру доступної для інших модулів, директива extern указує на те, що перемінна або процедура є зовнішньою стосовно виконуваної процедури. Обидві директиви застосовуються для компонування основної програми або процедури з декількох об'єктних модулів і дуже зручні для побудови великих програм.

Глобальні перемінні з'являються в такий спосіб:

  • в об'єктному модулі, де знаходиться така перемінна, необхідно вказати на можливість доступу до неї за допомогою директиви public;

  • в об'єктних модулях, з яких відбувається звертання до загальної перемінної, необхідно оголосити неї з директивою extern.

3.4. Особливості 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

4. Завдання на лабораторну роботові.

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

Тип даних:

1) dd

2) dw

3) db

5. Методичні вказівки з оформлення звіту

Звіт до лабораторної роботи винний містити:

тему лабораторної роботи;

формулювання мети і задач, що вирішуються в ході виконання роботи;

докладний звіт про роботові стеку;

докладний звіт про організацію підпрограм та способи предачі в останні параметрів;

висновки.

6. Критерії оцінювання.

На 3 бали:

Вміти дати відповіді на питання для самоконтролеві та самоперевірки. Виконати завдання 1

На 4 бали:

Виконати завдання 2

На 5 балів:

Виконати завдання 3

8. Питання для самоперевірки

Навіщо потрібні процедури?

Як передати в процедуру дані типові db?

Навіщо потрібно “чистити” стік після виконання підпрограми?

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

9. Література

1. Голуб Н. Г. Искусство программирования на Ассемблере. Лекции и упражнения.- СПб.: ООО”ДиаСофтЮП”, 2002. – 656 с.

2. Магда. Ю. С. M12 Ассемблер для процессоров Intel Pentium. – СПб.: Питер, 2006. – 410с.

3. Ирвин Кип. Язык ассемблера для процессоров Intel, 4-е издание.: Пер с англ. – М.: Издательский дом ”Вильямс”, 2005. – 912с.

.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]