Алгоритмическая структура «Цикл» в языке Ассемблер
К изучению языка Ассемблер учащиеся подходят, как правило, имея начальные знания в области программирования. Поэтому им проще будет понять, как реализуются основные алгоритмические структуры в Ассемблере, если при изложении нового материала преподаватель будет проводить аналогию с изученным ими ранее языком программирования (например, Turbo Pascal).
Алгоритмическая структура “цикл”, как известно, обеспечивает выполнение некоторой последовательности действий, которая называется телом цикла.
Выделяется три типа циклов: цикл “ДЛЯ”, цикл “ПОКА”, цикл “ДО”. Друг от друга различные типы циклов отличаются в основном лишь способом проверки окончания цикла.
В языке программирования Паскаль для реализации каждого типа цикла имеются специальные операторы, но любой из этих трех типов можно организовать при помощи условного оператора и оператора безусловного перехода.
Система команд языка Ассемблер тоже позволяет организовать циклическое выполнение некоторого фрагмента программы, к примеру, используя команды условной передачи управления или команду безусловного перехода JMP.
Как и в языке Паскаль, в Ассемблере существует специальная команда, которая позволяет сокращать листинг циклической программы.
Данная команда выполняет следующие функции:
- Автоматически уменьшает значение счетчика.
- Выполняет проверку на выход из цикла.
- Выполняет переход на начало тела цикла.
Команда LOOP может быть использована лишь в случае цикла с известным числом повторений, т.е. цикла “ДЛЯ”. Количество повторений цикла должно быть присвоено регистру СХ до начала цикла.
Таким образом, команда LOOP заменила тройку команд:
Рассмотрим использование этой команды на практике.
Пример: Составим программу, которая выводит на экран 1000 нулей.
(1) prg segment para public ‘code’
(2) assume cs:prg,ss:prg,es:prg,ds:prg
(3) org 100h
(4) start: jmp go
(5) go:
(6) mov ax, 0600h
(7) mov bh,07
(8) mov cx, 0000
(9) mov dx,184fh
(10) mov cx,1000
(11) Zero:
(12) mov ah,02
(13) mov dl,30h
(14) int 21h
(15) loop Zero
(16) ret
(17) prg ends
(18) end start
Строки с (1) по (10) и с (16) по (18) вы уже знаете.
Строка (11) – это метка (начало цикла). Строка (15) – конец цикла. Все, что находится в пределах строк (11) – (15), является циклом. Сам цикл будет повторяться 1000 раз, для чего мы и заносим в СХ число 1000 (строка (10)).
В строке (12) заносим в регистр ah число 02 (запрос функции вывода одного символа).
В строке (13) в регистр dl заносим код выводимого символа (код символа “0” – 30h).
В строке (14) вызываем прерывание int 21h.
Теперь на экране появится первый ноль. Остается уменьшить счетчик (СХ) на 1 и повторить. Что мы и делаем в строке (15).
Задача 1 для практики: Составить фрагмент программы на языке Ассемблер, подсчитывающий сумму первых 10 натуральных чисел (результат записать в АХ).
Задача 2 для практики: Составить фрагмент программы на языке Ассемблер, вычисляющий значение выражения: (результат записать в АХ).
Задача 3 для практики: Составить фрагмент программы на языке Ассемблер, вычисляющий факториал заданного числа К (К – от 0 до 8).
Источник статьи: http://urok.1sept.ru/%D1%81%D1%82%D0%B0%D1%82%D1%8C%D0%B8/556346/
Инструкция LOOP
| Что такое JavaScript |
Если вы интересуетесь программированием вообще, и сайтостроением в частности, то вы наверняка слышали слово JavaScript. И, если вы до сих пор не узнали толком, что же это такое, то пришло время сделать это. Подробнее.
Инструкция LOOP в Ассемблере уменьшает значение в регистре СХ в реальном режиме или ECX в защищённом. Если после этого значение в СХ не равно нулю, то команда LOOP выполняет переход на МЕТКУ. Синтаксис:
МЕТКА — это допустимый в Ассемблере идентификатор. О метках в Ассемблере я рассказывал здесь.
Алгоритм работы команды LOOP:
- CX = CX — 1
- Если CX не равен 0, то выполнить переход (продолжить цикл)
- Иначе не выполнять переход (прервать цикл и продолжить выполнение программы)
То есть команда LOOP выполняется в два этапа. Сначала из регистра СХ вычитается единица и его значение сравнивается с нулём. Если регистр не равен нулю, то выполняется переход к указанной МЕТКЕ. Иначе переход не выполняется и управление передаётся команде, которая следует сразу после команды LOOP.
Как выполнить цикл в Ассемблере
Выполнение цикла в Ассемблере можно организовать с помощью нескольких команд. Одна из таких команд — это команда LOOP. Команда цикла в Ассемблере всегда уменьшает значение счётчика на единицу. Это значение находится в регистре СХ (или ECX). Отличия между командами цикла заключаются только в условиях, при которых выполняется переход к метке или цикл завершается.
Команда LOOP выполняет переход к метке во всех случаях, когда значение в регистре СХ не равно нулю. Чтобы организовать цикл с помощью этой команды, нам надо сначала в регистр СХ записать число итераций цикла (то есть сколько раз цикл должен быть выполнен), затем вставить в код метку, а затем написать команды, которые должны быть выполнены в цикле. А уже в конце списка этих команд записать команду LOOP.
Более понятно это будет в примере программы (см. ниже).
Возможные ошибки
Начинающие довольно часто совершают одни и те же ошибки при организации циклов в Ассемблере. А именно — неправильно задают или обнуляют значение счётчика перед выполнение цикла.
При обнулении счётчика перед циклом при первой итерации цикла значение в регистре CX будет равно FFFFh (потому что команда LOOP отнимет от СХ единицу, а в СХ у нас был 0), и цикл в программе будет выполняться, соответственно 65536 раз.
Ещё один момент: диапазон адресов для передачи управления в команде LOOP ограничен в пределах -128…+127 байтов относительно адреса следующей команды. Если учесть, что в реальном режиме процессора средняя длина машинной команды равна 3 байта, то получается, что блок команд, выполняющихся в цикле, может состоять примерно из 42 команд. Если же в вашем цикле будет больше команд, то, например, MASM, выдаст сообщение об ошибке, которое будет выглядеть примерно так:
error A2075: jump destination too far : by 10 byte(s)
Здесь говорится, что местоположение перехода слишком далеко (примерно на 10 байт больше допустимого).
Ещё одна ошибка — это изменение значения регистра CX в теле цикла. В итоге команда LOOP будет работать неправильно. К тому же при этом можно попасть в бесконечный цикл. Пример:
Здесь в теле цикла увеличивается значение регистра СХ, поэтому он никогда не будет равен нулю, и, следовательно, цикл никогда не завершится.
А теперь о происхождении мнемоники LOOP. В общем то это не мнемоника, а слово. В переводе с английского оно означает “петля”, “виток”, “цикл”.
Источник статьи: http://www.av-assembler.ru/instructions/loop.php
Команды организации циклов на языке Ассемблер.
Для организации циклов используются и команды: LOOP, LOOPNE, LOOPE, JCXZ. При этом данные команды опираются на регистр счетчика CX.
|
команда LOOP |
Команда LOOP эквивалентна следующим командам:
DEC CX // уменьшение CX на 1
JNZ МЕТКА // переход в случае CX=0
Предназначена для анализа не только значения CX, но и флага PF.
Позволяет осуществить переход только в том случае если значение регистра CX=0.
Используется либо для предварительной проверки значения CX либо для выхода из цикла в произвольной точке его тела.
Команды передачи управления на языке Ассемблер.
1. Безусловный переход.
Осуществляется командой JMP, с указанием метки, на которую будет осуществляться переход. В зависимости от типа перехода после мнемоники JMP может осуществляться переход этих типов: а) SHORT – точка перехода задается в виде восьми битного смещения со знаком, который будет суммировать. Преимущество: адресная часть сокращается до байта, недостаток: переход всего на 127 байт.
б) FAR – переход осуществляется по абсолютному адресу заданному сегментом и смещением. Преимущество: перемещается в любой сегмент, недостаток: большая адресная часть пространства. в) NEAR – ближайший тип, переход осуществляется только по смещению в пределах текущего сегмента.
мнемоника | условие | флаги |
JB/JNAE | если меньше | CF=1 |
JBE/JNA | если меньше или равно | CF=1 и ZF=1 |
JAE/JNB | если больше или равно 0 | CF=0 |
JA/JNBE | если больше | CF=0 и ZF=0 |
JE/JZ | если ZF=1 | ZF=1 |
JNE/JNZ | если ZF=0 | ZF=0 |
JL/JNGE | если SF=OFF | SF=OF |
JLE/JNLE | если ZF=1 и SF=OF | ZF=1 и SF=OF |
JP/JPE | если четно | PF=1 |
JNP/JPO | если нечетно | PF=0 |
JS | если знак — | SF=1 |
JNS | если знак + | SF=0 |
JC | если перенос | CF=1 |
JNC | если без переноса | СА=0 |
JO | если переполнение | OF=1 |
JNO | если без переполнения | OF=0 |
Типы перехода могут быть явно не указаны, в команде в этом случае он будет определяться компилятором самостоятельно.
Условный переходы.
Инструкция условного перехода осуществляет переход в случае
выполнения того или иного условия и определяется, как бит в регистре флагов, т.е. к моменту выполнения команды условного перехода необходимо выполнять команды проверки условия. Синтаксическая диаграмма аналогичная команде JMP.
прим.: команда CMP позволяет сравнить два числа с помощью вычитания, при этом результат не сохраняется, а суммируются только флаги.
27. Логическая организация файла.
Программист имеет дело с логической организацией файла, представляя файл в виде определенным образом организованных логических записей. Логическая запись — это наименьший элемент данных, которым может оперировать программист при обмене с внешним устройством. Даже если физический обмен с устройством осуществляется большими единицами, операционная система обеспечивает программисту доступ к отдельной логической записи. На рисунке 1.3 показаны несколько схем логической организации файла. Записи могут быть фиксированной длины или переменной длины.
Рис. 1.3. Способы логической организации файлов
Записи могут быть расположены в файле последовательно (последовательная организация) или в более сложном порядке, с использованием так называемых индексных таблиц, позволяющих обеспечить быстрый доступ к отдельной логической записи (индексно-последовательная организация). Для идентификации записи может быть использовано специальное поле записи, называемое ключом. В файловых системах ОС UNIX и MS-DOS файл имеет простейшую логическую структуру — последовательность однобайтовых записей.
28. Логические действия на языке Ассемблер.
Выполняются над операндами побитно. Логические операции выполняет процессор.
Команды побитовых сдвигов.
пример: MOV AX, 11h 0001 0001 0
Команды логических сдвигов.
Выполняют перемещение операнда на один разряд вправо/влево. При этом циклического переноса вытесняемых разрядов в начало/конец не происходит. Сдвиг может происходить только на один разряд.
Источник статьи: http://megalektsii.ru/s17484t3.html
Программирование на Ассемблере для начинающих с примерами программ
Многие считают, что Assembler – уже устаревший и нигде не используемый язык, однако в основном это молодые люди, которые не занимаются профессионально системным программированием. Разработка ПО, конечно, хорошо, но в отличие от высокоуровневых языков программирования, Ассемблер научит глубоко понимать работу компьютера, оптимизировать работку с аппаратными ресурсами, а также программировать любую технику, тем самым развиваясь в направлении машинного обучения. Для понимания этого древнего ЯП, для начала стоит попрактиковаться с простыми программами, которые лучше всего объясняют функционал Ассемблера.
IDE для Assembler
Первый вопрос: в какой среде разработки программировать на Ассемблере? Ответ однозначный – MASM32. Это стандартная программа, которую используют для данного ЯП. Скачать её можно на официальном сайте masm32.com в виде архива, который нужно будет распаковать и после запустить инсталлятор install.exe. Как альтернативу можно использовать FASM, однако для него код будет значительно отличаться.
Перед работой главное не забыть дописать в системную переменную PATH строчку:
Программа «Hello world» на ассемблере
Считается, что это базовая программа в программировании, которую начинающие при знакомстве с языком пишут в первую очередь. Возможно, такой подход не совсем верен, но так или иначе позволяет сразу же увидеть наглядный результат:
Для начала запускаем редактор qeditor.exe в папке с установленной MASM32, и в нём пишем код программы. После сохраняем его в виде файла с расширением «.asm», и билдим программу с помощью пункта меню «Project» → «Build all». Если в коде нет ошибок, программа успешно скомпилируется, и на выходе мы получим готовый exe-файл, который покажет окно Windows с надписью «Hello world».
Сложение двух чисел на assembler
В этом случае мы смотрим, равна ли сумма чисел нулю, или же нет. Если да, то на экране появляется соответствующее сообщение об этом, и, если же нет – появляется иное уведомление.
Здесь мы используем так называемые метки и специальные команды с их использованием (jz, jmp, test). Разберём подробнее:
- test – используется для логического сравнения переменных (операндов) в виде байтов, слов, или двойных слов. Для сравнения команда использует логическое умножение, и смотрит на биты: если они равны 1, то и бит результата будет равен 1, в противном случае – 0. Если мы получили 0, ставятся флаги совместно с ZF (zero flag), которые будут равны 1. Далее результаты анализируются на основе ZF.
- jnz – в случае, если флаг ZF нигде не был поставлен, производится переход по данной метке. Зачастую эта команда применяется, если в программе есть операции сравнения, которые как-либо влияют на результат ZF. К таким как раз и относятся test и cmp.
- jz – если флаг ZF всё же был установлен, выполняется переход по метке.
- jmp – независимо от того, есть ZF, или же нет, производится переход по метке.
Программа суммы чисел на ассемблере
Примитивная программа, которая показывает процесс суммирования двух переменных:
В Ассемблере для того, чтобы вычислить сумму, потребуется провести немало действий, потому как язык программирования работает напрямую с системной памятью. Здесь мы по большей частью манипулируем ресурсами, и самостоятельно указываем, сколько выделить под переменную, в каком виде воспринимать числа, и куда их девать.
Получение значения из командной строки на ассемблере
Одно из важных основных действий в программировании – это получить данные из консоли для их дальнейшей обработки. В данном случае мы их получаем из командной строки и выводим в окне Windows:
Также можно воспользоваться альтернативным методом:
Здесь используется invoke – специальный макрос, с помощью которого упрощается код программы. Во время компиляции макрос-команды преобразовываются в команды Ассемблера. Так или иначе, мы пользуемся стеком – примитивным способом хранения данных, но в тоже время очень удобным. По соглашению stdcall, во всех WinAPI-функциях переменные передаются через стек, только в обратном порядке, и помещаются в соответствующий регистр eax.
Циклы в ассемблере
Для создания цикла используется команда repeat. Далее с помощью inc увеличивается значение переменной на 1, независимо от того, находится она в оперативной памяти, или же в самом процессоре. Для того, чтобы прервать работу цикла, используется директива «.BREAK». Она может как останавливать цикл, так и продолжать его действие после «паузы». Также можно прервать выполнение кода программы и проверить условие repeat и while с помощью директивы «.CONTINUE».
Сумма элементов массива на assembler
Здесь мы суммируем значения переменных в массиве, используя цикл «for»:
Команда dec, как и inc, меняет значение операнда на единицу, только в противоположную сторону, на -1. А вот cmp сравнивает переменные методом вычитания: отнимает одно значение из второго, и, в зависимости от результата ставит соответствующие флаги.
С помощью команды jne выполняется переход по метке, основываясь на результате сравнения переменных. Если он отрицательный – происходит переход, а если операнды не равняются друг другу, переход не осуществляется.
Ассемблер интересен своим представлением переменных, что позволяет делать с ними что угодно. Специалист, который разобрался во всех тонкостях данного языка программирования, владеет действительно ценными знаниями, которые имеют множество путей использования. Одна задачка может решаться самыми разными способами, поэтому путь будет тернист, но не менее увлекательным.
Источник статьи: http://evilinside.ru/assembler-dlya-nachinayushhix-primery-prostyx-programm/