Материал: 775

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

а в другом модуле содержится:

. . .

public FarProc FarProc proc far

. . .

ret FarProc endp

. . .

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

Как уже описывалось, ассемблер обычно (по умолчанию) не различает верхний и нижний регистры букв, поэтому общедоступные метки преобразуются в верхний регистр. Это означает, что в обычном состоянии внешние метки будут интерпретироваться в верхнем регистре. Если требуется, чтобы во внешних метках регистры букв различались, используйте параметры командной строки /ml или /mx.

Для каждого идентификатора в директиве extrn можно также задать язык: C, PASCAL, BASIC, FORTRAN, PROLOG или notlanguage (в

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

extrn C myprog:near

то идентификатор myprog в исходном файле преобразуется во внешний идентификатор _myprog. Использование спецификатора языка в директиве extrn временно отменяет текущее задание языка.

4.4. Директива global

Зачем для обеспечения совместного использования меток разными модулями нужны две директивы – public и extrn? Единственная причина заключается в необходимости обеспечить совместимость с более ранними ассемблерами. Директива global делает все то, что делают директивы public и extrn.

Если с помощью данной директивы вы объявите метку глобальной, а затем определите ее (с помощью директив db, dw, proc, label или других подобных директив), то метка станет доступной другим модулям аналогично тому, как если бы вы вместо директивы global использовали директиву public. Если же вы, с другой стороны, объявляете метку

21

глобально, а затем используете ее без определения, то эта метка интерпретируется как внешняя метка, аналогично тому, как если бы вы объявили ее с помощью директивы extrn. Рассмотрим, например, следующий фрагмент:

...

 

.data

 

global

FinalCount:word,PromptString:byte

FinalCount

dw ?

...

 

.code

 

global

DoReport:near,TallyUp:far

TallyUp

proc far

...

 

call DoReport

...

Здесь метки FinalCount и TallyUp определены, поэтому они становятся общедоступными (для других модулей) метками (public). Метки PromptString и DoReport не определены, поэтому подразумевается, что это внешние (external) метки, которые объявлены общедоступными в других модулях.

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

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

Для каждого идентификатора в директиве global, как и для директив public или extrn, можно также задать язык: C, FORTRAN, PASCAL, BASIC, PROLOG и NOLANGUAGE (нет языка). Это приводит к тому, что к имени идентификатора до того, как одно в объектном файле станет общедоступным, автоматически применяются правила конкретного языка. Например, если вы описали

global C myprog

22

то идентификатор myprog в исходном файле станет общедоступным, как _myprog, поскольку по соглашениям языка Си перед именами идентификаторов следует символ подчеркивания. Использование идентификатора языка в директиве public временно отменяет текущее задание языка (используемое по умолчанию или заданное в директиве

.model).

4.5. Логические операции

Инструкции and (и), or (или), xor (исключающее или) и not (не) очень полезны при работе с отдельными битами слова или байта, а также для выполнения операций булевой алгебры.

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

and ax,dx

выполняет логическую операцию and с битом 0 регистра ax и битом 0 регистра dx, затем ту же операцию с битами 1, 2 и т.д. до бита 15.

 

 

 

 

Таблица 4.1

Выполнение процессором логических инструкций and, or и xor

 

 

 

a or b

 

Исходный

Исходный

a and b

a xor b

бит

бит

 

 

 

a

b

 

0

 

0

0

0

0

0

1

0

1

1

1

0

0

1

1

1

1

1

1

0

Инструкция and устанавливает каждый бит результата (операндаприемника) в значение 1 только в том случае, если оба соответствующих бита операнда-источника равны 1. Инструкция and позволяет выделить отдельный бит или принудительно установить его в значение 0.

Инструкция or устанавливает каждый бит операнда-приемника в значение 1, если любой из соответствующих битов операнда-источника равен 1. Инструкция or позволяет принудительно установить отдельные биты (или бит) в значение 1.

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

mov al,01010101b xor al,11110000b

23

устанавливают регистр al в значение 10100101b или A5h. Когда для регистра al выполняется операция xor со значением 11110000b (0F0h), биты со значением 1 в 0F0h переключают значения соответствующих битов в регистре al, а биты со значением 0 оставляют соответствующие биты al неизмененными.

Инструкция xor дает удобный способ обнуления содержимого регистра. Например:

xor ax,ax

Инструкция not изменяет значение каждого бита операнда на противоположное (как если бы над исходным операндом была выполнена операция xor со значением offh). Например:

mov

bl,10110001b

not

bl

; переключить bl в 01001110b

xor

bl,0ffh

; переключить bl обратно в значение 10110001b

4.6. Циклы и переходы

До этого момента мы рассматривали выполнение процессором 8086 инструкций в строгой последовательности. При этом каждая следующая инструкция выполнялась сразу после инструкции по предыдущему адресу. Рассматривая программу

. . .

mov ax,[BaseCount] push ax

. . .

мы могли быть уверены, что после инструкции mov будет выполнена инструкция push.

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

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

4.7. Безусловные переходы

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

. . .

mov ax,1

jmp AddTwoToax AddOneToAx:

24

inc ax

jmp axisSet AddTwoToax:

add ax, 2 axisSet:

. . .

регистр ax будет содержать значение 3, а инструкции add и jmp, следующие за меткой AddOneToax, никогда выполнены не будут. Здесь инструкция

jmp AddTwoToax

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

add ax,2

Иногда совместно с инструкцией jmp используется операция short. Для указания на целевую метку инструкция jmp обычно использует 16-битовое смещение. Операция short указывает, что нужно 8-битовое смещение, и позволяет сэкономить в инструкции jmp один байт. Например, фрагмент программы, который на два байта короче:

. . .

mov ax,1

jmp short AddTwoToax AddOneToAx:

inc ax

jmp short axisSet AddTwoToax:

inc ax axisSet:

. . .

Недостаток: короткие переходы могут осуществлять передачу управления на метки, отстоящие от инструкции jmp не далее, чем на 128 байтов, поэтому в некоторых случаях ассемблер может сообщать, что метка недостижима с помощью короткого перехода. К тому же операцию short имеет смысл использовать для ссылок вперед, поскольку для переходов назад (на предшествующие метки) ассемблер автоматически использует короткие переходы, если на метку можно перейти с помощью короткого перехода, и длинные − в противном случае.

Инструкцию jmp можно использовать для перехода в другой сегмент кода, загружая в одной инструкции и регистр cs, и регистр ip. Например, в программе

. . .

25

Источник: https://studfile.net/preview/16406832/