Файл: Отчет по лабораторным работам по дисциплине Вычислительные машины сети и системы.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 08.02.2024

Просмотров: 23

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ

РОССИЙСКОЙ ФЕДЕРАЦИИ

КУРГАНСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
Кафедра автоматизации производственных процессов

ОТЧЕТ

по лабораторным работам

по дисциплине

«Вычислительные машины сети и системы»

Выполнил:

студент гр. ___ ______ _._.

Проверил:

преподаватель Скобелев И.В.

Курган 2023

Оглавление


Введение 2

Лабораторная работа №1 (Изучение команд языка Ассемблера и применение ассемблерных вставок в программе на С++) 5

Лабораторная работа №2 (Изучение программирования на языке Ассемблера) 21

Лабораторная работа №3 (Изучение арифметических операций над байтами и словами) 26

Лабораторная работа №4 (Изучение логических операций и операции сдвига над данными) 28

Лабораторная работа №5 (Изучение команд условного и безусловного переходов. Организация ветвлений и циклов в программе) 29

Лабораторная работа №6 (Изучение использование стека и подпрограмм. Организация внутрисегментных и межсегментных переходов) 30

Список литературы 31

Приложение 36



Введение


Современный специалист в области автоматизации производства должен обладать достаточными знаниями по использованию средств вычислительной техники в организации и управлении технологическими процессами. Низкоуровневое программирование позволяет четко усвоить принципы работы вычислительных машин и систем, а также их функциональных блоков, более рационально использовать их вычислительную мощность на конкретном производстве, с учетом его особенностей.

Целью проведения лабораторных работ является изучение студентами организации и принципов функционирования памяти, микропроцессора, организации ввода – вывода, а также приобретение навыков низкоуровневого программирования на языке ассемблера.

Для выполнения лабораторных работ потребуется:

FASM или другой транслятор с языка ассемблера + компоновщик;

OllyDbgОтладчик.

Для изучения использовании ассемблерных вставок может понадобиться Embarcadero RAD Studio 10.4 или Microsoft Visual Studio 2022 или любая другая среда разработки.

Первой вопрос, который, я хочу рассмотреть и  который, мне кажется, сейчас очень важным, это 64-битовое программирование. Естественно речь пойдет об ассемблере. В качестве такового возьмем  fasm. Во-первых, поддерживает 64-битовое программирование, во-вторых, этот ассемблер является кроссплатформенным. Для того, чтобы начать писать 64-битовые программы достаточно 1.
Узнать структуру программы; 2. Использовать правильное соглашение вызова системных и вообще функций.

Программирование в Windows.

В 64-битовых Windows принята следующая конвенция вызова функций (в том числе вызов функций API).

1. Первые четыре параметра передаются в функцию через регистры: rcx, rdx, r8, r9. Остальные параметры (если они есть) передаются через стек.

2. Перед вызовом функции резервируется область в стеке, на случай, если вызываемая функция "захочет" временно сохранить параметры в стеке. Таким образом, параметры, которые передаются через стек, помещаются туда после резервируемой области.

3. При передаче параметров, размер которых меньше 64 бит, передаются как 64-битовые параметры. При этом следует обнулить старшие биты. Параметры, большие 64-бит передаются по ссылке.

4. Данные возвращаются через регистр rax. Если возвращаемое значение имеет размер больший 64 бит, то данное передается через область памяти, адрес которой передается в первом параметре. Для возвращения может также использоваться регистр xmm0.

5. Все регистры при вызове функций сохраняются за исключением rax, rcx, rdx, r8, r9, r10, r11, сохранность которых не гарантируется.

6. Граница стека должна быть выровнена по адресу кратному 16.

Рассмотрим в общих чертах схему вызова функции API с пятью параметрами.

...

sub rsp,40 ; резервируем стек

mov qword ptr [rsp+32],par5

mov r9,par4

mov r8,par3,

mov rdx,par2

mov rcx,par1

call f_api64

...

add rsp,40 ;восстанавливаем стек

...
Обратим внимание, что в нашем случае стек с учетом адреса возврата при вызове функции оказывается выровненным на величину кратную 16 (48 байт). С учетом такого выравнивания вызов функции, содержащей только 4 параметра будет выглядеть так
sub rsp,40 ; резервируем стек

mov r9,par4

mov r8,par3,

mov rdx,par2

mov rcx,par1

call f_api64

...

add rsp,40 ;восстанавливаем стек
Рассмотрим следующую программу
format PE64 GUI

entry start

section '.text' code readable executable

start:

sub rsp,8*5

mov r9,0

lea r8,[_caption]

lea rdx,[_message]

mov rcx,0

call [MessageBoxA]

add rsp,40

sub rsp,16

mov ecx,eax

call [ExitProcess]

section '.data' data readable writeable

_caption db 'Win64 assembly program',0

_message db 'Hello World!',0

section '.idata' import data readable writeable

dd 0,0,0,RVA kernel_name,RVA kernel_table

dd 0,0,0,RVA user_name,RVA user_table

dd 0,0,0,0,0

kernel_table:

ExitProcess dq RVA _ExitProcess

dq 0

user_table:

MessageBoxA dq RVA _MessageBoxA

dq 0

kernel_name db 'KERNEL32.DLL',0

user_name db 'USER32.DLL',0

_ExitProcess dw 0

db 'ExitProcess',0


_MessageBoxA dw 0

db 'MessageBoxA',0
Если имя программы prog.asm, то компилируется она просто командой

fasm prog.asm

Как видим, в Windows все просто.



Лабораторная работа №1 (Изучение команд языка Ассемблера и применение ассемблерных вставок в программе на С++)



Задание:

Изучить использование некоторых команд языка Ассемблера. Научиться применять системный отладчик Debug. Научиться вставлять ассемблерный код в программу на языке С++.
Выполнение работы


  1. Вызовите в командной строке системный отладчик debug. Задайте команду _а и введите несколько ассемблерных команд, изменяющих содержимое регистров (Например, с помощью команды MOV загрузить регистры ax и bx числами, выполнить сложение этих чисел).


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



Для запуска этой программы в MS Windows скачиваем и устанавливаем средство отладки для Windows по URL адресу https://learn.microsoft.com/ru-ru/windows-hardware/drivers/debugger/debugger-download-tools, нажмём «ПУСК» и выберем пункт «Выполнить», затем введите DEBUG и запустите. После окончания загрузки на экране появится приглашение в виде дефиса, что свидетельствует о готовности программы DEBUG для приема команд.
В оперативной памяти компьютера хранится много различных сервисных данных, например количество памяти, доступной в текущий момент. Для того, чтобы узнать сколько памяти доступно, введите команду:
D 40:13
Первые два байта, появившиеся в результате на экране, содержат объем памяти в килобайтах и в шестнадцатиричном представлении, причем байты располагаются в обратной последовательности.
Несколько следующих примеров показывают шестнадцатиричное обратное, шестнадцатиричное нормальное и десятичные представления.


Шестн. обратн.


Шестн. норм.


Десятичное


80 00


00 80


128


00 01


01 00


256


80 01


01 80


384


00 02


02 00


512


80 02


02 80


640





Далее рассмотрим использование команды E. Введем программу, которая складывает два числа – 10 и 20. Для этого, с помощью команды Е, начиная со смещения 100 в сегменте кода, начнем ввод следующих команд:
B8 10 00
BB 20 00 01 D8
Здесь три машинных команды, которые выполняют следующие действия:
∙Загрузка в регистр AX числа 10;
∙Загрузка в регистр BX числа 20;
∙Сложение регистров AX и BX.
Первые две команды (B8 и BB) содержат поля данных, в которых, как уже
упоминалось в теории, байты данных перевернуты. Видно что, вместо нужного числа 10 в команде B81000 находится число 1000, перевернув байты получим 0010. Аналогично для команды BB2000.
Ввести данные команды в память можно с помощью команды Е двумя способами: ∙ Одиночной командой E CS:0100 B8 10 00 BB 20 00 01 D8;
∙Побайтовым вводом. Введя E CS:100, нажав , через пробел вводим каждый
байт.
При вводе команд вторым способом перед вводом каждого байта отображается текущее содержимое байта в который планируется ввод.
Далее рассмотрим команду R, которая отображает состояние процессорной (регистровой) памяти. Введите команду R без параметров и нажмите .
В результате на экран будет выведено состояние всех основных регистров, флагов, а так же адрес, машинный код и ассемблерный мнемокод следующей выполняемой команды.
Команду R можно использовать для изменения текущего значения какого-либо регистра. Изменим содержимое регистра DX, для этого введите команду:
R DX
Результатом данной команды будет вывод на экран текущего содержимого регистра DX и прием нового значения, о чем будет сигнализировать символ «:». Введите после символа «:» значение FF0E и нажмите . Что бы убедиться в том, что значение в регистре DX поменялось, введите команду R или R DX еще раз.
Следующая команда Debug, необходимой для выполнения введенной программы, это команда T. Данная команда выполняет одну машинную инструкцию, находящуюся по адресу CS:IP. Поскольку при вводе программы использовалось только смещение, то регистр CS устанавливать не надо, но регистр IP желательно проверить. Введите команду R IP.
Убедившись, что значение в данном регистре равно 0100, начинаем выполнение программы. Если значение в регистре IP отлично от 0100, в таком случае введите 0100 после символа «:», в противном случае не нужно ничего вводить, просто нажмите , оставив пустую строку.
Введите команду T без параметров, в результате чего на экран будет выведено сообщение, аналогичное тому, что выводится при вводе команды R. Просмотрите содержимое регистров и убедитесь, что содержимое регистра AX изменилось на 0010. Введите команду Т еще раз. Убедитесь, что значение регистра BX изменилось на 0020. Для завершения программы введите команду Т третий раз и посмотрите результат сложения регистров AX и BX, находящийся в регистре AX.
Далее рассмотрим команды U и A.
Команда A так же как и команда E вводит в память команды, за исключением того, что данные команды принимаются не в машинных кодах, а в мнемокодах языка ассемблера. Так же, команда A, в отличии от команды Е не принимает набор команд одной строкой.

С помощью команды А введем программу, которая умножает число E1 на 5. Введите
команду:
A 100
Затем программу, разделяя ввод каждой команды нажатием :
MOV AX, 00E1
MOV BX, 0005 MUL BX
Для завершения ввода программы последнюю строку оставьте пустой, нажав . Теперь необходимо выполнить эту программу. С помощью команды Т выполните
введенную программу предварительно установив в регистр IP значение 0100.
Команда U не вводит никакие данные, а служит только для сопоставления мнемокодов ассемблера машинным кодам. Введите команду U 100. В результате вы
увидите дамп памяти, начиная с 100 смещения, в котором будут указаны машинные коды и соответствующие им команды ассемблера.



  1. Пошагово выполните загруженный фрагмент ассемблерной программы, следя за содержимым регистров с помощью команды _t. Посмотрите, какие еще есть возможности у системного отладчика.

  2. Создайте проект консольного приложения, обычным образом, как и во всех предыдущих лабораторных работах. Организуйте ввод значений чисел и вывод значений регистров.



  1. Создайте ассемблерную вставку в методе main().

Системы программирования Delphi, C++ Builder, Visual C++ позволяют вставлять в текст программы на языке высокого уровня участки кода, написанные на ассемблере. Этот ассемблер называется встроенным, и имеет незначительные синтаксические отличия от ассемблера TASM или MASM. Подробнее про него можно прочитать в справочной системе. Здесь приводятся краткие сведения.

  • C++ Builder, Visual C++:

Ассемблерный текст заключается в блок _asm{…}

_asm{

xor eax, eax

cmp eax, SomeVariable

}

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

  • Delphi:

Ассемблерные команды заключаются между словами asmend;

asm

xor eax, eax

cmp eax, SomeVariable

end;

Внутри ассемблерного блока можно обращаться по именам к переменным, функциям, процедурам и меткам. Переменные, объявленные внутри блока директивами DB, DW и т.п. будут размещены в сегменте кода, а не данных. Это нужно учесть, чтобы компилятор не стал исполнять их значения как машинные коды – это может привести к ошибке исполнения программы.

Если внутри ассемблерного блока нужны переходы по меткам, их делают локальными – имена таких меток следует начинать с символа @. Область действия локальной метки ограничена ассемблерным блоком:

asm

test SomeVariable, 0Fh

jz @M1

... // какие-то команды

@M1: // это локальная метка

...

end;
// Программа, в которой создается два числовых массива одинакового размера. Вычисляет сумму попарных произведений элементов этих массивов. Данная программа содержит ассемблерную вставку.
#include

#include
using namespace std;
// Константа для указания максимальной длинны массивов

constexpr unsigned int ARR_SIZE = 10;

constexpr unsigned int MAX = 15;

constexpr unsigned int MIN = -5;
void task()

{

// Объявление переменных

int result = 0;

unsigned int counter = 0;

int arr_a[ARR_SIZE], arr_b[ARR_SIZE];
cout << "a b\n";
// Инициализация массивов случайными значениями

for (int i = 0; i < ARR_SIZE; i++)

{

arr_a[i] = MIN + rand() % MAX;

arr_b[i] = MIN + rand() % MAX;
cout << arr_a[i] << " " << arr_b[i] << endl;

}
// Ассемблерная вставка

_asm {

BEGIN:

mov eax, 4 // перемещение указателя с шагом 4 байта

mul counter

mov ebx, eax
mov eax, dword ptr arr_a[ebx]

imul dword ptr arr_b[ebx]

add result, eax

inc counter

mov eax, counter

cmp eax, ARR_SIZE

jne BEGIN

}
// Вывод результатов вычислений на ассемблере

cout << "result: " << result << endl;
// Проверка вычислений на корректность с помощью С++

int cpp_result = 0;
for (int i = 0; i < ARR_SIZE; i++)

{

cpp_result += arr_a[i] * arr_b[i];

}
// Вывод результатов вычислений на С++

cout << "cpp_result: " << cpp_result << endl;

}

int main()

{

// Случайное зерно для генератора

srand((unsigned int)time(NULL));
// Основной код

task();

}


  1. Напишите программный код для исследования ассемблерных команд и доступа к переменным и массивам программы на языке C++. Можно использовать пример, рассмотренный на лекции.



  1. Изучите с помощью созданной программы способы получения данных из C++ в ассемблерной вставке и передачи результатов вычислений в программу на C++, способы согласования длины переменных и способы доступа к элементам массивов.

Программа на языке СИ может вызвать процедуру на языке Ассемблер, находящуюся в другом модуле, как и при вызове СИ-функции. В дополнение к шагам, описанным в Разделе С.1 "Написание процедуры на языке Ассемблер", могут оказаться полезными следующие правила:
1.Описывайте процедуры, вызываемые из СИ-программ с ключевым словом far, если СИ-модуль был скомпилирован в большой, сверхбольшой или средней модели памяти, и с ключевым словом near, если СИ-модуль был скомпилирован в малой или компактной модели. Ключевые слова far или near отменяют любые стандартные назначения. Если вы используете директиву .MODEL, имеющуюся в Micro soft Macro Assembler версии 5.0, объявление модели памяти для процедуры делается явно.
2.Обзор соглашений о связях языка СИ. По соглашениям языка СИ параметры опускаются в стек в том порядке, в каком они находятся в исходном коде. Например, вызов функции СИ calc(a,b); опускает b в стек раньше a. В противоположность остальным высокоуровневым языкам, в соглашениях о связях языка СИ положено, чтобы вызывающая процедура всегда восстанавливала стэк непосредственно после возвращения управления из вызываемой программы. Соглашения о связях языка СИ делают возможным вызов переменным числом параметров. (Поскольку первый параметр всегда опускается в стек последним, он имеет относительно указателя на запись активации один и тот же адрес. Независимо от количества переданных числом параметров применяются следующие этапы:
а)Возврат производится посредством простой инструкцией ret. Не восстанавливайте стек посредством инструкции ret size, поскольку вызывающая СИ-процедура сама восстановит стек, как только ей будет передано управление.
б)Параметры помещаются в стек в порядке, обратном тому, как они появлялись в исходном коде на языке СИ. Первый параметр будет находиться по младшим адресам памяти (поскольку-это последний помещаемый в стэк параметр, то есть стэк растет вниз).
с)Стандартно, параметры языка СИ передаются значением, исключая массивы, передаваемые по адресной ссылке.
3.Обзор соглашений о наименованиях языка СИ.
Наличие подчеркивания перед любым именем в языке СИ делает его глобальным. В языке СИ распознаются только первые восемь символов, поэтому не делайте имена, используемые СИ, длинной более восьми символов. Кроме того, если вы будете выполнять компановку с опцией /NOIGNORECASE, помните, что язык СИ чувствителен к буквенным регистрам, и не преобразуйте имена к верхнему регистру.
В следующем примере программа на языке СИ вызывает ассемблерную процедуру, которая вычисляет А*2**B, где А и В-первый и второй параметры, соответственно. Вычисления выполняются путем сдвига влево разрядов в А В раз.
Программа на языке СИ использует для создания интерфейса с ассемблерной процедурой описание extern. Не требуется никаких ключевых слов, поскольку ассемблерная процедура будет использовать соглашения о связях языка СИ.
extern int power2(int, int);

main()

{

printf("3 times 2 to the power of 5 is %d\n", power2(3,5));

}
Чтобы понять, как пишется ассемблерная процедура, рассмотрите рисунок С.2, на котором показана схема размещения параметров в стеке.
Старшие адреса | B | Arg<-2 | BP+6

(С каждым опусканием | A | Arg<-1 | BP+4

аргумента или каждым | Адрес возврата | BP+2

вызовом стек растет | Зарезервированный | BP

вниз) | BP |

Младшие адреса
Рисунок С.2. Запись активации СИ.
Адрес возврата имеет в длину байта, предполагая, что СИ-модуль был скомпилирован в малой или компактной модели. Если же СИ-модуль компилируется в большой, сверхбольшой или средней модели, то адреса Arg
.MODEL SMALL

.CODE

PUBLIC _power2

_power2 PROC

push bp ;Входная последовательность-сохранение старо-

го BP

mov bp,sp ;Установка указателя на запись активации
mov ax,[bp+4] ;Загрузка Arg 1 в AX

mov cx,[bp+6] ;Загрузка Arg 2 в CX

shl ax,cl ;AX = AX*(2 в степени CX)

;Возвращаемое значение остается в AX

pop bp ;Выходная последовательность-востанов-

ление старого BP

ret ;Выход

_power2 ENDP

END
Приведенный выше пример предполагает, что СИ-модуль компилируется в малой модели памяти. Смещение параметра и директива .MODEL изменятся для других моделей памяти.
Обратите внимание, что инструкция ret используется без переменной size, поскольку вызывающая программа после возвращения из процедуры сама выравнивает стек.

Процедуры высокоуровневых языков предполагают, что предварительно был выполнен некоторый инициализирующий код; вы должны быть уверены, что при старте модуля высокоуровневых языков выполнена корректная инициализация, а затем вызвать ассемблерную процедуру. Ассемблерная процедура может затем сама вызывать высокоуровневые языковые процедуры, как показано на рисунке С.3.
СИ-код Код на Ассемблере

(начало программы на СИ) |

main(){ |

asub(); |

} | PROC asub

| .

(C termination) | .

| .

| call ctest

ctest(){ | .

. | .

. |

| ret

. | ENDP asub

} |
Рисунок Вызов СИ из Ассемблера.
Для вызова высокоуровневых языков из языка Ассемблер вам следует соблюдать следующие правила:
-Каждый параметр опускайте в стек, соблюдая соглашения о связях высокоуровневых языков. Константы, такие, как адреса смещений, должны быть загружены в регистр до любых опусканий в стек.
-При длинных параметрах, всегда опускайте в стэк первыми сегмент, либо старшую часть параметра, независимо от соглашений о связях. -Выполняйте вызов. Вызов должен быть "дальним", если только высокоуровневая процедура не относится к малой модели памяти. -Если процедура использовала соглашения о связях языка СИ, то непосредственно сразу после вызова очистите стек от параметров с помощью инструкции: add sp, size, где size-это общий размер в байтах всех параметров, опущенных в стек.
Стандартные сегменты и типы для стандартных моделей памяти.
Модель Директива Имя Выравни- Способ объ Класс Группа

вание единения

Малая .CODE _TEXT WORD PUBLIC 'CODE'

.DATA _DATA WORD PUBLIC 'DATA' DGROUP

.CONST CONST WORD PUBLIC 'CONST' DGROUP

.DATA? _BSS WORD PUBLIC 'BSS' DGROUP

.STACK STACK PARA STACK 'STACK' DGROUP
Средняя .CODE name_TEXT WORD PUBLIC 'CODE'

.DATA _DATA WORD PUBLIC 'DATA' DGROUP

.CONST CONST WORD PUBLIC 'CONST' DGROUP

.DATA? _BSS WORD PUBLIC 'BSS' DGROUP

.STACK STACK PARA STACK 'STACK' DGROUP
Компакт- .CODE _TEXT WORD PUBLIC 'CODE'

ная .FARDATA FAR_DATA PARA Private 'FAR_DATA'

.FARDATA? FAR_BSS PARA Private 'FAR_BSS'

.DATA _DATA WORD PUBLIC 'DATA' DGROUP

.CONST CONST WORD PUBLIC 'CONST' DGROUP

.DATA? _BSS WORD PUBLIC 'BSS' DGROUP

.STACK STACK PARA STACK 'STACK' DGROUP
Большая .CODE name_TEXT WORD PUBLIC 'CODE'

.FARDATA FAR_DATA PARA Private 'FAR_DATA'

.FARDATA? FAR_BSS PARA Private 'FAR_BSS'

.DATA _DATA WORD PUBLIC 'DATA' DGROUP

.CONST CONST WORD PUBLIC 'CONST' DGROUP

.DATA? _BSS WORD PUBLIC 'BSS' DGROUP

.STACK STACK PARA STACK 'STACK' DGROUP
Директивы Таблицы С.1 относятся к следующим типам сегментов:
Директива Описание сегмента

.CODE Сегмент, содержащий весь код модуля.

.DATA Проинициализированные данные.

.DATA? Неинициализированные данные. Компиляторы фир-

мы Microsoft хранят неинициализированные дан-

ные отдельно, поскольку такие данные можно раз

местить более эффективно, чем проинициализиро-

ванные данные.

.FARDATA и .FARDATA? Данные, которые не будут объединяться с соот-

ветствующими сегментами других модулей. Сег-

мент размещенных здесь данных, тем не менее,

всегда может быть определен с помощью операто-

ра ассемблера SEG.

.CONST Постоянные данные. Компиляторы фирмы Microsoft

используют данный сегмент для элементов, та-

ких, как строковые константы и константы с

плавающей точкой.

.STACK Стек. Обычно, данный сегмент объявляется в

главном модуле и не должен быть переопределен.
Для создания реальных директив с помощью Таблицы С.1 используйте следующие шаги:
1.В определении сегмента следует задать имя, тип выравнивания, тип объединения, класс. Таким образом, сегмент кода для малой модели памяти должен быть объявлен следующим образом:
_TEXT SEGMENT WORD PUBLIC 'CODE'
Если тип объединения "private", просто не используйте никакого типа объединения.
2.Если у вас есть сегменты в DGROUP, поместите их в DGROUP с помощью директивы GROUP, как в примере:
GROUP DGROUP _DATA _BSS
3.Директивы ASSUME и ENDS используйте, как обычно. Помните, что при вводе, регистры DS и SS, оба указывают на DGROUP.
Следующий пример показывает программу "СИ-Ассемблер" из Раздела С.3, но без упрощенных сегментных директив из версии 5.0 Макроассемблера фирмы Microsoft.
_TEXT SEGMENT WORD PUBLIC 'CODE'

ASSUME cs: TEXT

PUBLIC Power2

_Power2 PROC

push bp ;Входная последовательность-сохранения регис-

тра BP.

mov bp,sp ;Установка записи активации.
mov ax,[bp+4] ;Загрузка Arg1 в AX.

mov cx,[bp+6] ;Загрузка Arg2 в CX.

shl ax,cl ;AX = AX+(2 в степени CX).

;Значение возврата остается в AX.

pop bp ;Выходная последовательность-восстановление ре-

гистра BP.

ret ;Выход.

_Power2 ENDP

_TEXT ENDS

END


  1. Напишите отчет о проделанной работе. В отчете алгоритм решения задачи изобразите в виде блок-схемы.


Пояснения к выполнению работы

Главная проблема при написании ассемблерных вставок - правильное понимание типов данных и их длины.

Ассемблерный код для исследования в Debug

mov bx,45

mov bl,2

mov bh,4

add bx,17

mov ax,56

Ассемблерная вставка

void main()

{ short a1,a2,a3,a5;

short ma[10];

int r1;

char s2, is[10]="A2b4C6L89";

for (int i=0; i<10; i++)

ma[i]=i*i;
//сделайте ввод значений a1 a2
_asm

{ lea ecx,is

lea edx,ma

mov ebx,0

mov bl,byte ptr a1

mov bh,byte ptr a2

mov a3,bx

mov r1,ebx

add cx,a1

mov bl, [ecx]

mov s2,bl

mov ax,a1

add ax,a1

add dx,ax

mov bx,[edx]

mov a5,bx

}
//Сделайте вывод значений r1, a3, s2, a5

//Сделайте цикл повтора приложения

}

Контрольные вопросы


  1. Для чего нужны ассемблерные вставки?

  2. Для чего используется язык ассемблера и чем он отличается от алгоритмического языка?

  3. Как в ассемблерной вставке получить доступ к переменным языка С?

  4. Как в ассемблере можно организовать доступ к элементам массива?

  5. Почему в ассемблерной вставке использована конструкция add ax,a1 add dx,ax?

  6. Почему в ассемблерной вставке использована конструкция mov bl,byte ptr a1?