Главная » Заметки » День 18. Сумбурное знакомство с языком ассемблера
День 18. Сумбурное знакомство с языком ассемблера
Автор статьи никого не призывает к правонарушениям и отказывается нести ответственность за ваши действия. Вся информация предоставлена исключительно в ознакомительных целях. Все действия происходят на виртуальных машинах и внутри локальной сети автора. Спасибо!

Оглавление цикла заметок о языке ассемблера

Эту заметку начал писать одновременно с предыдущей (день 17). Изучение Windows наскучило и мне захотелось побыстрее вернуться к своему любимому занятию – программированию. Перехожу к изучению ассемблера. На самом деле уже давно хотел с ним разобраться, но так и не начинал.

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

Начинать изучение необходимо с простого. Подойдет 16-битный  процессор 8086. Без эмуляции конечно же не обойтись. Скачиваем DOSbox. Далее в файле настроек ({Системный раздел}:\Users\{имя пользователя}\AppData\Local\DOSBox\dosbox-{версия}.conf) предлагается добавить стартовые команды. Да, кстати, читаю здесь (https://asmbase.ru/uchebnyj-kurs/001-neobhodimye-instrumenty/).:

keyb ru441 866          #Поддержка русской кодировки
mount g c:/fasm         #Монтируем корень папки fasm как раздел g
g:                      #Делаем этот раздел текущим
cd CWSDPMI/BIN/         #Входим в директорию CWSDPMI/BIN/ #
CWSDPMI -p -s-          #Запускаем CWSDPMI с параметрами -p -s-
cd /.                   #Возвращаемся в корень папки fasm

Далее скачиваем CWSDPMI и FASM. Код, который выше не сработал. Поэтому задаю его вручную после запуска DOSbox. После взял пример из папки FASM и создал новый файл t.asm с этим кодом. Далее захожу в DOSbox и запускаю его:

fasm t.asm

Судя по выводу – успешно. Появился файл T.COM. Так же пригодится Turbo Debugger, который необходимо скачать. Все, теперь можно приступать к изучению.

Предлагается знакомится с ассемблером со следующего кода:

use16               ;Генерировать 16-битный код
org 100h            ;Программа начинается с адреса 100h
 
    mov ax,255      ;Поместить 255 в регистр AX
    inc ax          ;Увеличить содержимое AX на 1
    nop             ;Эта команда ничего не делает
    mov bx,ax       ;Поместить в BX содержимое AX
 
    mov ax,4C00h    ;\
    int 21h         ;/ Завершение программы

Первая строка сообщает, что необходимо генерировать 16-битный код.

Следующая строка сообщает, что последующие команды будут располагаться в памяти, начиная с 100h. Так как в DOS первые данные (с адресов 0000h00FFh) заняты служебной информацией, а следующим является 100h.

Далее идут команды. Каждая команда обозначается символическим именем, например, mov, inc, nop и т.д. После имени идет операнд.

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

Отступы не являются обязательными как в Python, но с ними код становится значительно читаемым.

Регистр значения не имеет.

Следующая строка:

mov ax,255

Помещаем число 255 в ax. Первый операнд является приемником, второй источником.

Следующая команда выполняет инкремент. Далее идет команда nop, которая ничего не делает. Далее в BX копируется из AX. И две последние строки – стандартное завершение процесса.

Теперь необходимо запустить отладчик, чтобы посмотреть, что делает программа. Под 16-бит он не запускается. Перезапускаем DOSbox. Открываем программу в Turbo Debugger.

cd TD
td g:/t.com

С первого раза не открылся. Заходим в File > Open и открываем вручную (выбрав поиск расширений .com). В большой области располагается код программы. Первый столбец – адреса, следующий – байты машинного кода, третий – символическое обозначение команд.

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

Рис. 1. Программа Turbo Debugger

Чтобы выполнить команду пошагово, необходимо нажать F8. Изменения подсветились белым цветом. Кроме регистра AX, изменился регистр IP, который увеличился на размер выполненной машинной команды (на 3) и равен 103. Еще раз нажимаем F8.

Значение AX увеличилось на 1. И так далее.

Регистры процессора Intel 8086

Процессор 8086 является дальним родителем более сложных процессоров x86, поэтому написанные программы будут совместимы и с ними.

Процессор содержит 12 программных регистров, плюс регистр флагов (FLAGS) и указатель команд (IP), с которым я уже встретился. Далее наглядное изображение регистров (взял с сайта https://asmbase.ru/uchebnyj-kurs/004-registry-protsessora-8086/).

Рис. 2. Внутренние регистры процессора Intel 8086

Регистры общего назначения (РОН)

Регистры AX, BX, CX и DX предназначены для хранения данных и выполнения различных арифметических и логических операций. Каждый регистр поделен на две части по 8 бит. Регистр AX, это регистр AH (High) + AL (Low). Буквы выбраны не случайно, логика прослеживается.

Индексные регистры

Предназначены для хранения индексов при работе с массивами: SI (Source Index) содержит индекс источника и DI (Destination Index) – индекс приемника.

Регистры-указатели

Регистры BP (Base Pointer) и SP (Stack Pointer) применяют для работы со стеком. Первый для работы с переменными в стеке, второй для указания на вершину стека.

Сегментные регистры

Регистры CS (Code Segment), DS (Data Segment), SS (Stack Segment) и ES (Enhanced Segment) предназначены для обеспечения сегментной адресации. Названия говорят сами за себя. Последний сегмент является дополнительным. COM-программа всегда находится в одном сегменте. При запуске такой программы все сегментные регистры будут содержать одинаковые значения.

Указатель команд

Регистр IP (Instruction Pointer) содержит адрес команды, который изменяет сам процессор.

Регистр флагов

Регистр FLAGS содержит отдельные биты: флаги управления и признаки результата. Флаги управления меняют режим работы процессора:

  • D (Direction) – флаг направления. Управляет направлением обработки строк данных: 0 – от младших адресов к старшим. При значении 1, противоположно.
  • I (Interrupt) – флаг прерывания. При 1 прерывания разрешены.
  • T (Trap) – флаг трассировки.

Далее флаги признаков результата:

  • S (Sign) – знак результата, равен знаковому биту результата операции. Если бит равен 1, то результат отрицательный.
  • Z (Zero) – если бит равен 1, то результат равен нулю.
  • P (Parity) – признак четности.
  • C (Carry) – флаг переноса. При сложении/вычитании возникает заем разряда. При сдвигах хранит значение выдвигаемого бита.
  • A (Auxiliary) – флаг дополнительного переноса. Используется в операциях с упакованными двоично-десятичными числами.
  • O (Overflow) – флаг переполнения. Если бит равен 1, то результат получен за пределами допустимого диапазона значений.

Что-то пока очень сложно воспринимается. Я даже не написал своими словами, а списал с урока (https://asmbase.ru/uchebnyj-kurs/004-registry-protsessora-8086/). Посмотрим, как это будет разъясняться в последующих уроках.

Директивы объявления данных

Чтобы хранить значения в переменных, необходимо их научиться объявлять. Например, есть следующие директивы объявления данных:

  1. db – 1 байт (резервирование rb);
  2. dw, du – 2 байт (резервирование rw);
  3. dd – 4 байт (резервирование rd);
  4. dp, df – 6 байт (резервирование rp, rf);
  5. dq – 8 байт (резервирование rq);
  6. dt – 10 байт (резервирование rt);
  7. file – N байт.

Чтобы объявить байт со значением 2, необходимо:

x db 2

Для удобства скачал emu8086 (http://old-dos.ru/index.php?page=files&mode=files&do=show&id=6571), чтобы не производить слишком много манипуляций при изменении кода в DOSbox.

Немного просветился по языку ассемблер. Для дальнейшего изучения нашел пока две книги: Рудольфа Марека «Ассемблер на примерах» и Руслана Аблязова «Программирование на ассемблере на платформе х86-64». Посмотрим, какая понятнее.

Начну с первой. Вообще, изучаю ассемблер с целью разобраться с книгой Майкла Сикорски «Вскрытие покажет! Практический анализ вредоносного ПО».

Книга «Ассемблер на примерах»

Вначале заметки ассемблер и язык ассемблера упоминались как синонимы. Ассемблер – программа для перевода символических имен команд в машинные коды. Язык ассемблера – ориентированная на человека форма записи инструкций процессора. С этим разобрались.

Итак, вторая глава окунает в 40-е годы. Вспомним фон Неймана и первые компьютеры на лампах.

Процессор 80386

В отличие от 16-разрядного своего предшественника, является полностью 32-разрядным. То есть он может работать с 4 Гб оперативной памяти. Общие регистры те же самые, только с приставкой E (расширенный): EAX, EBX, ECX и EDX (аккумулятор, база, счетчик и данные).

Сегментные регистры процессора 80386

Их можно отнести к регистрам состояния. Регистры этой группы используются при вычислении реального адреса. Сегментные регистры 16-разрядные. Названия соответствуют выполняемым функциям: CS (Code Segment, сегмент кода) совместно с EIP определяют адрес памяти, откуда читать следующую команду. Регистр SS (Stack Segment, сегмент стека) вместе с ESP (SS:SP) указывают на вершину стека.

Регистры DS, ES, FS и GS используются для адресации данных в памяти.

Регистры состояния и управления процессора 80386

Регистр EFLAGS (регистр флагов). Состоит из одноразрядных флагов, отображающих в основном текущее состояние АЛУ (арифметико-логическое устройство). О них уже написано выше.

Прерывания

Под прерыванием понимается выполнение внеочередной команды. Т.е. процессор прекращает выполнять инструкции программы в нормальной последовательности и начинает выполнять другую программу. После выполнения, процессор вернется к прерванной.

Процессоры семейства х86 могут хранить 256 прерываний в специальной таблице. Программные прерывания порождает программист, чтобы программа взаимодействовала с ОС.

На этом достаточно. Заметка получилась достаточно объемной и сумбурной. Сначала я попробовал изучать ассемблер по урокам с сайта https://asmbase.ru, но как оказалось там написано уж слишком поверхностно. Поэтому перешел к изучению книги Рудольфа Марека «Ассемблер на примерах».

Просмотров: 99
31.05.2022
Автор