Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1




НазваниеКонспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1
страница6/41
Дата публикации03.03.2013
Размер5.22 Mb.
ТипКонспект
uchebilka.ru > Информатика > Конспект
1   2   3   4   5   6   7   8   9   ...   41

^ 2. Команда безусловного перехода jmp
При выполнении команды безусловного перехода jmp, независимо от состояния флагов процессора, программа продолжает выполняться с новой ветви. При этом новый адрес команды загружается в регистр-счетчик команд EIP и выполнение программного кода продолжается с этого адреса.

В языке ассемблера новое место, откуда продолжается выполнение программы, в большинстве случаев обозначается меткой, которую процессор преобразует в исполнительный адрес. Если переход происходит в текущий сегмент, то смещение метки загружается непосредственно в регистр-счетчик команд EIP. Если же метка находится в другом сегменте кода, то адрес сегмента дополнительно загружается в регистр CS. Для преобразования метки в вид сегмент: смещение используются три формата команды jmp:
jmp short целевой_адрес

jmp near ptr целевой_адрес

jmp far ptr целевой_адрес
Здесь целевой_aдpec - адрес команды, которая будет выполняться после перехода. Вот несколько примеров команды jmp:
jmp label1 : адрес команды, которая будет выполняться

:при переходе, находится в текущем сегменте : команд

jmp near ptr label1 : адрес следующей команды :находится в текущем сегменте команд

jmp short label1 : адрес команды, которая будет

: выполняться при переходе,

: находится в диапазоне

: -128 - +127

jmp far ptr label1 : адрес команды, которая будет

: выполняться при переходе,

: находится в другом сегменте
Рассмотрим операторы, указанные перед целевым адресом. Оператор short указывает на то, что нужно сделать переход на метку в диапазоне от -128 до +127, начиная от адреса следующей команды. В этом случае к содержимому регистра указателя команд EIP прибавляется 8-разрядное целое число.

Оператор near ptr указывает на метку в текущем сегменте, при этом к регистру указателя команд EIP прибавляется 16-разрядное смещение. Наконец, оператор far ptr указывает, что необходимо сделать переход на метку в другом сегменте. В этом случае сегментная часть адреса метки загружается в регистр CS, а смещение - в EIP.

Рассмотренные нами модификации команды jmp являются классическими для 16-разрядных приложений и берут свое начало от «времен MS-DOS», когда отдельный сегмент кода не мог использовать пространство памяти больше чем 64 Кбайта, а для создания больших программ требовалось определенным образом компоновать несколько сегментов кода и данных.

Любое современное приложение является 32-разрядным и оперирует с линейным пространством адресов размером до 4 Гбайт. При разработке ассемблерных программ, как упоминалось в главе 3, используется модель памяти flat, а это означает, что программа занимает непрерывную область адресов, в которой размещаются данные и код. По этой причине любые команды адресуются 32-разрядным смещением в пространстве адресов программы.

При запуске 32-разрядного приложения все сегментные регистры устанавливаются в одно и то же значение. Для программистов, работающих с программами в DOS, 32-разрядное Windows-приложение может напоминать СОМ-файл, поскольку в таком файле можно работать только со смещениями. В 32-разрядных приложениях все метки и переходы считаются ближними (near ptr) в диапазоне адресов 4 Гбайт.

Команду jmp можно использовать не только для безусловного перехода в сегменте программного кода, но и для организации ветвлений. Для этого можно применить один из ее форматов, показанных далее:
jmp regl6

jmp reg32

jmp word ptr [гедЩ

jmp dword ptr [reg32~]
Здесь reg16 (reg32) - один из 16- или 32-разрядных регистров. Для первых двух форматов команд из списка адрес, по которому передается управление, должен находиться в одном из этих регистров.

Если используется 32-разрядный регистр (reg32), то адрес команды, на которую передается управление, также является 32-разрядным. Этот формат команды jmp характерен для 32-разрядных Windows-приложений.

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

.code

...

L1:

xor EDX, EDX

...

lea ESI LI

... jmp ESI
В этом примере в регистр ESI помещается смещение метки L1, после чего с помощью команды jmp ESI управление передается на эту метку.
...

.data

label_offset DD LI

.code

...

LI:

xor EDX. EDX

...

lea ESI. label_offset

jmp dword ptr [ESI]

...
В этом примере в регистр ESI помещается адрес переменной labe1_pffset, в то время как сама переменная label_offset содержит адрес метки L1. Команда jmp dword ptr [ESI] в этом случае передает управление на метку L1.

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

Следующее 16-разрядное приложение, исходный текст которого показан в листинге 1, выводит на экран строки si, s2 и s3.
Листинг 1. Вывод трех символьных строк на экран

.model small

.stack 100h

.data

S1 DB Odh. Oah. "String 1$"

s2 DB Odh. Oah. "String 2$"

S3 DB Odh. Oah. "String 3$"
sarray label word : массив, в котором хранятся

: адреса строк
DW si : si и s2

DW s2

DW S3
num DW 0 : индекс в адресе перехода команды jmp

label_array label word : массив адресов меток

DW LI : адрес метки LI

DW L2 : адрес метки L2

DW L3 : адрес метки L3

.code

start:

mov AX, @data

mov DS, AX

mov ES, AX

:

mov CX. 3 : счетчик цикла -> CX

lea DI. label_array : адрес массива меток

next:

mov SI. DI

mov BX. num : индекс перехода -> BX

shl BX. 1 : умножить на 2 для правильной адресации

: меток в массиве label_array

add SI. BX : сформировать адрес перехода

: для команды jmp

jmp word ptr [SI] : перейти по адресу,находящемуся

: в регистре SI (L1 или L2)

wedge:
inc num : инкремент индекса переходов

loop next : повторить цикл

:

LI: : фрагмент кода при переходе на метку L1

lea DX. si

mov АН, 9h

int 21h

jmp wedge : вернуться в цикл

L2: : фрагмент кода при переходе на метку L2

lea DX. s2

mov АН. 9h

int 21h

jmp wedge
L3: : фрагмент кода при переходе на метку L3

lea DX. s3

mov АН. 9h

int 21h

:

mov AH. lh : ожидать ввода любого символа

int 21h

:

mov AX. 4c00h : завершение программы

int 21h

end start
end
В этой программе продемонстрирована техника использования команды безусловного перехода jmp для организации трех ветвлений по адресам, определяемым метками LI, L2 и L3. Адрес перехода команды jmp формируется в регистре SI следующим образом: вначале в SI загружается базовый адрес массива меток labe1_array, после чего к нему прибавляется смещение, кратное двум (метки LI - L3 имеют двухбайтовый адрес). Затем из сформированного таким образом адреса извлекается смещение одной из меток и выполняется переход на соответствующую ветвь программы. Например, для получения смещения метки L2 необходимо к адресу labe1_array прибавить значение 2 (индекс num = 1). После выполнения программы на экране должны отобразиться строки:
String 1

String 2

String 3
Как видно из примера, команду безусловного перехода jmp можно применить для организации ветвлений в программе в зависимости от значения каких-либо параметров. Рассмотрим еще один, довольно сложный пример, в котором команда jmp используется для организации ветвлений и фактически моделируется логическая структура высокого уровня switch ... case языка C++ (или оператор case языка Pascal), обладающая очень большими вычислительными возможностями. В языке ассемблера довольно сложно реализовать такую структуру, и один из вариантов реализации, который мы рассмотрим, базируется на использовании команды jmp.

Пример представляет собой 32-разрядную процедуру (она называется easel). В качестве входного параметра процедура принимает целое число из диапазона 0-2, а в регистре ЕАХ возвращает адрес строки, соответствующий значению параметра. Принципы организации процедур мы рассмотрим в следующих главах, сейчас же акцентируем наше внимание на работе программного кода процедуры '-э^ 1. не вникая в детали ее взаимодействия с другими частями программы.

Для извлечения единственного параметра используется регистр ЕВР, а сам параметр для выполнения дальнейших манипуляций помещается в регистр ЕВХ. Исходный текст процедуры представлен в листинге 2.
Листинг 2. Ассемблерный аналог конструкции case

.686

.model flat

option casemap: none

.data

si DB "String 1". 0

s2 DB "String 2". 0

S3 DB "String 3". 0

err DB "Incorrect parameter!". 0

label_array label dword : массив меток, в

: котором будут

: находиться смещения

: меток LI. L2 и L3
DD 3 DUP (?)
.code

_case_l proc

push EBP

mov EBP. ESP

mov EBX. dword ptr [EBP+8] : извлекаем параметр

: и сохраняем его в регистре ЕВХ

lea ESI. label_array : адрес массива меток -> ESI

mov [ESI], offset LI : заполняем массив меток

:смещениями mov [ESI+4]. offset L2 : меток LI. L2 и L3
mov [ESI+B]. offset L3

lea EAX. err_exit : сохраняем в регистре ЕАХ смещение

: метки для выхода из процедуры

: в случае ошибки

shl ЕВХ. 2 : поскольку для адресации

: используются двойные слова.

: умножаем номер строки на 4

cmp ЕВХ. 8 : значение учетверенного параметра

: не должно превышать 8 (номер строки

: лежит в диапазоне 0-2)

jle next1 : верхнее значение меньше 8? Если

: да. следующая проверка

jmp EAX : нет. параметр превышает значение 2.

: выйти из процедуры с ошибкой

nextl:

cmp ЕВХ. 0 : параметр не является отрицательным

: числом? Если

jge get_string : нет. продолжить выполнение

: процедуры

jmp EAX : да. параметр вне диапазона, выйти

: с ошибкой

get_string: : параметр находится в нужном

: диапазоне, получить адрес

: соответствующей строки и выйти из

: процедуры
cmovge EAX. [ESI][EBX]
jmp EAX

LI: : сюда передается управление при

: значении входного параметра.

: равном О

lea ЕАХ. S1 : адрес строки si -> ЕАХ

jmp exit : выход из процедуры

L2: : сюда передается управление при

: значении входного параметра.

: равной 1

lea ЕАХ. s2 : адрес строки s2 -> ЕАХ

jmp exit : выход из процедуры

L3: : сюда передается управление при

: значении входного параиетра.

: равной 2

lea ЕАХ. s3 : адрес строки S3 -> ЕАХ

jmp exit : выход из процедуры

err_exit: : сюда передается управление

: при возникновении ошибки

lea ЕАХ. err : адрес сообщения об ошибке -> ЕАХ

exit:

pop EBP

ret

_case_l endp

end
Анализ работы процедуры начнем со строк
lea ESI. label_array

mov [ESI], offset LI

mov [ESI+4]. offset L2

mov [ESI+B]. offset L3
Как и в предыдущем примере, вначале заполняем массив меток смещениями используемых ветвей программы. Поскольку 32-разрядные приложения работают со смещениями, равными двойному слову, то наш массив labelarray состоит из трех двойных слов, в которых и сохраняются смещения меток LI, L2 и L3. Все эти действия и выполняют четыре команды, показанные выше.

Следующая команда помещает в регистр ЕАХ смещение метки, куда должно передаваться управление в случае ошибки:
lea ЕАХ.

err_exit
Для передачи управления в нашей процедуре используется команда
jmp ЕАХ
Она принимает в качестве операнда регистр (в данном случае - ЕАХ), содержащий смещение команды, куда передается управление.

С помощью следующей команды устанавливается смещение одной из меток (LI, L2 или L3), в которую должно передаваться управление при корректном значении параметра процедуры:
Shi EBX. 2
Фрагмент программного кода, в котором выполняется проверка параметра на принадлежность диапазону 0-2, думаю, понятен и в объяснениях не нуждается. Если полученный параметр корректен, то выполняется команда
cmovge ЕАХ. [ESI][EBX]
Остановимся на работе этой инструкции ассемблера более подробно. Описание группы команд, к которой принадлежит cmovge, приводится далее в этой главе, но в нашем случае эта инструкция выполняет две функции:

  • анализирует результат предыдущей операции (флаг SF);

  • если SF - 1, то в регистр ЕАХ помещается смещение одной из меток (LI, L2 или L3). Само смещение находится по адресу, равному сумме адресов массива labe"l_array (регистр ESI) и индекса строки (регистр ЕВХ).

Подобную процедуру при желании можно усовершенствовать и использовать для организации ветвлений в программах на ассемблере.
^ 3. Организация циклов
Очень часто условные переходы используются при программировании циклических операций, или циклов, когда обрабатывается группа элементов. Количество итераций (прохождений) в цикле чаще всего определяется количеством обрабатываемых элементов, хотя это и не обязательно. Цикл может закончиться в одном из двух случаев:

  • выполнены все итерации;

  • обнаружено условие, согласно которому должен произойти выход из цикла.

Рассмотрим следующий пример: пусть необходимо подсчитать количество символов в строке. Условимся, что такая строка оканчивается нулем, и будем использовать этот факт как признак конца цикла. Вот фрагмент программного кода, реализующий этот алгоритм:
.data

si DB "ABCDFEG". 0 .code

mov AL. 0

lea SI. si
next:

cmp byte ptr [SI]. 0

je exit

inc SI

inc AL

jmp next
exit:
Проанализируем этот фрагмент кода. В качестве счетчика элементов используется регистр AL, в который перед началом вычислений помещается 0. Для анализа элемента на равенство нулю нам понадобится адрес строки или, что одно и то же, адрес первого элемента строки. Значение адреса помещается в регистр SI. Таким образом, к элементу строки можно получить доступ по его адресу, определяемому парой регистров DS : SI. В каждой итерации анализируется признак конца строки с помощью команды
cmp byte ptr [SI]. 0
Если признак конца строки обнаружен, то происходит выход из цикла. Если элемент строки не равен 0, то к счетчику элементов в регистре AL прибавляется 1, а в регистр SI загружается адрес следующего элемента строки при помощи команды
inc SI
Далее цикл повторяется. Как видно из примера, цикл заканчивается по условию (достигнут конец строки).

Если известно заранее количество итераций в цикле, то признаком окончания цикла является выполнение всех итераций. В следующем примере подсчитывается количество вхождений символа А в строку si. Размер строки определяется константой 1 en, поэтому можно использовать это значение для инициализации счетчика цикла:
.data

si DB "ABCAEFGAGEBA"

len EQU $-sl .code

mov DX. len

mov AL. 'A'

xor BL. BL

lea SI. si next:

cmp byte ptr [SI]. AL

je inc_counter continue:

dec OX

jz exit

inc SI

jmp next i nc_counter:

inc BL

jmp continue

exit:
Посмотрим, как работает этот код. Поскольку количество итераций заранее известно и равно 1 en, можно загрузить это значение в регистр DX и по окончании каждой итерации уменьшать содержимое DX на 1. Выход из цикла произойдет при значении DX, равном 0. Количество обнаруженных в строке символов А запоминается в счетчике символов, в качестве которого используется регистр BL (начальное значение равно 0).

В самом цикле выполняется сравнение значения текущего символа с содержимым регистра AL. Если обнаружено совпадение, то есть проверяемый элемент равен А, то регистр BL инкрементируется:
cmp byte ptr [SI]. AL je inc_counter

inc_counter: inc BL
В нашем последнем примере использовался счетчик цикла на регистре BL. В языке ассемблера для организации циклов с заранее определенным количеством итераций очень удобно применять команду loop, специально предназначенную для подобных целей.

Команда loop выполняет декремент содержимого регистра СХ (ЕСХ), и если оно не равно нулю, то осуществляется переход на указанную метку вперед или назад в диапазоне от -128 до +127 байт. Содержимое регистра СХ (ЕСХ) рассматривается как целое число без знака. Перед использованием команды loop в регистр СХ (ЕСХ) нужно поместить счетчик итераций. Команда loop является последней в цикле и анализирует содержимое счетчика: как только оно становится равным нулю, происходит выход из цикла.

Следующий пример демонстрирует в общих чертах методику использования команды loop:
.data

counter DW 5

.code

xor AX. AX

mov CX. counter : счетчик итераций -> СХ
next:

inc AX : инкремент регистра АХ

loop next : следующая итерация
После окончания цикла регистр АХ будет содержать значение Команду loop можно представить ее функциональным аналогом, состоящим из других команд, как показано в этом примере:
.data

counter DW 5 .code

xor AX. AX

mov CX. counter : счетчик итераций -> СХ
next:

Inc AX : инкренент регистра АХ

dec CX : декренент регистра СХ

jcxz skip : если СХ - 0. выйти из цикла

jmp next : следующая итерация

skip:
Если вместо команды jcxz в этом фрагменте кода применить jz, то исходный текст будет выглядеть так:
.data

counter DW 5 .code

хог АХ. АХ

mov СХ. counter : счетчик итераций -> СХ
next:

inc АХ : инкренент регистра АХ

dec СХ : декремент регистра СХ

jnz next : если СХ - 0. выйти из цикла.

: иначе следующая итерация
Модификациями команды loop являются команды loope/loopz и loopne/loopnz. Рассмотрим вначале команду loope/loopz. Обозначения loope и loopz представляют собой синонимы и относятся к одной и той же команде. Эта команда обладает дополнительными возможностями по обработке циклов. Она выполняет декремент содержимого регистра СХ (ЕСХ), и если оно не равно 0 и флаг ZF установлен в 1, то выполняется переход на указанную метку вперед или назад.

Рассмотрим пример использования команды loope. Это простое 16-разрядное приложение, которое выводит на экран дисплея строку без начальных пробелов (листинг 3).
Листинг 3. Вывод строки без начальных пробелов на экран

.model small

.data

si DB " String with leading blanks !$"

len EQU $-sl

msg DB "Blank string!$"

.code

start:

mov AX. @data

mov DS. AX

lea SI. si : адрес строки -> SI

dec SI : декремент адреса для организации цикла

mov СХ. len : размер строки -> СХ

mov AL. ' ' : шаблон для сравнения -> AL

next:

inc SI : переход к адресу следующего элемента

emp byte ptr [SI]. AL : сравнить элемент строки с

:пробелом

loope next : повторять, пока не будет обнаружен

: символ отличный от пробела, либо не

: будет достигнут конец строки

стр СХ. 0 : был достигнут конец строки?

je fail : да. строка состоит из пробелов.

: вывести соответствующее сообщение

mov DX. SI : нет. в строке есть другие символы.

: поместить адрес первого символа.

: отличного от пробела, в регистр DX

show:

mov АН. 9h : отобразить сообщения

int 21h

mov АН. lh

int 21h

mov AX. 4С00И

int 21h
fail:

lea DX. msg

jmp show

end start
end
Перейдем к анализу команды loopne/loopnz. Отличие этой команды от loope/loopz состоит в том, что цикл выполняется, пока выполняется условие ZF - 0. Обозначения loopne и loopnz являются синонимами и относятся к одной и той же команде. Пример использования команды 1 оорпе приводится в листинге 4. Как ив предыдущем примере, это 16-разрядное приложение, которое выводит на экран дисплея часть строки, следующей за символом + (то есть String 2).
1   2   3   4   5   6   7   8   9   ...   41

Похожие:

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций для студентов заочной формы обучения направления 080201 (Информатика)
Предлагаемый конспект лекций представляет собой пособие по предмету “Теория информации”, который читается в Сумском государственном...

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций 2007 Экология. Конспект лекций. Для студентов специальностей...
Экология. Конспект лекций. Для студентов специальностей 080201 «Информатика», 090220 «Оборудование химических производств и предприятий...

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций по дисциплине информационные и телекоммуникационные...

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций по дисциплине “
«Компьютерная инженерия», специальности 091501 «Компьютерные сети и системы», 091502 «Системное программирование»

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций по курсу Выбранные вопросы информатики (часть 2)...
Точно так же как художник может выбирать для рисования различные инструменты, программист, создающий аплет Java, может выбирать различные...

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций по дисциплине “Статистика в машиностроении ” для студентов специальности
Конспект лекций предназначен для самостоятельного изучения студентами теоретической части курса “ Статистика в машиностроении ” (для...

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций по дисциплине “ основы защиты информации” для направления...
Министерство образования и науки украины восточноукраинский государственный университеТ

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций по курсу Начертательная геометрия
Конспект лекций по курсу начертательная геометрия (для студентов заочной формы обучения всех специальностей академии). Сост. Лусь...

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций и методические указания к выполнению контрольной работы к изучению курса
Конспект лекций и методические указания к выполнению контрольной работы по курсу “Проектирование специальных станочных и контрольных...

Конспект лекций по курсу Системное программирвание для специальности Информатика Лекция 1 iconКонспект лекций по курсу «Организация производства»
Конспект лекций по курсу «Организация производства» (для студентов и слушателей заочной формы обучения фпоизо специальностей 050100...

Вы можете разместить ссылку на наш сайт:
Школьные материалы


При копировании материала укажите ссылку © 2013
контакты
uchebilka.ru
Главная страница


<