Информационные технологииStfw.Ru 🔍

Ассемблер в Delphi

Главное направление статьи, это познакомиться с использованием ассемблера в Object Pascal. Хотя, не будем пропускать и те аспекты программирования, которые будут настойчиво просить пояснения для определенных примеров, приведённых в этой статье.
🕛 24.03.2010, 12:47
Применение Ассемблера в Борландовком Delphi

Перед тем, как начать, очень хочется определиться с уровнем познаний, необходимых для нормального усвоения данного материала. Требуется быть знакомым со встроенными средствами отладки в Delphi. Так же требуется иметь представление о подобных терминах как тип реализации (instantiation), null pointer и распределение памяти. Если в чём-то из вышеупомянутого Вы сомневаетесь, то попробуйте быть весьма внимательны и осторожны при воплощении данного материала на практике. К тому же, будет обсуждаться лишь 32-битный код, так что потребуется компилятор не ниже Delphi 2..

Для чего применять Ассемблер? По-моему, Object Pascal, это инструмент, позволяющий создавать эффективный и быстрый код, хотя применение ассемблера в некоторых ситуациях дает возможность решать кое-какие задачи более эффективно. За всю работу с Delphi, я пришёл к выводу, что применение низкоуровневого кода требуется в 2-х случая.

(1) Обработка крупного числа данных. Nb. В данный случай не входит ситуация, когда применяется язык запроса данных.

(2) В высокоскоростных подпрограммах работы с дисплеем. Nb. Есть ввиду применение простых процедур на чистом паскале, однако никак не внешних библиотек и DIRECTX.

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

Что такое Ассемблер? Надеюсь, что Все читатели этой статьи имеют хотя бы поверхностное представление о работе процессора. Грубо говоря, это калькулятор с крупным объёмом памяти. Память, это не более чем упорядоченная последовательнось двоичных цифр. Каждая такая цифра является байтом. Любой байт может содержать в себе значение от до 255, а так же имеет собственный эксклюзивный адрес, с помощью которого процессор находит необходимые значения в памяти. Процессор так же имеет набор регистров (это возможно расценить как глобальные переменные). К примеру eax,ebx,ecx и edx, это универсальные 32-битные регистры. Это означает, что самое большое количество, которое мы можем записать в регистр eax, это 2 в степени 32 минус 1, или 4294967295.

Как мы уже выяснили, процессор манипулирует значениями регистров. Машинный код операции прибавления 10 к значению регистра eax будет выглядеть так


05/0a/00/00/00

Хотя, такая запись совершенно не читабельна и, как следствие, не пригодна при отладке утилиты. Так вот Ассемблер, это простое представление машинных команд в более удобном виде. Сейчас давайте посмотрим, как будет выглядеть прибавление 10 к eax в ассемблерном представлении:


add eax,10 {a := a + 10}

А вот так смотрится вычитаение значения ebx из eax


sub eax,ebx {a := a - b }

Чтоб сохранить значние, возможно просто поместить его в иной регистр


mov eax,ecx {a := c }

или даже лучше, сохранить значение по определённому адресу в памяти


mov [1536],eax {сохраняет значение eax по адресу 1536}

и естественно взять его от туда


mov eax,[1536]

Хотя, здесь есть важный миг, про который забывать не лучше. Потому как регистр 32-битный(4 байта), то его значение будет записано тут же в 4 ячейки памяти 1536, 1537, 1538 и 1539.

А сейчас давайте посмотрим, как компилятор трансформирует действия с переменными в машинный код. Предположим у нас есть строка


Count := ;

Для компилятора это значит, что нужно просто запомнить значение. Следовательно, компилятор генерирует код, который сохраняет значение в памяти по определённому адресу и следит, чтоб не случилось никаких накладок, и обзывает этот адрес как 'Count'. Вот как смотрится подобный код


mov eax, mov Count,eax

Компилятор не может применять строку типа


mov Count,

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


Count := Count + 1;

то


mov eax,Count add eax,1 mov Count,eax

Для переменных, тип которых отличается от целого, всё усложняется. Хотя, рассмотрим эту тематику слегка потом, а теперь предлагаю зафиксировать теорию практическими примерами.

Итак, рассмотрим I пример. Немедленно извинюсь за тривиальность, однако с чего-то нужно начинать.

function Sum(X, Y: integer): integer; begin Result := X + Y; end; 

А вот так будет выглядеть оперция сложения 2-х целых чисел на ассемблере:

function Sum(X,Y:integer):integer; begin asm mov eax,X add eax,Y mov Result,eax end; end; 

Этот код прекрасно работает, хотя он не даёт нам преимущества в скорости, а так же потерялось восприятие кода. Однако не стоит огорчаться, потому как те немногие познания, которые Вы почерпнули из этого материала, возможно применять с большей пользой. Предположим, нам нужно преобразовать очевидные значения Red,Green, и Blue в цвета типа TCOLOR, подходящие для эксплуатации в Delphi. Тип TCOLOR описан как 24-битный True Colour хранящийся в формате целого количества, т.е. 4 байта, старший из которых равен нулю, а дальше по порядку алый, зеленоватый, синий.

function GETCOLOUR(Red,Green,Blue:integer):TCOLOR; begin asm {ecx будет содержать значение TCOLOR} mov ecx, {начинаем с красной компоненты} mov eax,Red {требуется убедиться, что пурпурный располагается в диапазоне <=Red<=255} and eax,255 {сдвигаем значение алого в правильное положение} shl eax,16 {выравниваем значение TCOLOR} xor ecx,eax {проделываем также самое с зелёным} mov eax,Green and eax,255 shl eax,8 xor ecx,eax {и также самое с синим} mov eax,Blue and eax,255 xor ecx,eax mov Result, ecx end; end;

Заметьте, что я применял несколько бинарных операций. Эти операции к тому же определены именно в Object Pascal.

Assembler   Теги:

Читать IT-новости в Telegram
Информационные технологии
Мы в соцсетях ✉