Двоичное кодирование информации

Любая информация внутри компьютера хранится и обрабатывается в виде длинного кода, состоящего всего из двух символов. Этот код называется двоичным или бинарным.
По своей сути он очень похож на всем известный код Морзе, в котором двумя символами (длинный и короткий импульс) шифруются буквы для передачи текстовой информации по проводам или другим способом.
Компьютеры же пошли значительно дальше. В них в форме бинарного кода хранятся не только текстовые данные, но и программы, музыка, изображения и даже видео высокой четкости.
Перед выводом информации на экран, в аудиосистему или распечатыванием, компьютер «переводит» ее в понятный человеку язык. Но внутри компьютера она хранится и обрабатывается исключительно в виде двоичного кода.
Если вы не программист, знать систему использования бинарного кода в совершенстве не обязательно. Для понимания принципов работы компьютера достаточно разобраться с вопросом в общих чертах. В этом вам и поможет предлагаемая статья.
Почему в компьютере используется двоичный код
Люди для записи текстовой информации используют буквы. В русском языке их 33. Комбинациями из десяти цифр (от 0 до 9) мы записываем числовые данные. При работе с графической информацией пользуемся палитрой из миллионов цветов. Наши уши различают звуки в диапазоне от 16 до 20000 Гц.
Если добавить к этому обоняние, вкусовые и тактильные ощущения, получится огромнейшее разнообразие информационных импульсов, которые может воспринимать, хранить и обрабатывать наш мозг.
При помощи технических средств невозможно воссоздать аналогичную систему работы с информацией.
Людям проще всего создавать приборы, принимающие одно из двух состояний: лампочка горит или нет, магнитное поле есть или его нет и т.д. И значительно сложнее, например, заставить лампочку в разных ситуациях светиться одним из 10 цветов. Не говоря уже о 10 миллионах цветов, воспринимаемых человеком.
В технике намного удобнее иметь дело с множеством простых элементов, чем с небольшим количеством сложных.
Чтобы иметь возможность хранить и обрабатывать информацию техническими средствами, люди решили переводить ее на максимально простой «язык», состоящий всего из двух «букв» – так называемый двоичный или бинарный код.

Идея использования бинарного кода принадлежит немецкому математику Готфриду Лейбницу (1646 — 1716).
Он разработал двоичную арифметику и даже сделал чертеж двоичной вычислительной машины, но не сумел ее построить.
Используя разные комбинации большого количества двух символов, в бинарном коде можно зашифровать любую числовую, текстовую, звуковую или графическую информацию.
Компьютер же является ничем иным, как машиной, предназначенной для хранения и обработки информации в таком виде.
Перевод данных в двоичный код называется кодированием.
Противоположный процесс, в результате которого бинарный код превращается в привычную для людей информацию, называется декодированием.
Компьютер осуществляет кодирование «на лету» при получении данных извне: ввод текста пользователем с клавиатуры, запись видео с веб-камеры, запись звука с микрофона и т.д.
Перед выводом информации на экран, в аудиосистему или же ее распечатыванием, происходит обратный процесс (декодирование).
Как осуществляется кодирование различных типов данных, рассмотрим немного ниже. Сначала давайте разберемся, из каких же символов формируется двоичный код внутри компьютера и как он там хранится.
С технической стороны компьютерный двоичный код реализуется наличием или отсутствием определенных свойств (импульсов) у мельчайших запоминающих элементов. Эти импульсы могут быть:

• фотооптическими
Так, поверхность любого оптического диска (CD, DVD или BluRay) состоит из спирали, которую формируют мелкие отрезки. Каждый из них может быть либо темного, либо светлого цвета. Диск быстро вращается в дисководе. На его спиральной дорожке фокусируется лазер, отражение которого попадает на фотоэлемент. Темные участки спирали поглощают свет и не передают его на фотоэлемент, светлые – наоборот, отражая свет, передают импульс фотоэлементу. В результате фотоэлемент получает информацию, зашифрованную в дорожке диска в виде темных и светлых точек.
• магнитными
Например, внутри жесткого диска находится быстро вращающаяся пластина. Вся ее поверхность тоже представляет собой спираль, состоящую из последовательности миллионов мелких участков. Каждый из них является элементом, который может принимать одно из двух состояний: «намагниченное», «ненамагниченное». Эти элементы и формируют двоичный код, в котором кодируется какая-то информация. Считывание состояния элементов осуществляется специальной головкой, которая быстро движется по поверхности пластины;
• электрическими
Например, оперативная память компьютера является микросхемой, состоящей из миллионов маленьких ячеек, созданных из микроскопических транзисторов и конденсаторов. Каждая такая ячейка может либо содержать электрический заряд, либо нет. Комбинации заряженных и разряженных ячеек оперативной памяти и формируют в ней двоичный код.
В аналогичной форме информация хранится и во всех других запоминающих микросхемах (флешки, SSD-носители и др.).
Процессор компьютера обрабатывает двоичный код тоже в виде электрических импульсов.
Иногда можно встретить ошибочное мнение, что бинарный код внутри компьютера записан в виде обычных нулей и единиц. Это следствие непонимания технической стороны вопроса. Привычных для нас нулей и единиц в компьютере нет. «Символами» компьютерного двоичного кода является наличие или отсутствие у мельчайшего запоминающего элемента определенного свойства (см. выше).
Чтобы было нагляднее, в учебных материалах отсутствие у элемента такого свойства лишь условно обозначают нулем, а его наличие – единицей. Но с таким же успехом их можно бы было обозначать точкой и тире или крестиком и ноликом.
Единицы компьютерной информации
В предыдущем пункте уже говорилось о том, что бинарный код внутри компьютера хранится в виде комбинаций большого количества элементов, каждый из которых может иметь одно из двух состояний.
Такой мельчайший элемент, участвующий в формировании бинарного кода, называется битом.
Битом является, например, каждая темная или светлая точка дорожки оптического диска, каждая запоминающая ячейка оперативной памяти компьютера и т.д.
Чем больше битов содержит какой-то носитель, тем больше информации на нем можно закодировать. К примеру, оптический диск типа «CD» может содержать около 6 млрд. битов. Жесткий диск — в десятки раз больше.
Но каждый отдельный бит сам по себе не имеет практической ценности. Для кодирования информации используются блоки из нескольких битов.
Представим, например, что в каком-то запоминающем устройстве содержится только один бит. В нем можно будет закодировать всего одно из двух состояний чего либо, например, одну из двух цифр или один из двух цветов. Понятное дело, что практическая ценность такого носителя минимальна.
Блок из 2 битов может принимать одно из 4 состояний:

В 3-хбитном блоке можно закодировать уже одно из 8 состояний:

Ну а 8-битный блок может принимать аж 256 разных состояний. Это уже достаточно существенная частичка двоичного кода, позволяющая отобразить один из значительного количества вариантов.
Например, каждому состоянию 8-битного блока можно сопоставить какую-то букву. Вариантов, а их 256, будет достаточно для кодирования всех русских букв, включая строчные и прописные их варианты, а также всех знаков препинания. Заменяя каждую букву соответствующим 8-мибитным блоком, из двоичного кода можно составить текст.
Этот принцип и используется для записи в компьютере текстовой информации (подробнее речь об этом пойдет ниже).
Как видите, 8-битная ячейка имеет вполне реальную практическую ценность. Поэтому ее и решили считать минимальной единицей компьютерной информации. Эта единица получила название байт.
Текстовые файлы состоят из сотен, тысяч или даже десятков тысяч букв. Соответственно, для их хранения в двоичном коде требуются сотни, тысячи или десятки тысяч байтов.
Поэтому на практике гораздо чаще приходится имеет дело не с байтами, а с более крупными единицами:
• килобайтами (1 килобайт = 1024 байт);
• мегабайтами (1 мегабайт = 1024 килобайт);
• гигабайтами (1 гигабайт = 1024 мегабайт);
• терабайтами (1 терабайт = 1024 гигабайт).
Кодирование числовой информации
Для работы с числовой информацией мы пользуемся системой счисления, содержащей десять цифр: 0 1 2 3 4 5 6 7 8 9. Эта система называется десятичной.
Кроме цифр, в десятичной системе большое значение имеют разряды. Подсчитывая количество чего-нибудь и дойдя до самой большой из доступных нам цифр (до 9), мы вводим второй разряд и дальше каждое последующее число формируем из двух цифр. Дойдя до 99, мы вынуждены вводить третий разряд. В пределах трех разрядов мы можем досчитать уже до 999 и т.д.
Таким образом, используя всего десять цифр и вводя дополнительные разряды, мы можем записывать и проводить математические операции с любыми, даже самыми большими числами.
Компьютер ведет подсчет аналогичным образом, но имеет в своем распоряжении всего две цифры — логический ноль (отсутствие у бита какого-то свойства) и логическая единица (наличие у бита этого свойства).
Система счисления, использующая только две цифры, называется двоичной.
При подсчете в двоичной системе добавлять каждый следующий разряд приходится гораздо чаще, чем в десятичной.
Вот таблица первых десяти чисел в каждой из этих систем счисления:

Как видите, в десятичной системе счисления для отображения любой из первых десяти цифр достаточно 1 разряда. В двоичной системе для тех же целей потребуется уже 4 разряда.
Соответственно, для кодирования этой же информации в виде двоичного кода нужен носитель емкостью как минимум 4 бита (0,5 байта).
Человеческий мозг, привыкший к десятичной системе счисления, плохо воспринимает систему двоичную. Хотя обе они построены на одинаковых принципах и отличаются лишь количеством используемых цифр. В двоичной системе точно так же можно осуществлять любые арифметические операции с любыми числами. Главный ее минус — необходимость иметь дело с большим количеством разрядов.
Так, самое большое десятичное число, которое можно отобразить в 8 разрядах двоичной системы — 255, в 16 разрядах – 65535, в 24 разрядах – 16777215.
Компьютер, кодируя числа в двоичный код, основывается на двоичной системе счисления. Но, в зависимости от особенностей чисел, может использовать разные алгоритмы:
• небольшие целые числа без знака
Для сохранения каждого такого числа на запоминающем устройстве, как правило, выделяется 1 байт (8 битов). Запись осуществляется в полной аналогии с двоичной системой счисления.
Целые десятичные числа без знака, сохраненные на носителе в двоичном коде, будут выглядеть примерно так:

• большие целые числа и числа со знаком
Для записи каждого такого числа на запоминающем устройстве, как правило, отводится 2-байтний блок (16 битов).
Старший бит блока (тот, что крайний слева) отводится под запись знака числа и в кодировании самого числа не участвует. Если число со знаком «плюс», этот бит остается пустым, если со знаком «минус» – в него записывается логическая единица. Число же кодируется в оставшихся 15 битах.
Например, алгоритм кодирования числа +2676 будет следующим:
1. Перевести число 2676 из десятичной системы счисления в двоичную. В итоге получится 101001110100;
2. Записать полученное двоичное число в первые 15 бит 16-битного блока (начиная с правого края). Последний, 16-й бит, должен остаться пустым, поскольку кодируемое число имеет знак +.
В итоге +2676 в двоичном коде на запоминающем устройстве будет выглядеть так:

Примечательно, что в двоичном коде присвоение числу отрицательного значения предусматривает не только изменение старшего бита. Осуществляется также инвертирование всех остальных его битов.
Чтобы было понятно, рассмотрим алгоритм кодирования числа -2676:
1. Перевести число 2676 из десятичной системы счисления в двоичную. Получим все тоже двоичное число 101001110100;
2. Записать полученное двоичное число в первые 15 бит 16-битного блока. Затем инвертировать, то есть, изменить на противоположное, значение каждого из 15 битов;
3. Записать в 16-й бит логическую единицу, поскольку кодируемое число имеет отрицательное значение.
В итоге -2676 на запоминающем устройстве в двоичном коде будет иметь следующий вид:

Запись отрицательных чисел в инвертированной форме позволяет заменить все операции вычитания, в которых они участвуют, операциями сложения. Это необходимо для нормальной работы компьютерного процессора.
Максимальным десятичным числом, которое можно закодировать в 15 битах запоминающего устройства, является 32767. Иногда для записи чисел по этому алгоритму выделяются 4-байтные блоки. В таком случае для кодирования каждого числа будет использоваться 31 бит плюс 1 бит для кодирования знака числа. Тогда максимальным десятичным числом, сохраняемым в каждую ячейку, будет 2147483647 (со знаком плюс или минус).
• дробные числа со знаком
Дробные числа на запоминающем устройстве в двоичном коде кодируются в виде так называемых чисел с плавающей запятой (точкой). Алгоритм их кодирования сложнее, чем рассмотренные выше. Тем не менее, попытаемся разобраться.
Для записи каждого числа с плавающей запятой компьютер чаще всего выделяет 4-байтную ячейку (32 бита):
• в старшем бите этой ячейки (тот, что крайний слева) записывается знак числа. Если число отрицательное, в этот бит записывается логическая единица, если оно со знаком «плюс» – бит остается пустым.
• во втором слева бите аналогичным образом записывается знак порядка (что такое порядок поймете позже);
• в следующих за ним 7 битах записывается значение порядка.
• в оставшихся 23 битах записывается так называемая мантисса числа.

Чтобы стало понятно, что такое порядок, мантисса и зачем они нужны, переведем в двоичный код десятичное число 6,25.
Порядок кодирования будет примерно следующим:
1. Перевести десятичное число в двоичное (десятичное 6,25 равно двоичному 110,01);
2. Определить мантиссу числа. Для этого в числе необходимо передвинуть запятую в нужном направлении, чтобы слева от нее не осталось ни одной единицы. В нашем случае запятую придется передвинуть на три знака влево. В итоге, получим мантиссу ,11001;
3. Определить значение и знак порядка.
Значение порядка – это количество символов, на которое была сдвинута запятая для получения мантиссы. В нашем случае оно равно 3 (или 11 в двоичной форме);
Знак порядка – это направление, в котором пришлось двигать запятую: влево – «плюс», вправо – «минус». В нашем примере запятая двигалась влево, поэтому знак порядка – «плюс»;
Таким образом, порядок двоичного числа 110,01 будет равен +11, а его мантисса ,11001. В результате в двоичном коде на запоминающем устройстве это число будет записано следующим образом

Обратите внимание, что мантисса в двоичном коде записывается, начиная с первого после запятой знака, а сама запятая упускается.
Числа с плавающей запятой, кодируемые в 32 битах, называю числами одинарной точности.
Когда для записи числа 32-битной ячейки недостаточно, компьютер может использовать ячейку из 64 битов. Число с плавающей запятой, закодированное в такой ячейке, называется числом двойной точности.
Двоичное кодирование текстовой информации
Существует несколько общепринятых стандартов кодирования текста в двоичном коде.
Одним из наиболее «старых» (разработан еще в 1960-х гг.) является стандарт ASCII (от англ. American Standard Code for Information Interchange). Это 7-битный стандарт кодирования. То есть, используя его, компьютер записывает каждую букву или знак в одну 7-битную ячейку запоминающего устройства.
Как известно, ячейка из 7 битов может принимать 128 различных состояний. Соответственно, в стандарте ASCII каждому из этих 128 состояний соответствует какая-то буква, знак препинания или специальный символ.
Дальнейшее развитие компьютерной техники показало, что 7-битный стандарт кодирования является слишком «тесным». В 128 состояниях, принимаемых 7-битной ячейкой, невозможно закодировать буквы всех существующих в мире письменностей.
Поэтому разработчики программного обеспечения начали создавать собственные 8-битные стандарты кодировки текста. За счет дополнительного бита диапазон кодирования в них был расширен до 256 символов. Чтобы не было путаницы, первые 128 символов в таких кодировках, как правило, соответствуют стандарту ASCII. Оставшиеся 128 — реализуют региональные языковые особенности.
Восьмибитными кодировками, распространенными в нашей стране, являются KOI8, UTF8, Windows-1251 и некоторые другие.
Разработаны также и универсальные стандарты кодирования текста (Unicode), включающие буквы большинства существующих языков. В них для записи одного символа может использоваться до 16 битов и даже больше.
Существование большого количества кодировок текста является причиной многих проблем. Вы, наверное, уже встречались с ситуацией, когда в некоторых программах на экране вместо букв отображаются непонятные «кракозябры». Это потому, что компьютер иногда «ошибается» и неверно определяет кодировку, в которой этот текст хранится в его памяти.
В перспективе, вероятно, будет принят единый стандарт кодирования текста, полностью учитывающий разнообразие существующих письменностей, на который постепенно перейдут все компьютеры, независимо от локации и используемого программного обеспечения. Но произойдет это, судя по всему, не скоро.
Кодирование изображений в двоичный код
Чтобы сохранить в двоичном коде фотографию, ее сначала виртуально разделяю на множество мелких цветных точек, называемых пикселями (что-то на подобии мозаики).
После разбивки на точки цвет каждого пикселя кодируется в бинарный код и записывается на запоминающем устройстве.

Первая цифровая фотокамера, созданная в 1975 г. инженерами компании Kodak, весила 3 кг, делала черно-белые снимки размером 100Х100 пикселей и сохраняла их в двоичном коде на магнитную ленту.
Запись одного снимка длилась дольше 20 секунд.
Если говорят, что размер изображения составляет, например, 512 х 512 точек, это значит, что оно представляет собой матрицу, сформированную из 262144 пикселей (количество пикселей по вертикали, умноженное на количество пикселей по горизонтали).
Прибором, «разбивающим» изображения на пиксели, является любая современная фотокамера (в том числе веб-камера, камера телефона) или сканер.
И если в характеристиках камеры значится, например, «10 Mega Pixels», значит количество пикселей, на которые эта камера разбивает изображение для записи в двоичном коде, — 10 миллионов.
Чем на большее количество пикселей разделено изображение, тем реалистичнее выглядит фотография в декодированном виде (на мониторе или после распечатывания).
Однако качество кодирования фотографий в бинарный код зависит не только от количества пикселей, но также и от их цветового разнообразия.
Алгоритмов записи цвета в двоичном коде существует несколько. Самым распространенным из них является RGB. Эта аббревиатура – первые буквы названий трех основных цветов: красного – англ.Red, зеленого – англ. Green, синего – англ. Blue.
Из школьных уроков рисования, Вам, наверное, известно, что смешивая эти три цвета в разных пропорциях, можно получить любой другой цвет или оттенок.
На этом и построен алгоритм RGB. Каждый пиксель записывается в двоичном коде путем указания количества красного, зеленого и синего цвета, участвующего в его формировании.
Чем больше битов выделяется для кодирования пикселя, тем больше вариантов смешивания этих трех каналов можно использовать и тем значительнее будет цветовая насыщенность изображения.
Цветовое разнообразие пикселей, из которых состоит изображение, называется глубиной цвета.
Если для кодирования каждого пикселя какого-то изображения выделяется 8 битов двоичного кода, цветовое разнообразие составит 256 цветов.
Глубина цвета 12-битов даст 4096 цветов, 16-битов — 65536 цветов, 18-битов — 262144 цветов.
Максимальная глубина цвета, используемая в компьютерной технике — 24 бита. Такую глубину часто называют True Color («Настоящий цвет»). Она позволяет отобразить около 16,7 млн. цветов. Глаз человека не способен воспринимать большее их количество.
Тем не менее, часто встречается и так называемая 32-битная глубина цвета. Она не предусматривает увеличение количества оттенков. Дополнительные биты, выделяемые для кодирования каждого пикселя, предназначены для регулирования степени его прозрачности или же не используются.
Описанная выше техника формирования изображений из мелких точек является наиболее распространенной и называется растровой. Но кроме растровой графики, в компьютерах используется еще и так называемая векторная графика.
Векторные изображения создаются только при помощи компьютера (фотокамеры этого делать «не умеют») и формируются не из пикселей, а из графических примитивов (линий, многоугольников, окружностей и др.).
Зачем нужна векторная графика? В известной детской песенке поется, что для изображения «человечка» достаточно нарисовать всего две «палки» и «огуречек». А представьте, насколько трудно вручную составить человечка из большого числа точек.
Векторная графика — это чертежная графика. Она очень удобна для компьютерного «рисования» и широко используются дизайнерами при графическом оформлении печатной продукции, в том числе создании огромных рекламных плакатов, а также в других подобных ситуациях.
Векторное изображение в двоичном коде записывается как совокупность примитивов с указанием их размеров, цвета заливки, места расположения на холсте и некоторых других свойств.
Например, чтобы записать на запоминающем устройстве векторное изображение круга, компьютеру достаточно в двоичный код закодировать тип объекта (окружность), координаты его центра на холсте, длину радиуса, толщину и цвет линии, цвет заливки.
В растровой системе пришлось бы кодировать цвет каждого пикселя. И если размер изображения большой, для его хранения понадобилось бы значительно больше места на запоминающем устройстве.
Тем не менее, векторный способ кодирования не позволяет записывать в двоичном коде реалистичные фото. Поэтому все фотокамеры работают только по принципу растровой графики. Рядовому пользователю иметь дело с векторной графикой в повседневной жизни приходится не часто.
Кодирование звуковой информации
Любой звук, слышимый человеком, является колебанием воздуха, которое характеризируется двумя основными показателями: частотой и амплитудой.
Амплитуда колебаний — это степень отклонения состояния воздуха от начального при каждом колебании. Она воспринимается нами как громкость звука.
Частота колебаний — это количество отклонений состояний воздуха от начального за единицу времени. Она воспринимается как высота звука.
Так, тихий комариный писк — это звук с высокой частотой, но с небольшой амплитудой. Звук грозы наоборот имеет большую амплитуду, но низкую частоту.
Если графически изобразить звуковую волну, она будет выглядеть следующим образом:

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

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

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

Описанный принцип разделения звуковой волны на мелкие участки и лежит в основе двоичного кодирования звука.
Аудиокарта компьютера разделяет звук на очень мелкие временные участки и кодирует степень интенсивности каждого из них в двоичный код. Такое «дробление» звука на части называется дискретизацией. Чем выше частота дискретизации, тем точнее фиксируется геометрия звуковой волны и тем качественней получается запись.
Так, простая речь (например, диктофонная запись) нормально воспринимается человеком, если частота дискретизации при кодировании была не ниже 8000 Гц (8 КГц). То есть, каждая секунда такой записи в двоичном коде должна состоять как минимум из 8000 частей.
Музыкальные же произведения, хранимые в компьютере, должны иметь еще более высокую частоту дискретизации. При записи стандартных звуковых CD она составляет минимум 44,1 КГц (44100 Гц).
Качество записи сильно зависит также от количества битов, используемых компьютером для кодирования каждого участка звука, полученного в результате дискретизации.
Представим, например, что для кодирования каждого такого участка компьютер использует 8 битов. Как известно, 8-битная ячейка может принимать одно из 256 значений. Но вдруг разнообразие интенсивности участков, полученных при дискретизации какого-то звука, оказалось более широким (например, 512 вариантов). В таком случае, компьютер «округлит» интенсивность участков до ближайших доступных значений чтобы «уложиться» в 256 вариантов и качество записи получится низким.
Количество битов, используемых для кодирования каждого участка звука, полученного при дискретизации, называется глубиной звука.
Глубины звука в 8-битов достаточно для кодирования простой речи. Но музыкальные произведения с такой глубиной будут звучать отвратительно. Поэтому гораздо чаще встречаются звуковые файлы, закодированные с глубиной 16, 24 или даже 32 бита.
Следует учитывать, что далеко не все устройства, предназначенные для воспроизведения «цифрового» звука, могут работать с файлами, закодированными с высокой частотой дискретизации и/или большой глубиной звука. Такие файлы могут проигрываться на одном компьютере, и «не открываться» на другом (если звуковая карта не поддерживает настолько высокий уровень дискретизации или глубины звука).
Особенности бинарного кодирования видео
Видеозапись состоит из двух компонентов: звукового и графического.
Кодирование звуковой дорожки видеофайла в двоичный код осуществляется по тем же алгоритмам, что и кодирование обычных звуковых данных (см. предыдущий пункт).
Принципы кодирования видеоизображения схожи с кодированием растровой графики (рассмотрено выше), хотя и имеют некоторые особенности.
Как известно, видеозапись — это последовательность быстро меняющихся статических изображений (кадров). Одна секунда видео может состоять из 25 и больше картинок. При этом, каждый следующий кадр лишь незначительно отличается от предыдущего.
Учитывая эту особенность, алгоритмы кодирования видео, как правило, предусматривают запись лишь первого (базового) кадра. Каждый же последующий кадр формируются путем записи его отличий от предыдущего.
ПОДЕЛИТЬСЯ:

НАПИСАТЬ АВТОРУ
1. Регистры
Регистры – это специальные ячейки памяти, расположенные непосредственно в процессоре. Работа с регистрами выполняется намного быстрее, чем с ячейками оперативной памяти, поэтому регистры активно используются как в программах на языке ассемблера, так и компиляторами языков высокого уровня.
Регистры можно разделить на регистры общего назначения, указатель команд, регистр флагов и сегментные регистры.
1.1. Регистры общего назначения
К регистрам общего назначения относится группа из 8 регистров, которые можно использовать в программе на языке ассемблера. Все регистры имеют размер 32 бита и могут быть разделены на 2 или более частей.
Как видно из рисунка, регистры ESI, EDI, ESP и EBP позволяют обращаться к младшим 16 битам по именам SI, DI, SP и BP соответственно, а регистры EAX, EBX, ECX и EDX позволяют обращаться как к младшим 16 битам (по именам AX, BX, CX и DX), так и к двум младшим байтам по отдельности (по именам AH/AL, BH/BL, CH/CL и DH/DL).
- EAX/AX/AH/AL (accumulator register) – аккумулятор;
- EBX/BX/BH/BL (base register) –регистр базы;
- ECX/CX/CH/CL (counter register) – счётчик;
- EDX/DX/DH/DL (data register) – регистр данных;
- ESI/SI (source index register) – индекс источника;
- EDI/DI (destination index register) – индекс приёмника (получателя);
- ESP/SP (stack pointer register) – регистр указателя стека;
- EBP/BP (base pointer register) – регистр указателя базы кадра стека.
Несмотря на существующую специализацию, все регистры можно использовать в любых машинных операциях. Однако надо учитывать тот факт, что некоторые команды работают только с определёнными регистрами. Например, команды умножения и деления используют регистры EAX и EDX для хранения исходных данных и результата операции. Команды управления циклом используют регистр ECX в качестве счётчика цикла.
Ещё один нюанс состоит в использовании регистров в качестве базы, т.е. хранилища адреса оперативной памяти. В качестве регистров базы можно использовать любые регистры, но желательно использовать регистры EBX, ESI, EDI или EBP. В этом случае размер машинной команды обычно бывает меньше.
К сожалению, количество регистров катастрофически мало, и зачастую бывает трудно подобрать способ их оптимального использования.
1.2. Указатель команд
Регистр EIP (указатель команд) содержит смещение следующей подлежащей выполнению команды. Этот регистр непосредственно недоступен программисту, но загрузка и изменение его значения производятся различными командами управления, к которым относятся команды условных и безусловных переходов, вызова процедур и возврата из процедур.
1.3. Регистр флагов
Значение флагов CF, DF и IF можно изменять напрямую в регистре флагов с помощью специальных инструкций (например, CLD для сброса флага направления), но нет инструкций, которые позволяют обратиться к регистру флагов как к обычному регистру. Однако можно сохранять регистр флагов в стек или регистр AH и восстанавливать регистр флагов из них с помощью инструкций LAHF , SAHF , PUSHF , PUSHFD , POPF и POPFD .
1.3.1. Флаги состояния
- Флаг переноса CF устанавливается при переносе из старшего значащего бита/заёме в старший значащий бит и показывает наличие переполнения в беззнаковой целочисленной арифметике. Также используется в длинной арифметике.
- Флаг чётности PF устанавливается, если младший значащий байт результата содержит чётное число единичных битов. Изначально этот флаг был ориентирован на использование в коммуникационных программах: при передаче данных по линиям связи для контроля мог также передаваться бит чётности и инструкции для проверки флага чётности облегчали проверку целостности данных.
- Вспомогательный флаг переноса AF устанавливается при переносе из бита 3-го результата/заёме в 3-ий бит результата. Этот флаг ориентирован на использование в двоично-десятичной (binary coded decimal, BCD) арифметике.
- Флаг нуля ZF устанавливается, если результат равен нулю.
- Флаг знака SF равен значению старшего значащего бита результата, который является знаковым битом в знаковой арифметике.
- Флаг переполнения OF устанавливается, если целочисленный результат слишком длинный для размещения в целевом операнде (регистре или ячейке памяти). Этот флаг показывает наличие переполнения в знаковой целочисленной арифметике.
Из перечисленных флагов только флаг CF можно изменять напрямую с помощью инструкций STC , CLC и CMC .
Флаги состояния позволяют одной и той же арифметической инструкции выдавать результат трёх различных типов: беззнаковое, знаковое и двоично-десятичное (BCD) целое число. Если результат считать беззнаковым числом, то флаг CF показывает условие переполнения (перенос или заём), для знакового результата перенос или заём показывает флаг OF, а для BCD-результата перенос/заём показывает флаг AF. Флаг SF отражает знак знакового результата, флаг ZF отражает и беззнаковый, и знаковый нулевой результат.
В длинной целочисленной арифметике флаг CF используется совместно с инструкциями сложения с переносом ( ADC ) и вычитания с заёмом ( SBB ) для распространения переноса или заёма из одного вычисляемого разряда длинного числа в другой.
Инструкции условного перехода Jcc (переход по условию cc ), SETcc (установить значение байта-результата в зависимости от условия cc ), LOOPcc (организация цикла) и CMOVcc (условное копирование) используют один или несколько флагов состояния для проверки условия. Например, инструкция перехода JLE (jump if less or equal – переход, если «меньше или равно») проверяет условие « ZF = 1 или SF ≠ OF ».
Флаг PF был введён для совместимости с другими микропроцессорными архитектурами и по прямому назначению используется редко. Более распространено его использование совместно с остальными флагами состояния в арифметике с плавающей запятой: инструкции сравнения ( FCOM , FCOMP и т. п.) в математическом сопроцессоре устанавливают в нём флаги-условия C0, C1, C2 и C3, и эти флаги можно скопировать в регистр флагов. Для этого рекомендуется использовать инструкцию FSTSW AX для сохранения слова состояния сопроцессора в регистре AX и инструкцию SAHF для последующего копирования содержимого регистра AH в младшие 8 битов регистра флагов, при этом C0 попадает во флаг CF, C2 – в PF, а C3 – в ZF. Флаг C2 устанавливается, например, в случае несравнимых аргументов (NaN или неподдерживаемый формат) в инструкции сравнения FUCOM .
1.3.2. Управляющий флаг
Флаг направления DF (бит 10 в регистре флагов) управляет строковыми инструкциями ( MOVS , CMPS , SCAS , LODS и STOS ) – установка флага заставляет уменьшать адреса (обрабатывать строки от старших адресов к младшим), обнуление заставляет увеличивать адреса. Инструкции STD и CLD соответственно устанавливают и сбрасывают флаг DF.
1.3.3. Системные флаги и поле IOPL
- Флаг разрешения прерываний IF – обнуление этого флага запрещает отвечать на маскируемые запросы на прерывание.
- Флаг трассировки TF – установка этого флага разрешает пошаговый режим отладки, когда после каждой выполненной инструкции происходит прерывание программы и вызов специального обработчика прерывания.
- Поле IOPL показывает уровень приоритета ввода-вывода исполняемой программы или задачи: чтобы программа или задача могла выполнять инструкции ввода-вывода или менять флаг IF, её текущий уровень приоритета (CPL) должен быть ≤ IOPL .
- Флаг вложенности задач NT – этот флаг устанавливается, когда текущая задача «вложена» в другую, прерванную задачу, и сегмент состояния TSS текущей задачи обеспечивает обратную связь с TSS предыдущей задачи. Флаг NT проверяется инструкцией IRET для определения типа возврата – межзадачного или внутризадачного.
- Флаг возобновления RF используется для маскирования ошибок отладки.
- VM – установка этого флага в защищённом режиме вызывает переключение в режим виртуального 8086.
- Флаг проверки выравнивания AC – установка этого флага вместе с битом AM в регистре CR0 включает контроль выравнивания операндов при обращениях к памяти: обращение к невыравненному операнду вызывает исключительную ситуацию.
- VIF – виртуальная копия флага IF; используется совместно с флагом VIP.
- VIP – устанавливается для указания наличия отложенного прерывания.
- ID – возможность программно изменить этот флаг в регистре флагов указывает на поддержку инструкции CPUID.
1.4. Сегментные регистры
Процессор имеет 6 так называемых сегментных регистров: CS, DS, SS, ES, FS и GS. Их существование обусловлено спецификой организации и использования оперативной памяти.
16-битные регистры могли адресовать только 64 Кб оперативной памяти, что явно недостаточно для более или менее приличной программы. Поэтому память программе выделялась в виде нескольких сегментов, которые имели размер 64 Кб. При этом абсолютные адреса были 20-битными, что позволяло адресовать уже 1 Мб оперативной памяти. Возникает вопрос – как имея 16-битные регистры хранить 20-битные адреса? Для решения этой задачи адрес разбивался на базу и смещение. База – это адрес начала сегмента, а смещение – это номер байта внутри сегмента. На адрес начала сегмента накладывалось ограничение – он должен был быть кратен 16. При этом последние 4 бита были равны 0 и не хранились, а подразумевались. Таким образом, получались две 16-битные части адреса. Для получения абсолютного адреса к базе добавлялись четыре нулевых бита, и полученное значение складывалось со смещением.
Сегментные регистры использовались для хранения адреса начала сегмента кода (CS – code segment), сегмента данных (DS – data segment) и сегмента стека (SS – stack segment). Регистры ES, FS и GS были добавлены позже. Существовало несколько моделей памяти, каждая из которых подразумевала выделение программе одного или нескольких сегментов кода и одного или нескольких сегментов данных: tiny, small, medium, compact, large и huge. Для команд языка ассемблера существовали определённые соглашения: адреса перехода сегментировались по регистру CS, обращения к данным сегментировались по регистру DS, а обращения к стеку – по регистру SS. Если программе выделялось несколько сегментов для кода или данных, то приходилось менять значения в регистрах CS и DS для обращения к другому сегменту. Существовали так называемые «ближние» и «дальние» переходы. Если команда, на которую надо совершить переход, находилась в том же сегменте, то для перехода достаточно было изменить только значение регистра IP. Такой переход назывался ближним. Если же команда, на которую надо совершить переход, находилась в другом сегменте, то для перехода необходимо было изменить как значение регистра CS, так и значение регистра IP. Такой переход назывался дальним и осуществлялся дольше.
32-битные регистры позволяют адресовать 4 Гб памяти, что уже достаточно для любой программы. Каждую Win32-программу Windows запускает в отдельном виртуальном пространстве. Это означает, что каждая Win32-программа будет иметь 4-х гигабайтовое адресное пространство, но вовсе не означает, что каждая программа имеет 4 Гб физической памяти, а только то, что программа может обращаться по любому адресу в этих пределах. А Windows сделает все необходимое, чтобы память, к которой программа обращается, «существовала». Конечно, программа должна придерживаться правил, установленных Windows, иначе возникает ошибка General Protection Fault.
Под архитектурой Win32 отпала необходимость в разделении адреса на базу и смещение, и необходимость в моделях памяти. На 32-битной архитектуре существует только одна модель памяти – flat (сплошная или плоская). Сегментные регистры остались, но используются по-другому 1 . Раньше необходимо было связывать отдельные части программы с тем или иным сегментным регистром и сохранять/восстанавливать регистр DS при переходе к другому сегменту данных или явно сегментировать данные по другому регистру. При 32-битной архитектуре необходимость в этом отпала, и в простейшем случае про сегментные регистры можно забыть.
1.5. Использование стека
Каждая программа имеет область памяти, называемую стеком. Стек используется для передачи параметров в процедуры и для хранения локальных данных процедур. Как известно, стек – это область памяти, при работе с которой необходимо соблюдать определённые правила, а именно: данные, которые попали в стек первыми, извлекаются оттуда последними. С другой стороны, если программе выделена некоторая память, то нет никаких физических ограничений на чтение и запись. Как же совмещаются два этих противоречивых принципа?
Пусть у нас есть функция f1, которая вызывает функцию f2, а функция f2, в свою очередь, вызывает функцию f3. При вызове функции f1 ей отводится определённое место в стеке под локальные данные. Это место отводится путём вычитания из регистра ESP значения, равного размеру требуемой памяти. Минимальный размер отводимой памяти равен 4 байтам, т.е. даже если процедуре требуется 1 байт, она должна занять 4 байта.
Функция f1 выполняет некоторые действия, после чего вызывает функцию f2. Функция f2 также отводит себе место в стеке, вычитая некоторое значение из регистра ESP. При этом локальные данные функций f1 и f2 размещаются в разных областях памяти. Далее функция f2 вызывает функцию f3, которая также отводит себе место в стеке. Функция f3 других функций не вызывает и при завершении работы должна освободить место в стеке, прибавив к регистру ESP значение, которые было вычтено при вызове функции. Если функция f3 не восстановит значение регистра ESP, то функция f2, продолжив работу, будет обращаться не к своим данным, т.к. она ищет их, основываясь на значении регистра ESP. Аналогично функция f2 должна при выходе восстановить значение регистра ESP, которое было до её вызова.
Таким образом, на уровне процедур необходимо соблюдать правила работы со стеком – процедура, которая заняла место в стеке последней, должна освобождать его первой. При несоблюдении этого правила, программа будет работать некорректно. Но каждая процедура может обращаться к своей области стека произвольным образом. Если бы мы были вынуждены соблюдать правила работы со стеком внутри каждой процедуры, пришлось бы перекладывать данные из стека в другую область памяти, а это было бы крайне неудобно и чрезвычайно замедлило бы выполнение программы.
Каждая программа имеет область данных, где размещаются глобальные переменные. Почему же локальные данные хранятся именно в стеке? Это делается для уменьшения объёма памяти занимаемого программой. Если программа будет последовательно вызывать несколько процедур, то в каждый момент времени будет отведено место только под данные одной процедуры, т.к. стек занимается и освобождается. Область данных существует всё время работы программы. Если бы локальные данные размещались в области данных, пришлось бы отводить место под локальные данные для всех процедур программы.
Локальные данные автоматически не инициализируются. Если в вышеприведённом примере функция f2 после функции f3 вызовет функцию f4, то функция f4 займёт в стеке место, которое до этого было занято функцией f3, таким образом, функции f4 «в наследство» достанутся данные функции f3. Поэтому каждая процедура обязательно должна заботиться об инициализации своих локальных данных.
2. Основные понятия языка ассемблера
2.1. Идентификаторы
Понятие идентификатора в языке ассемблера ничем не отличается от понятия идентификатора в других языках. Можно использовать латинские буквы, цифры и знаки _ . ? @ $ , причём точка может быть только первым символом идентификатора. Большие и маленькие буквы считаются эквивалентными.
2.2. Целые числа
В программе на языке ассемблера целые числа могут быть записаны в двоичной, восьмеричной, десятичной и шестнадцатеричной системах счисления. Для задания системы счисления в конце числа ставится буква b , o/q , d или h соответственно. Шестнадцатеричные числа, которые начинаются с «буквенной» цифры, должны предваряться нулём, иначе компилятор не сможет отличить число от идентификатора. Примеры чисел см. в разделе 2.6.
2.3. Символьные данные
Символы и строки в языке ассемблера могут заключаться в апострофы или двойные кавычки. Если в качестве символа или внутри строки надо указать апостроф или кавычку, то делается это следующим образом: если символ или строка заключены в апострофы, то апостроф надо удваивать, а кавычку удваивать не надо, и наоборот, если символ или строка заключены в двойные кавычки, то надо удваивать кавычку и не надо удваивать апостроф. Все следующие примеры корректны и эквивалентны: ‘don»t’ , ‘don»t’ , «don’t» , «don»»t» .
2.4. Комментарии
Комментарии в языке ассемблера начинаются с символа «точка с запятой» и могут начинаться как в начале строки, так и после команды.
2.5. Директива эквивалентности
Директива эквивалентности позволяет описывать константы:
Все вхождения имени заменяются операндом. Операндом может быть константное выражение, строка, другое имя.
2.6. Директивы определения данных
Языки высокого уровня обычно являются типизированными. Каждая переменная имеет тип, который накладывает ограничения на операции над переменной и на использование в одном выражении переменных разных типов. Кроме того, языки высокого уровня позволяют работать со сложными типами, таким как указатели, записи/структуры, классы, массивы, строки, множества и т.п.
Язык Паскаль имеет достаточно жёсткую структуру типов. Присваивания между переменными разных типов минимальны, над указателями определены только операции присваивания, взятия значения и получение адреса. Поддерживается много сложных типов.
Язык С, который создавался как высокоуровневая замена языку ассемблера, имеет гораздо менее жёсткую структуру типов. Все целочисленные типы совместимы, тип char, конечно, хранит символы, но также сопоставим с целыми типами, логический тип отсутствует в принципе (для языка С это именно так!), над указателями определены операции сложения и вычитания. Сложные типы, такие как массивы, строки и множества, не поддерживаются.
Что касается языка ассемблера, то тут вообще вряд ли можно говорить о какой-либо структуре типов. Команды языка ассемблера оперируют объектами, существующими в оперативной памяти, т.е. байтом и его производными (слово, двойное слово и т.д.). Символьный, логический тип? Какая глупость! Указатели? Вот тебе 4 байта и делай с ними, что хочешь. В итоге, конечно, и можно сделать, что хочешь, только предварительно стоит хорошо подумать, что из этого получится.
- DB (define byte) – определяет переменную размером в 1 байт;
- DW (define word) – определяет переменную размеров в 2 байта (слово);
- DD (define double word) – определяет переменную размером в 4 байта (двойное слово);
- DQ (define quad word) – определяет переменную размером в 8 байт (учетверённое слово);
- DT (define ten bytes) – определяет переменную размером в 10 байт.
Все директивы могут быть использованы как для объявления простых переменных, так и для объявления массивов. Хотя для определения строк, в принципе, можно использовать любую директиву, в связи с особенностями хранения данных в оперативной памяти лучше использовать директиву DB .
Синтаксис директив определения данных следующий:
Операнд задаёт начальное значение переменной. В качестве операнда может использоваться число, символ или знак вопроса, с помощью которого определяются неинициализированные переменные.
Если в качестве операнда указывается строка или если указано несколько операндов через запятую, то память отводится под несколько переменных указанного типа, т.е. получается массив. При этом именованным оказывается только первый элемент, а доступ к остальным элементам массива осуществляется с помощью выражения + .
Для того чтобы не указывать несколько раз одно и то же значение, при инициализации массивов можно использовать конструкцию повторения DUP .
a db 10011001b ; Определяем переменную размером 1 байт с начальным значением, заданным в двоичной системе счисления b db ‘!’ ; Определяем переменную в 1 байт, инициализируемую символом ‘!’ d db ‘string’,13,10 ; Определяем массив из 8 байт e db ‘string’,0 ; Определяем строку из 7 байт, заканчивающую нулём f dw 1235o ; Определяем переменную размером 2 байта с начальным значением, заданным в восьмеричной системе счисления g dd -345d ; Определяем переменную размером 4 байта с начальным значением, заданным в десятичной системе счисления h dd 0f1ah ; Определяем переменную размером 4 байта с начальным значением, заданным в шестнадцатеричной системе счисления i dd ? ; Определяем неинициализированную переменную размером 4 байта j dd 100 dup (0) ; Определяем массив из 100 двойных слов, инициализированных 0 k dq 10 dup (0, 1, 2) ; Определяем массив из 30 учетверённых слов, инициализированный повторяющимися значениями 0, 1 и 2 l dd 100 dup (?) ; Определяем массив из 100 неинициализированных двойных слов
К переменным можно применить две операции – offset и type . Первая определяет адрес переменной, а вторая – размер переменной. Однако размер переменной определяется по директиве, и даже если с директивой, например, DD определён массив из нескольких элементов, размер всё равно будет равен 4.
2.7. Команды
Команды языка ассемблера – это символьная форма записи машинных команд. Команды имеют следующий синтаксис:
Метка – это имя. Метка обязательно должна отделяться двоеточием, но может размещаться отдельно, в строке, предшествующей остальной части команды.
Метки нужны для ссылок на команды из других мест, например, в командах перехода. Компилятор языка ассемблера заменяет метки адресами команд.
Мнемокод – это служебное слово, указывающее операцию, которая должна быть выполнена. Язык ассемблера использует не цифровые коды операций, а мнемокоды, которые легче запоминаются. Мнемокод является обязательной частью команды.
Операнды команды, если они есть, отделяются друг от друга запятыми.
2.8. Операнды команд
- регистры, обращение к которым осуществляется по именам;
- непосредственные операнды – константы, записываемые непосредственно в команде;
- ячейки памяти – в команде записывается адрес нужной ячейки.
- Имя переменной, по сути, является адресом этой переменной. Встретив имя переменной в операндах команды, компилятор понимает, что нужно обратиться к оперативной памяти по определённому адресу. Обычно адрес в команде указывается в квадратных скобках, но имя переменной является исключением и может быть указано как в квадратных скобках, так и без них. Например, для обращения к переменной x в команде можно указать x или [x] .
- Если переменная была объявлена как массив, то к элементу массива можно обратиться, указав имя и смещение. Для этого существует ряд синтаксических форм, например: [] и [ + ] (см. раздел 5). Однако следует понимать, что смещение – это вовсе не индекс элемента массива. Индекс элемента массива – это его номер, и этот номер не зависит от размера самого элемента. Смещение же задаётся в байтах, и при задании смещения программист сам должен учитывать размер элемента массива.
- Адрес ячейки памяти может храниться в регистре. Для обращения к памяти по адресу, хранящемуся в регистре, в команде указывается имя регистра в квадратных скобках, например: [ebx] . Как уже говорилось, в качестве регистров базы рекомендуется использовать регистры EBX, ESI, EDI и EBP.
- Адрес может быть вычислен по определённой формуле. Для этого в квадратных скобках можно указывать достаточно сложные выражения, например, [ebx + ecx] или [ebx + 4 * ecx] .
В описаниях команд языка ассемблера для обозначения возможных операндов используют сокращения, состоящие из буквы r (для регистров), m (для памяти) или i (для непосредственного операнда) и числа 8, 16 или 32, указывающего размер операнда. Например:
add r8/r16/r32, r8/r16/r32 ; Сложение регистра с регистром add r8/r16/r32, m8/m16/m32 ; Сложение регистра с ячейкой памяти add r8/r16/r32, i8/i16/i32 ; Сложение регистра с непосредственным операндом add m8/m16/m32, r8/r16/r32 ; Сложение ячейки памяти с регистром add m8/m16/m32, i8/i16/i32 ; Сложение ячейки памяти с непосредственным операндом
Команды языка ассемблера обычно имеют 1 или 2 операнда, или не имеют операндов вообще. Во многих, хотя не во всех, случаях операнды (если их два) должны иметь одинаковый размер. Команды языка ассемблера обычно не работают с двумя ячейками памяти.
3. Пересылка и арифметические команды
3.1. Команды пересылки и обмена
Одна из основных команд языка ассемблер – это команда пересылки. С её помощью можно записать в регистр значение другого регистра, константу или значение ячейки памяти, а также можно записать в ячейку памяти значение регистра или константу. Команда имеет следующий синтаксис:
По команде MOV значение второго операнда записывается в первый операнд. Операнды должны иметь одинаковый размер. Команда не меняет флаги.
mov eax, ebx ; Пересылаем значение регистра EBX в регистр EAX mov eax, 0ffffh ; Записываем в регистр EAX шестнадцатеричное значение ffff mov x, 0 ; Записываем в переменную x значение 0 mov eax, x ; Переслать значение из одной ячейки памяти в другую нельзя. mov y, eax ; Но можно использовать две команды MOV .
На самом деле процессор имеет много команд пересылки – код команды зависит от того, куда и откуда пересылаются данные. Но компилятор языка ассемблера сам выбирает нужный код в зависимости от операндов, так что, с точки зрения программиста, команда пересылки только одна.
Для перестановки двух величин используется команда обмена:
Каждый из операндов может быть регистром или ячейкой памяти. Однако переставить содержимое двух регистров можно, а двух ячеек памяти – нет. Операнды должны иметь одинаковый размер. Команда не меняет флаги.
3.2. Оператор указания типа
Как было сказано, операнды команды MOV должны иметь одинаковый размер. В некоторых случаях компилятор может определить размер операнда. Например, регистр EAX имеет размер 32 бита, а регистр DX – 16 бит. Размер переменной определяется по директиве, указанной в её объявлении. Если можно определить размер только одного операнда, то размер второго операнда подгоняется под размер первого, если это возможно. Если же можно определить размеры обоих операндов, то они должны совпадать.
x db ? mov x, 0 ; 0 может иметь любой размер, в данном случае берётся 1 байт mov eax, 0 ; 0 может иметь любой размер, в данном случае берётся 4 байта mov al, 1000h ; Ошибка – попытка записать 2-байтное число в 1-байтный регистр mov eax, cx ; Ошибка – размеры операндов не совпадают
Однако не всегда бывает возможно определить размер пересылаемой величины по операндам команды MOV . Например, если один из операндов является ячейкой памяти, адрес которой записан в регистре, то по этому адресу можно записать и 1 байт, и 2 байта, и 4 байта. Если второй операнд является регистром, то размер пересылаемых данных определяется по размеру регистра. Если же второй операнд является константой, то размер пересылаемых данных определить нельзя, и компилятор фиксирует ошибку. Для того чтобы избежать этой ошибки, надо явно указать размер пересылаемых данных. Для этого используется оператор PTR :
В качестве типа используется BYTE , WORD или DWORD .
mov [ebx], 0 ; Ошибка, т.к. 0 может иметь любой размер mov byte ptr [ebx], 0 ; Пересылаем 1 байт mov dword ptr [ebx], 0 ; Пересылаем 4 байта
3.3. Команды сложения и вычитания
Команды сложения и вычитания реализуют хорошо всем известные арифметические операции. Единственное, что нужно учитывать при использовании этих команд – особенности сложения и вычитания, связанные с представлением чисел в памяти компьютера.
Команда ADD складывает операнды и записывает их сумму на место первого операнда. Команда SUB вычитает из первого операнда второй и записывает полученную разность на место первого операнда. Операнды должны иметь одинаковый размер. Если первый операнд – регистр, то второй может быть также регистром, ячейкой памяти и непосредственным операндом. Если первый операнд – ячейка памяти, то второй операнд может быть регистром или непосредственным операндом. Возможно сложение и вычитание как знаковых, так и беззнаковых чисел любого размера. Команды меняют флаги AF, CF, OF, PF, SF и ZF.
a dd 45d b dd -32d c dd ? mov eax, a add eax, b mov c, eax ; c = a + b
Команды инкремента и декремента увеличивают и уменьшают на 1 свой операнд.
Операндом может быть регистр или ячейка памяти любого размера. Команды меняют флаги AF, OF, PF, SF и ZF. Команды инкремента и декремента выгодны тем, что они занимают меньше места, чем соответствующие команды сложения и вычитания.
К арифметическим операциям можно также отнести команду изменения знака:
Операндом может быть регистр или ячейка памяти любого размера. Команда NEG рассматривает свой операнд как число со знаком и меняет знак операнда на противоположный. Команда меняет флаги AF, CF, OF, PF, SF и ZF.
mov ax, 1 neg ax ; AX = -1 = ffffh mov bl, -128 neg bl ; BL = -128, OF = 1
3.4. Команды умножения и деления
3.4.1. Команды умножения
Сложение и вычитание знаковых и беззнаковых чисел производятся по одним и тем же алгоритмам. Поэтому нет отдельных команд сложения и вычитания для знаковых и беззнаковых чисел. А вот умножение и деление знаковых и беззнаковых чисел производятся по разным алгоритмам, поэтому существуют по две команды умножения и деления.
Для беззнакового умножения используется команда MUL :
Операнд, указываемый в команде, – это один из сомножителей. Он может быть регистром или ячейкой памяти, но не может быть непосредственным операндом.
Местонахождение второго сомножителя и результата фиксировано, и в команде явно не указывается. Если операнд команды MUL имеет размер 1 байт, то второй сомножитель берётся из регистра AL, а результат помещается в регистр AX. Если операнд команды MUL имеет размер 2 байта, то второй сомножитель берётся из регистра AX, а результат помещается в регистровую пару DX:AX. Если операнд команды MUL имеет размер 4 байта, то второй сомножитель берётся из регистра EAX, а результат помещается в регистровую пару EDX:EAX.
Команда меняет флаги CF и OF. Если произведение имеет такой же размер, что и сомножители, то оба флага сбрасываются в 0. Если же размер произведения удваивается относительно размера сомножителей, то оба флага устанавливаются в 1.
x dw 256 mov ax, 105 mul x ; AX = AX * x, AX = 26880, CF = OF = 0 mov eax, 500000 mov ebx, 100000 mul ebx ; EDX:EAX = EAX * EBX, EDX:EAX = 50000000000, CF = OF = 1
Для знакового умножения используется команда IMUL :
Команда знакового умножения имеет несколько вариантов. Первый соответствует команде MUL – один из сомножителей указывается в команде, второй должен находиться в регистре EAX/AX/AL, а результат помещается в регистры EDX:EAX/DX:AX/AX.
Второй вариант команды IMUL позволяет указать регистр, который будет содержать один из сомножителей. В этот же регистр будет помещён результат. Второй сомножитель указывается непосредственно в команде.
Третий вариант команды IMUL позволяет указать и результат, и оба сомножителя. Однако результат может быть помещён только в регистр, а второй сомножитель может быть только непосредственным операндом. Первый сомножитель может быть регистром или ячейкой памяти.
Четвёртый вариант команды IMUL позволяет указать оба сомножителя. Первый должен быть регистром, а второй – регистром или ячейкой памяти. Результат помещается в регистр, являющийся первым операндом.
Команда IMUL устанавливает флаги так же, как и команда MUL . Однако расширение результата в регистр EDX/DX происходит только при использовании первого варианта команды IMUL . В остальных случаях часть произведения, не помещающаяся в регистр-результат, теряется, даже если в качестве результата указан регистр EAX/AX. При умножении двух 1-байтовых чисел, произведение которых больше байта, но меньше слова, в регистре-результате получается корректное произведение.
mov eax, 5 mov ebx, -7 imul ebx ; EAX = ffffffdd, EDX = ffffffff, CF = 0 mov ebx, 3 imul ebx, 6 ; EBX = EBX * 6 mov ebx, 500000 imul eax, ebx, 100000 ; EAX = EBX * 100000, старшая часть результата теряется x dd 40 mov eax, 55 imul eax, x ; EAX = EAX * x
3.4.2. Команды деления
Деление, как и умножение, реализуется двумя командами, предназначенными для знаковых и беззнаковых чисел:
DIV ; Беззнаковое деление IDIV ; Знаковое деление
В командах указывается только один операнд – делитель, который может быть регистром или ячейкой памяти, но не может быть непосредственным операндом. Местоположение делимого и результата для команд деления фиксировано.
Если делитель имеет размер 1 байт, то делимое берётся из регистра AX. Если делитель имеет размер 2 байта, то делимое берётся из регистровой пары DX:AX. Если же делитель имеет размер 4 байта, то делимое берётся из регистровой пары EDX:EAX.
Поскольку процессор работает с целыми числами, то в результате деления получается сразу два числа – частное и остаток. Эти два числа также помещаются в определённые регистры. Если делитель имеет размер 1 байт, то частное помещается в регистр AL, а остаток – в регистр AH. Если делитель имеет размер 2 байта, то частное помещается в регистр AX, а остаток – в регистр DX. Если же делитель имеет размер 4 байта, то частное помещается в регистр EAX, а остаток – в регистр EDX.
mov ax, 127 mov bl, 5 div bl ; AL = 19h = 25, AH = 02h = 2 mov ax, 127 mov bl, -5 idiv bl ; AL = e7h = -25, AH = 02h = 2 mov ax, -127 mov bl, 5 idiv bl ; AL = e7h = -25, AH = feh = -2 mov ax, -127 mov bl, -5 idiv bl ; AL = 19h = 25, AH = feh = -2 ; x = a * b + c mov eax, a imul b add eax, c ; Операнды команды сложения вычисляются слева направо mov x, eax ; x = a + b * c mov eax, b imul c add eax, a ; Операнды команды сложения вычисляются справа налево mov x, eax
3.5. Изменение размера числа
В операциях деления размер делимого в два раза больше, чем размер делителя. Поэтому нельзя просто загрузить данные в регистр EAX и поделить его на какое-либо значение, т.к. в операции деления будет задействован также и регистр EDX. Поэтому прежде чем выполнять деление, надо установить корректное значение в регистр EDX, иначе результат будет неправильным. Значение регистра EDX должно зависеть от значения регистра EAX. Тут возможны два варианта – для знаковых и беззнаковых чисел.
Если мы используем беззнаковые числа, то в любом случае в регистр EDX необходимо записать значение 0: aaaaaaaah → 00000000aaaaaaaah .
Если же мы используем знаковые числа, то значение регистра EDX будет зависеть от знака числа: 55555555h → 0000000055555555h , aaaaaaaah → ffffffffaaaaaaaah .
Записать значение 0 не сложно, а вот для знакового расширения необходимо анализировать знак числа. Однако нет необходимости делать это вручную, т.к. язык ассемблера имеет ряд команд, позволяющих расширять байт до слова, слово до двойного слова и двойное слово до учетверённого слова.
cbw ; Знаковое расширение AL до AX cwd ; Знаковое расширение AX до DX:AX cwde ; Знаковое расширение AX до EAX cdq ; Знаковое расширение EAX до EDX:EAX
Таким образом, если делитель имеет размер 2 или 4 байта, то нужно устанавливать значение не только регистра AX/EAX, но и регистра DX/EDX. Если же делитель имеет размер 1 байт, то можно просто записать делимое в регистр AX.
x dd ? mov eax, x ; Заносим в регистр EAX значение переменной x , которое заранее неизвестно cdq ; Знаковое расширение EAX в EDX:EAX mov ebx, 7 idiv ebx
В языке ассемблера существуют также команды, позволяющие занести в регистр значение другого регистра или ячейки памяти со знаковым или беззнаковым расширением.
MOVSX 1>, 2> ; Знаковое расширение – старшие биты заполняются знаковым битом MOVZX 1>, 2> ; Беззнаковое расширение – старшие биты заполняются нулём
Операнд1 и операнд2 могут иметь любой размер. Понятно, что операнд1 должен быть больше, чем операнд2. В случае равенства размера операндов следует использовать обычную команду пересылки MOV , которая выполняется быстрее.
Рассмотрим пример: необходимо вычислить x * x * x , где x – 1-байтовая переменная.
; Первый вариант mov al, x ; Пересылаем x в регистр AL imul al ; Умножаем регистр AL на себя, AX = x * x movsx bx, x ; Пересылаем x в регистр BX со знаковым расширением imul bx ; Умножаем AX на BX. Но! – результат размещается в DX:AX ; Второй вариант mov al, x ; Пересылаем x в регистр AL imul al ; Умножаем регистр AL на себя, AX = x * x cwde ; Расширяем AX до EAX movsx ebx, x ; Пересылаем x в регистр EBX со знаковым расширением imul ebx ; Умножаем EAX на EBX. Поскольку x – 1-байтовая переменная, результат благополучно помещается в EAX
Рассмотрим ещё один пример.
mov eax, x mov ebx, 429496730 ; 429496730 = 4294967296 / 10 imul ebx ; EDX = x / 10. Выполняется в ≈5 раз быстрее, чем деление
Чем обусловлено получение такого результата? Всегда ли будет работать этот механизм?
4. Переходы и циклы
Для изменения порядка выполнения команд в языке ассемблера используются команды условного и безусловного перехода, а также команды управления циклом. Все эти команды не меняют флаги.
4.1. Безусловный переход
Команда безусловного перехода имеет следующий синтаксис:
Операнд указывает адрес перехода. Существует два способа указания этого адреса, соответственно различают прямой и косвенный переходы.
4.1.1. Прямой переход
Если в команде перехода указывается метка команды, на которую надо перейти, то переход называется прямым.
jmp L . L: mov eax, x
Вообще, любой переход заключается в изменении адреса следующей исполняемой команды, т.е. в изменении значения регистра EIP. Казалось бы, в команде перехода должен задаваться именно адрес перехода. Однако в команде прямого перехода задаётся не абсолютный адрес, а разность между адресом перехода и адресом команды перехода. Действие команды перехода заключается в прибавлении этой величины к текущему значению регистра EIP 2 . Операнд команды перехода рассматривается как поле со знаком, поэтому при сложении его со значением регистра EIP значение в этом регистре может как увеличиться, так и уменьшиться, т.е. возможен переход и вперёд, и назад.
Запись в команде перехода не абсолютного, а относительного адреса перехода позволяет уменьшить размер команды перехода. Абсолютный адрес должен быть 32-битным, а относительный может быть и 8-битным, и 16-битным.
4.1.2. Косвенный переход
При косвенном переходе в команде перехода указывается не адрес перехода, а регистр или ячейка памяти, где этот адрес находится. Содержимое указанного регистра или ячейки памяти рассматривается как абсолютный адрес перехода. Косвенные переходы используются в тех случаях, когда адрес перехода становится известен только во время работы программы.
4.2. Команды сравнения и условного перехода
Команды условного перехода осуществляют переход, который выполняется только в случае истинности некоторого условия. Истинность условия проверяется по значениям флагов. Поэтому обычно непосредственно перед командой условного перехода ставится команда сравнения, которая формирует значения флагов:
Команда сравнения эквивалентна команде SUB за исключением того, что вычисленная разность никуда не заносится. Назначение команды CMP – установка и сброс флагов.
Что касается команд условного перехода, то их достаточно много, но все они записываются единообразно:
Все команды условного перехода можно разделить на три группы.
Рассмотрим пример: даны две переменные x и y , в переменную z нужно записать максимальное из чисел x и y .
mov eax, x cmp eax, y jge/jae L ; Используем JGE для знаковых чисел и JAE – для беззнаковых mov eax, y L: mov z, eax
Рассмотрим пример: пусть a , b и c – беззнаковые переменные размером 1 байт, требуется вычислить c = a * a + b , но если результат превосходит размер байта, передать управление на метку ERROR.
mov al, a mul al jc ERROR add al, b jc ERROR mov c, al
И, наконец, в третью группу входят две команды условного перехода, проверяющие не флаги, а значение регистра ECX или CX:
JCXZ ; Переход, если значение регистра CX равно 0 JECXZ ; Переход, если значение регистра ECX равно 0
Однако эта команда выполняется достаточно долго. Выгоднее провести сравнение с нулём и использовать обычную команду условного перехода.
С помощью команд перехода можно реализовать любые разветвления и циклы.
; if (x > 0) S cmp x, 0 jle L . ; S L: ; if (x) S1 else S2 cmp x, 0 je L1 . ; S1 jmp L2 L1: . ; S2 L2: ; if (a > 0 && b > 0) S cmp a, 0 jle L cmp b, 0 jle L . ; S L: ; if (a > 0 || b > 0) S cmp a, 0 jg L1 cmp b, 0 jle L2 L1: . ; S L2: ; if (a > 0 || b > 0 && c > 0) S cmp a, 0 jg L1 cmp b, 0 jle L2 cmp c, 0 jle L2 L1: . ; S L2: ; while (x > 0) do S L1: cmp x, 0 jle L2 . ; S jmp L1 L2: ; do S while (x > 0) L: . ; S cmp x, 0 jg L
4.3. Команды управления циклом
4.3.1. Команда LOOP
Команда LOOP позволяет организовать цикл с известным числом повторений:
mov ecx, n L: . . loop L
Команда LOOP требует, чтобы в качестве счётчика цикла использовался регистр ECX. Собственно, команда LOOP вычитает единицу именно из этого регистра, сравнивает полученное значение с нулём и осуществляет переход на указанную метку, если значение в регистре ECX больше 0. Метка определяет смещение перехода, которое не может превышать 128 байт.
При использовании команды LOOP следует также учитывать, что с её помощью реализуется цикл с постусловием, следовательно, тело цикла выполняется хотя бы один раз. Хуже того, если до начала цикла записать в регистр ECX значение 0, то при вычитании единицы, которое выполняется до сравнения с нулём, в регистре ECX окажется ненулевое значение, и цикл будет выполняться 2 32 раз.
Команда LOOP не относится к самым быстрым командам. В большинстве случаев её можно заменить последовательностью других команд.
4.3.2. Команды LOOPE / LOOPZ и LOOPNE / LOOPNZ
Эти команды похожи на команду LOOP , но позволяют также организовать и досрочный выход из цикла.
LOOPE ; Команды являются синонимами LOOPZ
Действие этой команды можно описать следующим образом: ECX = ECX — 1; if (ECX != 0 && ZF == 1) goto ;
До начала цикла в регистр ECX необходимо записать число повторений цикла. Команда LOOPE / LOOPZ , как и команда LOOP ставится в конце цикла, а перед ней помещается команда, которая меняет флаг ZF (обычно это команда сравнения CMP ). Команда LOOPE / LOOPZ заставляет цикл повторяться ECX раз, но только если предыдущая команда фиксирует равенство сравниваемых величин (вырабатывает нулевой результат, т.е. ZF = 1 ).
По какой именно причине произошёл выход из цикла надо проверять после цикла. Причём надо проверять флаг ZF, а не регистр ECX, т.к. условие ZF = 0 может появиться как раз на последнем шаге цикла, когда и регистр ECX стал нулевым.
Команда LOOPNE / LOOPNZ аналогична команде LOOPE / LOOPZ , но досрочный выход из цикла осуществляется, если ZF = 1 .
Рассмотрим пример: пусть в регистре ESI находится адрес начала некоторого массива двойных слов, а в переменной n – количество элементов массива, требуется проверить наличие в массиве элементов, кратных заданному числу x , и занести в переменную f значение 1, если такие элементы есть, и 0 в противном случае.
mov ebx, x mov ecx, n mov f, 1 L1: mov eax, [esi] add esi, 4 cdq idiv ebx cmp edx, 0 loopne L1 je L2 mov f, 0 L2:
5. Массивы
5.1. Модификация адресов
Как уже было сказано, массивы в языке ассемблера описываются по директивам определения данных с использованием конструкции повторения (см. раздел 2.6). Для того чтобы обратиться к элементу массива, необходимо так или иначе указать адрес начала массива и смещение элемента в массиве. Смещение первого элемента массива всегда равно 0. Смещения остальных элементов массива зависят от размера элементов.
Пусть X – некий массив. Тогда адрес элемента массива можно вычислить по следующей формуле:
адрес(X[i]) = X + (type X) * i, где i – номер элемента массива, начинающийся с 0
Напомним, что имя переменной эквивалентно её адресу (для массива – адресу начала массива), а операция type определяет размер переменной (для массива определяется размер элемента массива в соответствии с использованной директивой).
Для удобства в языке ассемблера введена операция модификации адреса, которая схожа с индексным выражением в языках высокого уровня – к имени массива надо приписать целочисленное выражение или имя регистра в квадратных скобках:
Однако принципиальное отличие состоит в том, в программе на языке высокого уровня мы указываем индекс элемента массива, а компилятор умножает его на размер элемента массива, получая смещение элемента массива. В программе на языке ассемблера указывается именно смещение, т.е. программист должен сам учитывать размер элемента массива. Компилятор же языка ассемблера просто прибавляет смещение к указанному адресу. Приведённые выше команды можно записать по-другому:
x + 4 [x + 4] [x] + [4] [x][4] [x + ebx] [x] + [ebx] [x][ebx]
Обратите внимание, что при использовании регистра для модификации адреса наличие квадратных скобок обязательно. В противном случае компилятор зафиксирует ошибку.
Адрес может вычисляться и по более сложной схеме:
База – это регистр или имя переменной. Индекс должен быть записан в некотором регистре. Множитель – это константа 1 (можно опустить), 2, 4 или 8. Смещение – целое положительное или отрицательное число.
mov eax, [ebx + 4 * ecx — 32] mov eax, [x + 2 * ecx]
5.2. Команда LEA
Команда LEA осуществляет загрузку в регистр так называемого эффективного адреса:
Команда не меняет флаги. В простейшем случае с помощью команды LEA можно загрузить в регистр адрес переменной или начала массива:
x dd 100 dup (0) lea ebx, x
Однако поскольку адрес может быть вычислен с использованием операций сложения и умножения, команда LEA имеет также ряд других применений (см. раздел 8.3.2).
5.3. Обработка массивов
Пусть есть массив x и переменная n , хранящая количество элементов этого массива.
x dd 100 dup(?) n dd ?
- В регистре можно хранить смещение элемента массива.
- В регистре можно хранить номер элемента массива и умножать его на размер элемента.
- В регистре можно хранить адрес элемента массива. Адрес начала массива можно записать в регистр с помощью команды LEA .
- При необходимости можно в один регистр записать адрес начала массива, а в другой – номер или смещение элемента массива.
mov eax, 0 mov ecx, n lea ebx, x L: dec ecx add eax, [ebx + ecx * type x] cmp ecx, 0 jne L
Модификацию адреса можно производить также по двум регистрам: x[ebx][esi] . Это может быть удобно при работе со структурами данных, которые рассматриваются как матрицы. Рассмотрим для примера подсчёт количества строк матриц с положительной суммой элементов.
mov esi, 0 ; Начальное смещение строки mov ebx, 0 ; EBX будет содержать количество строк, удовлетворяющих условию mov ecx, m ; Загружаем в ECX количество строк L1: mov edi, 0 ; Начальное смещение элемента в строке mov eax, 0 ; EAX будет содержать сумму элементов строки mov edx, n ; Загружаем в EDX количество элементов в строке L2: add eax, y[esi][edi] ; Прибавляем к EAX элемент массива add edi, type y ; Прибавляем к смещению элемента в строке размер элемента dec edx ; Уменьшаем на 1 счётчик внутреннего цикла cmp edx, 0 ; Сравниваем EDX с нулём jne L2 ; Если EDX не равно 0, то переходим к началу цикла cmp eax, 0 ; После цикла сравниваем сумму элементов строки с нулём jle L3 ; Если сумма меньше или равна 0, то обходим увеличение EBX inc ebx ; Если же сумму больше 0, то увеличиваем EBX L3: mov eax, n ; Загружаем в EAX количество элементов в строке imul eax, type y ; Умножаем количество элементов в строке на размер элемента add esi, eax ; Прибавляем к смещению полученный размер строки dec ecx ; Уменьшаем на 1 счётчик внешнего цикла cmp ecx, 0 ; Сравниваем ECX с нулём jne L1 ; Если ECX не равно 0, то переходим к началу цикла
6. Поразрядные операции
Поразрядные операции реализуют одну и ту же логическую операцию над всеми битами переменной. К поразрядным операциям относят также операции сдвига.
6.1. Логические команды
Операция отрицания меняет значение всех битов переменной на противоположное. Операция имеет один операнд, который может быть регистром или ячейкой памяти. Операция не меняет флаги.
Операция поразрядное «и» выполняет логическое умножение всех пар бит операндов.
Операция поразрядное «или» выполняет логическое сложение всех пар бит операндов.
Операция поразрядное исключающее «или» выполняет сложение по модулю 2 всех пар бит операндов.
Операции AND , OR и XOR имеют по два операнда. Первый может быть регистром или ячейкой памяти, а второй – регистром, ячейкой памяти или непосредственным операндом. Операнды должны иметь одинаковый размер. Результат помещается на место первого операнда. Операции меняют флаги CF, OF, PF, SF и ZF.
Операция XOR имеет интересную особенность – если значения операндов совпадают, то результатом будет значение 0. Поэтому операцию XOR используют для обнуления регистров – она выполняется быстрее, чем запись нуля с помощью команды MOV .
xor eax, eax ; При любом значении EAX результат будет равен 0
Операцию XOR можно также использовать для обмена значений двух переменных.
xor eax, ebx ; EAX = EAX xor EBX xor ebx, eax ; Теперь EBX содержит исходное значение EAX xor eax, ebx ; А теперь EAX содержит исходное значение EBX
6.2. Команды сдвига
Операции сдвига вправо и сдвига влево сдвигают биты в переменной на заданное количество позиций. Каждая команда сдвига имеет две разновидности:
Первый операнд должен быть регистром или ячейкой памяти. Именно в нём осуществляется сдвиг. Второй операнд определяет количество позиций для сдвига, которое задаётся непосредственным операндом или хранится в регистре CL (и только CL).
Команды сдвига меняют флаги CF, OF, PF, SF и ZF.
Существует несколько разновидностей сдвигов, которые отличаются тем, как заполняются «освобождающиеся» биты.
6.2.1. Логические сдвиги
При логическом сдвиге «освобождающиеся» биты заполняются нулями. Последний ушедший бит сохраняется во флаге CF.
SHL , ; Логический сдвиг влево SHR , ; Логический сдвиг вправо
6.2.2. Арифметические сдвиги
Арифметический сдвиг влево эквивалентен логическому сдвигу влево (это одна и та же команда) – «освобождающие» биты заполняются нулями. При арифметическом сдвиге вправо «освобождающиеся» биты заполняются знаковым битом. Последний ушедший бит сохраняется во флаге CF.
SAL , ; Арифметический сдвиг влево SAR , ; Арифметический сдвиг вправо
6.2.3. Циклические сдвиги
При циклическом сдвиге «освобождающиеся» биты заполняются ушедшими битами. Последний ушедший бит сохраняется во флаге CF.
ROL , ; Циклический сдвиг влево ROR , ; Циклический сдвиг вправо
6.2.4. Расширенные сдвиги
Расширенные сдвиги немного отличаются от остальных сдвигов. В расширенных сдвигах участвуют два регистра или ячейка памяти и регистр, которые как бы объединяются в единое целое и «освобождающиеся» биты одного операнда заполняются битами из другого операнда.
Команда SHLD сдвигает влево биты операнда1 на указанное количество позиций. Младшие («освободившиеся») биты операнда1 заполняются старшими битами операнда2. Сам операнд2 не меняется.
Команда SHRD сдвигает вправо биты операнда1 на указанное количество позиций. Старшие («освободившиеся») биты операнда1 заполняются младшими битами операнда2. Сам операнд2 не меняется.
Количество, как и в других операциях сдвига, задаётся непосредственным операндом или хранится в регистре CL. Но используются только последние 5 бит операнда, определяющего количество, т.е. максимальное количество позиций сдвига равно 32.
Команды расширенного сдвига обычно используют для создания упакованных данных.
6.3. Умножение и деление с помощью поразрядных операций
Для любой системы счисления сдвиг числа влево или вправо соответствует умножению или делению на основание системы счисления в некоторой степени. Двоичная система счисления, используемая в компьютере, не является исключением. Причём команды сдвига работают на порядок быстрее обычных операций умножения и деления.
6.3.1. Умножение
Для умножения используется сдвиг влево. Несмотря на наличие двух команда, по сути, сдвиг влево один. Он используется для умножения как знаковых, так и беззнаковых чисел. Однако результат будет правильным, только в том случае, если он умещается в регистр или ячейку памяти.
mov ax, 250 ; AX = 00fah = 250 sal ax, 4 ; Умножение на 24 = 16, AX = 0fa0h = 4000 mov ax, 1 ; AX = 1 sal ax, 10 ; Умножение на 210, AX = 0400h = 1024 mov ax, -48 ; AX = ffd0h = -48 (в дополнительном коде) sal ax, 2 ; AX = ff40h = -192 (в дополнительном коде) mov ax, 26812 ; AX = 68bch = 26812 sal ax, 1 ; AX = d178h = -11912 ; Знаковое положительное число перешло в отрицательное mov ax, 32943 ; AX = 80afh = 32943 sal ax, 2 ; AX = 02bch = 700 ; Большое беззнаковое число стало гораздо меньше
Сочетая сдвиги со сложением и вычитанием можно выполнить умножение на любое положительное число. Для умножения на отрицательное число следует добавить команду NEG .
mov ebx, x mov eax, ebx sal eax, 2 add eax, ebx ; EAX = x * 5 mov ebx, x mov eax, ebx sal eax, 3 sub eax, ebx ; EAX = x * 7 mov ebx, x mov eax, ebx sal eax, 2 add eax, ebx sal eax, 1 ; EAX = x * 10
Такой набор операций выполняется в 1.5-2 раза быстрее, чем обычное умножение. Но если оба сомножителя заранее неизвестны, то лучше использовать умножение.
6.3.2. Деление
Для деления используется сдвиг вправо. При делении нет проблем с переполнением, но для знаковых и беззнаковых чисел надо использовать разные механизмы.
Для деления беззнаковых чисел следует использовать логический сдвиг вправо.
mov ax, 43013 ; AX = a805h = 43013 shr ax, 1 ; AX = 5402h = 21506
Со знаковыми числами дело обстоит несколько сложнее. В принципе, для деления знаковых чисел следует использовать арифметический сдвиг вправо. Однако для отрицательных чисел получается не совсем корректный результат: 1 / 2 = 0, 3 / 2 = 1, но -1 / 2 = -1, -3 / 2 = -2,, т.е. результат отличается от правильного на единицу. Для того чтобы получить правильный результат, необходимо прибавить к делимому делитель, уменьшенный на 1. Однако это необходимо только для отрицательных чисел, поэтому для того, чтобы не делать проверок, используют следующий алгоритм.
; Деление на 2 mov eax, x cdq ; Расширяем двойное слово до учетверённого. Если в регистре EAX находится положительное число, ; то регистр EDX будет содержать 0, а если в регистре EAX находится отрицательное число, ; то регистр EDX будет содержать -1 (ffffffffh) sub eax, edx ; Если регистр EDX содержит 0, то регистр EAX не меняется. Если же регистр EDX содержит -1 ; (при отрицательном EAX), то к EAX будет прибавлена требуемая единица sar eax, 1 ; Деление на 2 n (в данном примере n = 3) mov eax, x cdq ; Расширяем двойное слово до учетверённого and edx, 111b ; Если EAX отрицателен, то EDX содержит делитель, уменьшенный на 1 add eax, edx ; Если EAX отрицателен, прибавляем полученное значение sar eax, 3 ; Если EAX был положителен, то EDX = 0, и предыдущие две операции ничего не меняют
Если число беззнаковое или если мы знаем, что число положительное, можно просто использовать сдвиг вправо, который выполняется примерно в 10 раз быстрее, чем деление. Если же для знакового числа не известно, положительное оно или отрицательное, то придётся использовать вышеприведённую последовательность команд, которая, однако, также выполняется примерно в 5-7 раз быстрее, чем деление.
6.3.3. Получение остатка от деления
Для беззнаковых и положительных чисел остаток от деления на 2 n – это последние n бит числа. Поэтому для получения остатка от деления на 2 n нужно выделить эти последние n бит с помощью операции AND .
mov eax, x and eax, 111b ; EAX = EAX % 2 3
Для отрицательного делимого x и положительного делителя n (x % n) = -(-x % n) .
mov eax, x neg eax and eax, 1111b ; EAX = EAX % 2 4 neg eax
7. Программа. Процедуры
7.1. Структура программы на языке ассемблера
Программа на языке ассемблера имеет следующую структуру:
Директива .686 указывает компилятору ассемблера, что необходимо использовать набор операций процессора определённого поколения.
Директива .model позволяет указывать используемую модель памяти и соглашение о вызовах. Как уже было сказано, на архитектуре Win32 используется только одна модель памяти – flat, что и указано в приведённом примере. Соглашения о вызовах определяют порядок передачи параметров и порядок очистки стека.
Директива option casemap: none заставляет компилятор языка ассемблера различать большие и маленькие буквы в метках и именах процедур.
Директивы .data , .data? , .const и .code определяют то, что называется секциями. В Win32 нет сегментов, но адресное пространство можно поделить на логические секции. Начало одной секции отмечает конец предыдущей. Есть две группы секций: данных и кода.
Секция .data содержит инициализированные данные программы.
Секция .data? содержит неинициализированные данные программы. Иногда нужно только предварительно выделить некоторое количество памяти, не инициализируя её. Эта секция для этого и предназначается. Преимущество неинициализированных данных в том, что они не занимают места в исполняемом файле. Вы всего лишь сообщаете компилятору, сколько места вам понадобится, когда программа загрузится в память.
Секция .const содержит объявления констант, используемых программой. Константы не могут быть изменены. Попытка изменить константу вызывает аварийное завершение программы.
Задействовать все три секции не обязательно.
Есть только одна секция для кода: .code . В ней содержится весь код.
Предложения и end устанавливают границы кода. Обе метки должны быть идентичны. Весь код должен располагаться между этими предложениями.
Любая программа под Windows должна, как минимум, корректно завершится. Для этого необходимо вызвать функцию Win32 API ExitProcess.
.686 .model flat, stdcall option casemap: none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib .code program: push 0 call ExitProcess end program
Выше приведён пример минимальной программы на языке ассемблера, которая делает только одно – корректно завершается. В ней появились две новые директивы: include и includelib . Первая позволяет включать в программу файлы, содержащие прототипы процедур, а также определения констант и структур, которые могут понадобиться для программирования под Win32. Вторая директива указывает, какие библиотеки использует программа. Компоновщик должен будет прилинковать их. Без указания включаемого файла kernel2.inc и библиотеки импорта kernel32.lib невозможно будет вызвать процедуру ExitProcess. Файл windows.inc в данном случае включать не обязательно, но он требуется достаточно часто, а включаемые файлы не увеличивают размер получаемой программы.
Команда PUSH кладёт в стек параметр для процедуры ExitProcess. Этот параметр определяет код завершения. Значение 0 – это код нормального завершения программы.
Команда CALL вызывает процедуру ExitProcess.
Если вы используете компилятор MASM32, то пункт меню Project содержит команды Assemble & Link и Console Assemble & Link, которые позволяют скомпилировать обычное и консольное приложение под Windows. Приведённую программу можно откомпилировать обоими способами.
7.2. Команды работы со стеком
Работа со стеком имеет непосредственное отношение к процедурам, т.к. стек используется для передачи параметров и для хранения локальных данных процедур. В принципе, для работы со стеком существуют всего две операции: положить данные и взять данные. Для каждой операции существует несколько команд, которые отличаются тем, с какими данными они работают.
Для того чтобы положить данные в стек используется команда PUSH :
Операнд может быть регистром, ячейкой памяти или непосредственным операндом. Размер операнда должен быть 2 или 4 байта. Операнд кладётся на вершину стека, а значение регистра ESP уменьшается на размер операнда.
Для того чтобы взять данные из стека используется команда POP :
Операнд может быть регистром или ячейкой памяти. Размер операнда должен быть 2 или 4 байта. В соответствии с размером операнда из вершины стека берутся 2 или 4 байта и помещаются в указанный регистр или ячейку памяти. Значение регистра ESP увеличивается на размер операнда.
Кроме этих основных команд существуют ещё команды, которые позволяют сохранять в стеке и восстанавливать из стека содержимое всех регистров общего назначения, и команды, которые позволяют сохранять в стеке и восстанавливать из стека содержимое регистра флагов.
Команда PUSHA сохраняет в стеке содержимое регистров AX, CX, DX, BX, SP, BP, SI, DI. Команда PUSHAD сохраняет в стеке содержимое регистров EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI. Для регистра (E)SP сохраняется значение, которое было до того, как мы положили регистры в стек. После этого значение регистра (E)SP изменяется как обычно.
Эти команды противоположны предыдущим – они восстанавливают из стека значения регистров (E)DI, (E)SI, (E)BP, (E)SP, (E)BX, (E)DX, (E)CX, (E)AX. Содержимое регистра (E)SP не восстанавливается из стека, а изменяется как обычно.
Команда PUSHF сохраняет в стеке младшие 16 бит регистра флагов. Команда PUSHFD сохраняет в стеке все 32 бита регистра флагов.
Команда POPF восстанавливает из стека младшие 16 бит регистра флагов. Команда POPFD восстанавливает из стека все 32 бита регистра флагов.
7.3. Синтаксис процедуры
Описание процедуры на языке ассемблера выглядит следующим образом:
Несмотря на то, что после имени процедуры не ставится двоеточие, это имя является меткой, обозначающей первую команду процедуры.
В языке ассемблера имена и метки, описанные в процедуре, не локализуются внутри неё, поэтому они должны быть уникальны.
Размещать процедуру в программе на языке ассемблера следует таким образом, чтобы команды процедуры выполнялись не сами по себе, а только тогда, когда происходит обращение к процедуре. Обычно процедуры размещают либо в конце секции кода после вызова функции ExitProcess, либо в самом начале секции кода, сразу после директивы .code .
7.4. Вызов процедуры и возврат из процедуры
Вызов процедуры – это, по сути, передача управления на первую команду процедуры. Для передачи управления можно использовать команду безусловного перехода на метку, являющуюся именем процедуры. Можно даже не использовать директивы proc и endp , а написать обычную метку с двоеточием после вызова функции ExitProcess.
С возвратом из процедуры дело обстоит сложнее. Дело в том, что обращаться к процедуре можно из разных мест основной программы, а потому и возврат из процедуры должен осуществляться в разные места. Сама процедура не знает, куда надо вернуть управление, зато это знает основная программа. Поэтому при обращении к процедуре основная программа должна сообщить ей адрес возврата, т.е. адрес той команды, на которую процедура должна сделать переход по окончании своей работы. Поскольку при разных обращениях к процедуре будут указываться разные адреса возврата, то и возврат управления будет осуществляться в разные места программы. Адрес возврата принято передавать через стек.
.686 .model flat, stdcall option casemap: none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib .code program: push L jmp Procedure L: nop push 0 call ExitProcess Procedure: pop eax jmp eax end program
Однако так обычно не делают – система команд языка ассемблера включает специальные команды для вызова процедуры и возврата из процедуры.
CALL ; Вызов процедуры RET ; Возврат из процедуры
Команда CALL записывает адрес следующей за ней команды в стек и осуществляет переход на первую команду указанной процедуры. Команда RET считывает из вершины стека адрес и выполняет переход по нему.
.686 .model flat, stdcall option casemap: none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib .code program: call Procedure push 0 call ExitProcess Procedure proc ret Procedure endp end program
7.5. Передача параметров процедуры
- Параметры можно передавать через регистры.
- Параметры можно передавать в глобальных переменных.
- Параметры можно передавать в блоке параметров.
- Параметры можно передавать через стек.
Передача параметров через стек – наиболее распространённых способ. Именно его используют языки высокого уровня, такие как С++ и Паскаль. Параметры помещаются в стек непосредственно перед вызовом процедуры.
При внимательном анализе этого метода передачи параметров возникает сразу два вопроса: кто должен удалять параметры из стека, процедура или вызывающая её программа, и в каком порядке помещать параметры в стек. В обоих случаях оказывается, что оба варианта имеют свои «за» и «против». Если стек освобождает процедура, то код программы получается меньшим, а если за освобождение стека от параметров отвечает вызывающая программа, то становится возможным вызвать несколько функций с одними и теми же параметрами просто последовательными командами CALL . Первый способ, более строгий, используется при реализации процедур в языке Паскаль, а второй, дающий больше возможностей для оптимизации, – в языке С++.
Основное соглашение о вызовах языка Паскаль предполагает, что параметры кладутся в стек в прямом порядке. Соглашения о вызовах языка С++, в том числе одно из основных соглашений о вызовах ОС Windows stdcall, предполагают, что параметры помещаются в стек в обратном порядке. Это делает возможной реализацию функций с переменным числом параметров (как, например, printf). При этом первый параметр определяет число остальных параметров.
В приведённом выше участке кода в стек кладутся несколько параметров и затем вызывается процедура. Следует помнить, что команда CALL также кладёт в стек адрес возврата. Таким образом, перед выполнением первой команды процедуры стек будет выглядеть следующим образом.
Адрес возврата оказывается в стеке поверх параметров. Однако поскольку в рамках своего участка стека процедура может обращаться без ограничений к любой ячейки памяти, нет необходимости перекладывать куда-то адрес возврата, а потом возвращать его обратно в стек. Для обращения к первому параметру используют адрес [ESP + 4] (прибавляем 4, т.к. на архитектуре Win32 адрес имеет размер 32 бита), для обращения ко второму параметру – адрес [ESP + 8] и т.д.
После завершения работы процедуры необходимо освободить стек. Если используется соглашение о вызовах stdcall (или любое другое, предполагающее, что стек освобождается процедурой), то в команде RET следует указать суммарный размер в байтах всех параметров процедуры. Тогда команда RET после извлечения адреса возврата прибавит к регистру ESP указанное значение, освободив таким образом стек. Если же используется соглашение о вызовах cdecl (или любое другое, предполагающее, что стек освобождается вызывающей программой), то после команды CALL следует поместить команду, которая прибавит к регистру ESP нужное значение.
- Параметры можно передавать в потоке кода.
В этом необычном методе передаваемые процедуре данные размещаются прямо в коде программы, сразу после команды CALL . Чтобы прочитать параметр, процедура должна использовать его адрес, который автоматически передаётся в стеке как адрес возврата из процедуры. Разумеется, процедура должна будет изменить адрес возврата на первый байт после конца переданных параметров перед выполнением команды RET .
.686 .model flat, stdcall option casemap: none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib .code program: call Procedure ; Команда CALL кладёт в стек адрес следующей команды db ‘string’,0 ; В нашем случае – адрес начала строки push 0 call ExitProcess Procedure proc pop esi ; Извлекаем из стека адрес начала строки xor eax, eax ; Обнуляем EAX, в нём будет храниться количество символов L1: mov bl, [esi] ; Заносим в регистр BL байт, хранящийся по адресу ESI inc esi ; Увеличиваем значение в регистре ESI на 1 inc eax ; Увеличиваем значение в регистре EAX на 1 cmp bl, 0 ; Сравниваем прочитанный символ с нулём jne L1 ; Если не 0, переходим к началу цикла push esi ; Кладём в стек адрес байта, следующего сразу за строкой ret ; Возврат из процедуры Procedure endp end program
7.6. Передача результата процедуры
Для передачи результата процедуры обычно используется регистр EAX. Этот способ используется не только в программах на языке ассемблера, но и в программах на языке С++. Объекты, имеющие размер не более 8 байт, могут передаваться через регистровую пару EDX:EAX. Вещественные числа передаются через вершину стека вещественных регистров. Если эти способы не подходят, то следует передать в качестве параметра адрес ячейки памяти, куда будет записан результат.
; Передача параметров через стек, возврат результата через регистр EAX .686 .model flat, c option casemap: none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib .data a dd 76 b dd -8 d dd ? .code program: push b ; Кладём параметры в стек push a call Procedure add esp, 8 ; Освобождаем 8 байт стека mov d, eax ; d = a – b push 0 call ExitProcess Procedure proc mov eax, [esp + 4] ; Заносим в регистр EAX первый параметр mov edx, [esp + 8] ; Заносим в регистр EDX второй параметр sub eax, edx ; В регистре EAX получилась разность параметров ret Procedure endp end program ; Передача параметров через стек, возврат результата по адресу .686 .model flat, c option casemap: none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib .data a dd 76 b dd -8 d dd ? .code program: push offset d ; Кладём в стек адрес переменной, куда будет записан результат push b push a call Procedure add esp, 12 ; Освобождаем 12 байт стека push 0 call ExitProcess Procedure proc mov eax, [esp + 4] ; Заносим в регистр EAX первый параметр mov edx, [esp + 8] ; Заносим в регистр EDX второй параметр sub eax, edx ; В регистре EAX получилась разность параметров mov edx, [esp + 12] ; Заносим в регистр EDX третий параметр – адрес результата mov [edx], eax ; Записываем результат по адресу в регистре EDX ret Procedure endp end program
7.7. Сохранение регистров в процедуре
Практически любые действия в языке ассемблера требуют использования регистров. Однако регистров очень мало и даже в небольшой программе невозможно будет разделить регистры между частями программы, т.е. договориться, что основная программа использует, например, регистры EAX, ECX, EBP, ESP, а процедура – регистры EBX, EDX, ESI, EDI. В принципе, сделать так можно, но смысла в этом нет, т.к. программировать будет крайне неудобно, придётся перемещать данные из регистров в оперативную память и обратно, что замедлит выполнение программы. Кроме того, существуют правила, которые изменить нельзя – в регистре ESP хранится адрес вершины стека, а команды умножения и деления всегда используют регистры EAX и EDX. Поэтому получается, что основная программа и процедура вынуждены использовать одни и те же регистры, причём, вычисления в основной программе прерываются для того, чтобы выполнить вычисления процедуры. Таким образом, чтобы основная программа могла продолжить вычисления, процедура должна при выходе восстановить те значения регистров, которые были до начала выполнения процедуры. Естественно, для этого процедуре придётся предварительно сохранить значения регистров. Всё вышесказанное относится также к случаю, когда одна процедура вызывает другую процедуру.
Особенно внимательно следует относиться к регистрам ESI, EDI, EBP и EBX. ОС Windows использует эти регистры для своих целей и не ожидает, что вы измените их значение.
Если вы пишите всю программу целиком, то, в принципе, можете добиться того, что после вызова процедуры в основной программе нужные регистры будут правильно проинициализированы. Если же вы пишите отдельные процедуры, которые затем будут использоваться в другой программе, то никаких гарантий нет, и сохранение и восстановление регистров становится жизненно необходимой операцией.
Где можно сохранить значения регистров? Конечно же, в стеке. Можно сохранить используемые регистры по одному с помощью команды PUSH , или все сразу с помощью команды PUSHAD . В первом случае в конце процедуры нужно будет восстановить значения сохранённых регистров с помощью команды POP в обратном порядке. Во втором случае для восстановления значений регистров используется команду POPAD .
При сохранении регистров указатель стека изменится на некоторое значение, зависящее от количества сохранённых регистров. Это нужно будет учитывать при вычислении адресов параметров процедуры, передаваемых через стек.
; Процедура получает два параметра по 4 байта Procedure proc push esi ; Сохраняем используемые регистры push edi mov esi, [esp + 12] ; Извлекаем параметры из стека. Адрес вычисляется mov edi, [esp + 16] ; с учётом 8 байт, использованных при сохранении регистров . pop edi ; Извлекаем сохранённые регистры из стека pop esi ; в обратном порядке ret Procedure endp ; Процедура получает два параметра по 4 байта Procedure proc pushad ; Сохраняем все регистры mov eax, [esp + 4 + 32] ; Извлекаем параметры из стека. Адрес вычисляется mov ebx, [esp + 8 + 32] ; с учётом 32 байт, использованных при сохранении регистров . popad ; Извлекаем сохранённые регистры из стека ret Procedure endp
7.8. Локальные данные процедур
Процедуры часто нуждаются в локальных данных. Локальные переменные размещаются в стеке. Для того чтобы отвести место под локальные переменные в процедуре на языке ассемблера, достаточно просто вычесть из регистра ESP размер требуемой памяти. После этого все вызываемые процедуры будут «знать», что место в стеке занято, и размещать свои данные в незанятой части стека.
При вызове других процедур, а также в ходе выполнения текущей процедуры в стек могут быть положены другие данные. При этом значение регистра ESP изменится. Поэтому регистр ESP не является надёжной точкой отсчёта для адресов локальных переменных. Для того чтобы получить такую точку отсчёта, значение регистра ESP переписывают в регистр EBP, предварительно сохранив значение регистра EBP в стеке. В этом случае регистр EBP отмечает часть стека, занятую на момент начала работы процедуры (отсюда происходит название регистра EBP – указатель базы кадра стека). При таком подходе первый параметр процедуры всегда находится по адресу [EBP + 8]. Адреса локальных переменных отсчитываются от регистра EBP с отрицательным смещением. По окончании работы процедуры значение регистра ESP восстанавливается по регистру EBP, а значение регистра EBP – из стека.
Procedure proc var_104 = byte ptr -104h var_4 = dword ptr -4 arg_0 = dword ptr 8 arg_4 = dword ptr 0ch push ebp mov ebp, esp sub esp, 104h mov edx, [ebp + arg_0] mov eax, [ebp + arg_4] push ebx push esi push edi . pop edi pop esi pop ebx mov esp, ebp pop ebp ret Procedure endp
Такой способ позволяет также отводить различное количество места под локальные данные, и при необходимости не заботится о парности команд PUSH и POP .
7.9. Рекурсивные процедуры
Рекурсия – ресурсоёмкий способ реализации алгоритмов. Она требует много места для хранения локальных данных на каждом шаге рекурсии, кроме того, рекурсивные процедуры обычно выполняются не очень быстро. Поэтому языку ассемблера, предназначенному для написания быстрых программ, рекурсия, в общем, не свойственна. Но при желании и на ассемблере можно написать рекурсивную процедуру. Принципы реализации рекурсивной процедуры на языке ассемблера такие же, как и на других языках. В процедуре должна быть терминальная ветвь, в которой нет рекурсивного вызова, и рабочая ветвь.
При реализации рекурсивных процедур становится особенно важным использование стека для передачи параметров и адреса возврата, что позволяет хранить данные, относящиеся к разным уровням рекурсивных вызовов, в разных областях памяти.
Для примера рассмотрим рекурсивную процедуру вычисления факториала целого беззнакового числа. Процедура получает параметр через стек и возвращает результат через регистр EAX.
factorial proc mov eax, [esp + 4] ; Заносим в регистр EAX параметр процедуры test eax, eax ; Проверяем значение в регистре EAX jz L1 ; Если EAX = 0, то обходим рекурсивную ветвь dec eax ; Уменьшаем значение в регистре EAX на 1 push eax ; Кладём в стек параметр для следующего рекурсивного вызова call factorial ; Вызываем процедуру add esp, 4 ; Очищаем стек, т.к. процедура использует RET без параметров mul dword ptr [esp + 4] ; Умножаем EAX, хранящий результат предыдущего вызова, на параметр текущего вызова процедуры ret ; Возврат из процедуры (без параметров) L1: inc eax ; Если EAX был равен 0, записываем в EAX единицу L2: ret ; Возврат из процедуры (без параметров) factorial endp
8. Оптимизация программ, написанных на языке ассемблера
Наиболее популярным применением ассемблера обычно считается именно оптимизация программ, то есть уменьшение времени выполнения программ по сравнению с языками высокого уровня. Но если просто переписать текст, например с языка С на ассемблер, переводя каждую команду наиболее очевидным способом, часто оказывается, что процедура на языке С выполняется быстрее. Вообще говоря, ассемблер, как и любой другой язык, сам по себе не является панацеей от неэффективного программирования – чтобы действительно оптимизировать программу, требуется не только знание команд процессора, но и знание алгоритмов, навык оптимальных способов их реализации и подробная информация об архитектуре процессора.
- выбор наиболее оптимального алгоритма – высокоуровневая оптимизация;
- наиболее оптимальная реализация алгоритма – оптимизация среднего уровня;
- подсчёт тактов, тратящихся на выполнение каждой команды, и оптимизация их порядка для конкретного процессора – низкоуровневая оптимизация.
8.1. Высокоуровневая оптимизация
Выбор оптимального алгоритма для решения задачи всегда приводит к лучшим результатам, чем любой другой вид оптимизации. Действительно, при замене пузырьковой сортировки, время выполнения которой пропорционально n 2 , на быструю сортировку, время выполнения которой пропорционально n * log(n) , вторая программа будет выполняться быстрее в подавляющем большинстве случаев, как бы она ни была реализована. Поиск лучшего алгоритма – универсальная стадия, и она относится не только к ассемблеру, но и к любому языку программирования, поэтому будем считать, что оптимальный алгоритм уже выбран.
8.2. Оптимизация среднего уровня
Реализация алгоритма на данном конкретном языке программирования – самая ответственная стадия оптимизации. Именно здесь можно получить выигрыш в скорости в десятки раз или сделать программу в десятки раз медленнее, при серьёзных ошибках в реализации. Методы оптимизации сильно зависят от конкретного реализуемого алгоритма, поэтому невозможно описать правила на все случаи жизни, хотя, конечно, есть ряд общих приёмов, например, хранение переменных, с которыми выполняется активная работа, в регистрах, использование таблиц переходов вместо длинных последовательностей проверок и условных переходов и т.п. Тем не менее, даже плохо реализованные операции не вносят заметных замедлений в программу, если они не повторяются в цикле. Практически можно говорить, что все проблемы оптимизации на среднем уровне так или иначе связаны с циклами, и именно поэтому мы рассмотрим основные правила, которые стоит иметь в виду при реализации любого алгоритма, содержащего циклы.
8.2.1. Вычисление констант вне цикла
Самым очевидным и самым важным правилом при создании цикла на любом языке программирования является вынос всех переменных, которые не изменяются на протяжении цикла, за его пределы. В случае ассемблера имеет смысл также по возможности разместить все переменные, которые будут использоваться внутри цикла, в регистры, а старые значения нужных после цикла регистров сохранить в стеке.
8.2.2. Перенос проверки условия в конец цикла
Циклы типа while или for, которые так часто применяются в языках высокого уровня, оказываются менее эффективными по сравнению с циклами типа until из-за того, что в них требуется лишняя команда перехода.
Предположим, в цикле должен быть один шаг. Тогда в цикле с предусловием будет выполнено сравнение, тело цикла, безусловный переход к началу цикла, сравнение и переход за цикл. В цикле с постусловием будет выполнено тело цикла, сравнение и нереализованный переход. Таким образом, в цикле с предусловием выполняется одно лишнее сравнение и два реализованных перехода (2 * 3 такта = 6 тактов) вместо одного нереализованного (1 такт). Вроде бы и немного, но если цикл окажется внутри другого цикла, то все эти лишние такты будут повторяться многократно. Кроме того, цикл с постусловием содержит на одну команду меньше.
Конечно, цикл с постусловием всегда выполняется хотя бы один раз, и во многих случаях перед циклом приходится добавлять ещё одну проверку, но в любом случае даже небольшое уменьшение тела цикла всегда оказывается необходимой операцией.
8.2.3. Выполнение цикла задом наперёд
Циклы, в которых значение счётчика растёт от единицы или нуля до некоторой величины, можно реализовать вообще без операции сравнения, выполняя цикл в обратном направлении. Флаги меняются не только командой сравнения, но и многими другими. В частности, команда DEC меняет флаги AF, OF, PF, SF и ZF. Команда сравнения кроме этих флагов меняет также флаг CF, но для сравнения с нулём можно обойтись флагами SF и ZF.
; Цикл от 10 до 1 mov edx, 10 loop_start: dec edx ; Уменьшаем EDX на 1. Если EDX = 0, то ZF = 1 jnz loop_start ; Переход если ZF = 0. Когда EDX = 0, ZF = 1, поэтому выходим из цикла ; Цикл от 10 до 0 mov edx, 10 loop_start: dec edx ; Уменьшаем EDX на 1. Если EDX = -1, то SF = 1 jns loop_start ; Переход если SF = 0. Когда EDX = -1, SF = 1, поэтому выходим из цикла
Циклы от 0 и от 1 являются, наверное, самыми распространёнными. Конечно, не все циклы можно заставить выполняться в обратном направлении сразу. Например, иногда приходится изменять формат хранения массива данных также на обратный, иногда приходится вносить другие изменения, но в целом, если это возможно, всегда следует стремиться к циклам, выполняющимся задом наперёд.
8.2.4. Разворачивание циклов
Для небольших циклов время выполнения проверки условия и перехода на начало цикла может оказаться значительным по сравнению со временем выполнения самого тела цикла. В таких случаях можно вообще не создавать цикл, а просто повторить его тело нужное число раз (разумеется, только в случае, если нам заранее известно это число!). Для очень коротких циклов можно, например, удваивать или утраивать тело цикла, если, конечно, число повторений кратно двум или трём. Кроме того, бывает удобно часть работы сделать в цикле, а часть развернуть.
; Цикл от 10 до -1 mov edx, 10 loop_start: dec edx jns loop_start ; Выходим из цикла, когда EDX станет равны -1 ; Но повторяем тело цикла ещё раз
Естественно, эти простые методики не перечисляют все возможности оптимизации среднего уровня, более того, они не описывают и десятой доли всех её возможностей. Умение оптимизировать программы нельзя сформулировать в виде набора простых алгоритмов – слишком много существует различных ситуаций, в которых всякий алгоритм оказывается неоптимальным. При решении любой задачи оптимизации приходится пробовать десятки различных небольших изменений, далеко не все из которых оказываются полезными. Именно потому, что оптимизация всегда занимает очень много времени, рекомендуется приступать к ней только после того, как программа окончательно написана.
8.3. Низкоуровневая оптимизация
8.3.1. Основные принципы
Так как современные процессоры используют весьма сложный набор команд, большинство операций можно выполнить на низком уровне очень многими способами. При этом иногда оказывается, что наиболее очевидный способ – не самый быстрый. Часто простыми перестановками команд, зная механизм выполнения команд на современных процессорах, можно заставить ту же процедуру выполняться на 50–200% быстрее. Разумеется, переходить к этому уровню оптимизации можно только после того, как текст программы окончательно написан и максимально оптимизирован на среднем уровне.
- Используйте регистр ЕАХ всюду, где возможно. Команды с непосредственным операндом, с операндом – абсолютным адресом переменной и команды XCHG с регистрами занимают на один байт меньше, если другой операнд – регистр ЕАХ.
- Если к переменной в памяти, адресуемой со смещением, выполняется несколько обращений – загрузите её в регистр.
- Не используйте сложные команды – ENTER , LEAVE , LOOP , строковые команды, если аналогичное действие можно выполнить небольшой последовательностью простых команд.
- Не используйте умножение или деление на константу – его можно заменить другими командами (см. раздел 6.3).
- Старайтесь программировать условия и переходы так, чтобы переход выполнялся по менее вероятному событию.
- Следующее эмпирическое правило, относящееся к переходам и вызовам, очень простое: избавляться от них везде, где только можно. Для этого организуйте программу так, чтобы она исполнялась прямым, последовательным образом, с минимальным числом точек принятия решения. В результате очередь команд будет почти всегда заполнена, а вашу программу будет легче читать, сопровождать и отлаживать. Процедуры, особенно небольшие, нужно не вызывать, а встраивать. Это, конечно, увеличивает размер программы, но даёт существенный выигрыш во времени её исполнения.
- Используйте короткую форму команды JMP , где возможно ( jmp short ).
- Команда LEA быстро выполняется и имеет много неожиданных применений (см. раздел 8.3.2).
- Многие одиночные команды, как это ни странно, выполняются дольше, чем две или три команды, приводящие к тому же результату. Это может быть связано с различными особенностями выполнения команд, в том числе, с возможностью/невозможность попарного выполнения команд в разных конвейерах (см. раздел 8.3.3).
- Старайтесь выравнивать данные и метки по адресам, кратным 2/4/8/16 (см. раздел 8.3.4).
- Если команда обращается к 32-битному регистру, например ЕАХ, сразу после команды, выполнявшей запись в соответствующий частичный регистр (АХ, AL, АН), может происходить пауза в один или несколько тактов.
8.3.2. Использование команды LEA
- Команда LEA может использоваться для трёхоперандного сложения (но только сложения, а не вычитания).
- Команда LEA может использоваться для сложения значения регистра с константой или вычитания константы из значения регистра. В данном случае вычитание возможно, т.к. оно рассматривается как сложение с отрицательной константой. Результат может быть помещён в тот же или другой регистр (кроме регистра ESP). Такой способ используется для сохранения флагов, т.к. команда LEA , в отличие от команд ADD , SUB , INC и DEC , не меняет флаги.
- Команда LEA может использоваться для быстрого умножения на константы 2, 3, 4, 5, 7(?), 8, 9. Адрес, загружаемый командой LEA , может быть суммой двух регистров, один из которых может быть умножен на константу 2, 4 или 8. Поэтому комбинируя умножение и сложение можно получить вышеперечисленные константы. Третье слагаемое может быть константой.
lea eax, [eax * 4 + eax] ; EAX = EAX * 5 lea eax, [ebx * 8 + ecx – 32]
8.3.3. Замена команд
- Вместо команды AND лучше использовать команду TEST, если нужен не результат, а проверка. Команда TEST лучше спаривается. Команда TEST также может быть использована для проверки на равенство нулю.
- Если за командой CALL сразу же следует команда RET , замените эти команды командой JMP . Вызываемая процедура осуществит возврат по адресу возврата, переданному вызывающей процедуре.
- Команду CBW можно заменить засылкой нуля, если расширяемое число положительное. Команду CDQ можно заменить засылкой нуля, если расширяемое число положительное, или парой команд MOV + SAR , если знак расширяемого числа не известен. Недостаток – команды XOR и SAR меняют флаги.
- Вместо команд инкремента и декремента можно использовать команду LEA .
- Сложение и вычитание с константой можно заменить командой LEA .
- Вместо умножения и деления на степень числа 2 используйте сдвиги.
- Умножение и деление на константу можно заменить командой LEA или сочетанием команд сдвига и команд сложения и вычитания.
- Деление на константу можно заменить умножением на константу.
- Обнуление регистров производится с помощью команды XOR .
- Не используйте команду MOVZX для чтения байта – это требует 3 тактов для выполнения. Заменой может служить такая пара команд, выполняющаяся за 2 такта:
- Засылку непосредственного операнда в ячейку памяти можно производить через регистр – такие команды лучше спариваются.
- Аналогично команды PUSH и POP , работающие с ячейкой памяти, можно заменить парой команд MOV + PUSH или POP + MOV .
push x mov eax, x push eax pop x pop eax mov x, eax
8.3.4. Выравнивание
- 80-битные данные должны быть выравнены по 16-байтным границам (то есть четыре младших бита адреса должны быть равны нулю).
- Восьмибайтные данные должны быть выравнены по восьмибайтным границам (то есть три младших бита адреса должны быть равны нулю).
- Четырёхбайтные данные должны быть выравнены по границе двойного слова (то есть два младших бита адреса должны быть равны нулю).
- Двухбайтные данные должны быть выравнены по границе слова.
- Метки для переходов, особенно метки, отмечающие начало цикла, должны быть выравнены по 16-байтным границам.
Каждое невыравненное обращение к данным означает потерю тактов процессора.
Для выравнивания данных и кода используется директива ALIGN :
Число должно быть степенью двойки. Данные и команда, расположенные после директивы ALIGN , будут размещены по адресу, кратному указанному числу.
9. Примеры
- Процедура вычисления наибольшего общего делителя двух беззнаковых чисел. Для нахождения НОД используется алгоритм Евклида: пока числа не равны, надо вычитать из большего числа меньшее. Процедура получает параметры через регистры EAX и EDX и возвращает результат через регистр EAX.
- Ввод и вывод в консольном приложении. В программе используются следующие функции Win32 API.
- SetConsoleTitle – меняет заголовок окна консоли. Получает один параметр – указатель на строку, которая будет выведена в заголовке. Строка должна заканчиваться нулём.
- GetStrHandle – возвращает идентификатор устройства ввода, устройства вывода или устройства отчёта об ошибках. Для консольного приложения всё три устройства являются консолью, но идентификаторы будут разными. Функция получает один параметр – указание, идентификатор какого устройства нужно вернуть. Чтобы получить идентификатор устройства ввода, надо передать функции число -10, чтобы получить идентификатор устройства вывода – число -11, а чтобы получить идентификатор устройства отчёта об ошибках – число -12. Функция возвращает требуемый идентификатор через регистр EAX.
- WriteConsole – выводит строку в консоль. Получает следующие параметры – идентификатор устройства вывода, адрес выводимой строки, количество символов для вывода, адрес переменной, куда будет записано количество выведенных символов, зарезервированный указатель.
- ReadConsole – вводит строку из консоли. Получает следующие параметры – идентификатор устройства ввода, адрес памяти, куда будет записана введённая строка, максимальное количество читаемых символов, адрес переменной, куда будет записано реальное количество введённых символов, зарезервированный указатель.
Не забывайте, что параметры кладутся в стек, начиная с последнего, и что введённая строка всегда будет содержать в конце символы с кодами 13 и 10, которые появляются при нажатии на клавишу ВВОД (без чего, однако, ввод не завершится).
- Процедура ввода целого числа в 16-ричной системе счисления. Процедура предназначена для использования в консольном приложении и предполагает, что идентификатор устройства ввода был получен основной программой и сохранён в переменной hStdIn.
- Процедура вывода числа в 16-ричной системе счисления. Процедура получает один параметр – выводимое число. Для вывода всегда формируется строка из 8-ми шестнадцатеричных цифр с лидирующими нулями. Поскольку количество символов заранее известно, они будут сразу же записываться в строку с конца, и инвертировать строку не придётся. Процедура предназначена для использования в консольном приложении и предполагает, что идентификатор устройства ввода был получен основной программой и сохранён в переменной hStdOut.
- Функция, находящая в одномерном массиве x сумму значений f(x[i]), где f – некоторая функция одного целочисленного аргумента, адрес которой передаётся через параметры. Функции используют соглашение о вызовах cdecl.
Sum proc push ebp mov ebp, esp push esi push edi mov ecx, [ebp + 8] ; Заносим в ECX первый параметр – количество элементов массива mov esi, [ebp + 12] ; Заносим в ESI второй параметр – адрес начала массива mov edi, [ebp + 16] ; Заносим в EDI третий параметр – адрес функции xor edx, edx ; Обнуляем регистр EDX L: push [esi] ; Кладём в стек элемент массива call edi ; Вызываем функцию, адрес которой находится в регистре EDI add esp, 4 ; Освобождаем стек add edx, eax ; Прибавляем результат функции к общей сумме add esi, 4 ; Переходим к следующему элементу массива dec ecx ; Уменьшаем значение регистра ECX на 1 jnz L ; Если ECX не равно 0, продолжаем цикл mov eax, edx ; Записываем полученную сумму в регистр EAX, ; через который должен возвращаться результат функции pop edi pop esi mov esp, ebp pop ebp ret Sum endp Sqr proc mov eax, [esp + 4] imul eax ret Sqr endp Negation proc mov eax, [esp + 4] neg eax ret Negation endp
Для вызова функции Sum будет использовать следующая последовательность команд.
- Процедура, проверяющая сбалансированность круглых и квадратных скобок в строке. Строка должна заканчиваться нулём. Для проверки сбалансированности открывающие скобки будем класть в стек, а при нахождении в строке закрывающей скобки будем извлекать из стека последнюю положенную туда открывающую скобку и проверять, что она соответствует закрывающей скобке. Будем считать, что скобок в тексте меньше, чем других символов, поэтому после сравнения делаем переход «если равно», считая, что это событие менее вероятно. При любом выходе из процедуры нужно очистить стек. Поскольку мы не можем заранее знать, сколько скобок будет туда положено и сколько извлечено, восстановление значения регистра ESP можно сделать только с помощью регистра EBP. Процедура возвращает значение через регистр EAX: если скобки сбалансированы, регистр EAX будет содержать значение истина (-1), в противном случае регистр EAX будет содержать значение ложь (0).
Brackets proc push ebx ; Сохраняем регистры push ebp mov ebp, esp ; Сохраняем начальное значение регистра ESP mov ebx, [ebp + 12] ; Заносим в регистр EBX адрес начала строки mov eax, -1 ; Заносим в регистр EAX предварительное значение результата xor edx, edx ; Обнуляем регистр EDX L1: mov dl, [ebx] ; Заносим в регистр DL очередной символ test edx, edx ; Проверяем значение в регистре EDX jz E1 ; Если EDX = 0, выходим из цикла inc ebx ; Меняем адрес символа cmp dl, ‘(‘ ; Сравниваем символ с открывающей круглой скобкой je L2 ; Если равно, . cmp dl, ‘[‘ ; Сравниваем символ с открывающей квадратной скобкой je L2 ; Если равно, . cmp dl, ‘)’ ; Сравниваем символ с закрывающей круглой скобкой je L3 ; Если равно, переходим к сравнению со скобкой из стека cmp dl, ‘]’ ; Сравниваем символ с закрывающей квадратной скобкой je L4 ; Если равно, переходим к сравнению с другой скобкой из стека jmp L1 ; Если символ – не скобка, возвращаемся к началу цикла L2: push dx ; . заносим открывающую скобку в стек (один байт записать в стек нельзя) jmp L1 ; Возвращаемся к началу цикла L3: cmp ebp, esp ; Если была закрывающая скобка, прежде всего проверяем, есть ли скобки в стеке – ; если мы положили что-то в стек, значение регистра ESP будет отличаться от регистра EBP je E2 ; Если значения регистров равны, выходим из процедуры pop cx ; Извлекаем из стека последнюю открывающую скобку cmp cl, ‘(‘ ; Сравниваем jne E2 ; Если скобки не равны, выходим из процедуры jmp L1 ; Иначе возвращаемся к началу цикла L4: cmp ebp, esp ; При нахождении закрывающей квадратной скобки, je E2 ; выполняем те же действия, что и при нахождении закрывающей круглой скобки, pop cx ; только скобку из стека сравниваем с другим значением cmp cl, ‘[‘ ; Дублирование сделано для того, чтобы уменьшить jne E2 ; количество переходов jmp L1 E1: cmp ebp, esp ; При достижении конца строки, сравниваем регистры ESP и EBP je E3 ; Если значения равны, обходим обнуление регистра EAX E2: xor eax, eax ; Если была несбалансированность, обнуляем регистр EAX E3: mov esp, ebp ; Восстанавливаем значение регистра ESP pop ebp pop ebx ret Brackets endp
1 В защищённом режиме программе выделяется один сегмент размером 4 Гб для кода и один сегмент размером 4 Гб для данных (физически они обычно совпадают). Виртуальный адрес состоит из 16-битного значения, хранящегося в сегментном регистре, и 32-битного смещения. Однако преобразование виртуального адреса в физический осуществляется не путём сложения, а по более сложной схеме. Сначала процессор преобразует виртуальный адрес в линейный. При этом он обращается к таблицам дескрипторов, которые заранее строятся операционной системой. На втором этапе по линейному адресу определяется физический. В этом преобразовании участвует другой набор системных таблиц – таблицы страничной трансляции, которые также составляются операционной системой. Оба набора таблиц могут динамически меняться, обеспечивая максимальное использование оперативной памяти.
В сегментные регистры записываются не адреса сегментов, а селекторы, которые представляют собой номера ячеек специальной таблицы, содержащей дескрипторы сегментов программ. Каждый дескриптор хранит все характеристики, необходимые для обслуживания сегмента: базовый линейный адрес сегмента, границу сегмента (номер последнего байта), а также атрибуты сегмента, определяющие его свойства. Процессор с помощью селектора определяет индекс дескриптора адресуемого сегмента, извлекает из него базовый линейный 32-битный адрес сегмента и, сложив его с 32-битным смещением, получает линейный адрес адресуемой ячейки памяти. Получив линейный адрес адресуемого байта, процессор с помощью таблиц трансляции преобразует его в 32-битный физический адрес. Этот адрес зависит от объёма оперативной памяти, установленной на компьютере.
В 32-битной модели Windows предоставляет всем запущенным приложениям один и тот же селектор для сегмента кода и один и тот же селектор для сегмента данных. Базы обоих сегментов равны 0, а границы – FFFFFFFF. Другими слова, каждому приложению как бы предоставляется всё линейное пространство. Поскольку базовые линейные адреса сегментов программы равны 0, виртуальные смещения, с которыми работают приложения, совпадают с линейными адресами. Другими словами, плоское виртуальное адресное пространство программы совпадает с плоским линейным адресным пространством. При этом все приложения используют один и тот же диапазон линейных адресов. Для того чтобы при одинаковых линейных адресах приложения занимали различные участки физической памяти и не затирали друг друга, Windows при смене приложения изменяет таблицы страничной трансляции, с помощью которых как раз и происходит преобразование линейных адресов в физические.
2 Если говорить точнее, то относительный адрес перехода отсчитывается не от самой команды перехода, а от следующей за ней команды. Дело в том, что выполнение любой команды начинается с засылки в регистр EIP адреса следующей по порядку команды и только затем выполняется собственно команда. Поэтому в команде перехода относительный адрес будет прибавляться к значению регистра EIP, которое уже указывает на следующую команду, а потому от этой следующей команды и приходится отсчитывать относительный адрес перехода. Однако, в любом случае, программисту нет необходимости самому высчитывать относительный адрес перехода, это делает компилятор языка ассемблера.
3 Компьютерная программа в целом или её отдельная процедура называется реентерабельной (от англ. reentrant – повторно входимый), если она разработана таким образом, что одна и та же копия инструкций программы в памяти может быть совместно использована несколькими пользователями или процессами. При этом второй пользователь может вызвать реентерабельный код до того, как с ним завершит работу первый пользователь и это как минимум не должно привести к ошибке, а в лучшем случае не должно вызвать потери вычислений (то есть не должно появиться необходимости выполнять уже выполненные фрагменты кода).
- никакая часть вызываемого кода не должна модифицироваться;
- вызываемая процедура не должна сохранять информацию между вызовами;
- если процедура изменяет какие-либо данные, то они должны быть уникальными для каждого пользователя;
- процедура не должна возвращать указатели на объекты, общие для разных пользователей.
В общем случае, для обеспечения реентерабельности необходимо, чтобы вызывающий процесс или функция каждый раз передавал вызываемому процессу все необходимые данные. Таким образом, функция, которая зависит только от своих параметров, не использует глобальные и статические переменные и вызывает только реентерабельные функции, будет реентерабельной. Если функция использует глобальные или статические переменные, необходимо обеспечить, чтобы каждый пользователь хранил свою локальную копию этих переменных. Содержание
Ассемблер
Ассемблер (англ. «Assembler») — это низкоуровневый язык программирования, который представляет собой промежуточное звено между машинным кодом и высокоуровневыми языками программирования. Он используется для написания программ, которые управляют компьютером или другими устройствами на более низком уровне, непосредственно взаимодействуя с аппаратным обеспечением. Код, написанный на этом языке, обычно сохраняется с помощью расширения ASM.
Программы на ассемблере пишутся в виде набора мнемонических инструкций, каждая из которых соответствует определенной команде процессора. Эти инструкции затем транслируются (ассемблируются) в машинный код — набор двоичных чисел, которые понимает центральный процессор и выполняет соответствующие операции.

Начинают изучение программирования обычно с вывода на экран строки «Hello, world!». В языке программирования Python для этого достаточно одной команды:
print("Hello, World!")
Просто, понятно и красиво. Однако, существует язык программирования, в котором для достижения того же результата необходимо написать более обширный кусок кода на ассемблере:
.MODEL SMALL .STACK 100h .DATA HelloMessage DB 'Hello, World!',13,10,'$' .CODE START: mov ax,@data mov ds,ax mov ah,9 mov dx,OFFSET HelloMessage int 21h mov ah,4ch int 21h END START
Несмотря на видимое отличие в сложности между Python и ассемблером, важно понимать, что каждая его команда выполняет всего лишь одну операцию, в то время как одна команда Python вызывает несколько операций процессора при выполнении. Оба языка имеют свои преимущества и применяются в различных сферах программирования.
Кратко про процессоры и машинный язык
Для более полного понимания языка ассемблера начнем с основ работы процессора и того, на каком языке можно общаться с ним.

Процессор представляет собой электронное устройство, которое, несмотря на свою маленькую размерность сегодня (раньше процессоры занимали целые залы), не обладает способностью понимать слова или цифры. Его реакция основана исключительно на двух уровнях напряжения: высокий уровень соответствует «1», а низкий уровень — «0». Таким образом, каждая команда процессора представляет собой последовательность нулей и единиц: «1» — это импульс, а «0» — его отсутствие.
Для взаимодействия с процессором используется машинный язык, который состоит из инструкций, записанных в двоичной форме. Каждая инструкция определяет одну простую машинную операцию: арифметические действия над числами, логические операции (побитовые), ввод-вывод и так далее.
Например, в архитектуре Intel 8088 инструкция 0000001111000011B представляет операцию сложения двух чисел, в то время как 0010101111000011B выполняет вычитание.
Программирование на машинном языке является сложной задачей, так как приходится оперировать огромными цепочками нулей и единиц. Написание или проверка такой программы требует большого труда, не говоря уже о понимании чужого кода.
Поэтому был разработан язык ассемблера, в котором операции обозначаются буквами и сокращениями английских слов, отражающих суть команды. Например, команда mov ax, 6 означает: «переместить число 6 в регистр AX».
Основы ассемблера
Ниже приведена таблица с примерами машинного кода, соответствующими инструкциями на ассемблере и их описаниями:

Проблема была решена, когда ЭВМ научились хранить программы в памяти. В 1950 году была разработана первая программа-транслятор, которая переводила программы, написанные на понятном человеку языке, в машинный код. Эта программа была названа программой-сборщиком, а язык программирования получил название «ассемблера» (от английского слова «assembler» — сборщик). Впервые этот термин стал использовать английский учёный Морис Уилкс (Maurice Wilkes).
Появление ассемблера значительно облегчило жизнь программистов. Они стали использовать команды, которые состояли из условных обозначений, близких к обычному языку. Кроме того, ассемблер позволил сократить размеры программ — это было особенно важно для компьютеров того времени.
Как устроен язык ассемблер
Ассемблер — язык второго поколения, если считать машинный язык первым поколением. Он напрямую взаимодействует с процессором, и каждая его команда представляет собой инструкцию для процессора, а не для операционной или файловой системы. Процесс перевода языка ассемблера в машинный код называется ассемблированием.

Команды ассемблера состоят из кодов операций и операндов. Операнды представляют собой адреса, из которых процессор берет данные для вычислений и в которые он помещает результат. Эти адреса могут быть ячейками оперативной памяти или регистрами — внутренней памятью процессора. Процессор работает с регистрами гораздо быстрее, чем с оперативной памятью.
Операции в языке ассемблера имеют мнемоническую форму, что делает их удобными для запоминания:
- ADD — сложение (от англ. addition);
- SUB — вычитание (от англ. subtraction);
- MUL — умножение (от англ. multiplication) и так далее.
Регистры и ячейки памяти получают символические имена, например:
- EAX , EBX , AX , AH — имена для регистров;
- mem1 — имя для ячейки памяти.
Пример команды сложения чисел из регистров AX и BX :
И вот команда вычитания чисел из регистров AX и BX :
В языке ассемблера также присутствуют директивы — команды управления компилятором, то есть программой-ассемблером.
Некоторые из них:
- INCLUDE — открыть файл и начать его компиляцию;
- EXIT — прекратить компиляцию файла;
- DEF — назначить регистру символическое имя и так далее.
Не думайте, что ассемблер — это просто набор инструкций процессора с удобной записью для программиста. Это полноценный язык программирования, на котором можно реализовать циклы, условные операторы, процедуры и функции.
Вот пример ассемблерного кода, который выводит на экран цифры от 1 до 10:
section .text global _start _start: mov ecx,10 mov eax, '1' label1: mov [num], eax mov eax, 4 mov ebx, 1 push ecx mov ecx, num mov edx, 1 int 0x80 mov eax, [num] sub eax, '0' inc eax add eax, '0' pop ecx loop label1 mov eax,1 int 0x80 section .bss num resb 1

Предлагаемая заработная плата обычно соответствует стандартам сферы информационных технологий и может варьироваться от 80 до 300 тыс. руб. в зависимости от уровня квалификации и опыта кандидата.
Стоит ли начинать изучение программирования с языка ассемблера
Нет, такой подход не рекомендуется. На это есть несколько причин:
- ассемблер существенно отличается от языков высокого уровня, поэтому переход с него на другой язык может быть сложным и запутанным процессом;
- опыт, полученный при изучении ассемблера, не будет особенно полезным при работе с другими языками. При изучении высокоуровневых языков после него, вам придется начинать все с нуля;
- ассемблер — очень детальный язык программирования. Все рутинные действия, которые обрабатываются автоматически трансляторами в других языках, приходится описывать здесь вручную. Это может быстро надоесть и стать утомительным.
Поэтому, даже если ваша профессия связана с ассемблером, рекомендуется начать изучение программирования с языка высокого уровня. После этого изучение ассемблера будет проходить более легко и эффективно.
Статьи по теме:
Словарь компьютерных терминов на букву А

АББРЕВИАТУРА (abbreviation). Слово, составленное из первых букв или сокращенных частей слов, входящих в состав названий или словосочетаний, заменяющее эти названия или словосочетания. Например, ЭВМ — электронная вычислительная машина.
АБЗАЦ (paragraph). 1. Часть текста, ограниченная двумя отступами. 2. Б текстовых редакторах — часть документа между двумя соседними маркерами конца А. Б текстовом редакторе MS Word эти маркеры автоматически вносятся в текст при нажатии клавиши (перевод строки) и видимы при нажатой кнопке 1Г (Непечатаемые знаки). Каждому А. можно придать свой формат, отличный от формата соседних абзацев.
АБОНЕНТ СЕТИ (network abonent, user node). 1. Пользователь, имеющий доступ к ресурсам компьютерной сети или к сети компьютерной связи. 2. Терминал, компьютер или рабочая станция, подключенные к вычислительной сети или сети компьютерной связи.
АБСОЛЮТНЫЙ АДРЕС, физический адрес (absolute address, physical address). I. Адрес в виде цифрового кода, однозначно идентифицирующий реально существующие в вычислительной системе байт, ячейку памяти или устройство. А. а. непосредственно интерпретируется аппаратными средствами или микропрограммами центрального процессора вычислительной системы. А. а. либо указывается как неизменяемый адрес в машинной команде, либо вычисляется, исходя из логического адреса, и не может быть далее уточнен программными средствами. Ср. логический адрес. 2. Цифровой код, однозначно определяющий положение данных на носителе данных. Например, для магнитного диска А. а. представляет код, состоящий из номера поверхности, номера дорожки и номера сектора. См. адресация.
АБСТРАКТНЫЙ КЛАСС, базовый абстрактный класс (abstract class, abstract base class). Б языке программирования C++ — класс, который не может быть использован для создания объектов, но выступает в качестве базы, на основе которой создаются другие классы. А. к. содержит хотя бы одну чисто виртуальную функцию. Ср. абстрактный тип данных.
АБСТРАКТНЫЙ ТИП ДАННЫХ (abstract data type). Понятие, введенное в конце 1970-х годов в теоретических исследованиях по языкам программирования. А. т. д. рассматривается как множество значений и множество операций над этими значениями, причем для описания семантики операций используются формальные математические, в частности, алгебраические, методы. Например, для А. т. д. «стек значений типа Т» с операциями push (протолкнуть в стек) и pop (вытолкнуть из стека) выполняется аксиома ∀ x ∈ T pop (push (x)) = x. Результаты исследований по А. т. д. имеют большое значение для объектно-ориентированного программирования, автоматического синтеза программ, искусственного интеллекта и других разделов информатики.
АБСТРАКТНЫЙ ФАЙЛ (named pipe). To же, что именованный канал.
АБСТРАКЦИЯ (abstraction). Процесс выявления основных характеристик какой-либо сущности с целью обособления ее от других видов сущностей. При проведении А. рассматривается множество различных сущностей в поисках общих основных характеристик. А. подразумевает, что деление сущностей на некоторые виды происходит с некоторой точки зрения. Одна и та же сущность с разных точек зрения может принадлежать к разным абстрактным типам. А. присутствует в любом моделировании, часто на многих уровнях и для различных целей. А. является одним из основных понятий унифицированного языка моделирования UML.
АВАРИЙНОЕ ЗАВЕРШЕНИЕ(abnormal end, abend). Непредусмотренное прекращение исполнения программы из-за возникновения условий, делающих невозможным ее дальнейшее выполнение. Такими условиями могут быть машинный сбой, ошибка, обнаруженная операционной системой, переполнение, деление на ноль или извлечение квадратного корня из отрицательного числа и т. п. При А. з. операционная система предпринимает меры по сохранению работоспособности вычислительной системы, выдает информацию об аварийной ситуации, освобождает ресурсы, занятые задачей, и при возможности продолжает решение других задач. Ср. аварийный останов.
АВАРИЙНЫЙ ОСТАНОВ, авост (abrupt end, abend). Автоматическое прекращение работы компьютера из-за отказа аппаратных средств или программного обеспечения. Ср. аварийное завершение.
АВАРИЙНЫЙ СИГНАЛ (alarm). Сигнал, предупреждающий пользователя о возникновении чрезвычайной ситуации в работе вычислительной системы. Обычно это сообщение об ошибке или сбое в работе программных или аппаратных средств, сопровождаемое звуком. А. с. предваряет аварийное завершение или сопровождает аварийный останов.
АВАРИЯ (crash). Неожиданный выход из строя программных или аппаратных средств. А. программы приводит к потере всех несохраненных данных и может потребовать перезагрузки операционной системы. А. аппаратных средств может привести к потере работоспособности всей вычислительной системы. Последствия такой А. устраняются ремонтом или заменой неисправных блоков. При этом возможны информационные потери. Например, при А. диска могут разрушиться хранящиеся на нем данные ABM (analog computer). To же, что аналоговая вычислительная машина.
АВОСТ (abend, abrupt end). To же, что аварийный останов.
АВТОКОД, язык ассемблера (autocode, assembly language). Простейший язык программирования, ориентированный на конкретный компьютер. По форме и содержанию А. наиболее близок к машинному языку. Структура команд А. определяется структурой команд и данными машинного языка, но, в отличие от последнего, А. допускает применение буквенных обозначений для кодов операций к адресов. Например, на А. формула X = Y+ Ζ программируется следующим образом: MOV AX, Y; Загрузить Υ в регистр MOV ВХ, Ζ; Загрузить Ζ в регистр ADD АХ, ВХ; Добавить Ζ κ Υ MOV X, АХ; Сохранить результат в X А. может иметь макросредства и средства управления трансляцией. Трансляция программы с А. осуществляется программой-ассемблером.
АВТОМАТ (automation, automata). 1. То же, что автоматическое устройство. 2. То же, что конечный автомат.
АВТОМАТИЗАЦИЯ (automation, OLE automation). 1. Система мероприятий по замене труда человека работой машин. 2. Способ управления программными объектами, используемый при связывании и внедрении объектов. А. позволяет одному приложению, которое называется клиентом А. или контроллером Α., использовать объекты и средства другого приложения, которое называется сервером А. Например, все приложения пакета программ Microsoft Office являются как клиентами, так и серверами А. См. связывание и внедрение объектов.
АВТОМАТИЗИРОВАННАЯ ОБУЧАЮЩАЯ СИСТЕМА (АОС) (automated training system, computer based training system (CBT)). Комплекс программных, технических и учебно-методических средств, предназначенных для активного индивидуального обучения человека на основе программного управления этим обучением. Работа с АОС ведется в режиме диалога и напоминает диалог ученика с педагогом-репетитором. АОС делятся на специализированные, предназначенные для обучения одному какому-либо предмету, и универсальные, обеспечивающие возможность эффективного обучения нескольким предметам. Основу специализированных систем составляют обучающие программы, написанные на традиционных языках программирования, например, на Паскале или Си. К специализированным АОС относятся и тренажеры, управляемые компьютером. Универсальные системы располагают проблемно-ориентированным языком и специальными средствами программирования педагогами сценария обучения и программ управления обучением. Б состав универсальных АОС входят также библиотека программ управления познавательной деятельностью, архив данных о процессе обучения каждого обучаемого, средства дружественного интерфейса и т. п. АОС развиваются на базе как серийной вычислительной техники (персональные компьютеры, локальные вычислительные сети), так и специально созданных тренажеров. Обучаемый может работать с АОС как индивидуально, так и в условиях класса автоматизированного обучения. Развитием АОС являются интеллектуальные обучающие системы. Ср. обучающая программа, обучающее приложение к программному продукту.
АВТОМАТИЗИРОВАННАЯ ПОДГОТОВКА (computer-based training (CBT)). То же, что обучающее приложение к программному продукту.
АВТОМАТИЗИРОВАННАЯ РАЗРАБОТКА ПРОГРАМ, инструмент CASE (computer-aided software engineering (CASE), CASE-tool). Набор согласованных средств разработки программ, в число которых входят языки визуального моделирования, генераторы кода и документации, автоматизированные средства тестирования, редакторы, компиляторы и другие компоненты. Как правило, инструмент А. р. п. ориентирован на определенный процесс разработки программного обеспечения и компоненты инструмента А. р. п. строго соответствуют фазам выбранного процесса. Ср. инструментальные программные средства.
АВТОМАТИЗИРОВАННАЯ СИСТЕМА (automated system). Система программных и аппаратных средств, предназначенных для автоматизации процесса деятельности человека. Б отличие от автоматической системы А. с. всегда функционирует при участии человека. И человек является ее главным звеном. См. автоматизированная обучающая система, автоматизированная система управления, автоматизированное рабочее место, система автоматизированного проектирования.
АВТОМАТИЗИРОВАННАЯ СИСТЕМА УПРАВЛЕНИЯ(АСУ) (automated control system). Комплекс программных и технических средств автоматизации управления различными объектами. Б отличие от систем автоматического управления в АСУ сбор и обработку информации, необходимой для выработки управляющих воздействий, осуществляют автоматические устройства — приборы и компьютеры, а окончательное решение принимает человек. Ср. офисное приложение.
АВТОМАТИЗИРОВАННОЕ ПРОЕКТИРОВАНИЕ (computer-aided design (CAD)). См. система автоматизированного проектирования.
АВТОМАТИЧЕСКАЯ СИСТЕМА(automatic system). Система программных и аппаратных средств, функционирующая самостоятельно, без участия человека. Ср. автоматизированная система.
АВТОМАТИЧЕСКИЙ ПЕРЕХОД НА НОВУЮ СТРОКУ (word-wrap). To же, что выравнивание текста. См. перенос слов.
АВТОМАТИЧЕСКИЙ ПОВТОР НАЖАТИЯ КЛАВИШИ(typematic). Автоматическое повторение ввода символа или команды, вызванное удерживанием соответствующей клавиши в нажатом состоянии. Например, при однократном нажатии клавиши на экране появится следующая страница, а если клавишу нажать и не отпускать, команда смены страницы будет автоматически повторяться, что приведет к листанию страниц. Продолжительность времени между двумя повторениями для клавиатуры персонального компьютера можно регулировать с помощью специальных команд операционной системы, например команды mode в MS-DOS или с помощью Панели управления Windows. Например, на рис. АЛ показано окно для настройки клавиатуры в операционной системе Windows.
АВТОМАТИЧЕСКИЙ СИНТЕЗ ПРОГРАММ (automatic program synthesis). Автоматическая генерация программы по некоторой спецификации. В зависимости от метода спецификации программы А. с. п. подразделяют на несколько категорий. Если спецификация задана в виде формального логического условия, связывающего входные и выходные данные, то говорят о дедуктивном А. с. п. Если спецификация задана в виде набора примеров, то говорят об индуктивном А. с. п., а если в виде формального, но неалгоритмического описания задачи, например, в виде диаграмм, то говорят о трансформационном А. с. п. Для А. с. п. обычно применяют методы искусственного интеллекта. В общем случае задача А. с. п. алгоритмически неразрешима, т. е. не существует алгоритма, который бы по произвольной спецификации строил соответствующую программу, однако известно множество частных, но практически важных случаев, в которых А. с. п. возможен. Результаты, получаемые в ходе теоретических исследований по А. с. п., находят практическое применение в оптимизирующих компиляторах, электронных таблицах и других областях.
АВТОМАТИЧЕСКОЕ СОХРАНЕНИЕ, автосохранение (autosave). Сохранение, выполняемое программой с заданной периодичностью или после определенного числа нажатий клавиш. А. с. служит гарантией от случайных потерь данных. Оно применяется в приложениях Windows, периодически сохраняя изменения, вносимые в документ. Например, в редакторе MS Word можно установить периодичность А. с. от одной минуты до двух часов.
АВТОМАТИЧЕСКОЕ УСТРОЙСТВО, автомат (automation). Устройство, способное функционировать без непосредственного участия человека.
АВТОНОМНАЯ ПРОГРАММА (autonomy program, stand-alone program). Программа, не зависящая от других программ в составе данной программной системы. Например, программа в виде загрузочного модуля, имеющая свои собственные средства инициализации и не требующая для своего выполнения управляющих действий операционной системы.
АВТОНОМНОЕ УСТРОЙСТВО (autonomy device, autonomy unit). Устройство, работающее независимо от других устройств вычислительной системы.
АВТОНОМНЫЕ ИСПЫТАНИЯ ПРОГРАММЫ (stand-alone program tests). Испытания программы по частям или целиком, но независимо от других программ, с которыми испытуемая программа должна взаимодействовать. Ср. комплексные испытания программного продукта. См. испытание программы.
АВТОРИЗАЦИЯ (authorization). 1. Процесс проверки имеющихся у пользователя прав и разрешений на доступ к ресурсу. См. аутентификация. 2. Предоставление пользователю определенных полномочий на выполнение некоторых работ в вычислительной системе. Ср. права доступа.
АВТОРСКАЯ СИСТЕМА (authoring system). То же, что система автоматизации авторской работы.
АВТОРСКИЙ ЯЗЫК(authoring language). Язык программирования высокого уровня, используемый для создания продуктов мультимедиа, презентаций, а также программ, баз данных и материалов для автоматизированных обучающих систем.
АВТОСОХРАНЕНИЕ (autosave). To же, что автоматическое сохранение.
АГЕНТ (agent). Программа, действующая от имени пользователя, выполняя специфические функции в фоновом режиме. Выполнив задачу, программа А. сообщает об этом пользователю.
АГРЕГАЦИЯ (aggregation). Б унифицированном языке моделирования UML форма ассоциации, описывающая отношение типа «часть—целое» между объектами. Отношение А. является менее строгим по сравнению с отношением композиции: часть может принадлежать нескольким целым и прекращение существования целого не означает прекращения существования его частей.
АДА (Ada). Универсальный язык программирования высокого уровня, ориентированный на разработку программного обеспечения компьютеров, встроенных в системы автоматизированного управления. Назван в честь Августы Ады Лав- лейс, считающейся первым в мире программистом. Первая версия Α., разработанная в США под руководством Дж. Ишбиа, появилась в 1980 г. Последняя версия, Ада-95 — в 1995 г. А. обладает средствами программирования процессов, протекающих параллельно в реальном времени. Программы на языке А. имеют модульную структуру, допускающую раздельную компиляцию модулей. Кроме того, в стандарте языка А. помимо собственно языка программирования впервые была определена и его поддерживающая среда программирования, т. е. средства разработки, корректировки и модернизации программ. Бее это позволяет создавать на языке А. очень большие программные проекты, например, программное обеспечение систем астронавигации.
АДАПТЕР (adapter). Электронная схема, позволяющая приспособить друг к другу устройства с различными способами представления данных. Например, аналоговое устройство нельзя напрямую соединить с цифровым устройством: для этого аналоговый сигнал должен быть сначала преобразован в цифровой или наоборот. Чтобы связать два несовместимых компонента аппаратных средств, требуется устройство сопряжения, важной составляющей которого и является А. Обычно А. монтируется на отдельной плате. См. адаптер дисплея, звуковой адаптер.
АДАПТЕР ДИСПЛЕЯ, видеоадаптер, видеокарта (display adapter, video- adapter, videocard). Адаптер, согласующий обмен графической информацией между центральным процессором и дисплеем. А. д. преобразует данные, поступающие из компьютера в цифровой форме, в соответствующее изображение на экране. Цифровой код текста или графического изображения размещается центральным процессором в видеопамяти. А. д. периодически «просматривает» содержимое видеопамяти или ее отдельных частей и по хранящемуся там коду «рисует» нужное изображение на экране дисплея. При этом он устанавливает формат экрана, управляет курсором и цветовыми характеристиками изображения. А. д., как правило, имеет несколько режимов работы, которые характеризуются типом отображаемой информации (текстовая или графическая), количеством используемых цветов, разрешающей способностью и размерами символов. См. текстовый режим, графический режим. А. д. современных персональных компьютеров позволяет выводить на экран дисплея изображения, получаемые с видеокамеры, видеомагнитофона или любого другого источника видеосигнала. Он состоит из четырех основных устройств: видеопамяти, видеоконтроллера, цифроаналогового преобразователя (ПАП) и постоянного запоминающего устройства (ПЗУ), которые могут монтироваться на отдельной плате, называемой видеоплатой или видеокартой. Видеопамять служит для хранения изображения. Видеоконтроллер отвечает за вывод изображения из видеопамяти на монитор и обработку запросов центрального процессора. ЦАП служит для преобразования формируемых видеоконтроллером цифровых видеоданных в аналоговый видеосигнал. В ПЗУ записаны наиболее универсальные программы управления выводом изображения на экран, экранные шрифты, служебные таблицы и т. п. ПЗУ не используется видеоконтроллером напрямую — к нему обращается только центральный процессор, и в результате выполнения им программ происходят обращения из ПЗУ к видеоконтроллеру и видеопамяти. ПЗУ необходимо только для первоначального запуска адаптера и работы в режиме MS-DOS; операционные системы с графическим интерфейсом — Windows или OS/2 — не используют ПЗУ для управления адаптером. Для ускорения вывода изображения на экран на плату адаптера могут устанавливаться дополнительные микросхемы — акселераторы или графические сопроцессоры. В IBM PC применяются следующие А. д., указанные в порядке возрастания графических возможностей: EGA (Enhanced Graphics Adapter) — A 79 улучшенный графический адаптер. Его максимальная разрешающая способность 640×350 пикселов. Может выводить одновременно 16 из 64 цветов. VGA (Video Graphics Adapter) — видеографический адаптер. Имеет текстовый режим 720×400 пикселов и графический режим 640×480 пикселов. Одновременно выводит 256 цветов. SVGA (Super VGA) — улучшенный VGA. Так обычно называются выпускаемые в последнее время различными фирмами платы, превосходящие по своим возможностям VGA. Разрешающая способность адаптеров некоторых фирм доходит до 1600×1280 и более пикселов. Количество выводимых цветов может достигать 16,7 млн. Также добавляются расширенные текстовые режимы вплоть до формата 132×50 знакомест. Многие фирмы выпускают адаптеры с улучшенными характеристиками, поддерживающие нестандартные режимы.
АДАПТЕР PCMCIA (PCMCIA-adapter). Тип адаптера, разработанный Международной ассоциацией производителей карт памяти для персональных компьютеров (PCMCIA). Предназначен для использования на портативных компьютерах. A. PCMCIA имеет небольшой размер и потребляет мало электроэнергии. Частота, на которой работает шина данных для его подключения, обычно равна 8,33 МГц.
АДАПТИВНАЯ ДИФФЕРЕНЦИАЛЬНАЯ ИМПУЛЬСНО-КОДОВАЯ МОДУЛЯЦИЯ (АДИКМ) (adaptive differential pulse code modulation (ADPCM)). Способ кодирования и сжатия данных о звуковых сигналах в цифровой форме. Позволяет передавать оцифрованную речь со скоростью свыше 32 Кбит/с. Применяется при записи звуковых фрагментов на компакт- дисках. Стандарт АДИКМ разработан Международным советом по мультимедиа.
АДАПТИВНАЯ СИСТЕМА (adaptive system). Система, автоматически настраивающаяся на условия применения. А. с. сама может изменять свои функциональные возможности в зависимости от изменения условий внешней среды. Например, операционная система Windows автоматически приспосабливается к имеющейся конфигурации компьютера.
АДАПТИВНОСТЬ (adaptively). Способность устройств или программ изменять свои параметры в связи с изменениями в них самих или в зависимости от условий применения для повышения эффективности.
АДДИТИВНЫЙ ЦВЕТ (additive color). Цвет, порожденный излучающим объектом. При смешении А. ц. осветляются, смешение трех основных А. ц. — красного, зеленого и синего — дает белый цвет. При попарном смешении основных А. ц. получают основные субтрактивные цвета.
АДИКМ (ADPCM). То же, что адаптивная дифференциальная импульсно-кодовая модуляция.
АДМИНИСТРАТОР (administrator). 1. То же, что системный администратор. 2. То же, что администратор базы данных.
АДМИНИСТРАТОР БАЗЫ ДАННЫХ, администратор (database administrator). Человек или группа лиц, ответственные за состояние, развитие и использование базы данных организации или учреждения. А. б. д. обеспечивает работоспособность базы данных, контролирует и поддерживает полноту, правильность, непротиворечивость и целостность данных, необходимый уровень защиты данных. Он взаимодействует с пользователями и программистами, программы которых используют доступ к базе данных. Роль А. б. д. аналогична роли системного инженера, сопровождающего операционную систему.
АДРЕС (address). 1. Номер, код или идентификатор места в памяти компьютера, где хранится или куда должна быть записана данная информация. Например, номер байта оперативной памяти или номер дорожки магнитного диска, имя внешнего устройства или узла сети. Различают логические и физические А. Логический А. указывается в машинной программе. При загрузке, а также при переадресации он преобразуется в зависимости от места, занимаемого программой и данными в оперативной памяти, в физический Α., закрепленный в вычислительной системе за реально существующим запоминающим устройством или его частью. Это преобразование выполняется соответствующим программным обеспечением и аппаратными средствами. См. адресация. 2. Часть команды, определяющая местоположение операнда. 3. Часть сообщения, указывающая адресат.
АДРЕС КОМАНДЫ (instruction address). Адрес ячейки памяти или первого байта области памяти, которая занята командой.
АДРЕС ОПЕРАНДА (source address). Адрес ячейки памяти или первого байта области памяти, откуда извлекается операнд.
АДРЕС IP (IP-address). 1. Уникальный адрес, идентифицирующий узлы или компьютеры в сети, управляемой протоколами TCP/IP. В сети, представляющей собой объединение нескольких подсетей, указывает информацию маршрутизации. A. IP представляет собой 32-разрядное значение, которое идентифицирует данный компьютер. Каждый байт A. IP представляется десятичным числом и отделяется от других десятичной точкой. 2. То же, что интернет-адрес.
АДРЕСАТ (target). Обладатель адреса (лицо, программа, устройство или компьютер), которому предназначаются сообщение, команда или данные. Например, А. считается и почтовый ящик, в который приходит сообщение по электронной почте, и пользователь — владелец этого ящика. Также А. является дисковод, на который послал команду центральный процессор, и программа, для которой с диска считываются данные.
АДРЕСАЦИЯ (addressing). Определение операнда в машинной команде. Способ вычисления физического адреса и выполнения операций над адресными регистрами. Рассмотрим наиболее распространенную схему А. Чтобы при выполнении программы устройство управления могло определить, какую команду необходимо выполнить в данный момент, и найти данные, указанные в этой команде, вся основная память машины делится на отдельные адресуемые ячейки — байты или машинные слова. Каждому байту или слову присвоен уникальный физический адрес. В традиционной схеме А. эти адреса являются номерами, начиная от нуля с шагом единица. Таким образом, к любой команде или элементу данных можно обратиться по адресу его самого левого элемента. При таком абсолютном методе А. адрес 1234 означает 1235-й байт или машинное слово при условии, что отсчет ведется от нулевой ячейки памяти. Однако при режиме мультипрограммирования место, занимаемое программой в оперативной памяти, зависит от наличия и расположения в ней других программ. Поэтому необходимо, чтобы программы были перемещаемыми, т. е. адреса внутри программ должны отсчитываться относительно некоторого начального базового адреса программы, который должен быть перемещаемым. Это же требуется и при независимой трансляции подпрограмм и отдельных программных модулей, адреса которых также отсчитываются от базового адреса и называются относительными адресами или смещениями. При загрузке программы в зависимости от места, занимаемого программой или ее сегментом, определяется значение ее базового адреса, которое посылается в базовый регистр процессора, и физический адрес ячейки интерпретируется аппаратурой как сумма содержимого базового регистра и относительного адреса. Например, если адресная часть команды содержит 1200, а содержимое базового регистра равно 300, то операнд будет выбираться из ячейки с физическим адресом 1500. Внутри циклов, которые есть почти в каждой программе, работает одна и та же последовательность команд, а изменяются только адрес или величина той или иной переменной. Для определения значения адреса, изменяемого в цикле, применяется так называемый индексный регистр, содержимое которого отражает значение параметра цикла. Адрес операнда в командах цикла определяется как указанный в команде относительный адрес плюс содержимое базового регистра плюс содержимое индексного регистра. При таком методе А. все данные могут смещаться при перемещении программы путем изменения значения базового регистра, а индексный регистр способствует простой организации выборки в цикле. При трансляции программ, написанных на языках программирования высокого уровня, компиляторы сами выбирают регистры, необходимые для базирования и индексации, а компоновщики и загрузчики устанавливают их нужные значения. Для уменьшения потерь времени на вычисление физических адресов во время выполнения программы такое вычисление производится специальными быстрыми аппаратными средствами.
АДРЕСАЦИЯ С ИНДЕКСИРОВАНИЕМ (indexed addressing). To же, что индексная адресация.
АДРЕСНАЯ КОНСТАНТА (address constant, A-constant). Константа, которая либо является адресом, либо используется при вычислении адресов. Обычно это числовая константа или числовое выражение, значение которого является адресом или составной частью адреса.
АДРЕСНАЯ ССЫЛКА (address reference). Ссылка в форме адреса.
АДРЕСНАЯ ШИНА (address bus). Шина или часть шины, предназначенная для передачи адреса.
АДРЕСНОЕ ПРОСТРАНСТВО ЗАДАЧИ, адресное пространство процесса (process address space). Множество логических адресов, по которым может обращаться задача. Система управления памятью устанавливает соответствие между А. п. з. и физической памятью ЭВМ, и при выполнении задачи для каждого логического адреса вычисляет физический адрес. См. адресация, управление памятью, виртуальная память.
АДРЕСНОЕ ПРОСТРАНСТВО ПРОЦЕССА (process address space). To же, что адресное пространство задачи.
АДРЕСНОЕ ПРОСТРАНСТВО ЦЕНТРАЛЬНОГО ПРОЦЕССОРА (CPU address space). Множество физических адресов ячеек оперативной памяти, с которыми может работать центральный процессор. Для машин, работающих в двоичной системе счисления, размер А. п. ц. п. составляет 2″ ячеек, где η — разрядность адресной шины процессора. Очевидно, этот размер ограничивает емкость оперативной памяти, на которую рассчитан процессор и к которой он может иметь прямой доступ. Реально физическая оперативная память может быть меньше или больше той, которую позволяет иметь А. п. ц. п. Если количество физических адресов, с которыми работает центральный процессор, меньше его адресного пространства, то оперативную память компьютера можно расширить. Для увеличения размера памяти сверх А. п. ц. п. должны применяться специальные программные и аппаратные средства. См. адресация, управление памятью, виртуальная память.
АДРЕСНЫЙ РЕГИСТР (address register). To же, что регистр адреса.
АКСЕССУАРЫ (accessory). Добавочные принадлежности к компьютеру или другому цифровому устройству. Например, сумка для ноутбука или чехол для смартфона.
АКТИВАЦИЯ, фокус управления (activation, focus of control flow). 1. To же, что активизация. 2. Выполнение операции. А. представляет собой период времени, в течение которого объект выполняет операцию (непосредственно или с помощью подчиненных операций). Посредством А. моделируется не только длительность выполнения операции, но и отношения потока управления между взаимодействующими объектами. А. является одним из основных понятий унифицированного языка моделирования UML. В обычных языках программирования А. соответствует вызов процедуры.
АКТИВИЗАЦИЯ (activation). Приведение объекта в состояние готовности к действию или использованию. Например, А. экранных объектов (панелей, меню, окон, кнопок и пр.) позволяет пользователю начать диалог с системой.
АКТИВИЗАЦИЯ ФАЙЛА (file activation). To же, что открытие файла.
АКТИВНАЯ ПРОГРАММА (active program). Программа, которой передано управление центральным процессором. Противоп. неактивная программа.
АКТИВНАЯ ЯЧЕЙКА (active cell). Ячейка электронной таблицы, с которой в настоящий момент работает или может работать пользователь. Она идентифицируется координатами строки и столбца, к которым принадлежит, и выделяется на экране контрастной рамкой. В А. я. пользователь может ввести данные, отредактировать или отформатировать ее содержимое.
АКТИВНОЕ ОКНО (active window). Окно, с которым в настоящий момент работает или может работать пользователь. На нем активизированы элементы управления, через него возможен ввод данных. При одновременном отображении на экране нескольких окон (рис. А.З) А. о. не перекрывается другими окнами и выделяется контрастным цветом рамки или заголовка, наличием мерцающего курсора и т. п. Чтобы сделать окно активным, как правило, достаточно навести на него указатель мыши и нажать ее левую кнопку. Противоп. неактивное окно.
АКТИВНЫЙ ДИСК (active disc). To же, что текущий диск.
АКТИВНЫЙ ФАЙЛ (active file). To же, что открытый файл.
АКТИВНЫЙ РАБОЧИЙ СТОЛ (active desktop). Собирательное название новых возможностей, добавленных фирмой Microsoft к обычному рабочему столу. На А. р. с. можно разместить любой объект веб-страницы (встроенную графику, гипертекстовые ссылки и т. п.), браузера и любой компонент Всемирной паутины WWW (например, доступные по WWW справочники). Веб-страницы, перечисленные в папке Favorites (Избранное) или размещенные на А. р. с, автоматически обновляются операционной системой Windows. Компонентами А. р. с. также являются веб-объекты, специально предназначенные для расположения на рабочем столе. Их содержимое обычно представляет собой новости, прогноз погоды, биржевые котировки и другую подобную информацию. Б компонентах А. р. с. применяются те же технологии, что и в других веб-объектах.
АЛГОЛ (Algol). Алгоритмический язык, разработанный в 1958 г. Первоначально А. не был языком программирования, так как предназначался лишь для обмена вычислительными алгоритмами между людьми. Название языка произошло от английских слов ALGOrithmic Language (алгоритмический язык) Б дальнейшем на основе А. были созданы языки программирования Алгол60 и Алгол68. Первая редакция языка программирования АлголбО, ориентированного на программирование численных решений научно-технических задач, была разработана П. Науром, Дж. Бэкусом и др. и опубликована в 1960 г. Б Алгол60 впервые были реализованы идеи блочной структуры программ, определения способов передачи параметров в процедуры, рекурсивных процедур. Для описания синтаксиса Алгол60 впервые был использован ставший классическим формальный язык Бэкуса—Наура. Идеи Алгол60 получили свое развитие во многих языках программирования высокого уровня. Б 1966—1969 гг. на основе АлголбО был разработан новый язык Алгол68. По сравнению с Алгол60 он обладает большими возможностями при программировании ввода и вывода данных и обработки текстов. Кроме того, в Алгол68 появились средства описания параллельно выполняемых операторов. Формальная строгость и общность описания сделали язык слишком сложным для широкого распространения. Это послужило толчком для создания более простого языка Паскаль.
АЛГОРИТМ (algorithm). Содержание и последовательность операций, точно определяющие решение задачи путем вычислительного процесса, преобразующего исходные данные в конечный результат. Характеристиками алгоритма являются: 1) однозначность результата при заданных исходных данных; 2) возможность разбиения процесса на конечное число отдельных операций, каждая из которых может быть выполнена человеком или вычислительной машиной; 3) способность получения результата для множества исходных данных, соответствующих множеству однотипных задач. Например, один из А. вычисления с помощью компьютера среднего арифметического трех чисел представляет собой следующую последовательность операций: ввод с клавиатуры трех чисел; вычисление суммы введенных чисел; деление полученной суммы на 3; вывод результата на экран дисплея. Б приведенном примере для записи А. был применен русский язык. Существуют специально созданные алгоритмические языки. Вычислительной машине А. задается в виде программы. Могут существовать несколько А. решения одной и той же задачи. Среди них следует выбирать наиболее эффективный, для вычислительной реализации которого требуется наименьшее количество операций, машинного времени, памяти и т. п. Изучение условий существования и способов построения (разработки) эффективных А. составляет основу теории алгоритмов.
АЛГОРИТМИЧЕСКИЙ ЯЗЫК (algorithmic language). Язык, предназначенный для записи, разработки и изучения алгоритмов, а также для обмена алгоритмами между людьми. А. я. является важным средством обучения. Например, при изучении информатики в школах применяется т. н. школьный А. я., в котором используются понятные школьнику служебные слова на русском языке. Б отличие от языков программирования, А. я. независим от ЭБМ. Б нем нет деталей, связанных с устройством машины. Обычно при разработке языка программирования высокого уровня сначала создается А. я. с тем же названием. Кроме того, языки программирования используются для обме- 86 A на алгоритмами и для их опубликования в научных изданиях. Поэтому понятие «А. я.» часто применяется в качестве синонима понятия «язык программирования».
АЛТ-ВВОД СИМВОЛОВ (character alt-input). Кодовый ввод символов с клавиатуры персонального компьютера. При нажатой клавише следует набрать на малой цифровой клавиатуре код символа, после этого клавишу отпустить. На экране появится тот символ, код которого был набран. Таким способом можно ввести любой допустимый вычислительной системой символ. Обычно при А.-в. с. применяется так называемая модифицированная альтернативная кодировка ГОСТа, первые 128 кодов которой являются десятичным представлением двоичного кода ASCII.
АЛУ (ALU). To же, что арифметико-логическое устройство.
АЛФАВИТНО-ЦИФРОВОЕ ПЕЧАТАЮЩЕЕ УСТРОЙСТВО (АЦПУ) (line printer (LPT)). To же, что линейный принтер.
АЛЬБОМНАЯ ОРИЕНТАЦИЯ СТРАНИЦЫ, ландшафтная ориентация страницы (landscape page orientation). Такое расположение страницы, когда ее высота меньше ширины. Противоп. книжная ориентация страницы.
АЛЬФА-ВЕРСИЯ (alpha release). Предварительная версия программы, предназначенная для альфа-тестирования.
АЛЬФА-КАНАЛ (alpha channel). Дополнительный 8-разрядный канал, применяемый в некоторых графических платах кроме трех традиционных RGB- каналов. Б таких платах для кодирования цвета пиксела используются 32 бита, причем младшие 24 бита содержат информацию о цвете, соответствующую RGB-каналам (по 8 бит на каждый цвет), а старшие 8 разрядов образуют А.-к. С его помощью можно формировать прозрачные области изображения, не зависящие от того или иного цвета.
АЛЬФА-ТЕСТИРОВАНИЕ(alpha testing). Предварительная стадия испытания программы или программного обеспечения, предназначенная для общей оценки будущего программного продукта и определения необходимости включения в него тех или иных свойств. Ср. бета-тестирование.
АМЕРИКАНСКИЙ НАЦИОНАЛЬНЫЙ ИНСТИТУТ СТАНДАРТОВ(АНСИ) (American National Standards Institute (ANSI)). Организация, определяющая стандарты, на основе которых в США разрабатываются аппаратные средства и некоторые виды программного обеспечения. Например, для языков С, Basic и SQL имеются стандарты, подготовленные ANSI.
АМЕРИКАНСКИЙ СТАНДАРТНЫЙ КОД ОБМЕНА ИНФОРМАЦИЕЙ (American standard code for information interchange, (ASCII)). Стандартная A 87 схема кодирования текстовой информации, при которой каждый текстовый или управляющий символ представляется семиразрядным двоичным кодом. Этот код с отдельными модификациями используется в большинстве вычислительных систем. Многие клавиатуры при нажатии клавиши вводят в компьютер именно такой код. Зарубежные персональные компьютеры имеют набор ASCII-кодированных символов, в котором отсутствуют символы кириллицы (русские буквы), поэтому были созданы различные модификации таблицы А. с. к. о. и., дополненные буквами кириллицы. Бее эти модификации имеют общую кодировку первых 128 символов, совпадающую с А. с. к. о. и. Эти символы и их коды приведены в табл. А.1. Чтобы определить код символа по этой таблице, нужно к первому числу столбца, в котором находится символ, приписать справа первое число его строки. Например, символ # находится на пересечении столбца, первое число которого есть 010, и строки, первое число которой — ООП. Следовательно, его код 0100011. Б литературе по программированию и при Алт-вводе символов применяется десятичная запись двоичного кода (см. двоичная система счисления). Например, код 0100011 символа # в десятичной системе счисления записывается числом 35. Обозначения: NUL — знак пробела; SON — начало заголовка; STX — начало текста; ЕТХ — конец текста; EOT — конец передачи; ENQ — запрос; АСК — подтверждение; BEL — звонок; BS — возврат на одну позицию; НТ — горизонтальная табуляция; LF — перевод строки; VT — вертикальная табуляция; FF — подача бланка; CR — возврат каретки; SO — переход на верхний регистр; SI — переход на нижний регистр; DLE — переключение кода; DC1, DC2, DC3, DC4 — управление устройствами 1, 2, 3 и 4 соответственно; NAK — переспрос; SYN — режим синхронного ожидания; ЕТВ — конец передачи блока; CAN — отмена; ЕМ — конец носителя; SUB — замена; ESC — переход; FS — разделитель файла; GS — разделитель группы; RS — разделитель записи; US — разделитель блока; DEL — стирание.
АНАЛИЗ ТРЕБОВАНИЙ (requirements analysis). Фаза процесса разработки программного обеспечения, во время которой анализируются требования и предметная область. На фазе А. т. разработчики фокусируют свое внимание на том, что им предстоит сделать, а на фазе проектирования — каким образом они будут это осуществлять.
АНАЛОГОВАЯ ВЫЧИСЛИТЕЛЬНАЯ МАШИНА (ABM) (analog computer). Вычислительная машина, которая обрабатывает информацию, представленную в форме непрерывно изменяемых физических величин, значения которых можно измерить. Такими величинами могут быть угловые или линейные перемещения, электрическое напряжение и пр., являющиеся аналогами математических переменных. Над аналоговыми величинами можно производить сложение, умножение, интегрирование и другие математические действия механическим или каким-либо физическим способом, измеряя результаты этих действий. Наибольшее распространение получили электронные АВМ. В них информация задается в виде электрического напряжения. Для решения математической задачи из элементов электрических цепей набирается электрическая схема, напряжение на выходе которой удовлетворяет тем же уравнениям, что и решение исходной математической задачи. Таким образом, напряжение является аналогом искомой математической переменной. Изменяя во времени параметры схемы, можно получать меняющиеся во времени решения. Поэтому физическое время также является аналоговой переменной в такой АВМ. К недостаткам АВМ относят сравнительно невысокую точность и малую универсальность, поэтому их используют в основном как управляющие устройства в различных системах управления и как измерительные устройства в системах сбора и обработки информации.
АНАЛОГОВАЯ ФОРМА ДАННЫХ (analog data form). Способ представления, хранения и передачи данных в виде непрерывно изменяющихся в некотором диапазоне физических величин, таких как электрическое напряжение или электрический ток, или аналоговых сигналов. А. ф. д. применяется в аналоговых вычислительных машинах.
АНАЛОГОВОЕ УСТРОЙСТВО (analog device). Устройство, в котором информация представляется в виде непрерывно изменяющихся в некотором диапазоне физических величин, таких как электрическое напряжение или электрический ток. См. аналоговый сигнал, аналоговая вычислительная машина. Противоп. цифровое устройство.
АНАЛОГОВЫЙ СИГНАЛ, непрерывный сигнал (analog signal, continuous signal). Носитель информации в виде непрерывно изменяющегося электрического напряжения или электрического тока. Переменная во времени амплитуда А. с. соответствует количественной характеристике переносимой им информации и часто представляет измеренную физическую величину, например, температуру, скорость и т. п. Для обработки переносимой А. с. информации на компьютере необходим аналого-цифровой преобразователь. См. аналоговое устройство, аналоговая вычислительная машина. Противоп. дискретный сигнал, цифровой сигнал.
АНАЛОГО-ЦИФРОВАЯ ВЫЧИСЛИТЕЛЬНАЯ СИСТЕМА, гибридная вычислительная система (hybrid computer). Вычислительная система, в которой сочетаются элементы аналоговых и цифровых вычислительных машин. Обычно в таких системах аналоговые устройства используются для решения уравнений, описывающих исследуемое явление или процесс в натуральном масштабе времени, а цифровые устройства — для хранения результатов решения, их последующей обработки и выдачи полученных данных в форме, удобной для восприятия человеком. Для преобразования непрерывно меняющихся во времени аналоговых величин в эквивалентные значения цифровых кодов здесь применяются специальные устройства — аналого-цифровые преобразователи. См. аналоговый сигнал, цифровой сигнал.
АНАЛОГО-ЦИФРОВОЙ ПРЕОБРАЗОВАТЕЛЬ (АЦП) (analog-to-digital converter (ADC)). Устройство для автоматического преобразования аналогового сигнала в цифровой сигнал. Например, для автоматической обработки экспериментальных данных поступающие с измерительных приборов непрерывно меняющиеся во времени аналоговые величины с помощью АЦП преобразуются в эквивалентные значения цифровых кодов, которые вводятся в компьютер. Противоп. цифроаналоговый преобразователь.
АНИМАЦИОННАЯ ПОСЛЕДОВАТЕЛЬНОСТЬ (animation path). Последовательность изображений, быстрая смена которых на экране создает иллюзию движения объекта. См. анимация, твининг.
АНИМАЦИЯ (animation). Создание иллюзии движения объекта на экране дисплея. Б основе А. лежит быстрая смена последовательно смещаемых относительно друг друга образов. Существует несколько способов Α., реализуемых в различных системах программирования. При одном способе на экране быстро рисуются и стираются последовательные фазы движения. При другом фазы заранее рисуются в виде полноэкранных кадров и запоминаются в памяти компьютера, чтобы затем последовательно отобразиться на экране. Б развитых системах применяются средства Α., для которых достаточно задать изображение объекта и его начальное и конечное положение. Качество А. зависит от скорости смены кадров. Чем выше скорость, тем плавнее движение. Современные компьютеры позволяют выполнять до 30 смен кадров в секунду.
АНТИВИРУСНАЯ ПРОГРАММА (antivirus program). Обслуживающая программа, предназначенная для поиска, диагностики, профилактики и «лечения» файлов, зараженных компьютерным вирусом. Б процессе поиска и диагностики определяются зараженные файлы и тип вируса. Профилактика позволяет предотвратить заражение. Например, резидентная А. п. предотвращает несанкционированное пользователем изменение файлов операционной системы, запись в сектор начальной загрузки и т. п. Лечение подразумевает удаление вируса, восстановление поврежденных файлов и т. п.
АОС (automated training system). To же, что автоматизированная обучающая система.
АППАРАТНОЕ ОБЕСПЕЧЕНИЕ, техническое обеспечение (hardware). Совокупность входящих в состав вычислительной системы аппаратных средств, необходимых для ее функционирования. А. о. составляют процессоры, внешние устройства, линии связи и т. д. Они технически обеспечивают эффективную работу системы, ее способность предоставлять пользователю определенные виды обслуживания. Этот термин определяет часть вычислительной системы, не являющуюся программным обеспечением.
АППАРАТНОЕ ПРЕРЫВАНИЕ (hardware interrupt). Прерывание, причиной которого является событие, произошедшее в аппаратных средствах. См. обработка прерываний, внешнее прерывание, внутреннее прерывание, прерывание от схем контроля АППАРАТНО-НЕЗАВИСИМЫЙ (hardware independent, device independent). Независимый от технических характеристик аппаратных средств конкретной вычислительной системы. Например, А.-н. формат хранения точечных рисунков позволяет воспроизвести рисунок максимально точно независимо от разрешающей способности и других параметров принтера, влияющих на качество изображения.
АППАРАТНЫЕ СРЕДСТВА, технические средства, оборудование (hardware). Электрические, электронные и механические схемы, блоки, приборы и устройства, составляющие материальную часть вычислительной системы. А. с. являются, например, и сам компьютер, и микросхемы, его составляющие. К А. с. также относятся дисплей, дисковод, принтер и пр. Противоп. программные средства.
АППАРАТНЫЙ (hardwired). Реализованный аппаратными средствами. Противоп. программный.
АППАРАТНЫЙ БЛОК, блок (hardware block, block). Конструктивно оформленная как единое целое совокупность взаимосвязанных устройств либо совокупность взаимосвязанных элементов или узлов одного устройства, выполняющих определенную функцию. Например, блок питания, обеспечивающий компьютер электроэнергией с заданными показателями, или системный блок, объединяющий основные устройства персонального компьютера.
АППАРАТНЫЙ КЛЮЧ (hardware key). Реализованный аппаратными средствами ключ защиты от несанкционированного доступа и несанкционированного копирования. Например, при защите программ А. к. часто представляет собой устройство, присоединяемое к параллельному порту персонального компьютера. Защищаемая программа обращается к параллельному порту и запрашивает секретный код. Если А. к. к компьютеру не присоединен, то защищаемая программа определяет ситуацию нарушения защиты и выполняет соответствующие действия. Обычно А. к. сконструирован таким образом, что его присоединение не мешает пользоваться другими устройствами, например, принтером.
АППАРАТНЫЙ СБОЙ, машинный сбой, сбой (hardware failure, machine failure, failure). Кратковременный отказ или ошибка в работе аппаратных средств вычислительной системы. Причинами, вызывающими А. с, как правило, являются изменение условий или несоблюдение правил эксплуатации оборудования, например, нестабильность питания, несоблюдение температурного режима, ненадежность соединений, попадание посторонних частиц в подвижные части и т. п.
АППАРАТУРА (hardware, equipment). Приборы и устройства, входящие в состав аппаратных средств вычислительной системы. Физическое оборудование компьютера.
АППЛЕТ (applet). Прикладная программа. Термин А. получил распространение в последнее время в связи с технологиями Всемирной паутины WWW, позволяющей внедрять А. в веб-документы с целью построения интерактивных веб-страниц. Для создания таких А. обычно применяется язык программирования Java, поэтому часто их называют апплетами Java АППЛИКАЦИЯ, графическая заготовка, художественная заготовка, клипарт (clip art). Заранее приготовленный графический рисунок или его фрагмент, предназначенные для вставки в документ. Современные графические и текстовые редакторы, а также настольные редакционно-издательские системы поставляются с библиотеками А.
АРГУМЕНТ (argument). Выражение, задающее объект или значение при обращении к процедуре, функции или макрокоманде, от которого зависит результат ее выполнения. См. фактический параметр.
АРИФМЕТИКО-ЛОГИЧЕСКОЕ УСТРОЙСТВО (АЛУ), арифметическое устройство (АУ) (arithmetic and logical unit (ALU)). Часть процессора, выполняющая над данными арифметические, логические и другие машинные операции. Под контролем устройства управления в АЛУ из оперативной памяти поступают операнды, а из устройства управления — управляющие сигналы, указывающие, какую операцию над этими операндами следует вы- полнить и куда поместить результат по окончании работы. Например, при выполнении сложения двух чисел устройство управления обеспечивает выборку этих чисел из соответствующих ячеек оперативной памяти в АЛУ. Затем оно посылает сигнал «сложить» и после выполнения АЛУ операции сложения пересылает результат в нужную ячейку памяти или регистр. См. функциональная схема ЭВМ.
АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ (arithmetical operations). Операции, выполняемые в соответствии с правилами арифметики. Б арифметико- логическом устройстве операндами и результатом А. о. является число. Б языках программирования операндами и результатом А. о. могут быть выражение, указатель и др. Б набор А. о. обычно входят: сложение (обозначается знаком +), вычитание (-), умножение (х или знак *, который труднее спутать с буквой х), деление (/) и возведение в степень (** или Т). Б языке программирования Си введены дополнительно две одноместные и одна двуместная А. о.: операция увеличения, или инкремент (+ +) и операция уменьшения, или декремент (- -) и операция деления по модулю (%). Операция увеличения увеличивает, а операция уменьшения уменьшает значение своего операнда на единицу. Существуют две возможности использования этих операций: первая, когда символы ++(—) находятся слева от операнда, — «префиксная» форма, и вторая, когда эти символы стоят справа от операнда, — «постфиксная» форма. Например, если а = 5 и ь = 5, то в результате операций + + а и — — ь переменные а и ь получат значения: а = 6, ь = 4. Тот же результат будет получен для а + + и ь — -. Однако префиксная и постфиксная формы различаются между собой, когда операция и ее операнд являются частью выражения. При этом действует правило: в префиксной форме значение операнда изменяется перед его использованием в выражении, а в постфиксной форме — после того, как значение будет использовано в выражении. Например, при а = 5 после выполнения оператора присваивания с = + + а будет с = биа = 6,а после выполнения оператора с = а + + будет с = 5, а = 6. Двуместная операция деления по модулю используется только в арифметике целых чисел. Ее результатом является остаток от деления целого числа, стоящего слева от знака операции %, на число, расположенное справа от него. Например, результатом арифметического выражения 7 % 3 (читается как «7 по модулю 3») будет 1, поскольку 7 = 2 % 3 + 1.
АРИФМЕТИЧЕСКИЙ ОПЕРАТОР (arithmetic operator). Б языках программирования — знак арифметической операции.
АРИФМЕТИЧЕСКИЙ СДВИГ (arithmetic shift). Одновременный сдвиг всех разрядов числа без изменения позиции знака числа при сдвиге влево и с занесением значения знакового разряда в освободившиеся разряды при сдвиге вправо.
АРИФМЕТИЧЕСКИЙ УСЛОВНЫЙ ОПЕРАТОР (arithmetic IF statement). Условный оператор в языке Фортран, в котором проверяемое условие задается в форме арифметического выражения. А. у. о. имеет вид: if (A) ml, m2, m3, где а — арифметическое выражение, ml, m2, m3 — метки исполняемых операторов. Если значение выражения а отрицательно (а < о), то выполнение программы продолжается с оператора, помеченного меткой ml, если а = о, то управление передается оператору, помеченному меткой т2, если же а >о, то оператору, помеченному меткой тЗ. Например, после оператора if (к- 2) 23, 7, ίο при к < 2 управление передается оператору, помеченному меткой 23, при к = 2 — оператору, помеченному меткой 7, и при к >2 — оператору, помеченному меткой ι о.
АРИФМЕТИЧЕСКИЙ ЦИКЛ (arithmetical cycle). To же, что цикл со счетчиком.
АРИФМЕТИЧЕСКОЕ ВЫРАЖЕНИЕ (arithmetic expression). Совокупность одной или нескольких констант, переменных, переменных с индексами и функций, соединенных знаками арифметических операций и скобками. Например, А. в. являются: 12.34, alfa, (а + в — с) * cos(3.14 * в). Значением А. в. является число. Последовательность выполнения операций в А. в. определяется скобками, а при их отсутствии устанавливается следующий порядок: 1) вычисление функций; 2) возведение в степень; 3) умножение и деление; 4) сложение и вычитание. Однотипные операции обычно выполняются последовательно слева направо.
АРИФМЕТИЧЕСКОЕ УСТРОЙСТВО (АУ) (arithmetical unit). To же, что арифметико-логическое устройство АРМ (automated working place). To же, что автоматизированное рабочее место.
АРТЕФАКТ (artifact). Элемент информации, используемый или порождаемый в процессе разработки программного обеспечения (например, внешний документ или результат работы). А. может быть, например, модель, техническое задание или программный продукт.
АРХИВ (archive). Совокупность образовавшихся в результате деятельности пользователя вычислительной системы рабочих материалов и средств их долговременного хранения. Рабочими материалами являются копии документов, редко используемых программ, данных и т. п. Б качестве средств долговременного хранения удобно использовать магнитные ленты и магнитные диски. В целях экономии памяти архивные файлы предварительно сжимают с помощью архиватора. Правильно организованный А. оберегает пользователя от потерь при любых аварийных ситуациях в компьютере. См. архиватор.
АРХИВАТОР (archivator). Программа или комплекс программ, выполняющие сжатие (архивирование) файлов для более компактного длительного хранения во внешней памяти и восстановление сжатых файлов в первоначальном виде (разархивирование). Б персональных компьютерах наиболее рас- пространены A. pkzip.exe/pkunzip.exe, arj.exe, rar.exe и в последнее время winzip.exe и winrar.exe. Бее они предоставляют возможность более компактного хранения файлов на дисках и позволяют: 1) упаковывать все, отдельные или соответствующие какому-либо шаблону файлы рабочего каталога в архивный файл; 2) добавлять файлы в архивный файл; 3) удалять файлы из архивного файла; 4) просматривать содержимое архивного файла; 5) извлекать из архивного файла отдельные файлы или распаковывать все файлы архива; 6) создавать самораспаковывающиеся архивные файлы. См. сжатие данных.
АРХИВАЦИЯ (archivation). To же, что архивирование.
АРХИВИРОВАНИЕ, архивация (archivation). Сжатие одного или более файлов с целью экономии памяти и размещение сжатых данных в одном архивном файле. А. выполняется специальной программой — архиватором.
АРХИВНЫЙ ФАЙЛ (archived file). 1. Файл, помещенный в архив. 2. Файл, являющийся результатом сжатия архиватора. В один А. ф. могут быть помещены несколько сжатых файлов. См. архиватор, сжатие файла.
АРХИТЕКТУРА (architecture). Организационная структура системы, включающая в себя разделение системы на части, связи между этими частями, механизмы взаимодействия и основные принципы проектирования системы. См. архитектура вычислительной системы, архитектура компьютера, архитектура программного обеспечения.
АРХИТЕКТУРА ВЫЧИСЛИТЕЛЬНОЙ СИСТЕМЫ (computer system architecture). Общая логическая организация вычислительной системы, определяющая процесс обработки данных и включающая архитектуру ЭВМ, а также структуру и характеристики программного обеспечения и принципы его взаимодействия с аппаратными средствами.
АРХИТЕКТУРА КЛИЕНТ-СЕРВЕР (client-server architecture). Способ организации взаимодействия программ или компонентов многокомпонентной программы, подразумевающий наличие программы или компонента программы, называемой сервером, и одной или нескольких других программ или компонентов, называемых клиентами. Клиент имеет возможность асинхронно для сервера инициировать выполнение процедур сервера и получать результаты их выполнения. Как правило, А. к.-с. обеспечивает возможность нескольким клиентам взаимодействовать с сервером параллельно и независимо друг от друга. Программы, являющиеся информационными системами для доступа к базам данных, часто построены по А. к.-с. На основе А. к.-с. организовано взаимодействие программ, обеспечивающих работу Интернета. См. автоматизация, Всемирная паутина, связывание и внедрение объектов.
АРХИТЕКТУРА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ (software architecture). Общая логическая организация системы программного обеспечения, вклю- чающая в себя разделение системы на модули, связи между ними, механизмы взаимодействия компонентов и основные принципы проектирования системы. См. архитектура.
АРХИТЕКТУРА СЕТИ, сетевая архитектура (network architecture). 1. Общая логическая и техническая организация компьютерной сети, выраженная в виде совокупности сетевых аппаратных и программных решений, методов доступа и используемых протоколов. 2. Совокупность сетевых аппаратных и программных решений, методов доступа и используемых протоколов. Например, см. архитектура SNA.
АРХИТЕКТУРА, УПРАВЛЯЕМАЯ МОДЕЛЬЮ (model driven architecture (MDA)). Концепция архитектуры программного обеспечения, в которой основным артефактом процесса разработки программного обеспечения является визуальная модель. Б качестве визуального языка моделирования используется унифицированный язык моделирования UML. А. у. п. предложена Консорциумом по объектным технологиям.
АРХИТЕКТУРА ФОН НЕЙМАНА, фоннеймановская архитектура (von Neumann architecture). Архитектура ЭВМ, разработанная Джоном фон Нейманом. Она основана на следующих принципах: а) основными блоками вычислительной машины являются 1) центральный процессор, состоящий из устройства управления и арифметико-логического устройства, 2) память и 3) устройства ввода/вывода; б) программа и данные хранятся в одной и той же линейно адресуемой памяти; в) устройство управления выбирает команды из памяти по очереди, одну за другой, интерпретирует их, соответственно управляет арифметико-логическим устройством, которое выполняет арифметические и логические операции над вызываемыми из памяти данными, и возвращает результат в память; г) устройства ввода/вывода используются для ввода программ и данных и вывода результатов расчетов АРХИТЕКТУРА ЭВМ (computer architecture). 1. С точки зрения пользователя — это совокупность основных характеристик компьютера, таких как система команд, организация памяти, система адресации, операции ввода/ вывода и управления и т. п. Компьютеры, имеющие одинаковую А. ЭВМ, с точки зрения программиста, являются совместимыми. Это означает, что независимо от конкретного исполнения их деталей и блоков компьютеры должны быть способны выполнить одну и ту же программу с одинаковым результатом. 2. С точки зрения разработчика вычислительной системы и конструктора аппаратных средств — это принцип действия, конфигурация и взаимное соединение основных логических узлов компьютера.
АРХИТЕКТУРА CISC (complex instruction set computing (CISC)). Архитектура процессора со сложной системой команд, каждая из которых выполняется в течение нескольких тактов процессора. Название дано в противоположность архитектуре RISC— процессоров с сокращенной системой команд, большинство из которых выполняется за один такт. К процессорам A. CISC относятся, например, широко распространенные процессоры компании Intel: от 8086 до 80486, а также процессоры семейства Pentium. Но в элементах этих процессоров часто используется архитектура RISC.
АРХИТЕКТУРА EISA (extended industry standard architecture (EISA)). To же, что расширенная архитектура промышленного стандарта.
АРХИТЕКТУРА ETHERNET (architecture Ethernet). Архитектура локальной вычислительной сети шинной топологии, разработанная компанией Xerox в 1976 г. с последующей доработкой компаниями Intel и DEC. Б A. Ethernet управление доступом основано на методе CSMA/CD. На основе A. Ethernet Институтом инженеров по электротехнике и электронике (IEEE) и международной организацией по стандартизации (ISO) были разработаны стандарты IEEE 802.3 и ISO 8802.3, регламентирующие технологию сетей Ethernet. Связь между компьютерами в такой сети выполнена на коаксиальных кабелях. Скорость передачи данных до 100 Мбит/с. Б одной сети может работать до 1024 рабочих станций.
АРХИТЕКТУРА MDI (multi-document interface, multiple document interface (MDI)). To же, что многодокументный интерфейс.
АРХИТЕКТУРА RISC(reduced instruction set computing (RISC)). Архитектура процессора с сокращенной системой команд, которые используются последовательно для выполнения более сложных операций. A. RISC характеризуется командами фиксированной длины, большим набором операций типа регистр—регистр и отсутствием косвенной адресации. Благодаря несложности команд и большому количеству регистров почти все команды занимают только один такт процессора, и поэтому он может работать на более высокой тактовой частоте, чем большинство процессоров архитектуры CISC. A. RISC обеспечивает простоту конструкции процессора и облегчает разработку трансляторов.
АРХИТЕКТУРА SNA (Systems Network Architecture (SNA)). To же, что системная сетевая архитектура.
АСИНХРОННАЯ ПЕРЕДАЧА (asynchronous transmission). To же, что асинхронная связь.
АСИНХРОННАЯ СВЯЗЬ, асинхронная передача (asynchronous connection, asynchronous transmission). Режим передачи данных, при котором временной интервал передачи символа может изменяться, поскольку ограничен специальными синхронизирующими сигналами. Следовательно, при А. с. каждый передаваемый символ требует посылки дополнительных сигналов, но при этом не нужна синхронизация передающего и приемного устройств. Ср. синхронная связь.
АСПЕКТО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ (aspect oriented programming (АОР)). Новейшая парадигма программирования, нацеленная на упрощение программирования типичных и повторяющихся фрагментов программ. Например, пусть в программе требуется записывать определенную информацию в файл протокола. При обычном программировании потребуется вставить соответствующий фрагмент кода в каждое место программы, где требуется производить запись в файл протокола, причем эти фрагменты будут единообразны. Б А. о. п. такой фрагмент (он называется аспектом) требуется написать только один раз, а также указать, в каком контексте данный аспект должен быть применен. После этого аспекто- ориентированная система программирования автоматически сгенерирует необходимые фрагменты исходного кода и вставит их в нужные места.
АССЕМБЛЕР (assembler). Общепринятое название транслятора с автокода.
АССОЦИАЦИЯ (association). Б унифицированном языке моделирования UML семантическое отношение между двумя и более классификаторами, включающее в себя связи между их экземплярами. См. агрегация, композиция.
АССОЦИАЦИЯ ВЫЧИСЛИТЕЛЬНОЙ ТЕХНИКИ (association for computing machinery (ACM)). Профессиональная организация предприятий и частных лиц, ведущих деятельность в сфере компьютерных технологий, в частности, занимающихся разработкой программ.
АССОЦИАЦИЯ СТАНДАРТОВ ПО ВИДЕОТЕХНИКЕ, индустриальный консорциум VESA, ассоциация VESA (Video Electronics Standards Association (VESA)). Организация, занимающаяся разработкой стандартов видеоадаптеров и мониторов. Объединяет более 50 видеотехнических фирм. Консорциумом VESA была предложена специальная графическая шина VLB, обеспечивающая ускорение вывода изображения на экран.
АССОЦИАЦИЯ VESA (Video Electronics Standards Association (VESA)). To же, что ассоциация стандартов по видеотехнике АСУ (automated control system). To же, что автоматизированная система управления.
АТОМАРНЫЙ (atomic). Действие или операция, выполняемые в виде единого блока, которые нельзя выполнить частично или прервать внешним событием. Как правило, атомарные операции невелики по размеру и просты (например, присваивание, простые арифметические или строчные вычисления). Атомарное вычисление происходит в определенной точке последовательности выполнения программы.
АТРИБУТ (attribute). 1. Признак или свойство, характеризующие объект. Например, атрибутами выводимых на экран символов являются шрифт, цвет, размер и т. п. 2. Б реляционных базах данных — имя одного и того же поля всех кортежей одной таблицы. 3. Б языках разметки — свойство элемента. 4. Б унифицированном языке моделирования UML А. называется именованное свойство какого-либо класса. Каждый объект этого класса содержит отдельное значение данного свойства. Ср. свойство класса.
АУ (arithmetic unit). To же, что арифметико-логическое устройство.
АУДИОВИЗУАЛЬНЫЙ (audiovisual). Определение, относящееся к данным, которые содержат изображение и его звуковое сопровождение, или к аппаратуре, воспроизводящей такие данные.
АУДИОДАННЫЕ, аудиоинформация (audio data, audio information). Информация о звуковых образах, представленная в цифровой форме, предназначенная для хранения, обработки и воспроизведения средствами вычислительной техники, а также для передачи по линиям связи. Примерами А. являются человеческая речь или музыкальное сопровождение видеоизображений, введенные в память компьютера. Ср. видеоданные.
АУДИОИНФОРМАЦИЯ (audio information). 1. Звуковые образы, человеческая речь. 2. То же, что аудиоданные.
АУТЕНТИФИКАЦИЯ (authentication). Процедура проверки правильности введенной пользователем регистрационной информации для входа в систему. А. используется для принудительного ограничения прав доступа к ресурсам и прав на выполнение операций в системе. См. пароль.
АУТЕНТИФИКАЦИЯ ЗАПРОС/ОТВЕТ (challenge/response authentication). То же, что аутентификация с запросом и ответом.
АУТЕНТИФИКАЦИЯ ПО СЕРТИФИКАТУ КЛИЕНТА (client certificate authentication). Метод аутентификации, в котором идентичность пользователя проверяется без использования пароля. Проверка выполняется путем вычислений, в которых используются открытый ключ, хранящийся в цифровом сертификате пользователя, и закрытый ключ, находящийся в компьютере пользователя. См. шифрование с открытым ключом, шифрование с закрытым ключом.
АУТЕНТИФИКАЦИЯ С ЗАПРОСОМ И ОТВЕТОМ, аутентификация запрос/ ответ (challenge/response authentication). Защищенная процедура аутентификации, при которой сервер для контроля доступа использует алгоритмы типа запрос/ответ и систему безопасности операционной системы.
АЦП (analog-to-digital converter). To же, что аналого-цифровой преобразователь.
АЦПУ (LPT). То же, что линейный принтер.
АЭРОГРАФ (air brush). Инструмент машинной графики, предназначенный для имитации разбрызгивания основным цветом.
За последнее время эту страницу посетили 5022 посетителей
- Главная страница
- Адрес и телефон
- VIP сервис
- Обратная связь
- Оставить заявку
- Связь с руководством
- Реклама на сайте
- Как добраться
- Безопасность
- mail@vsc-vrn.ru
Дата последнего изменения страницы — 30.10.23
Информация на данной странице не является офертой офертой
Все права защищены © 1998-2023 Ваш Сервисный Центр
Текущая версия движка сайта v.23.50



“There is no knowledge that is not power.” ― Ralph Waldo Emerson
Сейчас на сайте посетителей: 13