В современных операционных система задания по ВССиТ выполнять, мягко говоря проблематично. Для написания контрольных, да и просто освоения начальных навыков необходимо разобраться с компилятором MASM или TASM которые работают из под DOS.
Сами компиляторы, линковщики и все другие приблуды можно найти, например, на http://kalashnikoff.ru/ или http://www.wasm.ru/. А тут будет рассказываться о том, что ближе к телу.
Сами компиляторы, линковщики и все другие приблуды можно найти, например, на http://kalashnikoff.ru/ или http://www.wasm.ru/. А тут будет рассказываться о том, что ближе к телу.
Необходимые инструменты и их настройка.
И так, что нам нужно. Нам нужен эмулятор DOS-терминала и компилятор. Компилятор я выбрал MASM 6.11, так как им до этого пользовался, и кое что в моей памяти уже было.Как DOS-эмулятор я советую DOSBox. Версии есть и под Windows и под Linux. Под Linux его можно установить из стандартного репозитория. Для Ubuntu:
После запуска вы увидите экран с приглашением :
Пример на моем проекте:
$sudo apt-get install dosbox
или из Центра приложений.После запуска вы увидите экран с приглашением :
Z:\>
Смонтируйте диск C:\ для этого наберите:Z:\>mount c /home/user/folder_prodject
И перейдите в неё:Z:\>c:
командой dir вы сможете посмотреть содержание директории, а командой cd имя_директории перейти в другую папку находящуюся в точке монтирования или в её подпапках.Пример на моем проекте:
Если вы работаете много в DOS-эмуляторе, то такой способ может оказаться не очень удобным. Но моно настроить автоматическое монтирование диска C:\
Открываем /home/user/.dosbox/dosbox-0.74.conf в редакторе, и ищем строки:
Открываем /home/user/.dosbox/dosbox-0.74.conf в редакторе, и ищем строки:
[autoexec]
# Lines in this section will be run at startup.
# Yju can put your MOUNT lines here.
и пишем тут что-то типа:mount C /home/user/asm
PATH=%PATH%;C:\masm611\bin\
C:
При старте будет монтироваться C:\ диск в /home/user/asm, при этом эта директория должна существовать. PATH назначает пути поиска программ, это нужно что бы нам не мусорить в одной директории, а была возможность разнести компилятор и проект в разные. В конце стоит C: что бы DOSBox самостоятельно переводил нас на диск C:\ и берег наши телодвижения.На последнем рисунке показана команда cd и dir, обратите внимание на то как отражаются имена файлов написанных русскими буквами. Возможно это и лечиться, но нужно ли это нам? И не забывайте, что MS-DOS использовал название файлов в формате 8.3. То есть, на имя отводилось 8 символов, потом шла точка (.), а затем расширение файла. При других названиях тоже могут возникнуть проблемы.
Как использовать MASM 6.11.
Теперь разберем как нам компилировать код, который мы напишем.
Но можно сделать всё быстрее:
Ещё часто бывает нужен файл листинга программы, для этого используйте ключ /Fl:
C:\>ml /с имя_файла.asm
получим файл имя_файла.obj Ключ /c говорит компилятору не проводить линковку.C:\>link имя_файла.obj
получим исполняемый файл.Но можно сделать всё быстрее:
C:\>ml имя_файла.asm /AT
При этом мы получим и .obj файл и исполняемый .com. Флаг /AT говорит компилятору вызвать линковщик и передает ему флаг /T который обозначает модель TINY.Ещё часто бывает нужен файл листинга программы, для этого используйте ключ /Fl:
C:\>ml имя_файла.asm /Fl
Файл листинга будет записан в имя_файла.lstПишем программку.
Всё, на этом самое сложное закончилось. Теперь начинаем писать программу на ассемблере.
Так как в задачах часто просят вывести решение формул на экран, то и будем разбирать подобный пример. Сумма делений с x= от 1 до 10:
Так как в задачах часто просят вывести решение формул на экран, то и будем разбирать подобный пример. Сумма делений с x= от 1 до 10:
Основные команды которые будем использовать
mov приёмник,источник - на просто языке это "=", значение приёмника становиться равно значению источника.
пример:
пример:
пример:
пример:
пример:
Если вы хотите подробнее узнать о командах, то можно обратиться к Справочнику команд.
пример:
mov ax,bx ;значит, ax=bx
mov ax,2 ;значит, ax=2
add приёмник,источник - складывает приёмник и источник, и помещает результат в в приёмник.пример:
mov ax,2
mov bx,5
add ax,bx ; в ax теперь сумма ax и bx, то есть 7
add ax,2 ; в ax теперь сумма ax+2, то есть 9
sub приёмник,источник - приёмник=приёмник-источникпример:
mov ax,5
mov bx,2
sub ax,bx ; в ax теперь разность ax и bx, то есть 3
sub ax,2 ; в ax теперь разность ax-2, то есть 1
mul источник - умножение без знака. Первый множитель находиться в al, ax либо eax, он же является приёмником, второй множитель нужно задать. Только нужно уточнить, что это без знаковое умножение.пример:
mov ax,2
mov bx,2
mul bx ; в ax теперь 4
div источник - деление без знака. Делимое должно находиться в ax, eax или eax:edx. Приёмником целого является al, ax, eax соответственно. А остаток будет записывается в ah, dx или edx соответственно.пример:
mov ax,5
mov bx,2
div bx ; в al теперь 2, а в ah теперь 1.
ещё две команды: push и pop. Первая сохраняет регистр в стеке, вторая его восстанавливает. Самое главное запомнить: первый вошёл, последний вышел. Пример:push ax
push cx
push bx
pop bx
pop cx
pop ax
Иначе вы можете получить не предсказуемый результат.Если вы хотите подробнее узнать о командах, то можно обратиться к Справочнику команд.
Регистры, ох уж эти регистры. Краткий экскурс.
Сейчас, что бы начать читать код, достаточно знать регистры общего назначения:
Они могут быть 8 битные (например, al, ah), 16 битные (например, ax) и 32 битные (например, eax).
Все 16 битные регистры делятся на на младший и старший, например, ax делиться на al и ah. Делиться значит состоит, а не математическое действие.
eax, ax, al - очень часто выступают как приёмник значений, например, при умножении и делении.
ebx, bx. bl, bh - свободный регистр, который можно использовать в хвост и гриву.
edx, dx - часто используется для пересылки дополнительной информации или остатка от деления.
ecx, cx - называется счетчик, используется в циклах.
Всё остальное в комментариях программы. Кстати точка с запятой (;) используется как команда начать комментарий, и всё что написано за ней в строке не интерпретируется компилятором
Они могут быть 8 битные (например, al, ah), 16 битные (например, ax) и 32 битные (например, eax).
Все 16 битные регистры делятся на на младший и старший, например, ax делиться на al и ah. Делиться значит состоит, а не математическое действие.
eax, ax, al - очень часто выступают как приёмник значений, например, при умножении и делении.
ebx, bx. bl, bh - свободный регистр, который можно использовать в хвост и гриву.
edx, dx - часто используется для пересылки дополнительной информации или остатка от деления.
ecx, cx - называется счетчик, используется в циклах.
Всё остальное в комментариях программы. Кстати точка с запятой (;) используется как команда начать комментарий, и всё что написано за ней в строке не интерпретируется компилятором
Тренируемся
Первое что нам нужно - это разложить наш пример на простые составляющие, что бы составить алгоритм. К примеру: x в кубе - это x*x*x. Вспоминаем: умножение это mul, то есть мы можем это записать:
mov ax,1 ; присвоили значение
mul ax ; умножили первый раз, то есть возвели в квадрат
mul ax ; умножили второй раз, то есть возвели в куб
Вот, так пошагово это и происходит.А теперь сам листинг решения примера:
.MODEL tiny ; задаём модель в данном случае .com
.CODE
.486 ; указываем модель процессора
org 100h ; выделяем память
start:
mov ecx,10 ; задаём количество циклов. 10 потому, что у нас x от 1 до 10
Lb1: ; устанавливаем метку для цикла
mov eax,11 ; находим х
sub eax,ecx ; x=11-число циклов (1, 2, 3... 11-1=10)
push ecx ; сохраним в стеке сх для использования в цикле
push eax ; сохраним в стеке ax что бы больше не высчитывать его
mul eax ; x^2 (^ - будет означать "в степени")
mov ecx,eax ; сохраним eax в ecx потом отнимать нужно будет
mov ebx,3 ; ebx = 3
mul ebx ; 3x^2
sub eax,1 ; 3x^2-1
mov ebx,eax ; сохраняем eax в ebx потом понадобиться
pop eax ; восстанавливаем eax так как уже нужен eax опять = x
push ebx ; и сохраняем ebx так как потом понадобиться
mov ebx,eax ; ebx = eax
mov eax,ecx ; помните ecx=x^2, теперь eax = ecx, но можно было просто перемножать
mul ebx ; eax = x^3
mov ebx,4 ; ebx = 4
mul ebx ; eax = 4x^3
sub eax,ecx ; eax = 4x^3-x^2
add eax,2 ; eax = 4x^3-x^2+2
pop ebx ; восстанавливаем ebx
mov a,eax ; делимое (a - это переменная)
mov z,ebx ; делитель (z - это тоже переменная) описаны в конце программы
finit ; инициализируем сопроцессор
fld a ; делимое в сопроцессор
fdiv z ; проводим деление в сопроцессоре
call tEnter ; это вызов функции которая переводит строку
call pFloat ; выводим результат деления в консоль
@4:
fadd t ; добавляем предыдущий результат деления, для получения суммы
; значений функции ( t - это переменная)
fst t ; запоминаем сумму в переменной
pop ecx ; вынимаем ecx из памяти для корректной работы цикла
loop Lb1 ; переходим на метку Lb1 пока ecx не станет равным нулю
call pEnter ; это вызов функции которая переводит строку
call pFloat ; выводим sum((4x^3-x^2+2)/(3x^2-1)) при x от 1 до 10 с шагом 1
int 20h ; Завершение работы программы (это называется
; вызвать прерывание 20h)
ret ; конец блока
; дальше начинается настоящее колдовство
;выводит целое число
pInt:
pushad ; сохраняем все регистры
mov bx,sp ; bx = sp
mov byte ptr ss:[bx-1],'$' ; символ конца строки
@1:cdq ; метка цикла. и команда cdq копирует знаковый бит регистра eax на
; все биты регистра edx
div ecx ; делим число на основание edx - остаток, eax - частное
add dl,'0' ; преобразование в ASCII
dec bx ; уменьшаем bx на 1
mov ss:[bx-1],dl ; добавляем в стоку перед предыдущим
test eax,eax ; проверяем есть ли в eax ещё что-нибудь
jne @1 ; если есть повторяем цикл
mov ax,ss ; выводим строку на экран
mov ds,ax ; ds = ax
dec bx ; уменьшаем bx на 1
mov dx,bx ; dx = bx
xchg sp,bx ; если не обменять вылезет мусор
mov ah,9 ; номер функции прерывания
int 21h ; вызываем прерывание
xchg sp,bx ; если не обменять программа завершиться
popad ; восстанавливаем данные из стека
ret
;выводит число
pFloat:
pushad ; сохраняем все регистры
mov ecx,10 ; задаём основание системы счисления
push ecx ; сохраняем основание
mov bp,sp ; bp = sp
fst dword ptr ss:[bp-4] ; выводим из сопроцессора как двойное слово в регистр ss
xor eax,eax ; обнуляем eax (xor бинарное или)
mov edx,ss:[bp-4] ; edx = ss:[bp-4]
shl edx,1 ; сдвигаем в edx все биты на 1 влево
mov ecx,edx ; ecx = edx
shr ecx,24 ; сдвигаем в ecx все биты в право на 24
sub cx,126 ; вычитаем их cx 126 - Порядок (экспонента)
shl edx,7 ; сдвигаем edx влево на 7
or edx,80000000h ; значащие биты (мантисса)
shld eax,edx,cl ; eax - целая часть
shl edx,cl ; edx - дробная часть
pop ecx ; сохраняем ecx
call pInt ; выводим на экран целую часть
;выводим на экран дробную часть
xchg eax,edx ; обмениваемся значениями
cdq ; преобразуем двойное слово в четверное
sub bp,28 ; вычитаем из bp 28
mov byte ptr ss:[bp],'.' ; добавляем разделитель десятичной дроби
@2:mul ecx ; умножаем на основание 10
add dl,'0' ; преобразование в ASCII
inc bp ; увеличиваем bp на единицу
mov ss:[bp],dl ; добавляем в строку
test eax,eax ; проверяем есть ли ещё знаки после запятой
jne @2 ; да? повторяем цикл
mov byte ptr ss:[bp+1],'$' ; нет? добавляем знак конца строки, иначе выведет мусор
sub sp,32 ; приводим строку в нормальное состояние
push ss
pop ds
mov dx,sp ; помещаем в dx откуда её и будем печатать
mov ah,9 ; функция прерывания прерывания
int 21h ; вызов прерывания
call nEnter ; вызов функции перевода строки
add sp,32 ; восстанавливаем sp
popad ; восстанавливаем регистры
ret
;вспомогательная функция - переводит строку
nEnter:
pushad
mov dx,offset str0
mov ah,9
int 21h
popad
ret
;вспомогательная функция, печатает строку "Temp rezult:"
tEnter:
pushad
mov dx,offset str1
mov ah,9
int 21h
popad
ret
;вспомогательная функция, печатает строку "Result:"
pEnter:
pushad
mov dx,offset strE
mov ah,9
int 21h
popad
ret
;переменные
a dd ?
z dd ?
t dd 0
str0 db 10,13,'$'
str1 db 'Temp result: ','$'
strE db 10,13,'Result: ','$'
end start ; конец программы
Вывод приложения
И вновь начало
Это был очень краткий экскурс в язык ассемблер. Я не ставил перед собой цели детального описания. Всё что тут написано служит только помощью в написании контрольной работы. Если кому-то (например, как мне) интересен язык, и хочется не только получить оценку по ВССиТ, но и что-нибудь начать понимать, воспользуйтесь дополнительной литературой.
Комментариев нет :
Отправить комментарий