Міністерство освіти і науки України
Національний університет «Львівська політехніка»
Кафедра АСУ
Методичка №1
Лабораторна робота №1
З курсу програмування в асемблері
Тема – введення в основи програмування на мові асемблер, за допомогою Win32API функцій.
Мета – навчитися використовувати функції Win32API при програмуванні в операційній системі Windows.
Львів 2010
ТЕОРЕТИЧНІ ПОЛОЖЕННЯ
Win32API (розшифровується як інтерфейс прикладних програм) - це система функцій ОС Windows, якими користується програма не залежно від мови програмування. Win32API використовує 32х-бітну адресацію. Під адресою розуміється 32 бітне число, котре визначає, де лежить об’єкт у пам’яті комп’ютера. Множина АРІ-функцій розширюється при переході до наступної версії Windows, таким чином, забезпечується сумісність розроблених раніше програм із новими версіями операційної системи.
Суть функцій Win32API зрозуміти значно легше, якщо уявити, з яких файлів вони викликаються і на які групи ці функції поділяються.
Основний набір функцій знаходиться в бібліотеці kernel32.dll, котра складає ядро операційної системи Windows. Під ядром розуміються базові операції, на яких реалізовані всі інші АРІ-функції (наприклад, операції з пам’яттю та процесами).
Файли в котрих знаходяться Win32API функції називаються динамічними бібліотеками. Деякі бібліотеки знаходяться постійно в оперативній пам’яті, наприклад, ядро. Інші бібліотеки можуть довантажуватися, в процесі виконання програми, або при її старті (за допомогою секції імпорту в ЕХЕ - модулі). При необхідності є можливість вивантажити бібліотеку, таким чином зекономити дорогоцінні ресурси пам‘яті. Динамічні бібліотеки іменуються у Windows як DLL(файли. Щоб визначити список функцій експорту DLL файлу, потрібно викликати ImpDefPro.exe У разі необхідності, програміст може створити свій DLL(файл з набором власних функцій.
Пізнати силу операційної системи можна за допомогою будь-якої мови програмування, що підтримує Win32API. Але кожна мова, накладає певну кількість обмежень на управління даними, що виражається великою кількістю типів та правил користування даними, проте асемблер не має ЖОДНИХ ОБМЕЖЕНЬ НА ПРОГРАМУ ТА ЇЇ ДАНІ, з якими вона працює. Це повинен робити сам програміст з метою захисту операційної системи від своїх некоректних дій. Це і робить мову асемблер такою геніальною.
Хоча асемблер розглядають як мову низького рівня, цю мову можна також розглянути, як мову високого рівня, якщо використовуватися макрокомандами та підпрограмами (як це буде показано в прикладах).
Основною метою системного програмування є написання коректних програм з необмеженими можливостями (в рамках операційної системи). Для збереження коректності ми будемо користуватися певними правилами програмування, які будуть зрозумілі на конкретних прикладах.
Особливості виклику функцій API
При програмуванні на WinAPI необхідно знати деякі правила, перелічимо їх:
Стандарт виклику функцій API оснований на передачі параметрів через стек (а не через регістри); кожен параметр для функцій API має довжину 4 байти, топу який має логічний зміст повинен розширятися до 4 байтів. Наприклад, NULL = 0000h, TRUE = 0001h.
Значення кожної функції API повертається в регістрі EAX. Якщо функція повертає структуру або рядок, то регістр EAX містить логічну ознаку виконання, а адресу структури або ж рядка (посилання на дані) необхідно передати до функції як параметр;
Усі АРІ-функції мають унікальні назви, вони ідентичні у будь-якій мові програмування.
Програми Windows звертаються до функцій API за допомогою команд апаратного виклику CALL, наприклад: call MessageBoxA, де MessageBoxA – іменована константа, що містить 32х-бітну адресу функції. Саме ця назва функції фігурує у файлі user32.dll (подивіться редактором цей файл).
При програмуванні на асемблері необхідно розрізняти команди для процесора та команди самого асемблера. Наприклад, для передачі параметрів використовується явний запис параметрів в стек (в зворотному порядку)
Наприклад:
Push param4
Push param3
Push param2
Push param1
Call MessageBoxA
Для спрощення передачі параметрів можна використовувати макрокоманду invoke, яка дозволяє сформувати всі параметри через кому:
Invoke MessageBoxА, param1, param2, param3, param4
Існують два типи АРІ функції:
Функції котрі використовують АNSI-кодування (1байт на символ)
Функції котрі використовують UNICODE-кодування (2 байта на один символ)
Функції АNSI закінчуються на букву “А”, UNICODE ( на букву “W”. Як правило, якщо програміст пише функцію без букви “A”, то автоматично використовується варіант АNSI - кодування.
Кожний параметр функції є 32х-бітним числом (в якому можуть використовуватись не всі біти). Для передачі рядка символів в якості параметра функції передається НЕ САМ РЯДОК, А ЙОГО АДРЕСА. В подальшому ми не робимо жодної різниці поміж даними типу рядок символів (тип string з Pascal) та послідовністю байтів в пам’яті, іменованим „буфером даних”. В асемблері передбачається, що в пам’ять можна записувати просто дані, не дивлячись якого вони типу. За один раз (одною командою) в пам’ять можна записати 1, 2 або 4 байти. В залежності від цього змінні поділяються на одно, двох та чотирьох байтові. До елементів масиву, можна звертатися таким же самим чином.
ПОРЯДОК ВИКОНАННЯ РОБОТИ
Відкриваємо F:\asm\RаdAsm.exe.
Закрити попередній проект за допомогою меню: Файл(Закрити Проект(Ctrl+Shift+C)
Створюємо новий проект: Файл(Новий Проект
(Ctrl+Shift+N)
У вікні майстра створення проекту, вибираємо тип асемблеру „masm”, тип проекту “Win32 App non res”(це означає, що програма є 32 розрядною і не використовує власних ресурсів, тобто іконок, діалогових вікон, меню і т.д.), ім’я та опис проекту вводимо індивідуально. Обов‘язково перевірити шлях до папки у вікні „Директорія”, куди буде збережений ваш проект, як правило, це повинно бути „c:\Users\ВЛАСНА_ГРУПА\”. Шлях та назва проекту мають складатися тільки з латинських букв і цифр, без пробілів. Натискаємо ”Next”.
Після цього, висвічується список можливих шаблонів для Win32 програм. Вибираємо проект „Звичайний” тобто „Simple_no_res”. Стандартний шаблон програми. Натискаємо „Next”.
Наступним кроком висвічується перелік файлів і папок, які потрібно створити для нашого проекту. Вибираємо файли „asm”(файл коду), „inc” (файл заголовків) а папки тільки „bak”(резервні копії колишніх змін). Натискаємо „Next”.
Наступним кроком висвічується перелік ключів та параметрів компіляції, програма встановлює параметри автоматично. Натискаємо „Готово” (“Finish”).
В правій частині програмного вікна з’являється список створених файлів котрі відносяться до проекту.
Клікаємо у вікні по файлу з розширенням „inc” (додатковий файл) – відкривається вікно з основними директивами коду, в котрий треба дописати необхідний текст представлений на Рис. 1.1. В цьому файлі будуть зберігатися константи, змінні, структури, шаблони, описи макросів та ініціалізації файлів що підключаються.
Наступним кроком в правій частині програмного вікна клікаємо по файлу з розширенням „asm” – відкривається вікно в яке треба дописати необхідний текст представлений на Рис 1.2. В цьому файлі міститься код програми.
Зберігаємо всі файли за допомогою послідовності пунктів меню: Файл(Зберегти всі файли (Ctrl+Shift+S).
Компілюємо проект за допомогою послідовності пунктів меню: Створити ( GO (F9).
Після компіляції програми з’явиться вікно яке відображає результат її роботи (Див. рис. 1.3. )
Рис 1.1. Лістінг файлу “Lab_1.inc”
Рис 1.2. Лістінг файлу “Lab_1.asm”
Рис 1.3. Результат виконання програми “Lab_1.ехе”
14. Створити аналогічні програми, котрі використовують наступні АРІ-функції: GetUserName, GetWindowsDirectory, GetSystemDirectory, GetTempPath, GetCurrentDirectory, GetDriveType, після чого відкомпілювати і запустити програму. Довідкова інформація можна отримати у файлі C:\Programing\Help\Help_API.exe
ВИПРАВЛЕННЯ ПОМИЛОК
Після компіляції, курсор зупиняється на рядку що містить помилку. Інформація про помилку знаходиться у вікні “Output” в нижній частині екрану. Повідомлення “Error” вказую на недопустиму помилку, а “Warning” – це попередження про некоректний запис, на який компілятор не зважає. Технологія відлагодження програми полягає у кроковій перевірці алгоритму. Для цього існують так звані контрольні точки перевірки. Див. розділ «Додаткова інформація по роботі з інтерактивним середовищем RadAsm (ICRA)». Кардинально переробляти алгоритм не бажано, краще запускати програму після кожного виправлення - тоді ймовірність помилки буде мінімальною. Доки не виправлено одна помилка, не переходити до виправлення інших помилок. Тоді взаємозв‘язок між помилками буде мінімальним. В наступному пункті приведені найчастіші помилки.
МОЖЛИВІ ПОМИЛКИ:
рядок з коментарем не позначений символом “;”
записана маленька буква замість великої або навпаки;
хибна послідовність параметрів або їх недостатність;
невірний тип параметрів (word замість dword);
передача змінної як параметра замість її адреси (addr).
Програма не може виконати АРІ-функцію, тому що в проект не підключені необхідні “inc” та “lib” файли. (Див. далі.)
якщо програма редактор була закрита, по якийсь причині, то потрібно зробити наступні кроки:
Відкрити RadAsm.exe
Викликати пункт меню Файл(Відкрити Проект (Ctrl+Shift+O).
Шукаємо свій проект з розширенням “.rap”;
Довідкова інформація
Про параметри функцій можна дізнатися з довідкового файлу WIN32.HLP (на англійській мові). Файл знаходиться в каталозі C:\Program Files\Common Files\Borland Shared\MSHelp\win32.hlp. Для отримання довідки необхідно запустити файл WIN32.HLP, вибрати розділ “index (указатель)”, набрати назву функції.
Підключення бібліотек імпорту
Щоб визначити, до якої бібліотеки відноситься АРІ функція, після знаходження її в довіднику (див. попередній пункт), потрібно натиснути кнопку „Quick info”. На проти стрічки „Import Library” буде вказано назву бібліотеки. Щоб задіяти функції цієї бібліотеки, проекту потрібно у файл *.inc, на початку дописати наступне:
іnclude namelib.inc
іncludelib namelib.lib
де namelib – це ім’я вище згаданої бібліотеки з „Quick info”.
Після вказаних дій всі АРІ функції, що відносяться до підключеної бібліотеки будуть без проблем викликатися.
По замовченню всі АSNI-функції пишуться без букви “А” (хоча насправді в кінці вона є, наприклад, MessageBox → MessageBoxА). Це пояснюється тим, що у файлі прототипів “namelib.inc” спеціально прописані альтернативні імена для полегшення програмування.
Додаткова інформація по роботі з інтерактивним середовищем RadAsm (ICRA)
Отримання довідки по інструкціях Асемблера.
Для цього, встановлюємо текстовий курсор над інструкцією асемблера і натискаємо клавішу “F1”.
Отримання довідки по функціях Win32Api.
Для цього, встановлюємо текстовий курсор над ім’ям функції по якій треба отримати довідку і натискаємо клавішу “F1”.
Автоматичний набір констант, функцій та елементів структур.
Під час набору перших букв констант, функцій та елементів структур ICRA допомагає вибрати потрібну вам константу, функцію або елемент структури. Вибір здійснюється клавішею “Tab”.
Пошук та автоматичний набір змінних, констант, макросів та структур котрі використовуються у програмі
Для автоматичного набору або пошуку необхідно натиснути комбінацію “Ctrl+Space”. Для вибору використовуйте клавішу “Tab”.
Створення багато рядкового коментаря.
Для створення багато рядкового коментарю використовується макрокоманда “comment #”. Коментар буде дійсний доки в тексті не зустрінеться аналогічний символ (в нашому випадку ( це символ “#”).
Встановлення Точок зупинки.
Для від лагодження програми використовується так звані точки зупинки, за допомогою котрих можна визначити вміст регістрів в конкретній точці програми.
Для цього потрібно зробити наступні кроки:
Підключити до проекту файл “RADbg.inc” (за допомогою директиви include).
Виділяємо стрічки в яких необхідно зробити зупинку та натискаємо клавішу “F5”. Повторне натиснення “F5” знімає точку зупинки. Для зняття всі точок зупинки застосовуємо комбінацію “Ctrl+Alt+F5”.
Встановлення закладок в тексті програми.
Для встановлення закладки використовуємо комбінацію “Shift+F8”. Повторне натиснення “Shift+F8” знімає закладку.
Перехід на наступну закладку здійснюється за допомогою комбінації “ F8”.
Перехід на попередню закладку здійснюється за допомогою комбінації “Ctrl + F8”.
Зняти всі закладки здійснюється за допомогою комбінації “Ctrl +Shift + F8”.
Перехід на конкретну закладку здійснюється за допомогою комбінації “Ctrl +1…9 ”, де число є порядковим номером закладки.
Пошук АSCIІ коду символа, та додання його до коду проекту за допомогою ІС RadAsm.
Для знаходження АSCIІ коду символа, необхідно викликати пункт меню Інструменти ( Таблиця АSCIІ. Перед вами з’явиться таблиця символів. При кліканні на символі в таблиці, в код програми добавиться шістнадцядковий код символу.
Пошук значення кольору, за допомогою ІС RadAsm.
Для знаходження значення коду потрібного вам кольору, необхідно викликати пункт меню Інструменти ( ColRef. Перед вами з’явиться вікно з розширеними можливостями вибору кольору.
Вибрати можна із стандартних, що знаходяться в лівій частині вікна, або самостійно з палітри кольорів (що з права). Після вибору кольору, клікнути по кнопці “OK”.
Напроти рядків “RGB”, ”Heх value”, “Dec value” є кнопки з назвою “Insert”. Кожна Кнопка “Insert” вписує в код значення кольору в своїй системі кодування (RGB, шістнадцяткове, чи десяткове число). В залежності в якій системі Вам потрібно на таку кнопку і натискуєте. Значення додається до коду вашого проекту.
КОНТРОЛЬНІ ЗАПИТАННЯ
Які помилки зустрічаються найбільш часто ?
Що таке функція API ?
Що означають букви “А” і ”W” в кінці назви АРІ -функції?
В який регістр повертає значення АРІ-функція?
Як визначити, функції, у DLL-файлі ?
Яким чином передаються параметри функціям API ?
Яка можлива довжина кожного параметра функції API?
Що означають ключові слова .data і .code ?
Що роблять функції MessageBox, GetComputerName, GetCurrentDirectory, GetDriveType, GetSystemDirectory, GetTempPath, GetUserName, GetWindowsDirectory ?
Завдання
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetDriveType, GetSystemDirectory, GetTempPath, GetUserName та GetWindowsDirectory в одну стрічку, формату :
Computer Name : ……
Current Directory : ……..
ітд.
У результуючому рядку поміняти регістр всіх букв.
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetUserName та GetWindowsDirectory в один рядок. Формат результату, аналогічний до варіанту №1. Замінити в рядку-результаті всі букви, ANSI значення яких парне число, на символ «!». Звернути увагу, потрібно накласти таку умову, щоб код Enter (#13 #10), було не змінні.
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetDriveType, GetSystemDirectory, GetTempPath, GetUserName та GetWindowsDirectory в одну стрічку. Написати дві процедури, одна з яких вручну об’єднує стрічки, друга видаляє з стрічки всі пробіли.
Викликати функцію GetDriveType. Перевірити результат функції, якщо результат “Змінний диск”, вивести на екран об’єднання результатів функцій GetComputerName та GetCurrentDirectory, протилежному випадку вивести на екран об’єднання результатів функцій GetUserName та GetWindowsDirectory.
Об’єднати результати функцій GetComputerName та GetCurrentDirectory в одну стрічку, попереставляти слова ззаду на перед.
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetDriveType, GetSystemDirectory, GetTempPath, GetUserName та GetWindowsDirectory в одну стрічку. Підняти всі букви до верхнього регістру.
Об’єднати результати функцій GetComputerName та GetCurrentDirectory в один рядок, та виконати реверс стрічки. Вивести результат.
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetDriveType, GetSystemDirectory, GetTempPath, GetUserName та GetWindowsDirectory в одну стрічку, формату :
Computer Name : ……
Current Directory : ……..
ітд.
Опустити всі символи у нижній регістр.
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetSystemDirectory, в одну стрічку. Вивести стрічку посимвольно.
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetSystemDirectory, в одну стрічку. Вивести стрічку посимвольно у зворотному напрямку. У вікні MessageBox’а вивисти 2 кнопки, «ОК» та «Cansel» . При у мові натиснення «ОК», продовжити виведення символів, при умові Cansel», вийти з програми.
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetSystemDirectory, в одну стрічку. Вивести у вікні MessageBox’у. При тому вивести 2 кнопки, «ОК» та «Cansel» . При у мові натиснення «ОК», повторно вивести стрічку, при умові Cansel», вийти з програми.
Вивести GetComputerName, GetCurrentDirectory, GetDriveType, GetSystemDirectory, GetTempPath, GetUserName та GetWindowsDirectory, окремими MessageBox’ами.
Об’єднати результати функцій GetComputerName та GetTempPath в один рядок. Обміняти кожну 2-гу літеру у рядках масивів.
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetUserName та GetWindowsDirectory в один рядок. Формат результату, аналогічний до варіанту №1. Замінити в рядку-результаті всі букви, ANSI значення яких більше числа 70, на символ «!».