Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабораторная 7

.docx
Скачиваний:
6
Добавлен:
18.07.2022
Размер:
34.59 Кб
Скачать

Санкт-Петербургский политехнический университет Петра Великого

Институт компьютерных наук и технологий

Высшая школа интеллектуальных систем и суперкомпьютерных технологий

ЛАБОРАТОРНАЯ РАБОТА №7

«Система команд, способы адресации и использование подпрограмм в архитектуре IntelArch-32»

по дисциплине «Архитектура вычислительных систем»

Выполнил

студент гр. 3530903/80001 А. В. Шильникова

Руководитель Н. М. Вербова

«___» __________ 2020 г.

Санкт-Петербург

2020

Цель работы: изучить ассемблерный код программы с вызовом подпрограммы.

Задачи:

1. Транслировать программу, написанную на С.

2. Перейти в режим отладки.

3. Проанализировать и прокомментировать все команды.

Вариант 6

Исходный код программы

//Третий параметр типа int* - адрес, по которому возвращает результат.

//В функции объявите и используйте локальную переменную типа long int.

void Fn(unsigned char A, char B, int* pointer)

{

long int li = 7;

while (li != 0)

{

A++;

B--;

li--;

}

*pointer = A + B;

}

int main()

{

unsigned char ucA = 4;

char c = 6;

int variable = 3;

int* pointer = &variable;

Fn(ucA, c, pointer);

return 0;

}

Дизассемблированный код с комментариями:

1: //Третий параметр типа int* - адрес, по которому возвращает результат.

2: //В функции объявите и используйте локальную переменную типа long int.

3:

4: void Fn(unsigned char A, char B, int* pointer)

5: {

009A1000 55 push ebp //сохраняем значение регистра ebp в стек, чтобы после выполнения программы или подпрограммы frame pointer можно было вернуть в состояние до вызова функции

009A1001 8B EC mov ebp,esp //в регистр ebp копируется значение из регистра esp

009A1003 83 EC 44 sub esp,44h //выделяем память для переменных

009A1006 53 push ebx

009A1007 56 push esi

009A1008 57 push edi //сохраняем в стек значения регистров ebx, esi, edi

6: long int li = 7;

009A1013 C7 45 FC 07 00 00 00 mov dword ptr [li],7 //записываем в локальную переменную li значение 7. dword ptr означает, что размер i составляет 32 бита, что соответствует размеру, занимаемому в памяти переменной типа long

7: while (li != 0)

009A101A 83 7D FC 00 cmp dword ptr [li],0 //устанваливаем флаг сравнения значения счетчика li со значением 0, то есть проверяем условие цикла while. dword ptr означает, что размер i составляет 32 бита, что соответствует размеру, занимаемому в памяти переменной типа long.

009A101E 74 1B je Fn+3Bh (09A103Bh) //условие сравнения – je (переход, если равно)

8: {

9: A++;

009A1020 8A 45 08 mov al,byte ptr [A] //заносим в al значение переменной A. byte ptr означает, что переменная имеет размер в один байт, что соответствует типу short

009A1023 04 01 add al,1 //прибавляем к al единицу

009A1025 88 45 08 mov byte ptr [A],al //заносим в переменную A значение регистра al

10: B--;

009A1028 8A 45 0C mov al,byte ptr [B] //заносим в al значение переменной B. byte ptr означает, что переменная имеет размер в один байт, что соответствует типу short

009A102B 2C 01 sub al,1 //вычитаем из al единицу

009A102D 88 45 0C mov byte ptr [B],al //заносим в переменную B значение регистра al

11: li--;

009A1030 8B 45 FC mov eax,dword ptr [li] //заносим в eax значение переменной li. dword ptr означает, что переменная имеет размер в 32 бита, что соответствует типу long

009A1033 83 E8 01 sub eax,1 //вычитаем из eax единицу

009A1036 89 45 FC mov dword ptr [li],eax //заносим в переменную li значение регистра eax

12: }

009A1039 EB DF jmp Fn+1Ah (09A101Ah) //возвращаемся к началу цикла и проверяем условие захода в него.

13: *pointer = A + B;

009A103B 0F B6 45 08 movzx eax,byte ptr [A] //в языке ассемблера существуют также команды, позволяющие занести в регистр значение другого регистра или ячейки памяти со знаковым или беззнаковым расширением. movzx - Беззнаковое расширение – старшие биты заполняются нулём. Запись в eax значение А

009A103F 0F BE 4D 0C movsx ecx,byte ptr [B] //movcx - Знаковое расширение – старшие биты заполняются знаковым битом. Запись в ecx значение B

009A1043 03 C1 add eax,ecx //складываются значения eax и ecx, сумма записываетс в eax

009A1045 8B 55 10 mov edx,dword ptr [pointer] //значение переменной pointer записывается в регистр edx

009A1048 89 02 mov dword ptr [edx],eax //значение регистра eax записывается в регистр edx

14: }

009A104A 5F pop edi

009A104B 5E pop esi

009A104C 5B pop ebx //получаем данные (edi, esi, ebx) из стека

009A104D 8B E5 mov esp,ebp //значение регистра ebp записывается в регистр esp

009A104F 5D pop ebp //получаем ebp из стека

009A1050 C3 ret //завершение выполнение программы

15:

16: int main()

17: {

009A1070 55 push ebp //сохраняем значение регистра ebp в стек, чтобы после выполнения программы или подпрограммы frame pointer можно было вернуть в состояние до вызова функции

009A1071 8B EC mov ebp,esp //в регистр ebp копируется значение из регистра esp

009A1073 83 EC 50 sub esp,50h //выделяем память для переменных

009A107B 33 C5 xor eax,ebp // обнулениe регистра eax

009A107D 89 45 FC mov dword ptr [ebp-4],eax //записываем в ebp-4 значение регистра eax

009A1080 53 push ebx

009A1081 56 push esi

009A1082 57 push edi //сохраняем в стек значения регистров ebx, esi, edi

18: unsigned char ucA = 4;

009A108D C6 45 FB 04 mov byte ptr [ucA],4 //записываем в локальную переменную ucA значение 4

19: char c = 6;

009A1091 C6 45 FA 06 mov byte ptr [c],6 //записываем в локальную переменную c значение 6

20: int variable = 3;

009A1095 C7 45 F4 03 00 00 00 mov dword ptr [variable],3 //записываем в локальную переменную variable значение 3

21: int* pointer = &variable;

009A109C 8D 45 F4 lea eax,[variable] //загружаем в регистр eax адрес переменной variable

009A109F 89 45 F0 mov dword ptr [pointer],eax //записываем в переменную pointer значение регистра eax

22: Fn(ucA, c, pointer);

009A10A2 8B 45 F0 mov eax,dword ptr [pointer] //записываем в регистр eax переменную pointer

009A10A5 50 push eax //записываем в стек регистр eax

009A10A6 0F B6 4D FA movzx ecx,byte ptr [c] // movzx - Беззнаковое расширение – старшие биты заполняются нулём. Запись в ecx значение C

009A10AA 51 push ecx //записываем в стек регистр ecx

009A10AB 0F B6 55 FB movzx edx,byte ptr [ucA] // movzx - Беззнаковое расширение – старшие биты заполняются нулём. Запись в edx значение ucA

009A10AF 52 push edx //записываем в стек регистр edx

009A10B0 E8 4B FF FF FF call Fn (09A1000h) //call записывает адрес следующей за ней команды в стек и осуществляет переход на первую команду указанной процедуры (Fn)

009A10B5 83 C4 0C add esp,0Ch //в регистр esp записывается сумма esp и 0С(192)

23: return 0;

009A10B8 33 C0 xor eax,eax // обнулениe регистра eax

24: }

009A10BA 5F pop edi

009A10BB 5E pop esi

009A10BC 5B pop ebx //получаем данные (edi, esi, ebx) из стека

009A10BD 8B 4D FC mov ecx,dword ptr [ebp-4] //записываем в регистр ecx значение ebp-4

009A10C0 33 CD xor ecx,ebp // обнулениe регистра ecx

009A10C7 8B E5 mov esp,ebp //записываем в регистр esp значение регистра ebp

009A10C9 5D pop ebp //получаем данные (ebp) из стека

009A10CA C3 ret //завершение выполнение программы

Вывод

В результате выполнения работы была написана программа с вызовом функции на языке C, дизассемблирован исходный код и проанализировано, как компилятор реализует команды языка высокого уровня на ассемблере и обращается к подпрограммам.