Что такое регистр в программировании
Перейти к содержимому

Что такое регистр в программировании

  • автор:

Учебники. Программирование для начинающих.

Programm.ws — это сайт, на котором вы можете почитать литературу по языкам программирования , а так-же посмотреть примеры работающих программ на С++, ассемблере, паскале и много другого..

Программирование — в обычном понимании, это процесс создания компьютерных программ.
В узком смысле (так называемое кодирование) под программированием понимается написание инструкций — программ — на конкретном языке программирования (часто по уже имеющемуся алгоритму — плану, методу решения поставленной задачи). Соответственно, люди, которые этим занимаются, называются программистами (на профессиональном жаргоне — кодерами), а те, кто разрабатывает алгоритмы — алгоритмистами, специалистами предметной области, математиками.
В более широком смысле под программированием понимают весь спектр деятельности, связанный с созданием и поддержанием в рабочем состоянии программ — программного обеспечения ЭВМ. Более точен современный термин — «программная инженерия» (также иначе «инженерия ПО»). Сюда входят анализ и постановка задачи, проектирование программы, построение алгоритмов, разработка структур данных, написание текстов программ, отладка и тестирование программы (испытания программы), документирование, настройка (конфигурирование), доработка и сопровождение.

Assembler

Глава 1. Архитектура реального режима

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

Как уже отмечалось выше, в современных микропроцессорах типа, например, Pentium, можно выделить часть (мы назвали ее МП 86), предназначенную для использования в реальном режиме и практически соответствующую процессору 8086. Ниже, используя термин «процессор», мы будем иметь в виду именно МП 86.
Процессор содержит двенадцать 16-разрядных программно-адресуемых регистров, которые принято объединять в три группы: регистры данных, регистры-указатели и сегментные регистры. Регистры данных и регистры-указатели часто объединяют под общим названием «регистры общего назначения». Кроме того, в состав процессора входят указатель команд и регистр флагов (рис. 1.6).
В группу регистров данных включаются четыре регистра АХ, ВХ, СХ и DX. Программист может использовать их по своему усмотрению для временного хранения любых объектов (данных или адресов) и выполнения над ними требуемых операций. При этом регистры допускают независимое обращение к старшим (АН, ВН, СН и DH) и младшим (AL, BL, CL и DL) половинам. Так, команда

пересылает старший байт регистра АХ в младший байт регистра ВХ, не затрагивая при этом вторых байтов этих регистров. Заметьте, что сначала указывается операнд-приемник, а после запятой — .операнд-источник, т.е. команда как бы выполняется справа налево.

Рис. 1.6. Регистры процессора.

Во многих случаях регистры данных вполне эквивалентны, однако предпочтительнее пользоваться регистром АХ, поскольку многие команды занимают в памяти меньше места и выполняются быстрее, если их операндом является регистр АХ (или его половина AL). С другой стороны, ряд команд использует определенные регистры неявным образом. Так, все команды циклов используют регистр СХ в качестве счетчика числа повторений; в командах умножения и деления регистры АХ и DX выступают в качестве неявных операндов; операции ввода-вывода можно осуществлять только через регистры АХ или AL и т.д.
Индексные регистры SI и DI так же, как и регистры данных, могут использоваться произвольным образом. Однако их основное назначение — хранить индексы, или смещения относительно некоторой базы (т.е. начала массива) при выборке операндов из памяти. Адрес базы при этом может находиться в базовых регистрах ВХ или ВР. Специально предусмотренные команды работы со строками используют регистры SI и DI в качестве неявных указателей в обрабатываемых строках.
Регистр ВР служит указателем базы при работе с данными в стековых структурах, но может использоваться и произвольным образом в большинстве арифметических и логических операций.
Последний из группы регистров-указателей, указатель стека SP, стоит особняком от других в том отношении, что используется исключительно как указатель вершины стека — специальной структуры, которая будет рассмотрена ниже.
Регистры SI, DI, BP и SP, в отличие от регистров данных, не допускают побайтовую адресацию.
Четыре сегментных регистра CS, DS, ES и SS являются важнейшим элементом архитектуры процессора, обеспечивая, как уже отмечалось выше, адресацию 20-разрядного адресного пространства с помощью 16-разрядных операндов. Подробнее о них будет рассказано в следующем разделе.
Указатель команд IP «следит» за ходом выполнения программы, указывая в каждый момент относительный адрес команды, следующей за исполняемой. Регистр IP программно недоступен (IP — это просто его сокращенное название, а не мнемоническое обозначение, используемое в языке программирования); наращивание адреса в нем выполняет микропроцессор, учитывая при этом длину текущей команды. Команды переходов, прерываний, вызова подпрограмм и возврата из них изменяют содержимое IP, осуществляя тем самым переходы в требуемые точки программы. В следующем разделе мы еще вернемся к роли регистра IP в выполнении программы.
Регисдр флагов (его часто называют FLAGS), эквивалентный регистру состояния процессора других вычислительных систем, содержит информацию о текущем состоянии процессора (рис. 1.7). Он включает 6 флагов состояния и 3 бита управления состоянием процессора, которые, впрочем, тоже называются флагами.

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

Флаги состояния заново устанавливаются процессором после выполнения каждой очередной команды, и по ним можно в какой-то степени судить о результате выполнения этой команды (например, не равен ли ее результат, нулю). Флаги управления позволяют изменять некоторые условия работы процессора, например, разрешать или запрещать аппаратные прерывания. Рассмотрим сначала флаги состояния.
Флаг переноса CF (Carry Flag) индицирует перенос или заем при выполнении арифметических операций. Переносом называется ситуация, когда в результате выполнения правильной, в общем, команды образуется число, содержащее более 16 двоичных разрядов и, следовательно, не помещающееся в регистр или ячейку памяти. Пусть, например, в регистре АХ содержится число 60000, а в регистре ВХ — 40000. При выполнении команды сложения

в регистре-приемнике результата, которым в данном случае будет служить регистр АХ, должно быть записано число 100000, которое, разумеется, там поместиться не может. В этом случае и устанавливается флаг CF, по состоянию которого можно установить, что произошел перенос и, следовательно, содержимое АХ (которое в данном случае будет равно 100000 — 65536 = 34464) не является правильным результатом.
Необходимо подчеркнуть, что ситуация переноса, как и вообще любая ошибка, возникшая по ходу выполнения программы, не приводит ни к каким последствиям, кроме установки соответствующего флага. Процессор, установив флаг, считает свою миссию выполненной и переходит к выполнению следующей команды. Если перенос в данном случае действительно является индикатором ошибки, программа должна после выполнения команды сложения проанализировать состояние флага CF, и при установленном флаге перейти на фрагмент обработки этой ошибки. Такой анализ выполняется с помощью команд условного перехода, в данном случае с помощью команды jc (jump if carry, переход по переносу):

add AX.BX

jc error ;B случае переноса переход

;на метку

error ;

Нормальное продолжение

Сказанное справедливо по отношению ко всем ошибочным ситуациям, возникающим в программе, — программа сама обязана отлавливать все ошибки и выполнять предусмотренные для таких случаев действия. Единственное, что может сделать процессор — это сообщить программе о подозрительном результате установкой того или иного флага.
Флаг паритета PF (Parity Flag) устанавливается в 1, если результат операции содержит четное число двоичных единиц, и сбрасывается в О, если число двоичных единиц нечетно. Этот флаг можно использовать, например, для поиска ошибок при передаче данных и при выполнении диагностических тестов.
Флаг вспомогательного переноса AF (Auxiliary Flag) используется в операциях над двоично-десятичными числами. Он индицирует перенос или заем из старшей тетрады (бита 4). Двоично-десятичный формат подразумевает запись в каждой половинке байта десятичной цифры в виде ее двоичного эквивалента, что позволяет хранить в байте двухразрядное десятичное число в диапазоне от 0 до 99 Двоично-десятичные числа используются, в частности, для обмена данными с измерительными приборами. Для их обработки в процессоре предусмотрен целый ряд специфических команд, при использовании которых приходится анализировать состояние флага вспомогательного переноса.
Флаг нуля ZF (Zero Flag) устанавливается в 1, если результат операции равен 0. Например, флаг ZF установится, если из 5 вычесть 5 или к 10 прибавить -10.
Флаг знака SF (Sign Rag) показывает знак результата операции, устанавливаясь в 1 при отрицательном результате. Как будет показано в следующей главе, процессор различает числа без знака, т.е. существенно положительные, и числа со знаком, которые могут быть как положительными, так и отрицательными. Признаком отрицательности числа служит установленный старший бит этого числа (бит 15 для слов или бит 7 для байтов). Флаг SF устанавливается, если в результате какой-либо операции сформировано число с установленным старшим битом, например, S000h или FFFFh.
Флаг переполнения OF (Overflow Rag) фиксирует переполнение, т.е. выход результата за пределы допустимого диапазона значений для чисел со знаком. В знаковом представлении числа от 0000h до 7FFFh считаются положительными, а числа от S000h до FFFFh, т.е. числа с установленным старшим битом — отрицательными. Флаг OF устанавливается, если, например, при сложении двух положительных чисел получился результат, превышающий 7FFFh (потому что, начиная с S000h, идут уже отрицательные числа), или при вычитании из отрицательного числа получился результат, меньший S000h (потому что такие числа считаются положительными). Позже этот вопрос будет рассмотрен более детально.
Перейдем теперь к управляющим флагам, которых в регистре флагов реального режима всего три.
Управляющий флаг трассировки (ловушки) TF (Trace Rag) используется для осуществления пошагового выполнения программы. Если TF=1, то после выполнения каждой команды процессор реализует процедуру прерывания через вектор с номером 1, расположенный по физическому адресу 04. Этот флаг активно используется в программах отладчиков, которые должны допускать выполнение отлаживаемой программы по шагам или с точками останова.
Управляющий флаг разрешения прерываний IF (Interrupt Rag) разрешает (если равен 1) или запрещает (если равен 0) процессору реагировать на прерывания от внешних устройств. Тем самым создается возможность выполнения особо ответственных фрагментов программ без каких-либо помех.
Управляющий флаг направления DF (Direction Rag) используется командами обработки строк. Если DF=0, строка обрабатывается в прямом направлении, от меньших адресов к большим; если DF=1, обработка строки идет в обратном направлении. Примеры использования этого флага будут приведены при рассмотрении соответствующих команд процессора.
Для установки и сброса управляющих флагов предусмотрены особые команды, например sti (set interrupt, установить прерывания) или cli (clear interrupt, сбросить прерывания).

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

Начиная с модели 80386 процессоры Intel предоставляют 16 основных регистров для пользовательских программ и ещё 11 регистров для работы с мультимедийными приложениями (MMX) и числами с плавающей точкой (FPU/NPX). Все команды так или иначе изменяют содержимое регистров. Как уже говорилось, обращаться к регистрам быстрее и удобнее, чем к памяти. Поэтому при программировании на языке Ассемблера регистры используются очень широко.

В этом разделе мы рассмотрим основные регистры процессоров Intel. Названия и состав/количество регистров для других процессоров могут отличаться. Итак, основные регистры процессоров Intel.

Таблица 2.1. Основные регистры процессора.

Название Разрядность Основное назначение
EAX 32 Аккумулятор
EBX 32 База
ECX 32 Счётчик
EDX 32 Регистр данных
EBP 32 Указатель базы
ESP 32 Указатель стека
ESI 32 Индекс источника
EDI 32 Индекс приёмника
EFLAGS 32 Регистр флагов
EIP 32 Указатель инструкции (команды)
CS 16 Сегментный регистр
DS 16 Сегментный регистр
ES 16 Сегментный регистр
FS 16 Сегментный регистр
GS 16 Сегментный регистр
SS 16 Сегментный регистр

Регистры EAX, EBX, ECX, EDX – это регистры общего назначения. Они имеют определённое назначение (так уж сложилось исторически), однако в них можно хранить любую информацию.

Регистры EBP, ESP, ESI, EDI – это также регистры общего назначения. Они имеют уже более конкретное назначение. В них также можно хранить пользовательские данные, но делать это нужно уже более осторожно, чтобы не получить «неожиданный» результат.

Регистр флагов и сегментные регистры требуют отдельного описания и будут более подробно рассмотрены далее.

Пока для вас здесь слишком много непонятных слов, но со временем всё прояснится)))

Когда-то процессоры были 16-разрядными, и, соответственно, все их регистры были также 16-разрядными. Для совместимости со старыми программами, а также для удобства программирования некоторые регистры разделены на 2 или 4 «маленьких» регистра, у каждого из которых есть свои имена. В таблице 2.2 перечислены такие регистры.

Вот пример такого регистра.

Структура регистра EAX

Из этого следует, что вы можете написать в своей программе, например, такие команды:

MOV AX, 1 MOV EAX, 1

Обе команды поместят в регистр AX число 1. Разница будет заключаться только в том, что вторая команда обнулит старшие разряды регистра EAX, то есть после выполнения второй команды в регистре EAX будет число 1. А первая команда оставит в старших разрядах регистра EAX старые данные. И если там были данные, отличные от нуля, то после выполнения первой команды в регистре EAX будет какое-то число, но не 1. А вот в регистре AX будет число 1. Сложно? Ну это пока… Со временем вы к таким вещам привыкните.

Мы пока не говорили о разрядах (битах). Эту тему мы обсудим в разделах, посвящённых системам счисления. А сейчас пока вам достаточно знать, что нулевой разряд (бит) – это младший бит. Он крайний справа. Старший бит – крайний слева. Номер старшего бита зависит от разрядности числа/регистра. Например, в 32-разрядном регистре старшим битом является 31-й бит (потому что отсчёт начинается с 0, а не с 1).

Ниже приведён список регистров общего назначения, которые можно поделить описанным выше способом и при этом к «половинкам» и «четвертинкам» этих регистров можно обращаться в программе как к отдельному регистру.

Таблица 2.2. «Делимые» регистры..

Регистр Старшие разряды Имена 16-ти и 8-ми битных регистров
31…16 15…8 7…0
EAX . AX
AH AL
EBX . BX
BH BL
ECX . CX
CH CL
EDX . DX
DH DL
ESI . SI
EDI . DI
EBP . BP
ESP . SP
EIP . IP

На этом мы закончим наше краткое знакомство с регистрами. Если вам пока не всё понятно – просто прочитайте этот раздел, чтобы более-менее представлять себе, что такое регистры. По мере приобретения новых знаний вы можете вернуться к этому разделу и уже на новом уровне воспринять эту информацию. А в следующем разделе мы коротко опишем процесс выполнения команды.

Регистры

Регистр — это определенный участок памяти внутри самого процессора, от 8-ми до 32-х бит длиной, который используется для промежуточного хранения информации, обрабатываемой процессором. Некоторые регистры содержат только определенную информацию.

Регистры общего назначения — EAX, EBX, ECX, EDX. Они 32-х битные и делятся еще на две части, нижние из которых AX, BX, CD, DX — 16-ти битные, и деляется еще на два 8-ми битных регистра. Так, АХ делится на AH и AL, DX на DH и DL и т.д. Буква «Н» означает верхний регистр.

Так, AH и AL каждый по одному байту, АХ — 2 байта (или word — слово), ЕАХ — 4 байта (или dword — двойное слово). Эти регистры используются для операций с данными, такими, как сравнение, математические операции или запись данных в память.

Регистр СХ чаще всего используется как счетчик в циклах.

АН в DOS программах используется как определитель, какой сервис будет использоваться при вызове INT.

Регистры сегментов — это CS, DS, ES, FS, GS, SS. Эти регистры 16-ти битные, и содержат в себе первую половину адреса «оффсет:сегмент».

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

Регистры оффсета — EIP, ESP, EBP, ESI, EDI. Эти регистры 32-х битные, нижняя половина которых доступна как регистры IP, SP, BP, SI, DI.

  • EIP — указатель команд, и содержит оффсет (величину смещения относительно начала программы) на линию кода, которая будет исполняться следующей. То есть полный адрес на следующую исполняемую линию кода будет CS:ЕIP.
  • Регистр ESP указывает на адрес вершины стека (адрес, куда будет заноситься следующая переменная командой PUSH).
  • Регистр ЕВР содержит адрес, начиная с которого в стек вносится или забирается информация (или «глубина» стека). Параметры функций имеют положительный сдвиг относительно ЕВР, локальные переменные — отрицательный сдвиг, а полный адрес этого участка памяти будет SS:EBP.
  • Регистр ESI — адрес источника, и содержит адрес начала блока информации для операции «переместить блок» (полный адрес DS:SI), а регистр EDI- адрес назначения в этой операции (полный адрес ES:EDI).

Регистры управления — CR0, CR1, CR2, CR3. Эти 32-х битные регистры устанавливают режим работы процессора (нормальный, защищенный и т.д.), постраничное распределение памяти и т.д. Они доступны только для программ в первом кольце памяти (Kernel, например). Трогать их не следует.

Регистры дебаггера — DR0, DR1, DR2, DR3, DR4, DR5, DR6, DR7. Первые четыре регистра содержат адреса на точки прерывания, остальные устанавливают, что должно произойти при достижении точки прерывания.

Контрольные регистры — TR6, TR7. Используются для контроля постраничной системы распределения памяти операционной системой. Нужны только если вы собираетесь написать свою ОС.

Что такое регистр в программировании

Ключевую роль в обработке данных в процессоре играют специальные ячейки, известные как регистры . Регистры в процессоре x86-64 можно разделить на четыре категории: регистры общего назначения, специальные регистры для приложений, сегментные регистры и специальные регистры режима ядра. Здесь нас будут интересовать прежде всего регистры общего назначения (general-purpose registers), которые в основном и используются в приложениях на ассемблере.

Начнем с того, что процессор архитектуры x86 имел восемь 32-битных регистров общего назначения, регистр флагов и указатель инструкций. Регистры общего назначения:

  • EAX (Accumulator): для арифметических операций
  • ECX (Counter): для хранения счетчика цикла
  • EDX (Data): для арифметических операций и операций ввода-вывода
  • EBX (Base): указатель на данные
  • ESP (Stack pointer): указатель на верхушку стека
  • EBP (Base pointer): указатель на базу стека внутри функции
  • ESI (Source index): указатель на источник при операциях с массивом
  • EDI (Destination index): указатель на место назначения в операциях с массивами
  • EIP : указатель адреса следующей инструкции для выполнения
  • EFLAGS : регистр флагов, содержит биты состояния процессора

Можно получить доступ к частям 32-битных регистров с меньшей разрядностью. Например, младшие 16 бит 32-битного регистра EAX обозначаются как AX. К регистру AX можно обращаться как к отдельным байтам, используя имена AH (старший байт) и AL (младший байт).

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

В архитектуре х64 эти регистры были расширены до 64 бит, а новые расширенные регистры получили имена, которые начинаются с буквы R , например, RAX , RBX и т.д. Кроме того, были добавлены 8 новых 64-битных регистров R8 — R15

Регистры в архитектуре х64

Для обращения к 32-, 16- и 8-битной части 64-разрядных регистров используются стандартные для архитектуры x86 имена регистров. Для доступа к подрегистрам новых 64-битных регистров R8 — R15 применяется соответствующий суффикс:

  • D : для получения младших 32 бит регистра, например, R11D
  • W : для получения младших 16 бит регистра, например, R11W
  • B : для получения младших 8 бит регистра, например, R11B

Таким образом, в архитектуре x86-64 мы можем использовать следующие регистры общего пользования:

  • Шестнадцать 64-разрядных регистров RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, R8, R9, R10, R11, R12, R13, R14 и R15
  • Шестнадцать 32-разрядных регистров EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, R8D, R9D, R10D, R11D, R12D, R13D, R14D и R15D
  • Шестнадцать 16-разрядных регистров AX, BX, CX, DX, SI, DI, BP, SP, R8W, R9W, R10W, R11W, R12W, R13W, R14W и R15W
  • Шестнадцать 8-разрядных регистров AL, AH, BL, BH, CL, CH, DL, DH, DIL, SIL, BPL, SPL, R8B, R9B, R10B, R11B, R12B, R13B, R14B и R15B

Например, запись в часть 64-битного регистра, например в регистр AL, влияет только на биты этой части. В случае AL загрузка 8-битного значения изменяет младшие 8 битов RAX, оставляя остальные 48 бит без изменений.

Хотя эти регистры и называются общего назначения, но это не значит, что их можно использовать для любых целей. Все регистры x86-64 имеют свое особое назначение, которое ограничивает их использование в определенных контекстах.

Регистр флагов RFLAGS, содержит биты состояния процессора:

Флаг переноса (Carry flag):казывает, был ли при сложении перенос или заимствование при вычитании. Используется в качестве входных данных для инструкций сложения и вычитания.

Флаг четности: устанавливается, если младшие 8 битов результата содержат четное число единиц.

Флаг настройки: указывает, был ли при сложении перенос или заимствование при вычитании младших 4 битов.

Флаг нуля (Zero flag): устанавливается, если результат операции равен нулю

Флаг знака (Sign flag): устанавливается, если результат операции отрицательный.

Флаг прерывания выполнения (Trap flag): используется при одношаговой отладке.

Флаг разрешения прерывания: установка этого бита разрешает аппаратные прерывания.

Флаг направления: контролирует направление обработки. Если не установлен, то порядок от самого младшего до самого старшего адреса. Если установлен, то порядок обратный — от самого старшего до самого младшего адреса.

Флаг переполнения (Overflow flag): если устанавлен, то операция привела к переполнению со знаком.

Уровень привилегий ввода-вывода (I/O privilege level): уровень привилегий текущего выполняемого потока. IOPL 0 — это режим ядра, а 3 — пользовательский режим.

Флаг вложенной задачи (Nested task flag): управляет цепочкой прерываний.

Флаг возобновления (Resume flag): используется для обработки исключений во время отладки.

Флаг режима виртуальной машины 8086: если установлен, режим совместимости с 8086 активен. Этот режим позволяет запускать некоторые приложения MS-DOS в контексте операционной системы в защищенном режиме.

Флаг проверки выравнивания (Alignment check flag): если установлен, проверка выравнивания памяти активна. Например, если установлен флаг AC, сохранение 16-битного значения по нечетному адресу вызывает исключение проверки выравнивания. Процессоры x86 могут выполнять невыровненный доступ к памяти, когда этот флаг не установлен, но количество требуемых командных циклов может увеличиться.

Флаг виртуального прерывания (Virtual interrupt flag): виртуальная версия флага IF в виртуальном режиме 8086..

Флаг ожидания виртуального прерывания: Устанавливается, когда прерывание находится в состоянии ожидания в виртуальном режиме 8086.

Флаг ID: если этот бит установлен, то поддерживается инструкция cpuid. Эта инструкция возвращает идентификатор процессора и информацию о его функциях.

Основными являются флаги переноса, нуля, знака и переполнения, которые называют флагами состояния. Как видно, не все биты из 64-х разрядного регистра флагов имеют назначение. Неуказанные биты не используются.

В дополнение к регистрам общего назначения x86-64 предоставляет регистры специального назначения, в том числе восемь регистров для работы с числами с плавающей точкой, реализованных в модуле x87 с плавающей точкой (floating-point unit или FPU). Intel назвала эти регистры ST0 — ST7. Каждый регистр с плавающей точкой имеет ширину 80 бит. В отличие от регистров общего назначения обычная пользовательская программа не может получить к ним прямой доступ.

Также есть шестнадцать 128-битных регистров XMM (XMM0 — XMM15) и набор инструкций SSE/SSE2. Каждый регистр можно настроить как четыре 32-битных регистра с плавающей точкой; два 64-битных регистра двойной точности с плавающей точкой; или шестнадцать 8-битных, восемь 16-битных, четыре 32-битных, два 64-битных или один 128-битный целочисленный регистр. В более поздних вариантах семейства процессоров x86-64 AMD/Intel удвоили размер регистров до 256 бит каждый (переименовав их в YMM0-YMM15), добавив поддержки восьми 32-битных значений с плавающей точкой или четырех 64-битных значений с плавающей точкой двойной точности. (целочисленные операции по-прежнему ограничивались 128 битами).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *