Лабораторна робота №2

Інформація про навчальний заклад

ВУЗ:
Національний університет Львівська політехніка
Інститут:
Не вказано
Факультет:
КН
Кафедра:
Не вказано

Інформація про роботу

Рік:
2015
Тип роботи:
Лабораторна робота
Предмет:
Системне програмування та операційні системи

Частина тексту файла (без зображень, графіків і формул):

Міністерство освіти і науки України Національний університет “Львівська політехніка” / Лабораторна робота № 2 Тема: Змішане програмування на мовах С та Асемблер Мета: оволодіти навиками створення програм, частини яких написані різними мовами програмування. Засвоїти правила взаємодії між програними модулями. ТЕОРЕТИЧНІ ВІДОМОСТІ Труднощі опису зв’язку програм написаних мовою C і асемблерних програм полягає в тому, що різні версії мови C мають різні угоди з виклику функцій та передавання їм параметрів. Для більш точної інформації варто користатися посібником з наявної версії мови C. До особливостей угод щодо виклику функцій та передавання їм параметрів можна віднести: більшість версій мови C забезпечують передачу параметрів через стек у зворотній (у порівнянні з іншими мовами) послідовності. Зазвичай доступ, наприклад, до двох параметрів, переданих через стек, здійснюється в такий спосіб: PUSH EBP MOV EBP,ESP MOV EAX,[EBP+8] MOV EDX,[EBP+12] ; тіло підпрограми ... POP EBP RET у мові C розрізняють великі і малі літери, тому ім’я асемблерного модуля повинне бути представлено в тому ж символьному регістрі, який використовують для посилання C-програми; у деяких версіях мови C потрібно, щоб асемблерні програми, що змінюють регістри EDI і ESI, записували їхній вміст у стек при вході і відновлювали ці значення зі стеку при виході; ассемблерні програми повинні повертати значення, якщо це необхідно, у регістрі EAX (подвійне слово) чи в регістровій парі EDX:EAX (8 слів); для деяких версій мови C, якщо ассемблерна програма встановлює прапор DF, то вона повинна скинути його командою CLD перед поверненням. Щоб скомпонувати разом модулі C++ і Макро асемблера, повинні бути дотримані наступні три умови: У модулях Макро Асемблера повинні використовуватися угоди про імена, прийняті в C++. C++ і Макро Асемблер повинні спільно використовувати відповідні функції й імена змінних у формі, прийнятної для C++. Для комбінування модулів у виконувану програму потрібно використовувати утіліту-компоновщик (TLINK, LINK тощо). Підкреслення і мова С Для забезпечення взаємодії програми написаної асемблером з програмами написаними мовами С чи С++, всі зовнішні мітки повинні починатися із символу підкреслення (_). Компілятор С і С++ вставляє символи підкреслення перед всіма іменами зовнішніх функцій і змінних при трансляції в об’єктний код автоматично, тому в асемблерних програмах перший символ підкреслення необхідно вставити самостійно. Тому, ідентифікатори глобальних змінних та назви функцій які використовуються в асемблерній програмі для взаємодії з С модулями, чи навпаки, повинні починатися із символу підкреслення. Наприклад, наступна програма мовою С (link2asm.cpp): extrn int ToggleFlag(); int Flag; main() { ToggleFlag(); } правильно компонується з наступною програмою на асемблері (casmlink.asm): .586    .MODEL FLAT    .DATA    EXTRN _Flag:dword    .CODE    PUBLIC _ToggleFlag    _ToggleFlag PROC ; прапорець скинутий?   cmp [_Flag], 0    jz SetFlag ; так, установити його   mov [_Flag], 0 ; ні, скинути його   jmp EndToggleFlag ; виконано   SetFlag: ; встановити прапорець   mov [_Flag], 1    EndToggleFlag:    ret    _ToggleFlag ENDP    END     При використанні в директивах EXTERN і PUBLIC специфікатора мови С правильно компонується з наступною програмою на Асемблері (cspec.asm) (приклад для 16-ти бітної програми): .MODEL Small    .DATA    EXTRN C Flag:word    .CODE    PUBLIC C ToggleFlag    ToggleFlag PROC ; прапорець скинутий?   cmp [Flag], 0    jz SetFlag ; так, установити його   mov [Flag], 0 ; ні, скинути його   jmp short EndToggleFlag ; виконано   SetFlag: ; установити прапорець   mov [Flag], 1    EndToggleFlag:    ret    ToggleFlag ENDP    END     Примітка: Мітки, на які відсутні посилання в програмі на С (такі, як SetFlag) не вимагають попередніх символів підкреслення. Турбо Асемблер (використовується тільки для 16-ти бітних програм) автоматично при записі імен Flag і ToggleFlag в об’єктний файл помістить перед ними символ підкреслення. Розпізнавання рядкових і прописних символів в ідентифікаторах В іменах ідентифікаторів Макро асемблер звичайно не розрізняє малі та великі літери (верхній і нижній регістр). Оскільки в С вони розрізняються, бажано задати таке розходження й у Макро Асемблері (принаймні для тих ідентифікаторів, що спільно використовуються Асемблером і С). Це можна зробити за допомогою макрокоманди OPTION CASEMAP:NONE. Типи міток Хоча в програмах Асемблера можна вільно звертатися до будь-якої змінної чи даних довільного розміру (8, 16, 32 біти і т.д.), у загальному випадку бажано звертатися до змінних відповідно до їхніх розмірів. Наприклад, якщо записати слово в байтову змінну, то зазвичай це приводить до проблем: ... SmallCount DB 0 ... mov WORD PTR [SmallCount],0ffffh Тому важливо, щоб в операторі Асемблера EXTRN, у якому описуються змінні С, задавався правильний розмір цих змінних, тому що при генерації розміру доступу до змінного С, Асемблер ґрунтується саме на цих описах. Якщо в програмі мовою С++ міститься оператор: char c то код Асемблера ... EXTRN c:WORD ... inc c ... може привести до дуже неприємних помилок, оскільки після того, як у коді мовою С змінна c збільшиться чергові 256 разів, її значення буде скинуто, а чарез те, що вона описана в Асемблері, як змінна розміром у слово, то байт за адресою OFFSET c+1 буде збільшуватися некоректно, що приведе до непередбачених результатів. Узгодження типів (С та Assembler) Між типами даних С та Макро асемблера існує співвідношення, що наведене в табл. 2.1. Узгодження між типами С і Assembler Тип даних С++ Тип даних Асемблера     unsigned char byte     char byte     enum dword     unsigned short dword     short dword     unsigned int dword     int dword     unsigned long dword     long dword     float dword     double qword     long double tbyte     near* dword      Передача параметрів У мові C функціям параметри передаються через стек. Перед викликом функції компілятор С спочатку заносить у стек передані цієї функції параметри, починаючи із самого правого параметра і закінчуючи лівим. У С виклик функції: ... Test(i, j, 1); ... компілюється в інструкції: mov eax,1 push eax push dword ptr _j push dword ptr _i call _Test add esp,12 де видно, що правий параметр (значення 1), заноситься в стек першим, потім туди заноситься параметр j та, нарешті, і. При поверненні з функції занесені в стек параметри усе ще знаходяться там, але вони більше не використовуються. Тому безпосередньо після кожного виклику функції C прокручує вказівник стеку назад у відповідності зі значенням, що він мав перед занесенням у стек параметрів (параметри, таким чином, відкидаються). У попередньому прикладі три параметри (по два байти кожен) займають у стеку разом 12 байт, тому компілятор C додає значення 12 до вказівника стеку, щоб відкинути параметри після звертання до функції Test. Важливий момент полягає в тому, що відповідно до використовуваних за замовчуванням угод С/C++ за видалення параметрів зі стеку відповідає викликаюча програма. Функції Асемблера можуть звертатися до параметрів, переданих через стек, з використанням регістру EBP. Наприклад, функція Test може мати таку реалізацію на мові Асемблера (prmstack.asm): .586 .MODEL FLAT .CODE PUBLIC _Test _Test PROC push ebp mov ebp,esp mov eax,[ebp+8] ; одержати параметр 1 add eax,[ebp+12] ; додати параметр 2 до параметра 1 sub eax,[ebp+16] ; відняти від суми параметр 3 pop ebp ret _Test ENDP Функція Test одержує доступ до переданих з програми мовою С параметрів через стек, з використанням регістру EBP. (EBP, це регістр для базової адресації за замовчуванням). На рис. 2.1 показано, як виглядає стек перед виконанням першої інструкції функції Test. = 25; = 4; Test(1, j, 1); ESP     Адреса повернення   ESP + 4 25 (_i)   ESP + 8 4 (_j)   ESP + 12 1        Рис. 2.1. Стан стеку перед виконанням першої інструкції функції Test Параметри функції Test мають фіксовані адреси відносно ESP, починаючи з комірки, на 4 байти старшої від адреси, за якою зберігається адреса повернення, що занесена туди при виклику. Завантаження регістра EBP значенням ESP дає можливість звертатися до цих параметрів відносно EBP. Однак, спочатку необхідно зберегти у стеку значення EBP для того, щоб забезпечити його відновлення при поверненні з функції, тому що викликаюча програма передбачає, що при поверненні EBP змінений не буде. Занесення в стек EBP змінює всі зміщення в стеку. На рис. 2.2 показано стан стеку після виконання наступних рядків коду: ... push ebp mov ebp, esp ... Організація передачі параметрів функції через стек і використання його для динамічних локальних змінних - це стандартний прийом для мови С. Як можна помітити, неважливо, скільки параметрів має програма мовою С: крайній лівий параметр завжди зберігається в стеку за адресою, що безпосередньо слідує за збереженою у стеку адресою повернення, наступний параметр, що передається, зберігається безпосередньо після крайнього лівого параметра і т.д. Оскільки порядок і тип переданих параметрів відомі, їх завжди можна знайти в стеку. Простір для локальних змінних можна зарезервувати, віднімаючи від ESP необхідну кількість байт. Наприклад, простір для локального масиву розміром у 100 байт можна зарезервувати, якщо почати функцію Test з інструкцій: push ebp mov ebp,esp sub esp,100 ESP  EBP    EBP викликаючої програми    ESP + 4 Адреса повернення EBP + 4   ESP + 8 25 (_i) EBP + 8   ESP + 12 4 (_j) EBP + 12   ESP + 16 1 EBP + 16         Рис. 2.2 Стан стеку після інструкцій PUSH і MOVE Тоді, до локальних даних у зарезервованому адресному провторі в стеку можна і далі звертатися чарез регістр EBP, але уже з від’ємним зміщення. При виході з підпрограми також необхідно відкоректувати вказівник стеку. Повернення значень Програми, які викликаються з С і написані на Асемблері можуть повертати значення. Значення функцій повертаються через напередвизначені регістри, що відображені у табл. 2.2.  Розташування резутратів виконання функцій   Тип значения, Розміщення значення,    що повертається функцією що повертається функцією         unsigned char EAX    char EAX    enum EAX    unsigned short EAX    short EAX    unsigned int EAX    int EAX    unsigned long EAX    long EAX     Виконання лабораторної роботи: Завдання 1.Створити дві програми. Перша програма реалізує взаємовиклики С – ASM та здійснює обчислення, заданого виразу, згідно варіанту (Табл. 2.3). Програма повинна складатися з кількох модулів, передача параметрів між якими здійснюється через стек. Константа передається через спільну пам’ять. Основний модуль – створюється мовою С. Він повинен забезпечувати: ввід даних з клавіатури; виклик підпрограми обчислення виразу; вивід на екран результату обчислення виразу. Модуль безпосередніх обчислень – здійснює всі обчислення виразу. Створюється мовою Assembler 2.Друга програма реалізує взаємовиклики С – ASM – С та здійснює обчислення, заданого виразу, згідно варіанту. Програма повинна складатися з кількох модулів, передача параметрів між якими здійснюється через стек. Основний модуль – створюється мовою С. Він повинен забезпечувати: ввід даних з клавіатури; виклик підпрограми обчислення виразу; Модуль безпосередніх обчислень – здійснює всі обчислення і вивід на екран результату обчислення виразу викликом стандартної функції printf() . Створюється мовою Assembler. 3.Відлагодити та протестувати програми. Результати роботи програм продемонструвати викладачу. Варіант №3 X = K-B2 *5+C2-E1; K = 37788663 Завдання №1(C-ASM): Фото виконання програми: / Код програми(C-ASM): Source.cpp #include<stdio.h> #include<conio.h> extern "C" int pruklad(int,int,char); extern "C"{ short B = 0, C = 0; char E = 0; } int main(){ int K = 0x37788663; printf("X = K - B2 * 5 + C2 - E1 where K = 37788663"); printf("\n"); printf("Char(E) from 0 to 255\n"); printf("Enter numbers:\n"); printf("Enter B = "); scanf("%d", &B); printf("Enter C = "); scanf("%d", &C); printf("Enter E = "); scanf("%d", &E); printf("Result in C(from_C): %d ",K-B*5+C-E ); printf("\n"); int X = pruklad(B,C,E); printf("Result in C from ASM(from_C) %d", X); printf("\n"); getch(); return 0; } Assembler.asm .386 .model flat,c option casemap:none PUBLIC pruklad .data _T1 dword 0 _T2 dword 0 _K EQU 37788663h .code pruklad PROC push ebp mov ebp,esp ;T1 = B2*5 mov eax, dword ptr[ebp+8] shl eax,2 add eax, dword ptr[ebp+8] mov _T1,eax ;T1 = K-T1 mov eax,_K sub eax,_T1 mov _T1,eax ;T2 = C2-E1 mov eax, dword ptr[ebp+12] sub eax, dword ptr[ebp+16] mov _T2,eax ;T1 = T1+T2 mov eax,_T1 add eax,_T2 mov _T1,eax pop ebp ret pruklad ENDP END Завдання№2(C-ASM-C): Фото роботи програми:/ Код програми(C-ASM-С): Source.cpp #include<stdio.h> #include<conio.h> extern "C" int pruklad(int,int,char); extern "C"{ short B = 0, C = 0; char E = 0; } int main(){ int K = 0x37788663; printf("X = K - B2 * 5 + C2 - E1 where K = 37788663"); printf("\n"); printf("Char(E) from 0 to 255\n"); printf("Enter numbers:\n"); printf("Enter B = "); scanf("%d", &B); printf("Enter C = "); scanf("%d", &C); printf("Enter E = "); scanf("%d", &E); printf("Result in C(from_C): %d ",K-B*5+C-E ); printf("\n"); pruklad(B,C,E); getch(); return 0; } Assembler.asm .386 .model flat,c option casemap:none EXTRN printf:near PUBLIC pruklad .data _T1 dword 0 _T2 dword 0 _K EQU 37788663h prnt db "Result in ASM(from_ASM): %d",10,13,0 .code pruklad PROC push ebp mov ebp,esp ;T1 = B2*5 mov eax, dword ptr[ebp+8] shl eax,2 add eax, dword ptr[ebp+8] mov _T1,eax ;T1 = K-T1 mov eax,_K sub eax,_T1 mov _T1,eax ;T2 = C2-E1 mov eax, dword ptr[ebp+12] sub eax, dword ptr[ebp+16] mov _T2,eax ;T1 = T1+T2 mov eax,_T1 add eax,_T2 mov _T1,eax ;cout result mov edx,offset prnt push eax push edx call near ptr printf pop edx pop eax pop ebp ret pruklad ENDP END Словесний опис алгоритму роботи програми: Створюємо прототип функції pruklad дописуємо до неї ключове слово extern аби доступ до неї міг здійснюватись з інших файлів, у нашому випадку файл Assembler.asm. У блоці extern ”C” описуємо змінні, які будуть використовуватись у асемблерному файлі, доступ до них буде здійснюватись через стек. За допомггою scanf здійснюємо зчитування даних з клавіатури і записуємо їх у відповідні змінні, які в подальшому будуть викорситовуватись у файлі програми асемблера. Слід звернути увагу на те як здійснюється операція множення на 5: mov eax, dword ptr[ebp+8] shl eax,2 add eax, dword ptr[ebp+8] mov _T1,eax В регістр eax ми заносимо число зі стеку(В), потім робимо зсув вліво на два(множення на 4), після чого до результату зсуву додаємо значення змінної яка зберігається в стеку (add eax,dword ptr [ebp+8]), після множення числа на 5 записуємо результат у зміну _Т1. Даний фрагмент коду використовується для виведення даних з асемблерівського файлу. mov edx,offset prnt push eax push edx call near ptr printfa pop edx pop eax mov eax,_K sub eax,_T1 mov _T1,eax Фрагмент коду під номером 2 використовується для віднімання чисел К та тимчасової змінної Т1 через регістр eax(акумулятор). Особливість завдання №1: Завдання №1 відрізняється від завдання №2 тим, що у першому ми викликаємо функцію pruklad, яка повертає значення у змінну Х, і потім здійснюємо вивід результату. Особливість завдання №2: Завдання №2 відрізняється від завдання №1 тим що вивід результату відбувається з асемблерного файлу за допомогою команди printf() мови С. Висновок: Після виконання даної лабораторної роботи я оволоділа навиками створення програм, частини яких написані різними мовами програмування. Засвоїла правила взаємодії між програними модулями.
Антиботан аватар за замовчуванням

05.02.2017 16:02-

Коментарі

Ви не можете залишити коментар. Для цього, будь ласка, увійдіть або зареєструйтесь.

Ділись своїми роботами та отримуй миттєві бонуси!

Маєш корисні навчальні матеріали, які припадають пилом на твоєму комп'ютері? Розрахункові, лабораторні, практичні чи контрольні роботи — завантажуй їх прямо зараз і одразу отримуй бали на свій рахунок! Заархівуй всі файли в один .zip (до 100 МБ) або завантажуй кожен файл окремо. Внесок у спільноту – це легкий спосіб допомогти іншим та отримати додаткові можливості на сайті. Твої старі роботи можуть приносити тобі нові нагороди!
Нічого не вибрано
0%

Оголошення від адміністратора

Антиботан аватар за замовчуванням

Подякувати Студентському архіву довільною сумою

Admin

26.02.2023 12:38

Дякуємо, що користуєтесь нашим архівом!