Міністерство освіти і науки, молоді та спорту України
Національний Університет «Львівська Політехніка»
кафедра АСУ
Звіт
Про виконання лабораторної роботи №1
із системного програмування
Львів-2012Лабораторна робота №1
Тема – введення в основи програмування на мові асемблер, за допомогою Win32API функцій.
Мета – навчитися використовувати функції Win32API при програмуванні в операційній системі Windows.
ТЕОРЕТИЧНІ ПОЛОЖЕННЯ
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. )
14. Створити аналогічні програми, котрі використовують наступні АРІ-функції: GetUserName, GetWindowsDirectory, GetSystemDirectory, GetTempPath, GetCurrentDirectory, GetDriveType, після чого відкомпілювати і запустити програму. Довідкова інформація можна отримати у файлі C:\Programing\Help\Help_API.exe
Завдання
Об’єднати результати функцій GetComputerName, GetCurrentDirectory, GetDriveType, GetSystemDirectory, GetTempPath, GetUserName та GetWindowsDirectory в одну стрічку, формату :
Computer Name : ……
Current Directory : ……..
ітд.
Опустити всі символи у нижній регістр.
.386
.model flat, STDCALL
option casemap :none
include firstlab.inc;
include RADbg.inc
.code
Start:
INVOKE GetComputerName,addr ComputerName,addr MaxSize
INVOKE GetCurrentDirectory,addr MaxSize, addr CurrentDirectory
INVOKE GetUserName,addr UserName, addr MaxSize
INVOKE GetWindowsDirectory, addr WindowsDirectory, addr MaxSize
INVOKE GetTempPath,addr MaxSize, addr TempPath
INVOKE GetSystemDirectory,addr SystemDirectory, addr MaxSize
INVOKE GetDriveType,addr DriveType
cmp eax, DRIVE_FIXED
jne L1
LEA esi, Fixed
jmp exit
L1: cmp eax, DRIVE_REMOVABLE
jne L2
LEA esi, Removable
jmp exit
L2: cmp eax, DRIVE_REMOTE
jne L3
LEA esi, Remote
jmp exit
L3: cmp eax, DRIVE_CDROM
jne L4
LEA esi, CDROM
jmp exit
L4: cmp eax, DRIVE_RAMDISK
jne L5
LEA esi, RAMDISK
jmp exit
L5:
LEA esi, Unknown
exit:
INVOKE wsprintf, addr result, addr format, addr ComputerName, addr CurrentDirectory, addr UserName, addr WindowsDirectory, addr TempPath, addr SystemDirectory, esi
INVOKE lstrlen, addr result
mov ecx, eax
LEA ESI,result
LP1:
push ecx
xor eax, eax
mov al, [esi]
INVOKE IsCharUpper, eax
cmp eax, 0
je LPend
add byte ptr [esi], 32
LPend:
inc esi
pop ecx
LOOP LP1
invoke MessageBox, NULL, addr result, addr windowtitle,MB_OK+MB_ICONEXCLAMATION
INVOKE ExitProcess, NULL
end Start
include WINDOWS.inc
include kernel32.inc
include user32.inc
include kernel32.inc
include advapi32.inc
includelib advapi32.lib
includelib kernel32.lib
includelib user32.lib
includelib kernel32.lib
.data
result db 512 dup (0)
format db 'ComputerName: %s', 13,10
db 'CurrentDirectory:%s',13 ,10
db 'UserName: %s',13,10
db 'WindowDirectory: %s', 10, 13
db 'TempPath: %s', 10, 13
db 'SystemDirectory: %s', 10, 13
db 'DriveType: %s', 0
MaxSize dd 256
windowtitle db 'Lab1', 0
ComputerName db 256 dup (0)
CurrentDirectory db 256 dup (0)
UserName db 256 dup (0)
WindowsDirectory db 256 dup (0)
TempPath db 256 dup (0)
SystemDirectory db 256 dup (0)
DriveType db 'C:\',0
Fixed db 'Fixed', 0
Removable db 'Removable', 0
Remote db 'Remote', 0
CDROM db 'CDROM', 0
RAMDISK db 'RAMDISK', 0
Unknown db 'Unknown', 0
Висновок: Впродовж виконання цієї лабораторної роботи, я розпочав розглядати роботу джампів, регістрів, функцій бібліотеки WinAPI в мові програмування Assembler. Ознайомився із базовим синтаксисом цієї мови.