![]() |
1. Заголовок или название темы должно быть информативным
2. Все тексты программ должны помещаться в теги [CODE=asm] [/CODE]
3. Прежде чем задавать вопрос, см. "FAQ",если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно, такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Ассемблера. Исключение только с согласия модератора.
5. НЕ используйте форум для личного общения! Все, что не относиться к обсуждению темы - на PM!
6. Проверяйте программы перед тем, как выложить их на форум!!
![]() |
BlackShadow |
![]() ![]()
Сообщение
#1
|
Гость ![]() |
От нечего делать опишу основные моменты при программировании на встроенном ассемблере в Паскале.
Есть 2 способа задействовать эту замечательную возможность:
Ну, на самом деле применений целое море, о чём можно убедиться полистав этот раздел форума. Рассмотрим вопрос адресации в реальном режиме (именно он используется "by def" при компиляции в BP). Адрес состоит из двух частей: сегментной части и смещения. Обе части являются 16-ти разрядными двоичными числами или, что на практике и применяется, 4-х разрядными шестнадцатиричными. Рассмотрим пример и на нём разберёмся, что и какая часть значит: Пусть сегментная часть (далее Seg) = $ABCD, а смещение (далее Ofs) = $1234. Это означает, что эта пара Seg:Ofs хранит следующий адрес Seg * $10 + Ofs = $ABCD * $10 + $1234 = $ABCD0 + $1234 = $ACF04. Как легко заметить, пользуясь таким способом адресации мы можем указать адрес любой ячейки памяти в пределах первого мегабайта ($00000..$FFFFF) и даже чуть-чуть больше, но это не имеет значения, т.к. процессор в реальном режиме даёт доступ только к первому МБ. Возникает естественный вопрос: а зачем нужен этот геморрой, и почему нельзя просто указывать полный адрес? А вот нельзя. А потому, что процессор при работе с памятью опирается на информацию, которая хранится в его регистрах, а т.к. мы используем 16-битный вариант команд, то, соответственно, в 1 регистр более 16 бит (4 16-ричные цифры) не впихнуть. Поэтому и приходится использовать 2 регистра: сегментный и какой-нибудь, который можно использовать для адресации. Рассмотрим предназначение регистров процессора:
Теперь давайте рассмотри примитивный набор команд. mov dst, src копирует значение src в dst. Есть один важный момент: командой mov нельзя скопировать значение одной переменной в другую за один приём. Примеры: (Показать/Скрыть)
inc p увеличивает на 1 значение операнда. После компиляции эта команда занимает меньше места чем команда прибавления единицы. Примеры: (Показать/Скрыть)
dec p соответственно уменьшает операнд на 1. add dst, src прибавляет к src значение dst. Результат сохраняется в dst, так что просто число там написать нельзя. Примеры: (Показать/Скрыть)
sub dst, src вычитает из dst значение src. mul n умножает значение регистра AL (AX) на n. Если n размером в 1 байт, то происходит следующее: AX = AL * n, если же слово, то старшие 16 бит произведения сохраняются в DX, а младшие в AX, т. е., умножив AX=$1010 на $100 получим в DX $0010 и в AX $1000. Примеры: (Показать/Скрыть)
div n делит значение в AX (DX:AX, как в команде mul) на n. При этом остаток сохраняется в AH (DX), а целая часть от деления в AL (AX). Например: (Показать/Скрыть)
cmp a, b - сравнивает значения a и b и устанавливает флаги процессора в соответствии с результатом сравнения. Например: (Показать/Скрыть)
jmp L - команда безусловного перехода на метку L. То что в BP называется GoTo. Например: (Показать/Скрыть)
j<cc> L - серия команд условного перехода. Тут <cc> определяет условия перехода:
Например: (Показать/Скрыть)
Рассмотрим ещё команду loop L она сравнивает CX с 0 и, если он отличен, то уменьшает его на 1 и делает переход на указанную метку. Пример: (Показать/Скрыть)
Теперь для закрепления сказанного рассмотрим реализацию вычисления факториала:
Стоит объяснить ещё и то, как возвращаются значения функций. Это всё зависит от типа результата: Byte, Char - через AL Word, Integer - через AX LongInt - старшая часть в DX, а младшие 16 бит в AX. Pointer - сегментная часть в DX, смещение - AX. Остальные типы возвращаются более извращённым способом... Так же отмечу, что убрав проверку на <0 можно переписать эту функцию так: Function Factorial(n: Integer): Integer; Assembler; Правда проблема переполнения остаётся, но зато покажите мне компилятор, который стандартное Function Factorial(n: Integer): Integer; скомпилирует вот так вот красиво... |
![]() ![]() |
Dark |
![]()
Сообщение
#2
|
![]() Знаток ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 408 Пол: Мужской Репутация: ![]() ![]() ![]() |
Оки, тады продолжаем
Работа с диском (DOS функции)
------------------------------------------------------------------------- Получить номер текущего диска: 19h IN: ah = 19h OUT: al = номер диска (00h -> A; 01h -> B; 00h -> C и т.д.) ------------------------------------------------------------------------- Изменить номер текущего диска: 0Eh IN: ah = 0Eh dl = новый диск (00h -> A; 01h -> B; 00h -> C и т.д.) OUT: al = номер диска, последнего в системе (00h -> A; 01h -> B; 00h -> C и т.д.) ------------------------------------------------------------------------- Свободное место на диске: 36h IN: ah = 36h dl = номер диска, (00h - текущий, 01h - A 02h - B и т.д.) OUT: ax = FFFF - неправильно задано устройство в dl или ax = число секторов в кластере bx = свободные кластеры cx = размер сектора в байтах dx = общее число кластеров на диске Таким образом, свободное пространство на диске - ax*bx*cx, полный объем - ax*cx*dx ------------------------------------------------------------------------- Создать каталог: 39h IN: ah = 39h ds:dx = указатель на имя создаваемого каталога в ASCIIZ формате (64 символа) OUT: CF = 0: Все ОК AX = не определен CF = 1: ошибка AX = код ошибки ------------------------------------------------------------------------- Удалить каталог: 3Ah IN: ah = 3Ah ds:dx = указатель на путь к удаляемому каталогу в ASCIIZ формате (64 символа) OUT: CF = 0: Все ОК AX = не определен CF = 1: ошибка AX = код ошибки ------------------------------------------------------------------------- Изменить текущий каталог: 3Bh IN: ah = 3Bh ds:dx = указатель на путь к новому каталогу в ASCIIZ формате (64 символа) OUT: CF = 0: Все ОК AX = не определен CF = 1: ошибка AX = код ошибки ------------------------------------------------------------------------- Получить текущий каталог: 47h IN: ah = 47h dl = номер диска ds:si = указатель на путь к новому каталогу в ASCIIZ формате (64 символа) OUT: CF = 0: Все ОК AX = неопределен (или 100h) CF = 1: ошибка AX = код ошибки Поиск файлов Поиск происходит следующим образом:
Область DTA (Data Transfer Area) располагается в PSP (префикс программного сегмента) со смещением 80h от его начала и занимает 128 байт. DTA может хранить две структуры:
Структура DTA:
------------------------------------------------------------------------- Получить адрес DTA: 2Fh IN: ah = 2Fh OUT: ES:BX = адрес DTA ------------------------------------------------------------------------- Установить адрес DTA: 1Ah IN: ah = 1Ah ds:dx = новая область DTA OUT: ------------------------------------------------------------------------- Найти первый файл по шаблону: 4Eh IN: ah = 4Eh cx = Атрибуты файла ds:dx = указатель на имя файла в ASCIIZ (можно применять символы ? и *) OUT: CF = 0: файл найден, информация в DTA CF = 1: Ошибка AX = 2 (файл не найден), 3 (несуществующий путь) или 12h (больше нет файлов) ------------------------------------------------------------------------- Найти следующий файл по шаблону: 4Fh IN: ah = 4Fh DTA заполнена предыдущим вызовом функции 4Eh OUT: CF = 0: файл найден, информация в DTA CF = 1: Ошибка AX = 12h - больше нет файлов ------------------------------------------------------------------------- Пример поиска файла var Таким образом несложно написать редактор наподобии EDIT от MICROSOFT =))) А также, применять для разработки своих вирусов... Сообщение отредактировано: volvo - 19.01.2009 19:42 -------------------- - Где я?
- Во тьме. - В какой тьме? - Во тьме твоего мозга. |
![]() ![]() |
![]() |
Текстовая версия | 18.06.2025 16:47 |