Язык ассемблер. Команды и основы ассемблера

0
0

В статье будут рассмотрены основы языка ассемблер применительно к архитектуре win32. Он представляет собой символическую запись машинных кодов. В любой электронно-вычислительной машине самым низким уровнем является аппаратный. Здесь управление процессами происходит командами или инструкциями на машинном языке. Именно в этой области ассемблеру предназначено работать.

Программирование на ассемблер

Написание программы на ассемблере - крайне трудный и затратный процесс. Чтобы создать эффективный алгоритм, необходимо глубокое понимание работы ЭВМ, знание деталей команд, а также повышенное внимание и аккуратность. Эффективность - это критический параметр для программирования на ассемблер.

Как выглядит программирование на ассемблер

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

Регистры

Регистрами в языке ассемблер называют ячейки памяти, расположенные непосредственно на кристалле с АЛУ (процессор). Особенностью этого типа памяти является скорость обращения к ней, которая значительно быстрее оперативной памяти ЭВМ. Она также называется сверхбыстрой оперативной памятью (СОЗУ или SRAM).

Существуют следующие виды регистров:

  1. Регистры общего назначения (РОН).
  2. Флаги.
  3. Указатель команд.
  4. Регистры сегментов.
Регистры ассемблера

Есть 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"" ".

Для указания комментирования в языке ассемблер используется символ точка с запятой - ";". Допустимо использовать комментарии как в начале строк, так и после команды. Заканчивается комментарий переводом строки.

Директива эквивалентности используется схожим образом тому, как в других языках указывают константные выражения. Эквивалентность указывается следующим способом:

<name> EQU <operand>

Таким образом в программе все вхождения <name> будут заменяться на <operand>, на месте которого допустимо указывать целое число, адрес, строку или другое имя. Директива EQU похожа по своей работе на #define в языке С++.

Директивы данных

Языки высокого уровня (C++, Pascal) являются типизированными. То есть, в них используются данные, имеющие определенный тип, имеются функции их обработки и т. д. В языке программирования ассемблер подобного нет. Существует всего 5 директив для определения данных:

  1. DB - Byte: выделить 1 байт под переменную.
  2. DW - Word: выделить 2 байта.
  3. DD - Double word: выделить 4 байта.
  4. DQ - Quad word: выделить 8 байтов.
  5. DT - Ten bytes: выделить 10 байтов под переменную.

Буква D означает Define.

Любая директива может быть использована для объявления любых данных и массивов. Однако для строк рекомендуется использовать DB.

Синтаксис:

<name> DQ <operand>[, <operand>]

В качестве операнда допустимо использовать числа, символы и знак вопрос - "?", обозначающий переменную без инициализации. Рассмотрим примеры:

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

Команды (инструкции)

Синтаксис команд ассемблера или инструкций ассемблера выглядит следующим образом:

<label>: <instruction operands>	[;Comment]

Метка (label:) обязательно завершается двоеточием и может располагаться в отдельной строке. Метки используются для того, чтобы ссылаться на команды внутри программы.

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

В роли операндов команды могут выступать:

  • регистры, обращение к которым происходит по их именам;
  • константы;
  • адреса.

Подробнее об адресах

Адрес может передаваться несколькими способами:

  1. В виде имени переменной, которая в ассемблере является синонимом адреса.
  2. Если переменная является массивом, то обращение к элементу массива происходит через имя его переменной и смещения. Для этого существует 2 формы: [<имя> + <смещение>] и <имя>[<смещение>]. Следует учитывать, что смещение - это не индекс в массиве, а размер в байтах. Программисту самому необходимо понимать, на сколько нужно сделать смещение в байтах, чтобы получить нужный элемент массива.
  3. Можно использовать регистры. Для обращения к памяти, в которой хранится регистр, нужно использовать квадратные скобки: [ebx], [edi].
  4. [] - квадратные скобки допускают применение сложных выражений внутри себя для вычисления адреса: [esi + 2*eax].

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

Адрес в ассемблере

Помимо этого, в ассемблер существуют сокращения: r - для регистров, m - для памяти и i - для операнда. Эти сокращения используются с числами 8, 16 и 32 для указания размера операнда: r8, m16, i32 и т. д.

add i8/i16/i32, m8/m16/m32 ;суммирование операнда с ячейкой памяти

Команда mov или пересылка

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

MOV <op1>, <op2>

В процессоре существует и другие команды для реализации пересылки. Например, XCHG - команда обмена операндов значениями. Но с точки зрения программиста, все они реализованы через команду базовую MOV. Рассмотрим примеры:

MOV i, 0 ; Записать в i значение 0
MOV ECX, EBX ; Пересылка значения EBX в ECX

В виде операнда может выступать как регистр, так и ячейка памяти. Однако если содержимое двух регистров можно переставить, то двух ячеек памяти - нет. Следует внимательно следить за тем, чтобы операнды имели одинаковый размер. Также заметим, что команда MOV не изменяет значения флагов.

Команда MOV в ассемблере

Инструментарий

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

  • Borland Turbo Assembler (TASM) - один из самых популярных инструментов. Хорошо подходит для разработки под DOS и плохо - под Windows.
  • Microsoft Macro Assembler (MASM) - это пакет для разработки на ассемблере в среде Windows. Существует как отдельно, так и в виде встроенной функции в среде Visual Studio. Ассемблер и языки высокого уровня часто совместимы. В том смысле, что последние могут использовать ассемблер напрямую. Например, С++.
  • Netwide Assembler (NASM) - популярный свободный ассемблер для архитектуры Intel.
Программирование на ассемблер

Существует множество инструментов. При этом следует сделать особую пометку о том, что нет единого стандарта синтаксиса ассемблера. Есть 2 наиболее применимых: AT&T-синтаксис, ориентированный на процессоры производства не Intel, и, соответственно, Intel-синтаксис.

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