Skip to content

Лекция 2

Inspirate789 edited this page May 15, 2022 · 16 revisions

Память в реальном режиме работы процессора - пример.

|     Номер параграфа начала сегмента     |
 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
            |              Смещение               |

[SEG]:[OFFSET] => физический адрес:

  1. SEG необходимо побитово сдвинуть на 4 разряда влево (или умножить на 16, что тождественно)
  2. К результату прибавить OFFSET
5678h:1234h =>
  56780
+  1234
= 579B4

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

Распространённые пары регистров: CS:IP, DS:BX, SS:SP.

Логическая структура памяти. Сегменты.

  • Сегмент кода (регистр CS)
  • Сегменты данных (основной регистр - DS, для дополнительных сегментов - ES, FS, GS)
  • Сегмент стека (регистр SS)

Команда организации цикла LOOP.

LOOP метка

  • Уменьшает регистр CX на 1 и выполняет переход на метку, если CX не равен нулю.
  • Метка не может быть дальше -128..127 байт от команды.

Структура программы на ассемблере.

(Зубков С. В. Assembler для DOS, Windows, Unix, глава 3)

  • Модули (файлы исходного кода)
    • Сегменты (описание блоков памяти)
      • команды процессора;
      • инструкции описания структур данных, выделения памяти для переменных и констант;
      • макроопределения.

Полный формат строки:

метка команда/директива операнды ; комментарий

Метки.

  • В коде:

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

        mov cx, 5
    label1:
        add ax, bx
        loop label1
    (5 раз прибавляем bx к ax)

    Метки обычно используются в командах передачи управления.

  • В данных:

    Метка в описании данных является ссылкой на переменную, расположенную после неё. Метка не является директивой выделения памяти.

    • label

      • метка label тип
      • Возможные типы:
        • BYTE (1 байт)
        • WORD (2 байта)
        • DWORD (4 байта)
        • FWORD (6 байт)
        • QWORD (8 байт)
        • TBYTE (10 байт)
        • NEAR - тип для хранения меток в коде или адресов команд для меток ближнего перехода
        • FAR - тип для хранения меток в коде или адресов команд для меток дальнего перехода
    • EQU, =

      • label EQU выражение (Пример выражения: 5 + 2, вычисляется на этапе компиляции)
      • Макрос
      • Вычисляет выражение в правой части и приравнивает его метке

Директивы выделения памяти.

Директива - инструкция ассемблеру, влияющая на процесс компиляции и не являющаяся командой процессора. Обычно не оставляет следов в формируемом машинном коде.

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

Псевдокоманды определения данных указывают, что в соответствующем месте располагается переменная, резервируют под неё место заданного типа, заполняют значением и ставят в соответствие метку.

Виды директив выделения памяти:

  • DB (1 байт)
  • DW (2 байта)
  • DD (4 байта)
  • DF (6 байт)
  • DQ (8 байт)
  • DT (10 байт)

Примеры:

  • a DB 1
  • float_number DD 3.5e7
  • text_string DB ‘Hello, world!’

DUP - заполнение повторяющимися данными.

  • ? - неинициализированное значение
  • Пример: uninitialized DW 512 DUP(?)

Описание сегментов программы.

Сегмент - блок памяти размером до 64 Кб.

Любая программа состоит из сегментов.

Виды сегментов:

  • сегмент кода (CS)
  • сегмент данных (DS и дополнительные ES, FS, GS)
  • сегмент стека (SS)

Описание сегмента - директива SEGMENT:

имя SEGMENT [READONLY] [выравнивание] [тип] [разрядность] [‘класс’]
...
имя ENDS

Параметры директивы SEGMENT.

Выравнивание:

  • BYTE (сегмент может начинаться с произвольного адреса)
  • WORD (Адрес начала сегмента кратен 2 байтам)
  • DWORD (Адрес начала сегмента кратен 4 байтам)
  • PARA (сегмент располагается в начале параграфа, т.е. адрес начала сегмента кратен 16 байтам) - по умолчанию
  • PAGE (сегмент располагается в начале страницы, т.е. адрес начала сегмента кратен 256 байтам)

Тип:

  • PUBLIC (сегменты с одним именем будут располагаться в памяти друг за другом независимо от порядка объявления)
  • STACK (сегмент будет использоваться под стек (сегмент стека), все такие сегменты будут объединяться в один, увеличивая общий стек)
  • COMMON (сегменты будут накладываться, т.е. начинаться с одного и того же адреса; память выделится по размеру наибольшего из сегментов; метки, на которые ссылаются сегменты, будут указывать на одни и те же ячейки памяти)
  • AT (нужен аргумент - номер параграфа начала сегмента; сегмент будет загружаться в память по некоторому фиксированному постоянному адресу, независимо от расположения остальных сегментов)
  • PRIVATE (сегмент не объединяется с другими) - по умолчанию

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

Модели памяти.

.model модель, язык, модификатор

Служит для определения модели памяти программы. Позволяет сократить запись программ определённых типов.

Модели:

  • TINY - один сегмент на всё (как в случае COM-программы)
  • SMALL - код в одном сегменте, данные и стек - в другом
  • COMPACT - допустимо несколько сегментов данных
  • MEDIUM - код в нескольких сегментах, данные - в одном
  • LARGE, HUGE - много сегментов кода и данных

Языки:

  • C
  • PASCAL
  • BASIC
  • SYSCALL, STDCALL

Этот параметр предназначен для связывания с языком высокого уровня (ЯВУ) и вызова подпрограмм.

Модификатор (определяет способ подключения стека):

NEARSTACK (по умолчанию) или FARSTACK (ближний или дальний).

Определение модели позволяет использовать сокращённые формы директив определения сегментов.

Завершение описания модуля. Точка входа.

END [точка_входа]
  • Точка входа - имя метки, объявленной в сегменте кода и указывающее на команду, с которой начнётся исполнение программы.
  • Если в программе несколько модулей, только один может содержать точку входа.

Сегментный префикс. Директива ASSUME.

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

Пример полной записи - DS:Var1

Директива ASSUME регистр:имя сегмента устанавливает значение сегментного регистра по умолчанию.

Data1 SEGMENT WORD 'DATA'
Var1 DW 0
Data1 ENDS

Data2 SEGMENT WORD 'DATA'
Var2 DW 0
Data2 ENDS

Code SEGMENT WORD 'CODE'
    ASSUME CS:Code
ProgramStart:
    mov ax,Data1
    mov ds,ax
    ASSUME DS:Data1
    mov ax,Data2
    mov es,ax 
    ASSUME ES:Data2
    mov ax,[Var2] 
    .
    .
    .
Code ENDS
END ProgramStart

Прочие директивы.

  • Задание набора допустимых команд: .8086, .186, .286, …, .586, .686, ...
  • Управление программным счётчиком:
    • ORG значение - начиная с этой директивы в сегменте отступ будет идти со значением параметра директивы (пример: ORG 100h - пропускает первые 256 байт)

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

    ; пример из 4 лабораторной работы (2 пример):
    SD1 SEGMENT para common 'DATA'
      C1 LABEL byte
      ORG 1h
      C2 LABEL byte
    SD1 ENDS
    ; C1 и C2 будут располагаться вплотную друг за другом (а если бы мы написали ORG 0h, то C1 и C2 наложились бы)
    • EVEN - автоматически выравнивает всё, что идёт после неё, по чётным адресам
    • ALIGN значение - явно задаёт кратность выравнивания (выравнивание будет кратно параметру директивы); нужен для ускорения работы программы (можно поставить выравнивание по размеру машинного слова)
  • Глобальные объявления:
    • public - позволяет объявить метку доступной из других программ
    • comm
    • extrn - подключает метку из другого файла и делает её видимой в текущем файле (используется в связке с public)
    • global
  • Условное ассемблирование:
IF выражение
...
ELSE
...
ENDIF

Виды переходов для команды JMP.

  • short (короткий): -128 .. +127 байт (аналогично команде loop)
  • near (ближний): в том же сегменте (без изменения регистра CS, меняется только IP)
  • far (дальний): в другой сегмент (с изменением значения в регистре CS)

Для короткого и ближнего переходов непосредственный операнд (константа в коде) прибавляется к IP, а не заменяет его.

Операнды - регистры и переменные заменяют старое значение в IP (CS:IP)

Команды различаются по занимаемому объёму памяти (far самый накладный)

Архитектура 8086 с точки зрения программиста (структура блока регистров).

  • Регистры общего назначения (РОН):
    • AX (AH, AL)
    • BX (BH, BL)
    • CX (CH, CL)
    • DX (DH, DL)
  • Индексные регистры:
    • SI
    • DI
  • Сегментные регистры:
    • CS
    • DS
    • ES
    • FS
    • GS
    • SS
  • Указательные регистры:
    • SP
    • BP
  • FLAGS
  • IP

Индексные регистры SI и DI.

SI - source index (индекс источника)

DI - destination index (индекс приёмника)

Применение:

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

Способы адресации.

(Зубков С. В. Assembler для DOS, Windows, Unix, глава 2)

  • Регистровая адресация (mov ax, bx) - самый простой способ
  • Непосредственная адресация (mov ax, 2)
  • Прямая адресация (mov ax, ds:0032)
  • Косвенная адресация (mov ax, [bx] - bx взят в [], чтобы взять из него смещение). В 8086 допустимы BX, BP, SI, DI.
  • Адресация по базе со сдвигом (mov ax, [bx]+2; <==> mov ax, 2[bx]). Удобно использовать для движения по массивам, задавая в bx номер элемента в массиве.
  • Адресация по базе с индексированием (допустимы BX + SI, BX + DI, BP + SI, BP + DI). Используется для движения по матрице. Равноценные варианты записи:
    • mov ax, [bx+si+2]
    • mov ax, [bx+2][si]
    • mov ax, 2[bx][si]
    • mov ax, [bx][si]+2
    • mov ax, [bx][si+2]

Регистр FLAGS.

16 битов - отдельные флажки.

0   1   2   3   4   5   6   7   8   9   10   11   12   13   14   15
CF  -   PF  -   AF  -   ZF  SF  TF  IF  DF   OF     IOPL    NT   -

Некоторые флаги напрямую менять нельзя, они меняются сами

TF, IF, IOPL, NT - системные флаги

  • CF (carry flag) - флаг переноса (при выходе за рязрядную сетку)
  • PF (parity flag) - флаг чётности
  • AF (auxiliary carry flag) - вспомогательный флаг переноса
  • ZF (zero flag) - флаг нуля
  • SF (sign flag) - флаг знака
  • TF (trap flag) - флаг трассировки
  • IF (interrupt enable flag) - флаг разрешения прерываний
  • DF (direction flag) - флаг направления
  • OF (overflow flag) - флаг переполнения (изменение знакового разряда)
  • IOPL (I/O privilege flag) (появился в 286 процессоре) - уровень приоритета ввода-вывода
  • NT (nested task) (появился в 286 процессоре) - флаг вложенности задач

В записи лекции можно подробнее посмотреть

Команда сравнения CMP.

CMP <приёмник>, <источник>

  • Источник - число, регистр или переменная
  • Приёмник - регистр или переменная; не может быть переменной одновременно с источником
  • Вычитает источник из приёмника, результат никуда не сохраняется (в отличие от команды SUB), а выставляются флаги CF, PF, AF, ZF, SF, OF

Команды условных переходов J..

(Зубков С. В. Assembler для DOS, Windows, Unix, глава 2)

  • Переход типа short или near
  • Обычно используются в паре с CMP
  • Термины “выше” и “ниже” - при сравнении беззнаковых чисел
  • Термины “больше” и “меньше” - при сравнении чисел со знаком

Виды условных переходов.

Часть 1:

Команда Описание Состояние флагов для выполнения перехода
JO Есть переполнение OF = 1
JNO Нет переполнения OF = 0
JS Есть знак SF = 1
JNS Нет знака SF = 0
JE, JZ Если равно/если ноль ZF = 1
JNE, JNZ Не равно/не ноль ZF = 0
JP/JPE Есть чётность / чётное PF = 1
JNP/JPO Нет чётности / нечётное PF = 0
JCXZ CX = 0 -

Часть 2:

Команда Описание Состояние флагов для выполнения перехода Знаковый
JB
JNAE
JC
Если ниже
Если не выше и не равно
Если перенос
CF = 1 Нет
JNB
JAE
JNC
Если не ниже
Если выше или равно
Если нет переноса
CF = 0 Нет
JBE
JNA
Если ниже или равно
Если не выше
CF = 1 или ZF = 1 Нет
JA
JNBE
Если выше
Если не ниже и не равно
CF = 0 и ZF = 0 Нет

Часть 3:

Команда Описание Состояние флагов для выполнения перехода Знаковый
JL
JNGE
Если меньше
Если не больше и не равно
SF <> OF Да
JGE
JNL
Если больше или равно
Если не меньше
SF = OF Да
JLE
JNG
Если меньше или равно
Если не больше
ZF = 1 или SF <> OF Да
JG
JNLE
Если больше
Если не меньше и не равно
ZF = 0 и SF = OF Да

Команда TEST.

TEST <приёмник>, <источник>

  • Логическое умножение
  • Аналог AND, но результат не сохраняется.
  • Выставляются флаги SF, ZF, PF.

Прерывания.

Прерывание - особая ситуация, когда выполнение текущей программы приостанавливается и управление передаётся программе-обработчику возникшего прерывания.

Виды прерываний:

  • аппаратные (асинхронные) - события от внешних устройств;
  • внутренние (синхронные) - события в самом процессоре, например, деление на ноль;
  • программные - вызванные командой INT;

Прерывание DOS 21h.

  • Аналог системного вызова в современных ОС.
  • Используется наподобие вызова подпрограммы.
  • Номер функции передаётся через AH.

Прерывание DOS - вывод на экран в текстовом режиме.

Функция Назначение Вход Выход
02 Вывод символа в stdout DL = ASCII-код символа -
09 Вывод строки в stdout DS:DX - адрес строки, заканчивающейся символом $ -

Прерывание DOS - ввод с клавиатуры.

Функция Назначение Вход Выход
01 Считать символ из stdin с эхом - AL - ASCII-код символа
06 Считать символ без эха, без ожидания, без проверки на Ctrl+Break DL = FF -
07 Считать символ без эха, с ожиданием и без проверки на Ctrl+Break - AL - ASCII-код символа
08 Считать символ без эха - AL - ASCII-код символа
10 (0Ah) Считать строку с stdin в буфер DS:DX - адрес буфера Введённая строка помещается в буфер
0Bh Проверка состояния клавиатуры - AL=0, если клавиша не была нажата, и FF, если была
0Ch Очистить буфер и считать символ AL=01, 06, 07, 08, 0Ah -
Clone this wiki locally