Препроцессор. Многострочные макросы. — КиберПедия 

История развития хранилищ для нефти: Первые склады нефти появились в XVII веке. Они представляли собой землянные ямы-амбара глубиной 4…5 м...

Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰)...

Препроцессор. Многострочные макросы.

2017-05-16 671
Препроцессор. Многострочные макросы. 0.00 из 5.00 0 оценок
Заказать работу

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

Многострочные макросы в большинстве своем похожи на макросы в MASM и TASM: определение многострочного макроса в NASM выглядит похоже.

%macro prologue 1

push ebp

mov ebp,esp

sub esp,%1

%endmacro

Здесь определяется как макрос С-подобная функция prologue: теперь вы можете вызвать макрос следующим образом:

myfunc: prologue 12

что будет развернуто в три строки кода

myfunc: push ebp

mov ebp,esp

sub esp,12

Число 1 после имени макроса в строке %macro определяет число параметров, которые ожидает получить макрос prologue. Конструкция %1 внутри тела макроса ссылается на первый передаваемый параметр. В случае макросов, принимающих более одного параметра, ссылка на них осуществляется как %2,%3 и т.д.

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

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

%macro silly 2

%2: db %1

%endmacro

silly 'a', letter_a; letter_a: db 'a'

silly 'ab', string_ab; string_ab: db 'ab'

silly {13,10}, crlf; crlf: db 13,10

 

Команды работы со строками. Примеры.

Команды обработки строковых примитивов

В системе команд процессоров Intel предусмотрено пять групп команд для обработки массивов байтов, слов и двойных слов (таблица). Для адресации памяти в командах, приведенных в таблице, используется регистр ESI, EDI или сразу оба этих регистра.

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

Команда Название Описание
MOVSB,MOVSW, MOVSD Move String data, или Переместить строку данных Копирует целочисленные данные из одного участка памяти в другой
CMPSB, CMPSW, CMPSD Compare strings, или Сравнить строки Сравнивает значение двух участков памяти произвольной длины
SCASB,SCASW, SCASD Scan string, или Сканировать строку Сравнивает целочисленное значение с содержимым участка памяти
STOSB, STOSW, STOSD Store String data, или Сохранить строковые данные Записывает целочисленное значение в участок памяти произвольной длины
LODSB, LODSW, LODSD Load accumulator from string, или Загрузить строковые данные Загружает целочисленное значение из памяти в аккумулятор (регистр AL, АХ или ЕАХ)

Команды MOVSB, MOVSW и MOVSD

Пример: копирование массива двойных слов. Предположим, что нам нужно скопировать массив, состоящий из двадцати двойных слов из переменной source в переменную target. После копирования данных, в регистрах ESI и EDI будут находиться значения, соответствующие адресам 21-го элемента массивов source и target (если бы они существовали):

segment.data

source times 10 DD 0xFFFFFFFF

msglen equ $-source

target times 10 DD 0

segment.text

cld;Сбросим флаг DF и установим прямое направление

mov ecx,LENGTHOF source;Зададим значение счетчика

mov esi, source;Зададим адрес источника данных

mov edi, target; Зададим адрес получателя данных

rep movsd; Копируем 20 двойных слов

 

Команды CMPSB, CMPSW и CMPSD

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

С командами CMPSB, CMPSW и CMPSD может использоваться префикс повторения.

Пример, Предположим, что мы хотим сравнить значения двух двойных слов, расположенных в памяти, с помощью команды CMPSD. В приведенном ниже фрагменте кода можно заметить, что исходный операнд (переменная source) меньше операнда получателя данных (переменная target). Поэтому при выполнении команды JA не произойдет переход программы на метку L1, а будет выполнена следующая за ней команда JMР:

segment.data

source DD 1234h

target DD 5678h

segment.data

mov esi, source

mov edi, target

cmpsd; Сравним двойные слова

ja LI; Перейдем, если source > target

jmp L2; Перейдем, если source <= target

Если же мы хотим сравнить между собой несколько двойных слов, нам нужно сбросить флаг направления DF, загрузить в регистр ECX счетчик повторения и поместить перед командой CMPSD префикс повторения REPE:

mov esi, source

mov edi, target

cld;Направление сравнения восходящее

mov ecx, [LENGTHsource]; Загрузим счетчик повторения

repe cmpsd;Повторим сравнение, пока операнды равны

Команды SCASB, SCASW и SCASD

Эти команды сравнивают значение, находящееся в регистрах AL/AX/EAX с байтом, словом или двойным словом, адресуемым через регистр EDI. Данная группа команд обычно используется при поиске какого-либо значения в длинной строке или массиве. Если перед командой SCAS поместить префикс REPE (или REP), строка или массив будет сканироваться до тех пор, пока значение в регистре ECX не станет равным нулю, либо пока не будет найдено значение в строке или массиве, отличное от того, что находится в регистре AL/AX/EAX (т.е. пока не будет сброшен флаг нуля ZF). При использовании префикса REPNE, строка или массив будет сканироваться до тех пор, пока значение в регистре ECX не станет равным нулю, либо пока не будет найдено значение в строке или массиве, совпадающее с тем, что находится в регистре AL/AX/EAX (т.е. пока не будет установлен флаг нуля ZF).

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

SECTION.data

alpha db "ABCDEFGH",0

msglen equ $-alpha

SECTION.text

_main:

mov edi, alpha;Загрузим в EDI адрес строки alpha

mov al,'F'; Загрузим в AL ASCII-код символа "F"

mov ecx, msglen; Загрузим в ECX длину строки alpha

cld;Направление сравнения восходящее

repne scasb; Сканируем строку пока не найдем символ "F"

jnz quit; Если не нашли, завершим работу

dec edi;Здесь символ найден, в EDI его адрес

Команды STOSB, STOSW и STOSD

Эта группа команд позволяет сохранить содержимое регистра AL/AX/EAX в памяти, адресуемой через регистр EDI. При выполнении команды STOS содержимое регистра EDI изменяется в соответствии со значением флага направления DF и типом используемого в команде операнда. При использовании совместно с префиксом REP, с помощью команды STOS можно записать одно и то же значение во все элементы массива или строки. Например, в приведенном ниже фрагменте кода выполняется инициализация строки stringl значением 0FFh:

SECTION.data

count dd 2

stringl times 11 db 0

SECTION.text

_main:

mov al, 0x61; Записываемое значение

mov edi, stringl; Загрузим в EDI адрес строки

mov ecx, [count]; Загрузим в ECX длину строки

cld; Направление сравнения восходящее

rep stosb;Заполним строку содержимым AL

Команды LODSB, LODSW и LODSD

Эта группа команд позволяет загрузить в регистр AL/AX/EAX содержимое байта, слова или двойного слова памяти, адресуемого через регистр ESI. Префикс REP практически никогда не используется с командой LODS. Таким образом, эта команда используется для загрузки одного значения в аккумулятор. Например, команду LODSB можно использовать вместо двух приведенных ниже команд (если флаг направления DF не установлен):

mov al,[esi];Загрузим байт в AL

inc esi; Адрес следующего байта

Умножение элементов массива, В приведенной ниже программе каждый элемент массива двойных слов array умножается на постоянное значение. Для загрузки в регистр EAX текущего элемента массива используется команда LODSD, а для сохранения — STOSD.

extern _printf

GLOBAL _main

SECTION.data

array dd 1,2,3,4,5,6,7,8,9,10

multiplier db 2

fp db "%d, ", 0

SECTION.text

_main:

cld; Направление -- восходящее

mov esi, array; Загрузим адрес массива в регистры ESI и EDI

mov edi, esi

mov ecx, 10; Загрузим длину массива

L1:

lodsd;Загрузим текущий элемент массива

mul byte [multiplier];Умножим его на константу

stosd; Запишем EAX в текущий элемент

loop L1;массива (его адрес в [EDI])

mov esi, array

mov ecx, 10

cyc:

push ecx

lodsd

push eax

push fp

call _printf

add esp, 8

pop ecx

loop cyc

mov ax, 0

ret

 

20. Основные конструкции языка. AT&T-синтаксис.

 

 

Основы смешанного программирования


Поделиться с друзьями:

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

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

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

История развития пистолетов-пулеметов: Предпосылкой для возникновения пистолетов-пулеметов послужила давняя тенденция тяготения винтовок...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.023 с.