FileName db “Введите имя файла:”, 13, 10, 0



Раз последний байт этой строки ноль, то это – sz-строка.

 

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

 

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

Povtor:

Команда1

Команда2

Команда3

КомандаN

JMP Povtor

Здесь Povtor – метка возврата, JMP Povtor – команда безусловного перехода на метку Povtor.

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

Как «посетить» каждый символ строки? С помощью «бегущего указателя». Им может быть любой регистр общего назначения (eax, ebx, ecx, edx, esi, edi). Например, возьмем ecx. До входа в цикл присвоим ему адрес начала строки, то есть ее первого символа:

Mov ecx, offset Filename

Здесь offset – директива взятия адреса метки.  

Будем в каждом повторе тела цикла увеличивать есх на 1, чтобы он «сдвигался» на очередной символ. Это команда инкремента inc ecx. Но эту «сдвижку» надо прекратить, когда регистр-указатель есх укажет на ноль-байт, это конец строки. Чтобы узнать , попали ли мы на ноль-байт, надо сначала выполнить сравнение

Cmp byte ptr [ecx], 0

Здесь [ecx] – это байт, на который указывает есх (скобки [] означают разадресацию). Слова byte ptr приказывают процессору считать число в есх указателем на одиночный байт (а не, предположим, слово или двойное слово).

Если это сравнение (а оно по сути есть вычитание) покажет равенство этих величин, то команда JE метка_выхода отреагирует на факт выполнения этого условия и «выбросит» исполнение на метку_выхода, котрую надо разместить где-нибудь за пределами цикла.

Ну, и что у нас получается на данный момент, если всю эту премудрость свести вместе? А вот что.

Mov ecx, offset Filename

povtor:

Cmp byte ptr [ecx], 0

JE metka_vyhoda

Inc ecx

JMP povtor

metka_vyhoda:

Чтобы сосчитать число повторов этого цикла (а это и есть количество символов в строке, то есть ее длина), нужно использовать какой-нибудь счётчик, ну, к примеру, регистр edx. До входа в цикл его надо обнулить, а перед каждым переходом на следующий символ его надо увеличивать на 1. На выходе из цикла этот счетчик и будет содержать длину строки.

Mov edx, 0 ; сброс счетчика

Mov ecx, offset Filename

povtor:

Cmp byte ptr [ecx], 0

JE metka_vyhoda

Inc ecx ; на след символ

Inc edx ; счетчику +1

JMP povtor

metka_vyhoda:

; тут в edx – длина строки

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

Вопросы для самопроверки

а) Как организовать бесконечный цикл?

б) Как производиться проверка на ноль-байт в строках?

в) Чем отличается работа команды безусловного перехода JMP от команды «перехода по равенству» JE?

г) Как установить указатель на начало строки?

д) Как синтаксически показывается операция разадресации указателя?

 

 


 

БИТЫ

Терминология

«Установить» бит – это значит, что после этого действия бит имеет значение 1, какое бы значение он ни имел до операции, хоть 0, хоть 1.

«Сбросить» бит – это значит, что после этого действия бит имеет значение 0, какое бы значение он ни имел до операции, хоть 0, хоть 1.

«Инвертировать» бит – это значит, что после этого действия бит имеет значение, обратное тому, что он имел до операции. Был 0, стал 1. Был 1, стал 0.

Имена частей регистров общего назначения

Регистры eax, ebx, ecx и edx имеют отдельные имена для своих частей:

Обратите внимание, что старшие половинки регистров (биты 16-31) никаких отдельных имен не имеют. Также нет отдельных имен у однобайтовых половин регистров  bp, sp, si, di.

Из схемы также следует, что старший бит в АН имеет смещение 15, а его младший бит имеет смещение 7.

Логические команды

В ассемблере есть логические команды AND, OR, XOR, NOT. Еще есть команда TEST, которая выполняется как AND, но с особенностями, о которых речь ниже.

В ассемблере эти команды обрабатывают пары битов и порождают как результат тоже бит. Биты трактуются: 0 – неправда, ложь; 1 – правда, истина.

Ассемблерный нюанс состоит в том, что один бит как операнд логической команде сообщить никак не возможно, синтаксис допускает операнды размерами, стандартными для процессора: байт, слово (word), двойное слово (dword). В этом случае логические команды AND, TEST, OR, XOR имеют всегда два операнда одинаковой разрядности (byte-byte, word-word, dword-dword). Второй операнд логической команды называют маской.

Биты этих операндов обрабатываются попарно (нулевой с нулевым, первый с первым, второй со вторым и т.д. до последней пары в разрядной сетке.).

Правила вычисления бита-результата («таблицы истинности») такие:

 

Первый бит 0 0 1 1
Второй бит (маска) 0 1 0 1
Результат AND (и TEST) 0 0 0 1
Результат OR 0 1 1 1
Результат XOR 0 1 1 0

 

Из битов-результатов составляется значение-результат, и по этому результату устанавливаются флаги. Это делает возможность «отловить» нулевое значение, отрицательное, короче, любое, которое детектируется флагами. И последнее действие при выполнении – команды AND, OR, XOR записывают значение в свой первый операнд; а TEST это значение никуда не пишет, у этой команды (по алгоритму это та же AND) дело заканчивается установкой флагов.

Особняком стоит команда NOT, у неё всегда один операнд (byte, word, dword). И работа этой команды проста – она просто меняет каждый бит своего операнда на противоположный и это значение опять пишет в этот свой единственный операнд.

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

Проблема 1. Как сбросить бит.

Решение такое:

ГарантированныйНоль = ПроизвольныйБит AND 0;

Итак, правило сброса словесно выражается так: чтобы сбросить бит, надо выполнить для него AND с маской ноль

 

Проблема 2. Как установить бит.

Решение:

ГарантированнаяЕдиница = ПроизвольныйБит OR 1;

Итак, правило установки бита словесно выражается так: чтобы установить бит, надо выполнить для него OR с маской 1.

 

Проблема 3. Как инвертировать бит.

Решение:

ИнвертированныйБит = ИсходныйБит XOR 1;

 

Написать на бумаге команду, которая установит старший бит регистра AН.

OR ah, 10000000B

Здесь В означает запись число в битовом формате.

 

Написать на бумаге команду, которая сбросит средние 4 бита регистра AL.

AND AL, 00111100B

 

 

Написать на бумаге команду, которая инвертирует три старших бита в регистре EAX.

XOR EAX, 0E0000000h

Здесь старшая тетрада Е (побитовое 1110) в маске обеспечивает инверсию именно трёх старших разрядов ЕАХ.


 

Вопросы для самопроверки

а) Дать определения понятиям «сброс», «установка» и «инвертирование» битов.

б) Что такое «таблица истинности» логических команд в ассемблере?

в) Как технически выполнить сброс, установку и инверсию отдельных битов?

г) Какое смещение имеет младший бит старшей части в ESI?

д) Чему будет рамен EAX после XOR EAX,EAX?

 


 

ПРОЦЕДУРЫ

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

 

Сначала о сложении.

Оно выполняется командой add операнд1, операнд2. Эта команда складывает операнд1 с операндом2 и записывает результат в операнд1:

Операнд1 = операнд1 + операнд2.

Операндами могут быть регистры, переменные и константы. Из этой логики вытекают ограничения: 1) операнды не могут одновременно находиться в памяти, т.к. компьютер может в каждый момент времени читать из памяти только одно число; 2)т.к. первый операнд перезаписывается, он не может быть константой. Значит, если нам в памяти даны переменные A и В, то сложить их придется так:

Mov EAX, A


Дата добавления: 2018-10-26; просмотров: 259; Мы поможем в написании вашей работы!

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






Мы поможем в написании ваших работ!