Программы на ассемблере

Изучение архитектуры персонального компьютера на примере микропроцессора фирмы Intel. Регистры общего назначения. Оперативная память; форматы данных и команд. Команд пересылки с различными способами адресации операндов. Структура программы на Ассемблере.

Рубрика Программирование, компьютеры и кибернетика
Вид курс лекций
Язык русский
Дата добавления 03.05.2014
Размер файла 506,4 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

ADD AX, BX

JMP Short M1

M2: ------/-------

M1: MOV AX, CX

----------/-----------

Замечание: команда, следующая за командой безусловной передачи управления, должна иметь метку, иначе к ней нельзя будет возвратиться.

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

PP Proc FAR

------/-------

PP endp

Процедура типа NEAR может быть вызвана только из того кодового сегмента, в котором содержится ее описание. Процедура типа FAR Может быть вызвана из любого сегмента. Поэтому тип вызова процедуры (дальность) определяется следующим образом: главная программа всегда имеет тип FAR, т.к. обращаются к ней из ОС или отладчика, если процедур несколько, и они содержатся в одном кодовом сегменте, то все остальные, кроме главной, имеют тип NEAR (пример 1). Если процедура описана в кодовом сегменте с другим именем, то у нее должен быть тип FARи должны быть использованы директивы внешних ссылок (пример 2).

Команда вызова процедуры или подпрограммы имеет вид: CALL <имя> ;

Адресация может быть использована как прямая, так и косвенная. При обращении к процедуре типа NEAR в стеке сохраняется адрес возврата, адрес команды, следующей за CALL, содержится в IP или EIP. При обращении к процедуре типа FAR в стеке сохраняется полный адрес возврата CS:EIP. Возврат из процедуры реализуется с помощью команды RET Она может иметь один из следующих видов:

RET [n] ; возврат из процедуры типа NEAR, и из процедуры типа FAR

RETN [n] ; возврат только из процедуры типа NEAR

RETF [n] ; возврат только из процедуры типа FAR.

Параметр n является необязательным, он определяет какое количество байтов удаляется из стека после возврата из процедуры.

Примеры прямого и косвенного перехода

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

Команды условной передачи управления

Команды условной передачи управления можно разделить на 3 группы:

• команды, используемые после команд сравнения

• команды, используемые после команд, отличных от команд сравнения, но реагирующие на значения флагов

JZ/JNZ

JC/JNC

JO/JNO

JS/JNS

JP/JNP

• команды, реагирующие на начальное значение регистра CX.

В общем виде команду условной передачи управления можно записать так: <имя> Jx <метка> ;<комментарий>

Здесь х - это одна, две, или три буквы определяют условия передачи управления. Метка, указанная в поле операнда, должна отстоять от команды не далее чем -128 ? +127 байт.

Примеры:

JE M1 ; передача управления на команду с меткой М1, если ZF=1

JNE M2 ; передача управления на команду с меткой М2, если ZF=0

JC M3 ; передача управления на команду с меткой М3, если CF=1

JNC M4 ; передача управления на команду с меткой М4, если CF=0

ADD AX, BX

JC M

Если в результате сложения CF =1, то управление передается на команду с меткой М, иначе - на команду, следующую за JC.

SUB AX, BX

JZ Met

Если результатом вычитания будет 0, то ZF = 1 и управление передается на команду с меткой Мet.

Часто команды передачи управления используются после команд сравнения <имя> CMP OP1, OP2 ; <комментарий>

По этой команде выполняется (OP1) - (OP2) и результат никуда не посылается, формируются только флаги. Команды условной передачи управления для беззнаковых и знаковых чисел можно представить в виде таблицы:

условие

Для беззнаковых чисел

Для знаковых чисел

>

JA

JG

=

JE

JE

<

JB

JL

> =

JAE

JGE

< =

JBE

JLE

< >

JNE

JNE

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

if AX = BX goto m следует заменить на:

if AX < > BX goto L

Goto m ; m - дальняя метка

---------------------

L: ----------------- ; L - близкая метка

На Ассемблере это будет так:

cmp AX, BX

jne L

Jmp m

----------------------

L: --------------------

С помощью команд jx и jmp можно реализовать цикл с предусловием 1) и с постусловием 2):

Команды для организации циклов

1) loop <метка>

2) loope < метка > ==loopz < метка >

3) Loopne < метка > ==loopnz < метка >

По команде в форме 1): (CX) = (CX) - 1 и если (CX) < > 0, управление передается на команду с указанной меткой.

По команде в форме 2): (CX) = (CX) - 1 и если (CX) < > 0 и одновременно ZF = 1, управление передается на команду с указанной меткой, т.е. цикл завершается, если или (CX) = 0 или ZF = 0 или (CX) = (ZF) = 0

По команде в форме 3): (CX) = (CX) - 1 и если (CX) < > 0 и одновременно ZF=0, управление передается на команду с указанной меткой, т.е. выход из цикла существляется, если или (CX) = 0 или ZF = 1 или одновременно (CX) = 0 и (ZF) = 1.

Следовательно, количество повторений цикла должно храниться в регистре CX.

Если CX нужно использовать внутри цикла, то содержание цикла должно начинаться командой сохранения в стеке содержимого регистра CX, а перед командой loop необходимо регистр CX восстановить. А для индексации, например, элементов массива внутри цикла можно использовать индексный регистр:

Пример использования команд условного перехода, сравнения и циклов.

Дана матрица целых байтовых величин, размером 4*5, необходимо подсчитать количество нулей и заменить их числом 0FFh. Под стек отведем 256 байтов, программу оформим как две последовательные процедуры: внешняя (FAR)- это связь с ОС, внутренняя (NEAR) - решение поставленной задачи.

1. title prim.asm

2. page , 132

3. ; сегмент стека

4. Sseg segment para stack `stack'

5. db 256 dup (?)

6. Sseg ends

7. ; сегмент данных

8. Dseg segment para public `data'

9. Dan db 0,2,5,0,,91 ; адрес первого элемента массива Dan

10. db 4,0,0,15,47 ;

11. db 24,15,0,9,55

12. db 1,7,12,0,4

13. Dseg ends

14. ; сегмент кодов

15. Cseg segment para public `code'

16. essume cs: cseg, ds:dseg, ss:sseg

17. start proc far

18. push DS ; для связи

19. push AX ; с ОС

20. mov BX, Dseg ; загрузка адреса сегмента данных

21. mov DS, BX ; в регистр DS

22. call main

23. ret

24. start endp

25. main proc near

26. mov BX, offset Dan

27. mov DL, 0 ; счетчик нулей в матрице

28. mov CX, 4 ; количество повторений внешнего цикла

29. nz1:push CX

30. mov SI, 0

31. mov CX, 5 ; количество повторений внутреннего цикла

32. nz2: push CX

33. cmp byte ptr [BX+SI], 0

34. jne mz

35. mov byte ptr [BX+SI], 0FFh

36. inc DL

37. mz: inc SI

38. pop CX

39. kz2: loop nz2

40. add BX, 5 ; переход к следующей строке матрицы

41. pop CX

42. kz1: loop nz1

43. add DL, `0' ; вывод на экран

44. mov AH, 6 ; количества нулей

45. int 21h

46. ret

47. main endp

48. Sseg ends

49. end start

Задача решена с помощью двух вложенных циклов, во внутреннем осуществляется просмотр элементов текущей строки (32-39), увеличение счетчика нулей и пересылка константы 0FFh в байт, содержащий ноль. Во внешнем цикле осуществляется переход к следующей строке очисткой регистра SI (строка 30 ) и увеличением регистра BX на количество элементов в строке (40).

Физически последняя команда программы (49) в качестве параметра указывает метку команды, с которой необходимо начинать выполнение программы.

Директива title задает заголовок каждой странице листинга, заголовок может содержать до 60 символов.

Директива page устанавливает количество строк на странице листинга - 1-й параметр (здесь он отсутствует, значит берется значение по умолчанию 57) и количество символов в каждой строке ( здесь 132, возможно от 60 до 132, по умолчанию - 80).

Page без параметров осуществляет перевод печати на новую страницу и увеличение на 1 номера страницы листинга. Эти директивы могут отсутствовать.

14. Массивы в Ассемблере

Массивы в языке Ассемблера описываются директивами определения данных, возможно с использование конструкции повторения DUP.

Например, x dw 30 dup ( ? )

Так можно описать массив чисел, состоящий из 30 элементов длиной в слово, но в этом описании не указано как нумеруются элементы массива, т.е. это может быть

x[0..29] и x[1..30] и x[k..29+k].

Если в задаче жестко не оговорена нумерация элементов, то в Ассемблере удобнее считать элементы от нуля, тогда адрес любого элемента будет записываться наиболее просто: адрес (x[i]) = x + (type x) * i

В общем виде, когда первый элемент имеет номер k , для одномерного массива будет: адрес (x[i]) = x + (type x) * (i - k)

Для двумерного массива - A[0..n-1, 0..m-1] адрес (i,j) - го элемента можно вычислить так: адрес (A[i,j]) = A + m * (type A) * i + (type A) *j

С учетом этих формул для записи адреса элемента массива можно использовать различные способы адресации. Для описанного выше массива слов, адрес его i-го элемента равен: x + 2*i = x + type (x) * i,

т.е. адрес состоит из двух частей: постоянной x и переменной 2 * i, зависящей от номера элемента массива. Логично использовать адресацию прямую с индексированием:

x - смещение, а 2*i - в регистре модификаторе SI или DI - x[SI]

Для двумерного массива, например:

A DD n DUP (m Dup (?) ) ; A[0..n-1, 0..m-1] получим:

адрес (A[i,j]) = A + m * 4 * i + 4 *j,

Т.е. имеем в адресе постоянную часть А и две переменных m * 4 * i и 4 *j , которые можно хранить в регистрах. Два модификатора есть в адресации по базе с индексированием, например: A[BX][DI].

Запишем фрагмент программы, в которой в регистр AL записывается количество строк матрицы X DB 10 dup ( 20 dup (?) ), в которых начальный элемент повторяется хотя бы один раз.

----------------------------------

mov AL, 0 ; количество искомых строк

mov CX, 10 ; количество повторение внешнего цикла

mov BX, 0 ; начало строки 20*i

m1: push CX

mov AH, X[BX] ; 1-й элемент строки в AH

mov CX, 19 ; количество повторений внутреннего цикла

mov DI, 0 ; номер элемента в строке ( j )

m2: inc DI ; j = j + 1

cmp AH, X[BX][DI] ; A[i,0] = A[i,j]

loopne m2 ; первый не повторился? Переход на m2

jne L ; не было в строке равных первому? Переход на L

inc AL ; первый повторился, увеличиваем счетчик строк

L: pop CX ; восстанавливаем CX для внешнего цикла

add BX, 20 ; в BX начало следующей строки

loop m1

15. Команды побитовой обработки данных

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

Логические команды: and, or, xor, not. Для всех логических команд, кроме not, операнды одновременно не могут находиться в памяти, значения флажков: OF = CF = 0, AF - не определен, SF, ZF, PF - определяются результатом команды.

Общий вид команды логического умножения:

<имя>and OP1, OP2 ; < комментарий>

По этой команде содержимое первого операнда (OP1) логически умножается на содержимое второго операнда (OP2), рез-т передается по адресу первого операнда. Результатом операции AND является "истина", если оба операнда имеют значение "истина", в остальных случаях результатом будет "ложь". Для компьютера "истина" - это 1, а "ложь" - это 0.

Пример: (AL) = 1011 0011, (DL) = 0000 1111,

and AL, DL ; (AL) = 0000 0011

Второй операнд называют маской. Основным назначением команды and является установка в ноль с помощью маски некоторых разрядов первого операнда. Нулевые разряды маски обнуляют соответствующие разряды первого операнда, а единичные оставляют соответствующие разряды первого операнда без изменения. Маску можно задавать непосредственно в команде и можно извлекать из регистра или памяти. Например:

1) and CX, 0FFh ; маской является константа

2) and AX, CX; маска содержится в регистре CX

3) and AX, TOT; маска в ОП по адресу (DS) + TOT

4) and CX, TOT[BX+SI]; маска в ОП по адресу (DS) + (BX) + (SI) + TOT

5) and TOT[BX+SI], CX; в ноль устанавливаются некоторые разряды ОП

6) and CL, 0Fh; в ноль устанавливаются старшие 4 разряда регистра CL

Команда логического сложения имеет вид:

<имя> or OP1,OP2 ; <комментарий>

Результатом выполнения этой команды является поразрядное логическое сложение содержимого первого и второго операндов, результат пересылается по адресу первого операнда. Результатом операции OR является "ложь", если оба операнда имеют значение "ложь", в остальных случаях результат равен "истина". Эта команда используется для установки в 1 заданных битов 1-го операнда с помощью маски OP2. Нулевые биты маски оставляют без изменения, а единичные устанавливают в единицу соответствующие биты первого операнда. Например:

(AL) = 1011 0011, (DL) = 0000 1111

or AL, DL ; (AL) = 1011 1111

Старшие биты регистра AL остались без изменения, а младшие все стали равными единицами. В команде могут использоваться различные операнды:

or CX, 00FFh ;

or TAM, AL ;

or TAM[BX][DX], CX

Если во всех битах результата будут 0, то ZF = 1.

Команда сложения по модулю 2 (исключающее или) имеет вид:

<имя> xor OP1, OP2 ; <комментарий>

Результат этой операции:

1 xor 1 = 0, 0 xor 0 = 0

1 xor 0 = 1 0 xor 1 = 1

Например:

(AL) = 1011 0011, маска = 000 01111

xor AL, 0Fh ; (AL) = 1011 1100

Команда отрицания:

<имя> not OP ; <комментарий>

Результом выполнения команды является инверсия значения операнда. Например,

(AL) = 0000 0000, not AL ; (AL) = 1111 1111

Значения флагов не изменяются.

Примеры.

1) xor AX, AX ; обнуляет регистр AX быстрее, чем команды mov и sub

2) Xor AX, BX; меняет местами значения AX и BX

xor BX, AX ; быстрее, чем команда

xor AX, BX; xchg AX, BX

3) Определить количество задолжников в группе из 25 студентов. Информация о студентах содержится в массиве байтов X DB 25 DUP (?), причем в младших 4 битах каждого байта содержатся оценки, т.е. 1 - сдал экзамен, 0 - "хвост". В DL сохраним количество задолжников.

-----------------------------

mov DL, 0

mov SI, 0 ; i = 0

mov CX, 25 ; количество повторений цикла

nz: mov AL, X[SI]

and AL, 0Fh ; обнуляем старшую часть байта

xor AL, 0Fh ;

jz m; ZF = 1, хвостов нет, передаем на повторение цикла

inc DL; увеличиваем количество задолжников

m: inc SI;переходим к следующему студенту

loop nz

add DL, "0"

mov AH, 6

int 21h

--------------------------

Команды сдвига

Формат команд арифметического и логического сдвига можно представить так:<имя> sXY OP1, OP2 ; <комментарий>

Здесь X - h или a, Y - l или r; OP1 - r или m, OP2 - r или CL

И для всех команд сдвига в CL используются только 5 младших разрядов, принимающих значения от 0 до 31. При сдвиге на один разряд:

Здесь знаковый бит распространяется на сдвигаемые разряды. Например,

(AL) = 11010101

sar AL, 1 ; (AL) = 11101010 и CF = 1

Сдвиги больше, чем на 1, эквивалентны соответствующим сдвигам на 1, выполненным последовательно.

Сдвиги повышенной точности для i186 и выше:

shrd OP1, OP2, OP3 ;

shld OP1, OP2, OP3 ;

Содержимое первого операнда (OP1) сдвигается на (OP3) разрядов также, как и в командах shr и shl но бит, вышедший за разрядную сетку, не обнуляется, а заполняется содержимым второго операнда, которым может быть только регистр.

Циклические сдвиги:

После выполнения команды циклического сдвига CF всегда равен последнему биту, вышедшему за пределы приемника

Циклические сдвиги с переносом содержимого флажка CF:

Для всех команд сдвига флаги ZF, SF, PF устанавливаются в соответствии с результатом. AF - не определен. OF - не определен при сдвигах на несколько разрядов, при сдвиге на 1 разряд в зависимости от команды: - для циклических команд повышенной точности и sal , shl флаг OF = 1, если после сдвига старший бит изменился; - после sar OF = 0; - после shr OF = значению старшего бита исходного числа.

16. Структуры в Ассемблере

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

<имя типа> struc

<описание поля>

------------------------

<описание поля>

<имя типа> ends

<имя типа> - это идентификатор типа структуры, struc и ends - директивы, причем <имя типа> в директиве ends также обязательно, так как такой директивой заканчивается сегмент. Для описания полей используются директивы определения DB, DW, DD и т.д. Имя, указанное в этих директивах, является именем поля, но имена полей не локализованы внутри структуры, поэтому они должны быть уникальными в рамках всей программы, кроме того, поля не могут быть структурами - не допускаются вложенные структуры.

Например,

TData struc ; data - идентификатор типа

y DW 2000

m DB ?

d DB 28

TData ends ;

y, m, d - имена полей. Значения, указанные в поле операндов директив DW и DB , называются значениями полей, принятыми по умолчанию, ? - означает, что значения по умолчанию нет.

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

Описание переменных типа структуры осуществляется с помощью директивы вида: имя переменной имя типа <начальные значения>

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

Начальным значение может быть: 1) ? 2) выражение 3) строка 4) пусто.

Например:

Идентификатор типа TData используется как директива для описания переменных так же, как используются стандартные директивы DB, DW и т.д. Если начальные значения не будут умещаться в отведенное ему при описании типа поле, то будет фиксироваться ошибка. Приоритетными являются начальные значения полей, указанные при описании переменных, т.е. если при описании переменной для поля указан ?, или какое-либо значение, то значения этих полей по умолчанию игнорируются.

Правила использования начальных значений и значений по умолчанию:

1) Если в поле переменной указан знак ?, то это поле не имеет начального значения, даже если это поле имеет значение по умолчанию (поле y переменной dt1);

2) Если в поле переменной указано выражение или строка, то значение этого выражения или сама строка становится начальным значением этого поля (поля m и d переменной dt1 и поле y переменной dt2);

3) Если начальное значение поля переменной "пусто" - ничего не указано при описании переменной, то в качестве начального устанавливается значение по умолчание - значение, указанное при описании типа, если же в этом поле при описании типа стоит знак ?, то данное поле не имеет никакого начального значения (поля m переменных dt2 и dt3).

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

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

dt4 TData <1980, ,> можно заменить на dt4 TData <1980>

dt5 TData <, , > нельзя заменить на dt5 TData < 5 >.

Если отсутствуют все начальные значения, опускаются все запятые, но угловые скобки сохраняются: dt6 TData < >

При описании переменных, каждая переменная описывается отдельной переменной, но можно описать массив структур, для этого в директиве описания переменной указывается несколько операндов и (или) конструкция повторения DUP. Например: dst TData <, 4, 1>, 25 DUP (<>)

Описан массив из 26 элементов типа Data, и первый элемент (первая структура) будет иметь начальные значения 2000, 4, 1, а все остальные 25 в качестве начальных будут иметь значения, принятые по умолчанию: 2000, ?, 28. Адрес первой структуры определяется именем dst, второй - (dst + 4), третьей - (dst + 8) и т.д

Работать с полями структуры можно так же, как с полями переменной комбинированного типа в языках высокого уровня: <имя переменной > . < имя поля>

Например, dt1.y, dt2.m, dt3.d

Ассемблер приписывает имени типа и имени переменной размер (тип), равный количеству байтов, занимаемых структурой

type TData = type dt1 = 4

И это можно использовать при программировании, например, так:

; выполнить побайтовую пересылку dt1 в dt2

mov CX, type TData ; количество повторений в CX

mov SI, 0 ; i = 0

m:mov AL, byte ptr dt1[si] ; побайтовая пересылка

mov byte ptr dt2[si], AL ; dt1 в dt2inc SI ; i = i+1

loop m ;

использование byte ptr обязательно, так как

Точка, указанная при обращении к полю, это оператор Ассемблера, который вычисляет адрес по формуле:

<адресное выражение> + <смещение поля в структуре>

Тип полученного адреса совпадает с типом поля, т.е.

type (dt1.m) = type m = byte

Адресное выражение может быть любой сложности, например:

1) mov AX, (dts+8).y

2) mov SI, 8

inc (dts[SI]).m ; Aисп = (dts + [SI]).m = (dts + 8).m

3) lea BX, dt1

mov [BX].d, 10 ; Aисп = [BX] + d = dt1.d

Замечания:

type (dts[SI]).m = type (dts[SI].m) = 1, но

type dts[SI].m = type dts = 4

Если при описании типа структуры в директиве, описывающей некоторое поле, содержится несколько операндов или конструкция повторения, то при описании переменной этого типа данное поле не может иметь начального значения и не может быть определено знаком ?, это поле должно быть пустым.

Одно исключение: если поле описано как строка, то оно может иметь начальным значением строку той же длины или меньшей, в последнем случае строка дополняется справа пробелами.

Например:

student struc

f DB 10 DUP (?) ; фамилия

i DB " ******* " ; имя

gr DW ? ; группа

oz DB 5, 5, 5 ; оценки

student ends

Описание переменных:

st1 student <"Petrov", > ; нельзя, т.к. поле f не строка

st2 student < , "Petr", 112, > ; можно, f - не имеет начального значения

st3 student < , "Aleksandra" > ; нельзя, в i 10 символов, а допустимо не больше 7.

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

Прямое обращение к полям структуры:

; prim1.asm

.model tiny

. code

org 100h ; обход 256 байтного префикса пр-го сегмента - PSP…

Start: mov AH, 9

mov DX, offset message

int 21h

;

lea DX, st1.s

int 21h

lea DX, st1.f

int 21h

lea DX, st1.i

int 21h

ret

;

message DB " hello",0dh,0ah,"$"

tst struc ; описание типа структуры

s DB "student","$"

f DB "Ivanov ","$"

i DB "Ivan ","$"

tst ends

st1 tst < > ; описание переменной типа tst

end start

Все сегментные регистры вначале выполнения программы содержат адрес блока PSP, который резервируется непосредственно перед EXE и COM файлами. Смещением для 1-ой команды программы является адрес 100h. Переход на первую выполняемую команду происходит с помощью директивы ORG 100h.

Обращение к полям структуры в цикле.

;Prim2.asm

.model tiny

.code

org 100h ; обход 256 байтного префикса программного сегмента

Start: mov AH, 9

mov DX, offset message

int 21h

mov SI, 0

mov CX, 3

m1:lea DX, st1[SI]

int 21h

add SI, 9

loop m1

ret

message DB "hello",0dh,0ah,"$"

tst struc; описание типа структуры

s DB "student","$"

f DB "Ivanov ","$"

i DB "Ivan ","$"

tst ends

st1 tst < >

end start

Prim3.asm - обращение к полям структур: цикл в цикле для работы с 2-мя записями

.model tiny

. code

org 100h ; обход 256 байтного префикса пр-го сегмента - PSP

Start: mov AH, 9

mov DX, offset message

int 21h

lea BX, st1 ; адрес первой записи в BX

mov CX, 2

m2:push CX

mov SI, 0

mov CX, 3

m1: push CX

lea DX, [BX] [SI] ; адресация по базе с индексированием

int 21h

add SI, 9 ; переход к следующему полю

pop CX

loop m1

add BX, type tst ;переход к следующей записи ; BX + количество байтов, занимаемой структурой типа tst

pop CX

loop m2

ret

message DB "hello",0dh,0ah,"$"

tst struc ; описание типа структуры

s DB ?

f DB ?

i DB ?

tst ends

st1 tst < "student $","Inanov $","Ivan, $" >

st2 tst < "student $","Petrov $","Petr, $" >

nd start

Результат работы программы:

hello

student Ivanov Ivan, student Petrov Petr

17. Записи в Ассемблере

Запись - это упакованные данные, которые занимают не отдельные, полные ячейки памяти (байты или слова), а части ячеек. Запись в Ассемблере занимает байт или слово (другие размеры ячеек для записи не допускаются), а поля записи - это группы последовательных битов. Поля должны быть прижаты друг к другу, между ними не должно быть пробелов. Размер поля в битах может быть любым, но в сумме размер всех полей не должен быть больше 16. Сумма размеров всех полей называется размером записи. Если размер записи меньше 8 или 16, то поля прижимаются к правой границе ячейки, оставшиеся левые биты равны нулю, но к записи не относятся и не рассматриваются. Поля имеют имена, но обращаться к ним по именам нельзя, так как наименьший адресуемый элемент памяти это байт. Для работы с записью необходимо описать вначале тип записи, а затем описать переменные этого типа.

Описание типа может располагаться в любом месте программы, но до описания переменных этого типа. Директива описания типа записи имеет вид:

<имя типа записи > record <поле> {, <поле>}

<поле> ::= <имя поля> : <размер> [= <выражение>]

Здесь <размер> и <выражение> - это константные выражения.

<размер> определяет размер поля в битах, <выражение> определяет значения поля по умолчанию. Знак ? Не допускается.

Например:

Год (Y), записанный двумя последними цифрами, удовлетворяет соотношению: 26 < Y max = 99 < 27 , а это значит, что для хранения года достаточно 7 битов.

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

Определенное директивой record имя типа (Trec, TData) используется далее как директива для описания переменных - записей такого типа.

имя записи имя типа записи <начальные значения>,

Угловые скобки здесь не метасимволы, а символы языка, внутри которых через запятую указываются начальные значения полей. Начальными значениями могут быть:

1) константное выражение, 2) знак ?, 3) пусто

В отличие от структуры, знак ? Определяет нулевое начальное значение, а "пусто", как и в структуре, определяет начальное значение равным значению по умолчанию. Например:

Так же, как и для структур:

Dat1 TData < 00, , > == Dat1 TData < 00 >

Dat2 TData < , , > == Dat2 TData < >

Одной директивой можно описать массив записей, используя несколько параметров в поле операндов или конструкцию повторения, например,

MDat TData 100 Dup ( < > )

Описано 100 записей с начальными значениями, равными принятым по умолчанию.

Со всей записью в целом можно работать как обычно с байтами или со словами, т.е. можно реализовать присваивание Rec1 = Rec2 :

mov AL, Rec2

mov Rec1, AL

Для работы с отдельными полями записи существуют специальные операторы width и mask. Оператор width имеет вид:

<имя поля записи>

width <имя записи или имя типа записи>

Значением оператора width является размер в битах поля или всей записи в зависимости от операнда.

Оператор mask имеет вид:

Mask <имя поля записи>

Mask <имя записи или имя типа записи>

Значением этого оператора является "маска" - это байт или слово, в зависимости от размера записи, содержащее единицы в тех разрядах, которые принадлежат полю или всей записи, указанных в качестве операнда, и нули в остальных, не используемых разрядах. Например:

mask A = 00111000b

mask B = 00000111b

mask Y = 1111111000000000b

mask Rec1 = mask TRec = 00111111b

Этот оператор используется для выделения полей записи, например, чтобы выявить всех родившихся 1-го числа, придется выделять поле D и сравнивать его значение с 1-ей.

mov AX, Dat1

and AX, mask D

cmp AX, 1

je yes

no:--------------------

------------------------ jmp m1

yes: ------------------------

При работе с записями, ассемблер имени любого поля приписывает в качестве значения число, на которое нужно сдвинуть вправо это поле, чтобы оно оказалось прижатым к правой границе ячейки, занимаемой записью. Так значением поля D для записи типа TData является ноль, для поля M - 5, для поля Y - 9. Значения имен полей используются в командах сдвига, например, определить родившихся в апреле можно так:

mov AX, Dat ; Ax = Y M D

and AX, mask M ; AX = 0 M 0

mov CL, M ; CL = 5

shr Ax, CL ; AX = 0 0 M

cmp AX, 4 ; M = 4 ?

je yes

no: ------------------

jmp m1

yes: --------------------------

18. Работа с подпрограммами в Ассемблере

Программа, оформленная как процедура, к которой обращение происходит из ОС, заканчивается командой возврата ret. Подпрограмма (ПП), как вспомогательный алгоритм, к которому возможно многократное обращение с помощью команды call, тоже оформляется как процедура с помощью директив proc и endp. Структуру процедуры можно оформить так:

<имя процедуры> proc <параметры>

<тело процедуры>

ret

<имя процедуры> endp

В Ассемблере один тип подпрограмм - процедура. Размещать ее можно в любом месте программы, но так, чтобы управление на нее не попадало случайно, а только по команде call. Поэтому описание ПП принято располагать в конце программного сегмента (после последней исполняемой команды), или вначале его - перед первой исполняемой командой.

Если программа содержит большое количество подпрограмм, то ПП размещают в отдельном кодовом сегменте - вариант структуры 3).

Замечания:

1) После имени в директивах proc и endp двоеточие не ставится, но имя считается меткой, адресом первой исполняемой команды процедуры.

2) Метки, описанные в ПП, не локализуются в ней, поэтому они должны быть уникальными в рамках всей программы.

3) Параметр в директиве начала процедуры один - FAR или NEAR.

Основная проблема при работе с ПП в Ассемблере - это передача параметров и возврат результатов в вызывающую программу. Существуют различные способы передачи параметров: 1) по значению, 2) по ссылке, 3) по возвращаемому значению, 4) по результату, 5) отложенным вычислением.

Параметры можно передавать: 1) через регистры, 2) в глобальных переменных, 3) через стек, 4) в потоке кода, 5) в блоке параметров.

Передача параметров через регистры - наиболее простой способ. Вызывающая программа записывает в некоторые регистры фактические параметры, подпрограмма использует их для выполнения вспомогательного алгоритма и записывает результат тоже в некоторый регистр. Основная программа использует этот результат. Этот метод используется, если параметров немного. Программист обязан следить за правильностью использования регистров в основной программе и подпрограммах. Примерами использования этого метода являются вызовы некоторых прерываний OC и BIOS.

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

Передача параметров через стек. Сразу перед обращением к процедуре фактические параметры (их значения или адреса) записываются в стек, а процедура их из стека извлекает. Именно этот способ используют языки высокого уровня.

Передача параметров в потоке кода заключается в том, что данные, передаваемые в ПП, располагаются сразу за командой обращения к ПП call. ПП, чтобы использовать эти данные, должна обратиться к ним по адресу, который записывается в стек автоматически как адрес возврата из ПП. Но ПП в этом случае должна перед командой возврата изменить адрес возврата на адрес байта, следующий за передаваемыми параметрами. Этот метод реализует передачу параметров медленнее, через регистры, глобальные переменные или стек, но примерно так же, как и метод передачи параметров в блоке параметров.

Блок параметров - это участок памяти, содержащий параметры и располагающийся обычно в сегменте данных. Процедура получает адрес начала этого блока при помощи любого из рассмотренных методов: в регистре, в переменной, в стеке, в коде или даже в другом блоке параметров. Примеры использования этого способа - многие функции OC и BIOS, например, поиск файла, использующий блок параметров DTA, или загрузка и исполнение программы, использующая блок параметров EPB.

Передача параметров по значению.

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

Например, нужно вычислить c = max (a,b) + max (7, a-1). Здесь все числа знаковые, размером в слово. Используем передачу параметров через регистры. Процедура получает параметры через регистры AX и BX, результат возвращает в регистре AX.

Процедура: AX = max (AX, BX)

max proc

cmp AX, BX

jge met1

mov AX, BX

met1: ret

max endp

Фрагмент вызывающей программы:

----------------------------------

; c = max (a,b) + max (7, a-1)

mov AX, a

mov BX, b

call max ; AX = max (a,b)

mov c, AX ; c = max (a,b)

mov BX, a

Dec BX

call max ;AX = max (7, a-1)

add c, AX

---------------------------------

Передача параметров по ссылке.

Оформим как процедуру вычисление x = x div 16

Процедура имеет один параметр-переменную х, которой в теле процедуры присваивается новое значение. Т.е. результат записывается в некоторую ячейку памяти. И чтобы обратиться к процедуре с различными параметрами, например, a и b, ей нужно передавать адреса памяти, где хранятся значения переменных a и b. Передавать адреса можно любым способом, в том числе и через регистры. Можно использовать различные регистры, но чаще используются BX, BP, SI, DI. Пусть адрес параметра передается через регистр BX, тогда фрагмент программы:

Фрагмент основной программы:

----------------------------

lea BX, a

call Proc_dv

lea BX, b

call Proc_dv

-------------------------------

Процедура:

Proc_dv proc

push CX

mov CL, 4

shr word ptr [BX], CL ; x = x div 16

pop CX

ret

Proc_dvendp

Сдвиг на 4 разряда вправо эквивалентен делению нацело на 16 и выполняется быстрее.

Здесь первая команда в процедуре сохраняет в стеке значение регистра CX, так как затем использует CL в команде сдвига и возможно этот регистр используется в основной программе. Т.к. регистров немного а и ПП и основная программа могут использовать одни и те же регистры, то при входе в ПП нужно сохранять в стеке значения регистров, которые будут использоваться в ПП, а перед выходом из нее восстанавливать значения этих регистров. Для поддержки этого, начиная с ix186, в систему команд введены команды сохранения в стеке и извлечения из него сразу всех регистров общего назначения pusa и popa, а, начиная с ix386, pushad popad.

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

Если параметров много, например, массив, адрес начала массива, как блока параметров, можно передать через регистр, даже если результат ПП не будет записываться по этому адресу.

Даны два массива целых положительных чисел без знака

X DB 100 dup (?)

Y DB 50 dup (?)

Вычислить DL = max (X[i]) + max (Y[i]), использовав процедуру max (A[i]), пересылая адрес массива через регистр BX, а результат сохраняя в AL.

-------------------------------; фрагмент программы

lea BX, X

mov CX, 100

call max ; AL = max (X[i])

mov DL, AL ; DL = max (X[i])

lea BX, Y

mov CX, 50

call max ; AL = max (Y[i])

ADD DL, AL

---------------------------------

Процедура max: AL = max (A[0..n-1]), BX - начальный адрес A, CX = n

Max proc

push CX

push BX

mov AL, 0 ; нач. значение max

met1: cmp [BX], AL

jle met2

mov AL, [BX]

met2: inc BX

loop met1

pop BX

pop CX

ret

max endp

Передача параметров через стек.

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

Если ПП имеет k параметров PP(a1, a2, ….ak) размером в слово и параметры сохраняются в стеке в последовательности слева направо, то команды, реализующие обращение к ПП, должны быть следующими:

; обращение к процедуре PP содержимое стека при входе в PP

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

Для доступа к последнему параметру можно использовать выражение [BP + 4], например, mov AX, [BP = 4] ; ak AX. После "водных действий" в ПП идут команды, реализующие вспомогательный алгоритм, а за ними должны быть команды, реализующие "выходные действия":

----------

pop BP; восстановить старое значение BP ret 2*k ; очистка стека от k параметров

PPendp; возврат в вызывающую программу

Необходимо помнить, что n в команде возврата ret n - это количество освобождаемых байтов в стеке, поэтому количество параметров должно быть умножено на длину параметра, т.е. программист сам должен подсчитать значение параметра в команде ret.

Команда ret вначале считывает значение адреса возврата (av), а затем удаляет из стека параметры. Очистку стека можно выполнять не в ПП, а после выхода из нее, в основной программе, сразу после команды call PP, например, командой add SP*2.

Каждый способ имеет свои достоинства и недостатки, если в ПП, то исполняемый код будет короче, если в основной программе, то можно вызвать ПП несколько раз с одними и теме же параметрами последовательными командами call.

Для удобства использования параметров, переданных через стек, внутри ПП можно использовать директиву equ, чтобы при каждом обращении к параметрам не вычислять точное смещение относительно BP, например, так:

Фрагмент программы:

-------------------------

push x

push y

push z

call PP

-------------------------

Структура подпрограммы:

PPproc near; процедура

push BP

mov BP, SP

pp_x equ [BP + 8]

pp_y equ [BP + 6]

pp_z equ [BP + 4]

---------------------

mov AX, pp_x; использование параметра x

----------------------

pop BP

ret 6

ppendp

Пример передачи параметров через стек.

Пусть процедура заполняет нулями массив A[0..n-1] , основная программа обращается к ней для обнуления массивов X[0..99] и Y[0..49]. Через стек в ПП передается имя массива и его размер, размер можно передавать по значению, а имя массива нужно передавать по ссылке, так как этот параметр является и входным и выходным.

; процедура zero_1

zero_1proc

push BP; входные

mov BP, SP; действия

push BX; сохранение значений

push CX; регистров

mov CX, [BP + 4]; CX = n считывание из стека

mov BX, [BP + 6]; BX = A параметров

m1:mov byte ptr [BX], 0; цикл обнуления

inc BX; массива

loop m1; A[0..n-1]

; восстановление регистров и выходные действия

pop CX

pop BX

pop BP

Ret 4

zero_1endp

Фрагмент основной программы:

X DB 100 dup (?)

Y DB 50 dup (?)

------------------------

lea AX, X; загрузка параметров:

push AX; адреса массива X

mov AX, 100; и его размера

push AX; в стек

call zero_1; обращение к ПП

lea AX, Y; загрузка параметров для массива Y

puah AX;

mov AX, 50;

push AX;

call zero_1; обращение к ПП

---------------------------

О передаче параметров в ПП.

1. Передача по значению:

mov AX, word ptr value

call PP

2. Передача по ссылке:

mov AX, offset value

call PP

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

4. Передача параметров по результату заключается в том, что ПП передается адрес только для записи по этому адресу результата работы ПП.

5. Передача параметров по имени макроопределения. Пример:

name macro parametr

mov AX, parametr

nameendm

Обращение к ПП может быть таким:

name value; обращение к макро

call PP; обращение к ПП

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

Использование локальных параметров.

Если локальных параметров немного, то их размещают в регистрах, но если регистров недостаточно, то возможны различные варианты: им можно отвести место в сегменте данных, но тогда большую часть времени эта область памяти не будет использоваться. Лучший способ - разместить локальные параметры в стеке на время работы ПП, а перед выходом из ПП их удалить. Для этого после входных действий в процедуре нужно уменьшить значение указателя на вершину стека SP на количество байтов, необходимых для хранения локальных величин и затем записывать их в стек и извлекать их оттуда можно с помощью выражений вида: [BP - n], где n определяет смещение локального параметра относительно значения BP.

Например, если предполагается, что ПП будет использовать 3 локальные параметра размером в слово, то стек графически можно представить так:

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

PPproc

push BP; сохранить старое значение BP

mov BP, SP; (SP) BP

sub SP, k1 ; отвести в стеке k1 байтов под

; локальные параметры

push AX; сохранить в стеке регистры,

--------------; используемые в ПП

<тело процедуры>

pop AX; восстановить регистры

-------------;

mov SP, BP; восстановить SP, т.е. освободить место в

; стеке от локальных параметров

pop BP ; восстановить BP равным до обращения к ПП

ret k2 ; очистка стека от фактических

; параметров и возврат в вызывающую программу

PPendp; конец ПП

Подсчет количества различных символов в заданной строке. Строка задана как массив символов. Начальный адрес ее передадим в ПП через регистр BX, длину строки через CX, а результат - через AX. Создадим процедуру, в которой выделяется 256 байтовый локальный массив L по количеству возможных символов. Каждому элементу этого массива будем присваивать единицу, если символ, цифровой код которого равен K, в заданной строке существует. Затем подсчитаем количество единиц в этом массиве. Вначале весь массив обнуляется. К первому элементу этого массива можно обратиться так: L1 = [BP - 256] к K - му Lk = [BP - 256 + k]

Работая со строками, эту задачу можно решить проще.

Count_s proc ;

; входные действия

push BP

mov BP, SP

sub SP, 256

push BX

push CX

push SI

; Обнуление локального массива

mov AX, CX ; сохранение длины исходной строки

mov CX, 256 ; возможное количество символов

mov SI, 0; индекс элемента массива

m1:mov byte ptr [BP - 256 + SI], 0 ;

inc SI

loop m1

; просмотр заданной строки и запись 1 в локальный массив

mov CX, AX ; длину строки в CX

mov AX, 0

m2:mov AL, [BX] ; код очередного символа в AL

mov SI, AX ; пересылаем его в SI

mov byte ptr [BP - 256 + SI], 1 ;пересылаем 1 в к -й элемент мас.

inc BX

loop m2;

; подсчет количества 1 в локальном массиве

mov AX, 0 ; результат будет в AX

mov CX, 256 ; количество повторений цикла

mov SI, 0 ; индекс массива в SI

m3:cmp byte ptr [BP - 256 + SI], 1

jne m4

inc AX

m4:inc SI

loop m3

; выходные действия

pop SI; восстановление

pop CX; регистров

pop BX ;

mov SP, BP ; освобождение стека от локальных параметров

pop BP; восстановить старое BP

ret

const_s endp

19. Рекурсия в Ассемблере

Основные трудности, возникающие при реализации рекурсии - это опасность "зацикливания " рекурсии и использование параметров. Зацикливания не произойдет, если в процедуре есть рекурсивная и не рекурсивная ветви и при выполнении некоторого условия вычислительный процесс пойдет по не рекурсивной ветви. Рекурсивное обращение ПП можно представить, если предположить, что при каждом обращении создается копия ПП и адреса возврата сохраняются в стеке. А структура стека позволяет извлекать их в последовательности, обратной поступлению.

Также решается и проблема с параметрами. В рекурсивную процедуру нельзя передавать параметры через ячейки памяти в сегменте данных, а если такая необходимость возникает, то при входе в ПП их необходимо сохранять в стеке, а при выходе из нее восстанавливать. Это значит, что лучше сразу параметры передавать через стек.

Пример рекурсивной функции. Вычисление n-го ряда Фибоначчи:

F(n) = 1, если n = 0 или n = 1 и

F(n) = F(n - 1) + F(n - 2), если n >1

Fib proc ; BX = F(n), AL = n

cmp AL, 1

ja m1 ; если n > 1, m1

; не рекурсивная ветвь

mov BX, 1 ; если n < 1 или n = 1 BX = F(n) = 1

ret

; рекурсивная ветвь

m1: push AX ;

dec AL ; AL = n - 1

call Fib ; BX = F(n-1)

push BX ; сохранить в стеке F(n-1)

dec AL ; AL = n - 2

call Fib ; BX = F(n - 2)

pop AX ; AX = F(n - 1)

add BX, AX ; BX = F(n - 2) + F(n - 1)

pop AX ; восстановить AX

ret

Fibendp

Работа со строками

Строка - это последовательность байт, слов или двойных слов. Все команды для работы со строками считают, что строка-источник находится по адресу DS:SI (DS:ESI), а строка приемник - по адресу ES:DI (ES:EDI).

Все команды работают с одним элементом строки: одним байтом, одним словом или одним двойным словом в зависимости от команды и /или от типа операндов.

Чтобы выполнить действие над всей строкой, слева от команды записывается специальный префикс. Префикс - это команда повторения операции. Префикс действует только на команды работы со строками, поставленный рядом с любой другой командой он никак не влияет на ее выполнение. Существуют следующие префиксы:

rep - повторять

repe - повторять пока равно

repz - повторять пока ноль

repne - повторять пока не равно

repnz - повторять пока не ноль

Префикс повторять:

1)rep <строковая команда> заставляет повторяться указанную команду n раз, где n - содержимое регистра CX (ECX). Если (CX) = 0, то команда не выполнится не разу.

2)repe <стр. команда> = repz <стр. rоманда>

Указанная строковая команда будет повторяться до тех пор пока флаг ZF = 1, но не более n раз, где n = (CX) или (ECX). Работу команда с этими префиксами можно на псевдокоде описать так:

m: if CX = 0 then goto m1;

CX = CX - 1;

< стр команда>ж

if ZF = 1 then goto m

m1: -------------------------

3) repne <стр команда> = repnz <стр команда>

Указанная строковая команда повторяется до тех пор, пока флаг ZF = 0, но не более n раз, где n - содержимое счетчика CX (ECX).

Семантика этих префиксов на псевдокоде:

m:if CX = 0 then goto m1;

CX = CX - 1;

<стр команда>ж

if ZF = 0 then goto m;

m1: ---------------------------

Префикс rep используется обычно с командами: movs, lods, stos, ins и outs

Префиксы repe, repz, repne, repnz с командами cmps и scas.

Команды копирования для строк.

1) movs op1, op2 ; источник op2 = DS:SI (DS:ESI), приемник op1 = ES:DI (ES:EDI)

2) movsb; байт данных из (DS:SI) пересылается в ES:DI

3) movsw; слово данных из (DS:SI) пересылается в ES:DI

4) movsd ; дв. слово данных из (DS:SI) пересылается в ES:DI

При использовании команды 1) - movs Ассемблер сам определяет по типу указанных в команде операндов сколько байтов данных нужно переслать - 1, 2 или 4. В этой команде можно изменить DS на другой регистр: ES, GS, FS, CS, SS, но регистр операнда приемника ES изменять нельзя. Чаще команды для строк используются без операндов.

После выполнения любой команды со строками содержимое регистров SI и DI автоматически изменяется в зависимости от значения флажка DF.

Если DF = 0 , то (SI/ESI) и (DI/EDI) увеличивается на 1 или 2 или 4,

Если DF = 1 , то (SI/ESI) и (DI/EDI) уменьшается на 1 или 2 или 4 в зависимости от операндов или кода команды.

Команды сравнения строк.

1) cmps op1, op2 ;

2) cmpsb; сравнение байтов

3) cmpsw; сравнение слов

4) cmpsd; для i386 и > сравнение двойных слов

По команде 1) в зависимости от типа операндов сравнивается содержимое байтов, слов или двойных слов, расположенных по адресам источника и приемника.

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

1) repe / repz и 2) repne / repnz

При использовании префиксов 1) сравнение идет до первого совпадения, 2) - до первого несовпадения. Команды:

1) scas op1 ; op1 - приемник

2) scasb; сравнивает (AL) с байтом из ES:DI / ES:EDI

3)scasw; сравнивает (AX) со словом из ES:DI / ES:EDI

4)scasd; для i386 и выше, сравнивает (EAX) с двойным

; словом из ES:DI / ES:EDI

При работе команды 1) количество сравниваемых байтов зависит от разрядности операнда.

Команды cmps и scas устанавливают флаги аналогично команде cmp.

Команды считывания из памяти строки, размером в байт, слово , или двойное слово и запись в регистр AL, или AX, или EAX.

1) lods op2; op2 - источник DS:SI или DS:EDI

2) lodsb; 1 байт из DS:SI или DS:EDI AL

3) lodsw; 2 байта из DS:SI или DS:EDI AX

4) lodsd; 4 байта из DS:SI или DS:EDI EAX

lods op2 работает как lodsb или lodsw или lodsd в зависимости от типа операнда и здесь DS можно заменить на ES, FS, GS, CS SS.

Команды записи строки из регистра AL, AX или EAX в память по адресу ES:DI или ES:EDI.

1) stos op1 ; op1 - приемник

2) stosb

3) stosw

4) stosd ; для i386 и выше

При использовании этих команд с префиксом rep строка длиной в (CX)/(ECX) ячеек заполнится числом, хранящимся в аккумуляторе AL, AX или EAX.

Считывание из порта ввода/вывода и запись в область памяти.

1) ins op1, DX

2) insb

3) insw

4) insd; i386 и >

Эти команды считывают из порта ввода, номер которого содержится в регистре DX, байт (insb), слово (insw) или двойное слово (insd) и пересылает их в память по адресу ES:DI или ES:EDI. Команда 1) принимает одну из форм 2), 3), 4) в зависимости от типа операнда. При использовании с префиксом rep она считывает из порта ввода/вывода блок данных (байтов, слов или двойных слов) длинной, определяемой регистром CX (ECX) и пересылает в память по адресу приемника.

Запись в порт ввода/вывода содержимого ячейки памяти, размером в байт, слово или двойное слово, находящегося по адресу DS:SI или DS:EDI:

1) outs DX, op2

2) outsb

3) outsw

4) outsd; i386 и >

Номер порта в командах работы с портами в/в должен находиться в регистре DX. В команде outs можно заменить DS на ES, FS, GS, CS SS. Используя префикс rep можно переслать в порт блок данных размером в (CX) или (ECX) байт, слов или двойных слов.

Команды управления флагами.

После выполнения команд со строками изменяется содержимое регистров - индексов в зависимости от значения флажка направления DF. Автоматически его значение не изменяется, его должен изменить программист с помощью команд:

cld; Clear Df, DF = 0


Подобные документы

  • Ассемблер как символический аналог машинного языка. Архитектура микропроцессора: организация памяти, способы адресации операндов, правила использования регистров. Текст программы. Этапы программирования на ассемблере, алгоритмы выполнения задач.

    контрольная работа [515,1 K], добавлен 20.01.2016

  • Внутренняя архитектура микропроцессора Intel 486. Формат данных и команд. Регистры общего назначения. Программная модель устройства FPU, регистр флагов. Разработка структуры и микропрограммы микропроцессора, управляющего автомата с жесткой логикой.

    курсовая работа [1,6 M], добавлен 27.05.2013

  • Изучение базовых команд ПК на базе МП i286 и их форматов. Изучение прямых способов адресации данных. Наработка практических навыков работы с командами. Разработка регистровой модели выполнения операций передачи данных. Программа реализации команд.

    контрольная работа [42,2 K], добавлен 12.03.2011

  • Функциональная схема микропроцессора Intel 8086 (i8086). Формирование физического адреса памяти, выборка команд из памяти и запись их в очередь команд. Система команд процессора. Суть защищенного режима, переход из защищенного режима в реальный режим.

    практическая работа [93,3 K], добавлен 24.03.2013

  • Типы команд, синтаксис ассемблера и код операции, по которому транслируется команда. Команды вычисления и непосредственной пересылки данных между регистрами. Поле для определения операции вычисления. Управление последовательностью выполнения программы.

    реферат [29,1 K], добавлен 13.11.2009

  • Краткий обзор процессоров фирмы intel. Основные характеристики i80286: режим реальной адресации, режим защиты, сопроцессор i80287, условия программирования i80287. Основные характеристики i80386: 32-битная архитектура, способы адресации.

    курсовая работа [29,9 K], добавлен 23.06.2007

  • Модель целочисленного MMX-расширения и особенности работы сопроцессора. Отображение ММХ-регистров на регистры стека сопроцессора. Система команд MMX: команды пересылки, сложения и вычитания, сравнения, логических операций, сдвига, упаковки и распаковки.

    презентация [240,3 K], добавлен 11.12.2013

  • Изучение элементов структуры микропроцессора i80386 и алгоритмов выполнения множества команд. Разработка проекта структуры АЛУ и структуры микро-ЭВМ на базе гипотетического процессора. Описание и создание программы эмуляции по выполнению заданных команд.

    курсовая работа [484,4 K], добавлен 07.09.2012

  • Характеристика регистров памяти как устройств временного хранения данных. Различия между прерываниями и исключениями команд, их обработка. Вычисление производительности ЭВМ. Программа с использованием отложенного запуска команд. Виды компьютерных сетей.

    контрольная работа [24,9 K], добавлен 09.11.2010

  • Архитектура микроконтроллеров семейства Mega. Организация памяти. Способы адресации памяти данных. Энергонезависимая память данных. Таблица векторов прерываний. Счетчик команд и выполнение программы. Абсолютный вызов подпрограммы. Сторожевой таймер.

    дипломная работа [213,9 K], добавлен 02.04.2009

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.