Вот подкопилось информации, решил поделиться ей с софт-форумчанами - написать статейку. Ну, естсвенно, я пользовался источниками, не сам же это все выдумал. Так что я, можно сказать, "криатиффный аффтар". Литературного образования у меня нет, так что просьба - не бить ногами - пишу как умею. Просьба не флудить сообщениями, типа "уау, клево!" (для этого есть кнопочка "thanks"), и "полный отстой для ламеров" - я все-таки ориентируюсь на простых юзеров, а не на гуру с пятью дипломами программиста. Ух-х! Начинаем...
Сегодня мы поговорим об Ассемблере.
Первое, что нужно понять: ассемблер - это низкоуровневый язык. Значит никаких визуальных опор, красивых автосоздаваемых форм, как в Дельфи, здесь нет. Язык асма (мы так его будем дальше для краткости называть) оперирует понятиями процессора. То есть он умеет то, что умеет процессор. Как то:
- числовые операции (сложить;вычесть;разделить;умножить;сравнить два числа)
- Запись в порты и чтение оттуда
- переслать одно число в другое
Вот вообщем-то и все.Так чисто теоретически, чтобы вывести символ на терминал необходимо обратиться к технической документации на видеокарту, а чтобы прочитать сектор с диска - к документации по накопителю. К счастью, эту часть работы берут на себя драйверы, и выполнять ее вручную обычно не требуется (к тому же, в нормальных операционных системах, таких, например, как Windows NT с прикладного уровня порты вообще недоступны).
Кстати о числах.В асме после двоичного числа всегда должна стоять буква "b", а после шестнадцатеричного - "h" (binary и hex соответсвенно). Это нужно для того, чтобы при ассемблировании нашей программы асм смог отличать десятичные, шестнадцатеричные и двоичные числа. Например: 10 - это "десять", 10h - это "шестнадцать" а 10b - это "два" в десятичной системе.
Еще одним важным понятием является регистр. Объяснить, что это такое, не погрешив против истины, невозможно.Поэтому нужно запомнить, что "это что-то, куда запихиваются данные" Грубовато, но это наиболее точное определение регистра простым языком.основных регистров на x86 всего семь. И прежде чем складывать, вычитать или каким-нибудь другим образом манипулировать двумя числами, по крайней мере, одно из них необходимо загрузить в регистр. EAX, EBX, ECX, EDX, ESI, EDI – это регистры общего назначения. Они могут свободно участвовать в любых математических операциях или операциях обращения к памяти. Их всего семь. Семь 32-разрядных регистров. Четыре первых из них (EAX, EBX, ECX и EDX) допускают обращения к своим 16-разрядным половинкам, хранящим младшее слово - AX, BX, CX и DX. Каждый из них в свою очередь делиться на старший и младший байты - AH/AL, BH/BL, CH/CL и DH/DL. Важно понять, что AL, AX и EAX это не три разных регистра, а разные части одного и того же регистра.Есть еще один, это EIP, содержащий указатель на следующую выполняемую команду.Его можно менять манипулируя инструкциями перехода.
Вы так же наверняка слышали слово "стек". Стек - это такой способ хранения данных. Что-то среднее между списком и массивом. Он построен по принципу FILO (First in - Last Out) - первым зашел - последним вышел.Команда PUSH кладет новую порцию данных на верхушку стека, а команда POP – снимает ее оттуда. Это позволяет сохранять данные в памяти не заботясь об их абсолютных адресах.Команда CALL func забрасывает в стек адрес следующей за ней команды, а RET стягивает его оттуда.
Для сравнения двух чисел используется комманда СМР. Для перехода на какую-либо часть программы используется емейство команд условного перехода Jxx.JE прыгает, если числа равны (Jump if Equal), а JNE если неравны (Jump if Not Equal). JB/JA работают с беззнаковыми числами, а с JL/JG - со знаковыми. Любые два не противоречащих друг другу условия могут быть скомбинированы друг с другом, например, JBE – переход в случае, если одно беззнаковое число меньше или равно другому. Безусловный же переход осуществляется командой JMP.
Ассемблерные вставки.
На чистом ассемблере программировать довольно сложно. Все-таки низкоуровневый язык не предназначен для "визуального" программирования элементов интерфейса, окон, вывода графики на экран и т.д и т.п. А вот ассемблерные вставки - другое дело. Они позволяют программировать на асме из среды программирования высокого уровня, к которой человек привык. То есть это гибрид Дельфи (Си) и ассемблера.Изучение ассемблера происходит почти безо всякого напряжения и усилий. Для ассемблерных вставок в Дельфи служит слово "asm".
Итак пример:
Вычтем из одного числа другое с помощью ассемблерной вставки.Выбери в Дельфи "создать консольное прложение" (мы ж собираемся низкоуровнево кодить, так что никаких окон ). И вводи:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
x:integer;// объявляем переменные
y:integer;
z:integer;
begin
x := 10; // заносим значение переменных
y := 4;
asm // начало ассемблерной вставки
mov eax, x; // загружаем значение переменной x в регистр EAX
mov ebx, y; // загружаем значение переменной y в регистр EBX
sub eax, ebx; // вычитаем EAX из EBX, записывая результат в EAX
mov z, eax; // загружаем значение EAX в переменную z
end;
writeln(z); // выводим результат на экран
end.
Мы вычли из 10 число 6. Мучительно вспоминаем сколько же это будет, считаем для верности на бабушкиных счетах, смотрим на экран...Шесть! Программа успешно выполнилась! Что ж теперь ты сможешь сделать свой собственный простейший калькулятор на ассемблерных вставках и хвастать друзьям, какой ты мега-крутой программист
PS. Искренне надеюсь, что данный опус хоть кого-нибудь заинтересовал, и что хоть кто-то нашел в себе силы дочитать его до конца