Автор: xrnd | Рубрика: Учебный курс | 13-12-2010
Работать с отдельными битами операндов можно, используя логические операции и сдвиги. Однако, кроме них в системе команд x86 существуют специальные команды для работы с битами: это команды сканирования битов и команды проверки (и модификации) битов. Впервые они появились в процессоре i386. Так что сейчас вы вряд ли найдёте процессор, в котором их нет.
Команды сканирования битов
Сканирование битов выполняется командами BSF и BSR. Эти команды очень похожи. У них 2 операнда. Первый операнд должен быть 16-битным регистром, в него записывается результат. Второй операнд может быть 16-битным регистром или словом в памяти — это обрабатываемое значение.
Команда BSF просматривает биты второго операнда от младшего к старшему и помещает индекс первого единичного бита в регистр. Биты нумеруются, начиная с нуля. Если единичный бит найден, то флаг нуля сбрасывается (ZF=0). Если все биты нулевые, то флаг нуля устанавливается (ZF=1), а значение первого операнда будет неопределённым (на разных процессорах может быть по-разному). Например, мой процессор (Athlon XP) в этом случае не изменяет значение в регистре. Пример кода:
mov ax,01011000b ;AX=58h
bsf bx,ax ;BX=3, ZF=0
xor ax,ax ;AX=0
bsf bx,ax ;BX=?, ZF=1 |
mov ax,01011000b ;AX=58h
bsf bx,ax ;BX=3, ZF=0
xor ax,ax ;AX=0
bsf bx,ax ;BX=?, ZF=1
Читать полностью »
Автор: xrnd | Рубрика: Книги | 22-10-2010
Полное название: «Intel Architecture Software Developer’s Manual. Volume 2: Instruction Set Reference»
Язык: английский.
Эта книга — официальная документация компании Intel по системе команд архитектуры x86. В ней содержится подробное описание всех целочисленных команд 32-битного ассемблера, а также команд некоторых расширений процессора. Кроме того рассматривается формат машинных команд и их коды. Это лучший справочник, которой должен быть всегда под рукой. Рекомендую всем, кто программирует на ассемблере.
Книга на английском языке и, насколько я знаю, на русский она не переводилась. Но чтобы пользоваться ею, серьезного знания английского не требуется. Описание каждой команды включает в себя алгоритм её работы на псевдоязыке, который понятен без перевода.
Скачать книгу
Автор: xrnd | Рубрика: Учебный курс | 17-10-2010
До этой части учебного курса все переменные в наших программах были только глобальными — они создавались и инициализировались при запуске программы и к ним можно было обратиться из любой её части.
Локальные переменные используются для хранения промежуточных результатов во время выполнения процедуры. В отличие от глобальных, эти переменные являются временными и создаются при запуске процедуры. Для локальных переменных существует понятие области видимости — так называется область программы, в которой доступна переменная. Обычно в ассемблере область видимости ограничена процедурой, создавшей локальную переменную. Хотя возможны и более сложные варианты 😉
Создание локальных переменных
Чтобы создать локальные переменные в процедуре, необходимо выделить для них память. Эта память выделяется в стеке. Сделать это очень просто — достаточно вычесть из регистра SP значение, равное суммарному размеру всех локальных переменных в процедуре. Так как ширина стека равна 16 бит, то это значение должно быть кратно 2 байтам. При выходе из процедуры нужно восстановить указатель стека. Обычно это выполняется командой mov sp,bp (В bp сохраняется значение sp при входе в процедуру, как в случае с параметрами, передаваемыми через стек). Код процедуры с локальными переменными будет выглядеть следующим образом:
;Процедура с локальными переменными
myproc:
push bp ;Сохранение BP
mov bp,sp ;Копирование указателя стека в BP
sub sp,locals_size ;Выделение памяти для локальных переменных
...
mov sp,bp ;Восстановление указателя стека
pop bp ;Восстановление BP
ret ;Возврат из процедуры |
;Процедура с локальными переменными
myproc:
push bp ;Сохранение BP
mov bp,sp ;Копирование указателя стека в BP
sub sp,locals_size ;Выделение памяти для локальных переменных
...
mov sp,bp ;Восстановление указателя стека
pop bp ;Восстановление BP
ret ;Возврат из процедуры
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 10-09-2010
В предыдущей части учебного курса мы использовали флаг CF, чтобы вернуть из процедуры информацию об ошибке. Чтобы у вас сложилась полная картина, я решил в этой части подробнее рассказать о командах управления флагами.
Как вы, наверно, помните флаги изменяются в результате выполнения арифметических и логических команд, а также команд сдвига. Регистр флагов можно сохранить в стек с помощью команды PUSHF и восстановить из стека с помощью команды POPF. Кроме того, в процессоре существуют специальные команды, которые позволяют явно установить или сбросить флаги CF, DF и IF. Это очень простые команды: у них нет операндов и результатом является только изменение значения соответствующего флага.
Флаг переноса CF
Команда CLC сбрасывает флаг CF.
Команда STC устанавливает флаг CF в единицу.
Команда CMC инвертирует значение флага CF.
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 08-07-2010
В этой части учебного курса мы рассмотрим основы создания процедур. Процедура представляет собой код, который может выполняться многократно и к которому можно обращаться из разных частей программы. Обычно процедуры предназначены для выполнения каких-то отдельных, законченных действий программы и поэтому их иногда называют подпрограммами. В других языках программирования процедуры могут называться функциями или методами, но по сути это всё одно и то же 🙂
Команды CALL и RET
Для работы с процедурами предназначены команды CALL и RET. С помощью команды CALL выполняется вызов процедуры. Эта команда работает почти также, как команда безусловного перехода (JMP), но с одним отличием — одновременно в стек сохраняется текущее значение регистра IP. Это позволяет потом вернуться к тому месту в коде, откуда была вызвана процедура. В качестве операнда указывается адрес перехода, который может быть непосредственным значением (меткой), 16-разрядным регистром (кроме сегментных) или ячейкой памяти, содержащей адрес.
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 31-05-2010
Стеком называется структура данных, организованная по принципу LIFO («Last In — First Out» или «последним пришёл — первым ушёл»). Стек является неотъемлемой частью архитектуры процессора и поддерживается на аппаратном уровне: в процессоре есть специальные регистры (SS, BP, SP) и команды для работы со стеком.
Обычно стек используется для сохранения адресов возврата и передачи аргументов при вызове процедур (о процедурах в следующей части), также в нём выделяется память для локальных переменных. Кроме того, в стеке можно временно сохранять значения регистров.
Схема организации стека в процессоре 8086 показана на рисунке:
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 13-05-2010
Циклический сдвиг отличается от линейного тем, что выдвигаемые с одного конца биты вдвигаются с другой стороны, то есть движутся по кольцу. В процессора x86 существует 2 вида циклического сдвига: простой и через флаг переноса (CF). У всех команд, рассматриваемых в этой части учебного курса, по 2 операнда, таких же, как у команд линейного сдвига. Первый операнд — сдвигаемое значение и место для записи результата. Второй операнд — счётчик сдвигов, который может находится в регистре CL или указываться непосредственно.
Простой циклический сдвиг
Циклический сдвиг вправо выполняется командой ROR, а влево — командой ROL. Схема работы этих команд представлена на рисунке (на примере 8-битного операнда):
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 07-05-2010
Сдвиги — это особые операции процессора, которые позволяют реализовать различные преобразования данных, работать с отдельными битами, а также быстро выполнять умножение и деление чисел на степень 2. В этой части мы рассмотрим операции линейного сдвига, а в следующей будут циклические.
Логический сдвиг вправо
Логический сдвиг всегда выполняется без учёта знакового бита. Для логического сдвига вправо предназначена команда SHR. У этой команды два операнда. Первый операнд представляет собой сдвигаемое значение и на его место записывается результат операции. Второй операнд указывает, на сколько бит нужно осуществить сдвиг. Этим операндом может быть либо непосредственное значение, либо регистр CL. Схема выполнения операции показана на рисунке:
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 05-05-2010
Кроме команды LOOP и команд условных переходов существуют ещё две команды, позволяющие организовывать циклы. Это команды LOOPZ (или её синоним LOOPE) и LOOPNZ (синоним — LOOPNE). Действие этих команд очень напоминает LOOP, за исключением того, что дополнительно анализируется флаг нуля ZF.
Переход к метке цикла осуществляется в том случае, если после декремента содержимое CX не равно 0 и выполняется условие: ZF=1 (для команды LOOPZ/LOOPE) или ZF=0 (LOOPNZ/LOOPNE).
Эти команды удобно использовать в алгоритмах, где цикл должен завершаться в двух случаях:
- выполнено требуемое количество итераций;
- выполнено некоторое условие досрочного завершения цикла.
Читать полностью »
Автор: xrnd | Рубрика: Учебный курс | 27-04-2010
Наконец-то мы добрались и до переходов! В этой части научимся программировать условные и безусловные переходы. Вообще, трудно представить себе программу без проверки условий и переходов. С их помощью в программе реализуются различные управляющие конструкции, ветвления и даже циклы.
Безусловные переходы
Безусловный переход — это переход, который выполняется всегда. Безусловный переход осуществляется с помощью команды JMP. У этой команды один операнд, который может быть непосредственным адресом (меткой), регистром или ячейкой памяти, содержащей адрес. Существуют также «дальние» переходы — между сегментами, однако здесь мы их рассматривать не будем. Примеры безусловных переходов:
jmp metka ;Переход на метку
jmp bx ;Переход по адресу в BX
jmp word[bx] ;Переход по адресу, содержащемуся в памяти по адресу в BX |
jmp metka ;Переход на метку
jmp bx ;Переход по адресу в BX
jmp word[bx] ;Переход по адресу, содержащемуся в памяти по адресу в BX
Читать полностью »