Простой пример обработки сообщения от мыши.
Для обработки сообщения от мыши в DOS`е нам потребуется прерывание 33h.
int 33h Вход: ax =0000h Выход: ax =0000h, если мышь или драйвер мыши не установлены. ax =0ffffh, драйвер и мышь установлены. Bx=число кнопок: 0002 или 0ffffh – две 0003 – три 0000 – другое количество
int 33h Вход: ax=0001h Спрятать курсор: int 33h Вход: ax=0002h
int 33h Вход: ax=000сh es:dx = адрес обработчика cx = условие вызова бит 0: любое перемещение бит 1: нажатие левой копки бит 2: отпускание левой копки бит 3: нажатие правой копки бит 4: отпускание правой копки бит 5: нажатие средней копки бит 6: отпускание средней копки cx = 0000h – отменить обработчик
Обработчик оформляется как дальняя процедура, на входе ax — содержит условие вызова, bx – состояние кнопок, cx и dx – x и y координаты курсора, si и di – счетчик последнего перемещения по горизонтали и вертикали, ds – сегмент данных драйвера мыши.
Делать будем com программу, используя TASM, параметры транслятора и компоновщика такие:
АССЕМБЛЕР в 2023? Что такое «Reverse Engineering» и «Cyber Security». Показываю как ломают софт.
bintasm mouse.asm bintlink /t /x mouse.obj /t – создать файл типа .com /x – не создавать файл карты(map) .model tiny ; код, данные и стек размещаются в одном сегменте, размером 64 кб .code ; основной сегмент кода org 100h ; счетчик для com start: mov ax,12h ;установка видеорежима 640х480, 16 цветов int 10h mov ax,0000h ;инициализация мыши int 33h mov ax,0ch ; установка обработчика мыши mov cx,0001h ; любое перемещение lea dx,handler_I ; смещение обработчика int 33h ;—————————————— mov ah,10h ; ждем нажатие любой кнопки int 16h mov ax,000ch mov cx,0000h ; отменяем обработчик int 33h ret ; конец программы handler_I: ; наш обработчик ; cx и dx – x и y координаты курсора, а для int 10h это номера строки и столбца push cs pop ds ; в ds сегмент кода и данные программы mov bh,0 ; номер видеостраницы mov ah,0ch ; вывести точку на экран mov al,color_m ; цвет точки int 10h retf ; выход из процедуры color_m db 0000010 end start
Здесь необходимо заметить, что в режиме 12h возвращаемые координаты совпадают с координатами пикселов. Если использовать режим 13h, то необходимо координату X разделить на 2. Программу можно оптимизировать, необходимо в обработчике мыши использовать прямую запись в видеопамять вместо прерывания 10h.
Массивы на Ассемблере
Создание одномерного массива на Ассемблере.
.model tiny .code org 100h start: push cs pop ds ;————————————— mov cx,99 ;Значение счетчика циклов для команды loop mov si,0 ;Индекс первого элемента, si так же будет и значением ARR_loop: mov array[si],si;array[0]=0,array[1]=1. array[n]=n inc si loop ARR_loop ;цикл int 20h ;————————————— array dw 99 dup (?) ;Не инициализированный массив end start
Создание двухмерного массива на Ассемблере.
.model tiny .code org 100h start: push cs pop ds ;в сегмент данных заносим сегмент кода mov si,0 ;Начальная строка mov bx,0 ;Начальный столбец ;————————————— array_loop: mov array[bx][si],bx ;Заполняем элементы массива текущим индексом столбца inc si ;На следующий элемент строки cmp si,10 ;Конец строки? jz NextLine ;если да, переходим на метку NextLine jmp array_loop ;иначе, продолжаем заполнять строку NextLine: mov si,0 ;Обнуляем индекс элемента строки inc bx ;Переходим на следующий столбец cmp bx,10 ;Последний столбец? jz exit ;если да,выход jmp array_loop ;иначе, продолжаем заполнять следующею строку exit: ;————————————— int 20h ;Выход из com программы ;————————————— array dw 10 dup (10 dup (?)) end start
Поиск числа в двухмерном массиве на Ассемблере.
Основы Ассемблера, часть #02. Самая простая программа
.model tiny .code org 100h start: push cs pop ds ;в сегмент данных заносим сегмент кода mov si,0 mov bx,0 ;Поиск———————————- array_find: mov ax,array[bx][si] call Proverka inc si ;На следующий элемент строки cmp si,2 ;Конец строки? jz NLine ;если да, переходим на метку NextLine jmp array_find ;иначе, продолжаем заполнять строку NLine: mov si,0 ;Обнуляем индекс элемента строки inc bx ;Переходим на следующий столбец cmp bx,3 ;Последний столбец? jz exit ;если да,выход jmp array_find ;иначе, продолжаем заполнять следующею строку exit: ;————————————— int 20h ;Выход из com программы ;————————————— array dw 2 dup (3 dup (0)) message db «Yes «,0dh,0ah,’$’ ;————————————— Proverka proc cmp ax,0 jz YES ret YES: mov ah,9 mov dx,offset message int 21h ret Proverka endp end start
Пример расчета факториала на Ассемблере.
Пример расчета факториала, на мой взгляд, очень полезная программа для понимания работы стека.
Прямая запись в видео память на ассемблере.
Рисование горизонтальной линии, с помощью прямой записи в видео память.
.model tiny .code org 100h start: mov al,13h int 10h mov ax,0A000h mov es,ax mov dx,320*100+160 ;320*y1+x1(начальная точка) mov cx,13 ;Длина линии call gline mov ah,10h int 16h ret ;———————————————————— gline proc mov di,dx mov al,111b ;color rep stosb ;копируем al в ES:DI, dec DI ret gline endp ;———————————————————— end start
Вывод ASCII кодов на ассемблере.
.model tiny .code org 100h start: mov ax,13h int 10h mov cx,256 ;Счетчик кругов для loop mov ax,0003h ;Установка видеорижима 3, курсор в 0,0 int 10h ;и очистка экрана mov ax,0b800h mov es,ax ;Загружаем в дополнительный сегментный регистр абсол.адрес mov di,0 ;Смещение относительно адреса 0b800h mov ah,010b ;Атрибуты, цвет текста зеленый mov al,00h ;ASCII код mov es:[di],ax ;Грузим не в регистр а по адресу который наход. в регистре ;———————- cloop: add di,4 ;Смещение на 4 байта, чтобы выглядело нормально inc al ;Следущий ASCII код mov es:[di],ax ;Грузим по адресу в видеопамять loop cloop ;Дальше. ;———————- mov ah,10h ;Ждем нажатие Any Key int 16h ret end start
Источник: blagin.ru
Язык ассемблер. Команды и основы ассемблера
В статье будут рассмотрены основы языка ассемблер применительно к архитектуре win32. Он представляет собой символическую запись машинных кодов. В любой электронно-вычислительной машине самым низким уровнем является аппаратный. Здесь управление процессами происходит командами или инструкциями на машинном языке. Именно в этой области ассемблеру предназначено работать.
Программирование на ассемблер
Написание программы на ассемблере — крайне трудный и затратный процесс. Чтобы создать эффективный алгоритм, необходимо глубокое понимание работы ЭВМ, знание деталей команд, а также повышенное внимание и аккуратность. Эффективность — это критический параметр для программирования на ассемблер.
Главное преимущество языка ассемблер в том, что он позволяет создавать краткие и быстрые программы. Поэтому используется, как правило, для решения узкоспециализированных задач. Необходим код, работающий эффективно с аппаратными компонентами, или нужна программа, требовательная к памяти или времени выполнения.
Регистры
Регистрами в языке ассемблер называют ячейки памяти, расположенные непосредственно на кристалле с АЛУ (процессор). Особенностью этого типа памяти является скорость обращения к ней, которая значительно быстрее оперативной памяти ЭВМ. Она также называется сверхбыстрой оперативной памятью (СОЗУ или SRAM).
Существуют следующие виды регистров:
- Регистры общего назначения (РОН).
- Флаги.
- Указатель команд.
- Регистры сегментов.
Есть 8 регистров общего назначения, каждый размером в 32 бита.
Доступ к регистрам EAX, ECX, EDX, EBX может осуществляться в 32-битовом режиме, 16-битовом — AX, BX, CX, DX, а также 8-битовом — AH и AL, BH и BL и т. д.
Буква «E» в названиях регистров означает Extended (расширенный). Сами имена же связаны с их названиями на английском:
- Accumulator register (AX) — для арифметических операций.
- Counter register (CX) — для сдвигов и циклов.
- Data register (DX) — для арифметических операций и операций ввода/вывода.
- Base register (BX) — для указателя на данные.
- Stack Pointer register (SP) — для указателя вершины стека.
- Stack Base Pointer register (BP) — для индикатора основания стека.
- Source Index register (SI) — для указателя отправителя (источника).
- Destination Index register (DI) — для получателя.
Специализация РОН языка ассемблер является условной. Их можно использовать в любых операциях. Однако некоторые команды способны применять только определенные регистры. Например, команды цикла используют ESX для хранения значения счетчика.
Регистр флагов. Под этим подразумевается байт, который может принимать значения 0 и 1. Совокупность всех флагов (их порядка 30) показывают состояние процессора. Примеры флагов: Carry Flag (CF) — Флаг переноса, Overflow Flag (OF) — переполнения, Nested Flag (NT) — флаг вложенности задач и многие другие. Флаги делятся на 3 группы: состояние, управление и системные.
Указатель команд (EIP — Instruction Pointer). Данный регистр содержит адрес инструкции, которая должна быть выполнена следующей, если нет иных условий.
Регистры сегментов (CS, DS, SS, ES, FS, GS). Их наличие в ассемблере продиктовано особым управлением оперативной памятью, чтобы увеличить ее использование в программах. Благодаря им можно было управлять памятью размером до 4 Гб. В архитектуре Win32 необходимость в сегментах отпала, но названия регистров сохранились и используются по-другому.
Стек
Это область памяти, выделенная для работы процедур. Особенность стека заключается в том, что последние данные, записанные в него, доступны для чтения первыми. Или иными словами: первые записи стека извлекаются последними. Представить этот процесс себе можно в качестве башни из шашек.
Чтобы достать шашку (нижнюю шашку в основание башни или любую в середине) нужно сначала снять все, которые лежат сверху. И, соответственно, последняя положенная на башню шашка, при разборе башни снимается первой. Такой принцип организации памяти и работы с ней продиктован ее экономией. Стек постоянно очищается и в каждый момент времени одна процедура использует его.
Идентификаторы, целые числа, символы, комментарии, эквивалентность
Целые числа в ассемблере можно указывать в системах отсчета с основаниями 2, 8, 10 и 16. Любая другая запись чисел будет рассматриваться компилятором ассемблера в качестве идентификатора.
В записи символьных данных допускается использовать как апострофы, так и кавычки. Если в символьной строке требуется указать один из них, то правила следующие:
- в строке, заключенной в апострофы, кавычки указываются один раз, апостроф — дважды: ‘can»t’, ‘ he said «to be or not to be» ‘;
- для строки, заключенной в кавычки, правило обратное: дублируются кавычки, апострофы указываются как есть: «couldn’t», » My favourite bar is «»Black Cat»» «.
Для указания комментирования в языке ассемблер используется символ точка с запятой — «;». Допустимо использовать комментарии как в начале строк, так и после команды. Заканчивается комментарий переводом строки.
Директива эквивалентности используется схожим образом тому, как в других языках указывают константные выражения. Эквивалентность указывается следующим способом:
Таким образом в программе все вхождения будут заменяться на , на месте которого допустимо указывать целое число, адрес, строку или другое имя. Директива EQU похожа по своей работе на #define в языке С++.
Директивы данных
Языки высокого уровня (C++, Pascal) являются типизированными. То есть, в них используются данные, имеющие определенный тип, имеются функции их обработки и т. д. В языке программирования ассемблер подобного нет. Существует всего 5 директив для определения данных:
- DB — Byte: выделить 1 байт под переменную.
- DW — Word: выделить 2 байта.
- DD — Double word: выделить 4 байта.
- DQ — Quad word: выделить 8 байтов.
- DT — Ten bytes: выделить 10 байтов под переменную.
Буква D означает Define.
Любая директива может быть использована для объявления любых данных и массивов. Однако для строк рекомендуется использовать DB.
В качестве операнда допустимо использовать числа, символы и знак вопрос — «?», обозначающий переменную без инициализации. Рассмотрим примеры:
real1 DD 12.34 char db ‘c’ ar2 db ‘123456’,0 ; массив из 7 байт num1 db 11001001b ; двоичное число num2 dw 7777o ; восьмеричное число num3 dd -890d ; десятичное число num4 dd 0beah ; шестнадцатеричное число var1 dd ? ; переменная без начального значения ar3 dd 50 dup (0) ; массив из 50 инициализированных эл-тов ar4 dq 5 dup (0, 1, 1.25) ; массив из 15 эл-тов, инициализированный повторами 0, 1 и 1.25
Команды (инструкции)
Синтаксис команд ассемблера или инструкций ассемблера выглядит следующим образом:
: [;Comment]
Метка (label:) обязательно завершается двоеточием и может располагаться в отдельной строке. Метки используются для того, чтобы ссылаться на команды внутри программы.
Инструкции указывают операцию, которая должна быть выполнена. В ассемблере операции представлены в виде буквенных сокращений для облегчения понимания. Инструкции также могут называться мнемокодами.
В роли операндов команды могут выступать:
- регистры, обращение к которым происходит по их именам;
- константы;
- адреса.
Подробнее об адресах
Адрес может передаваться несколькими способами:
- В виде имени переменной, которая в ассемблере является синонимом адреса.
- Если переменная является массивом, то обращение к элементу массива происходит через имя его переменной и смещения. Для этого существует 2 формы: [ + ] и []. Следует учитывать, что смещение — это не индекс в массиве, а размер в байтах. Программисту самому необходимо понимать, на сколько нужно сделать смещение в байтах, чтобы получить нужный элемент массива.
- Можно использовать регистры. Для обращения к памяти, в которой хранится регистр, нужно использовать квадратные скобки: [ebx], [edi].
- [] — квадратные скобки допускают применение сложных выражений внутри себя для вычисления адреса: [esi + 2*eax].
В ассемблере адрес передается через квадратные скобки. Ввиду того, что переменная является также адресом, она может использоваться как с квадратными скобками, так и без.
Помимо этого, в ассемблер существуют сокращения: r — для регистров, m — для памяти и i — для операнда. Эти сокращения используются с числами 8, 16 и 32 для указания размера операнда: r8, m16, i32 и т. д.
add i8/i16/i32, m8/m16/m32 ;суммирование операнда с ячейкой памяти
Команда mov или пересылка
Данная инструкция является основной среди команд ассемблера. Она позволяет записывать в регистр значение другого регистра, ячейки памяти или константы. Она же осуществляет запись в ячейку памяти значения регистра или константы. Синтаксис команды:
В процессоре существует и другие команды для реализации пересылки. Например, XCHG — команда обмена операндов значениями. Но с точки зрения программиста, все они реализованы через команду базовую MOV. Рассмотрим примеры:
MOV i, 0 ; Записать в i значение 0 MOV ECX, EBX ; Пересылка значения EBX в ECX
В виде операнда может выступать как регистр, так и ячейка памяти. Однако если содержимое двух регистров можно переставить, то двух ячеек памяти — нет. Следует внимательно следить за тем, чтобы операнды имели одинаковый размер. Также заметим, что команда MOV не изменяет значения флагов.
Инструментарий
Дальнейшее теоретическое изучение ассемблера может быть трудным, поэтому стоит задуматься об инструментах, используемых для разработки программ с его помощью. Здесь будет приведен лишь краткий список популярных средств:
- Borland Turbo Assembler (TASM) — один из самых популярных инструментов. Хорошо подходит для разработки под DOS и плохо — под Windows.
- Microsoft Macro Assembler (MASM) — это пакет для разработки на ассемблере в среде Windows. Существует как отдельно, так и в виде встроенной функции в среде Visual Studio. Ассемблер и языки высокого уровня часто совместимы. В том смысле, что последние могут использовать ассемблер напрямую. Например, С++.
- Netwide Assembler (NASM) — популярный свободный ассемблер для архитектуры Intel.
Существует множество инструментов. При этом следует сделать особую пометку о том, что нет единого стандарта синтаксиса ассемблера. Есть 2 наиболее применимых: ATассемблер для чайников» и изучать этот замечательный язык.
Источник: www.syl.ru
MASM32: Немного основ ассемблера
Эта статья идет прямиком в дополнение к предыдущей. Я не рассказал про самые основы ассемблера. Хотя в интернете полно материала на эту тему, я все равно решил ее немного затронуть. Что же нужно знать для начала, чтобы понимать и писать несложные программы или ассемблерные вставки?
1. У процессора есть определенный набор регистров.
Представьте, что регистр — это переменная, которая всегда объявлена, и вы можете ее свободно использовать, только переменная эта хранится не в оперативной памяти, а прямиком в процессоре, поэтому работа с регистрами очень быстрая. Существует 8 регистров общего назначения, каждый из них может хранить 4 байта. Чаще всего мы будем использовать следующие регистры: eax, ebx, ecx, edx. Каждый из этих регистров делится еще на несколько следующим образом:
Если поделить EAX на две части по 16 бит (по 2 байта), то младшая часть — это регистр AX. Если AX поделить на две части по 8 бит (по 1 байту), то младшая его часть — AL, а старшая — AH. То же самое справедливо и для остальных перечисленных регистров.
Существуют еще регистры esi и edi (в отличие от предыдущих, у них есть только младшая 16-битная часть si и di). Они используются для выполнения различных операций пересылки данных.
Регистр esp используется для того, чтобы адресовать стек, а ebp — чтобы обращаться к локальным переменным в стеке. Над этими можно пока не задумываться, потому что MASM32 позволяет обойтись без их использования.
В программах мы будем использовать чаще всего только шесть вышеперечисленных регистров. Советую немного прочитать про двоичные формы представления чисел (про перевод десятичных чисел в двоичные и наоборот, а также про дополнительный и прямой код, это пригодится в будущем. Если не всё поняли, опять-таки ничего страшного, про арифметику я еще буду упоминать в дальнейшем.
2. Регистр флагов. Об этом регистре поговорим отдельно. В нем хранятся различные биты, позволяющие узнать информацию о текущем состоянии процессора. Напрямую с этим регистром обычно не работают, существует много команд ассемблера, позволяющих работать с отдельными его битами.
Что ж, небольшой пример, в котором вы уже будете способны разобраться. Предположим, мы хотим сложить два числа и проверить, не равен ли результат нулю.
Источник: kaimi.io