Что такое машинная команда
Машинный код
Машинный код (платформенно-ориентированный код), машинный язык — система команд (набор кодов операций) конкретной вычислительной машины, которая интерпретируется непосредственно процессором или микропрограммами этой вычислительной машины. [1]
Каждая инструкция выполняет определённое (обычное элементарное) действие, такое как операция с данными (например, сложение или копирование; в регистре или в памяти) или переход к другому участку кода (изменение порядка исполнения; при этом переход может быть безусловным или условным, зависящим от результатов предыдущих инструкций). Каждая исполнимая программа состоит из последовательности таких атомарных инструкций.
Машинный код можно рассматривать как примитивный язык программирования или как самый низкий уровень представления скомпилированных или ассемблированных компьютерных программ. Хотя вполне возможно создавать программы прямо в машинном коде, сейчас это делается редко в силу громоздкости кода и трудоёмкости управления ресурсами процессора, за исключением ситуаций, когда требуется экстремальная оптимизация. Поэтому подавляющее большинство программ пишется на языках более высокого уровня и транслируется в машинный код компиляторами. Машинный код иногда называют нативным кодом (также собственным или родным кодом — от англ. native code ), когда говорят о платформенно-зависимых частях языка или библиотек. [2]
Программы на интерпретируемых языках (таких как Бейсик или Python) не транслируются в машинный код, вместо этого они либо исполняются непосредственно интерпретатором, либо транслируются в псевдокод (байт-код). Однако интерпретаторы этих языков (которые сами можно рассматривать как процессоры) как правило представлены в машинном коде.
Каждая модель процессора имеет свой собственный набор команд, хотя во многих моделях эти наборы команд сильно перекрываются. Говорят, что процессор A совместим с процессором B, если процессор A полностью «понимает» машинный код процессора B. Если процессор A знает несколько команд, которых не понимает процессор B, то B несовместим с A.
Раньше процессоры просто выполняли инструкции одну за другой, но новые суперскалярные процессоры способны выполнять несколько инструкций за раз.
Также инструкции бывают постоянной длины (у RISC-, MISC-архитектур) и диапазонной (у CISC-архитектур; например, для архитектуры x86 команда имеет длину от 8 до 120 битов).
Содержание
Микрокод
В некоторых компьютерных архитектурах поддержка машинного кода реализуется ещё более низкоуровневым слоем программ, называемых микропрограммами, что позволяет обеспечить единый интерфейс машинного языка у всей линейки или семейства компьютеров, которые могут иметь значительные структурные отличие между собой. Это делается для облегчения переноса программ в машинном коде между разными моделями компьютеров. Примером этого является семейство компьютеров IBM System/360 и их преемников: несмотря на разные шины шириной от 8 до 64 бит и выше, тем не менее у них общая архитектура на уровне машинного языка.
Использование слоя микрокода для реализации эмулятора позволяет компьютеру представлять архитектуру совершенно другого компьютера. В линейке System/360 это использовалось для переноса программ с более ранних машин IBM на новое семейство — например, эмулятор IBM 1401/1440/1460 на IBM S/360 model 40.
Абсолютный и позиционно-независимый код
Позиционно-независимый код (англ. position-independent code ) — программа, которая может быть размещена в любой области памяти, так как все ссылки на ячейки памяти в ней относительные (например, относительно счётчика команд). Такую программу можно переместить в другую область памяти в любой момент, в отличие от перемещаемой программы, которая хотя и может быть загружена в любую область памяти, но после загрузки должна оставаться на том же месте. [1]
Возможность создания позиционно-независимого кода зависит от архитектуры и системы команд целевой платформы. Например, если во всех инструкциях перехода в системе команд должны указываться абсолютные адреса, то код, требующий переходов, практически невозможно сделать позиционно-независимым. В архитектуре x86 непосредственная адресация в инструкциях работы с данными представлена только абсолютными адресами, но поскольку адреса данных считаются относительно сегментного регистра, который можно поменять в любой момент, это позволяет создавать позиционно-независимый код со своими ячейками памяти для данных. Кроме того, некоторые ограничения набора команд могут сниматься с помощью самомодифицирующегося кода или нетривиальных последовательностей инструкций.
Программа «Hello, world!»
Программа «Hello, world!» для процессора архитектуры x86 (ОС DOS, вывод при помощи BIOS Int 10h (англ.) выглядит следующим образом (в шестнадцатеричном представлении побайтно):
BB 11 01 B9 0D 00 B4 0E 8A 07 43 CD 10 E2 F9 CD 20 48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21
Данная программа работает при её размещении по смещению 10016. Отдельные инструкции выделены цветом:
Машинная команда
Каждая программа состоит из отдельных машинных команд; команда является указанием процессору произвести какую-либо элементарную операцию, например, копирования информации, сложения
и др. Все программы более высокого уровня (текстовый редактор, лазерный проигрыватель и прочие, в том числе написанные на языках программирования) сводятся к последовательности машинных команд.
Совокупность всех операций, которые может выполнять машина, образует систему ее команд. Система команд зависит от конструкции ЭВМ;
в пределах одного семейства компьютеры имеют совместимые инструкции.
Несмотря на отдельные отличия, системы машинных команд имеют много общего. Любая ЭВМ обязательно содержит следующие группы команд обработки информации.
1. Команды передачи данных (перепись), копирующие информацию из одного места в другое.
2. Арифметические операции, которым фактически обязана своим рождением вычислительная техника. Конечно, доля вычислительных действий в современном компьютере заметно уменьшилась, но они по-прежнему играют в программах важную роль.
3. Логические операции, позволяющие компьютеру производить анализ получаемой информации. После выполнения такой команды, с помощью условного перехода ЭВМ способна выбрать дальнейший ход выполнения программы. Простейшими примерами команд рассматриваемой группы могут служить сравнение, а также известные логические операции И, ИЛИ, НЕ (инверсия). Кроме того, к ним часто добавляется анализ отдельных битов кода, их сброс и установка.
4. Сдвиги двоичного кода. Для доказательства важности этой группы команд достаточно вспомнить правило умножения столбиком: каждое последующее произведение записывается в такой схеме со сдвигом на одну цифру влево.
5. Команды ввода и вывода информации для обмена с внешними устройствами.
6. Команды управления, к которым прежде всего следует отнести условный и безусловный переход, а также команды обращения к подпрограмме (переход с возвратом). Некоторые ЭВМ имеют специальные команды для организации циклов, но это не обязательно: любой цикл может быть сведен к той или иной комбинации условного и безусловного переходов. Часто к этой же группе команд относят операции по управлению процессором; с ростом сложности устройства процессора количество такого рода команд увеличивается.
По степени сложности команд и их ассортименту процессоры разделяют на две группы — RISC и CISC (см. “Процессор”).
Пожалуй, наиболее удивительным является тот факт, что с помощью относительно небольшого многообразия универсальных команд удается создать программное обеспечение, которое способно себя вести весьма сложным образом.
Любая команда ЭВМ обычно состоит из двух частей — операционной и адресной. Операционная часть (иначе она еще называется кодом операции — КОП) указывает, какое действие необходимо выполнить с информацией. Адресная часть описывает, где используемая информация хранится и куда поместить результат.
Команды могут быть одно-, двух- и трехадресные в зависимости от количества возможных операндов. Первые ЭВМ имели наиболее простую и наглядную трехадресную систему команд. Например: взять числа из адресов памяти А1 и А2, сложить их и сумму поместить в адрес А3. Для реализации этого сложения на одноадресной машине потребуется выполнить не одну, а три команды:
a) извлечь содержимое ячейки А1 в сумматор;
b) сложить сумматор с числом из А2;
c) записать результат из сумматора в А3.
Может показаться, что одноадресной машине для решения любой задачи потребуется втрое больше команд, чем трехадресной. На самом деле это далеко не всегда так. Попробуйте самостоятельно спланировать программу вычисления выражения Y = (X1 + X2) * X3/X4 и вы с удивлением обнаружите, что потребуется 3 трехадресных команды и всего 5 одноадресных. Таким образом, одноадресная машина в чем-то даже эффективнее, т.к. она не производит ненужной записи в память промежуточных результатов.
Ради полноты изложения следует сказать о возможности реализации безадресной (нульадресной) машины, использующей особый способ организации памяти — стек. Хотя подобная машина неудобна для человека, она легко реализуется в компьютере; в частности, именно так устроена JAVA-машина.
Чтобы получить хотя бы некоторое представление об уровне машинных команд, приведем примеры нескольких типичных инструкций для процессоров семейства Intel.
С точки зрения программиста, машинные команды — это самый низкий уровень. Но для процессора каждая инструкция распадается на еще более простые составные части, которые принято называть тактами. На каждом такте процессор выполняет какие-либо совсем элементарные действия, например, обнуляет один из своих внутренних регистров, копирует содержимое из одного регистра в другой, анализирует содержимое отдельных битов информации и т.д. Для синхронизации последовательных машинных тактов они инициируются с помощью специального тактового генератора. Его частота выбирается инженерами таким образом, чтобы к началу следующего такта все операции предыдущего успевали надежно заканчиваться.
Различные по сложности операции выполняются за разное количество тактов. Например, передача содержимого одного регистра в другой выполняется гораздо быстрее, чем умножение чисел. Существенно удлиняется выполнение команды, если ее данные берутся не из внутренних регистров самого процессора, а из оперативной памяти (именно поэтому в процессор встраивается внутренний кэш).
Из сказанного выше отчетливо следует, что тактовая частота, определяющая время выполнения составляющих машинной команды, является важной характеристикой процессора: чем она выше, тем быстрее при прочих равных условиях работает процессор. Подчеркнем, что в случае различных алгоритмов выполнения операций внутри разных моделей процессоров использовать тактовую частоту как меру сравнения их быстродействия весьма проблематично.
Методические рекомендации
Курс информатики основной школы
В базовом курсе достаточно дать ученикам лишь наиболее общее представление о машинных командах. При этом важно подчеркнуть два аспекта проблемы. Во-первых, как и любой исполнитель, компьютер имеет собственную систему команд. А во-вторых, эта система является базовой для реализации всех остальных уровней программного обеспечения.
Предложенное в статье объяснение понятия тактовой частоты не является традиционным, но оно достаточно просто для понимания и хорошо согласуется с устройством процессоров.
Курс информатики в старших классах
При изучении программного обеспечения можно рекомендовать учителю в ознакомительном плане изложить материал данной статьи. Хотя полученные знания, вероятно, не будут непосредственно применяться учениками, для формирования общих представлений об обработке информации на компьютере они являются весьма полезными.
5 См., например, эксперименты 3.6.2 в: Еремин Е.А. Популярные лекции об устройстве компьютера. СПб.: BHV-Петербург, 2003, 272 с.
Структура и форматы машинных команд
Машинная команда представляет собой код, определяющий операцию вычислительной машины и данные, участвующие в операции. Команда должна содержать в явной или неявной форме информацию об адресе результата операции, и об адресе следующей команды.
Машинная операция – это действия машины по преобразованию информации, выполняемые под воздействием одной команды.
Программа – последовательность команд, отображающих все действия, необходимые для решения задачи по некоторому алгоритму.
Машинный такт – период тактовой частоты работы процессора.
Машинный цикл – количество машинных тактов, требуемых для выполнения одной команды.
По характеру выполняемых операций различают следующие основные группы команд:
Машинная команда состоит из операционной и адресной частей. Эти части могут состоять из нескольких полей. В общем виде машинная команда имеет следующую структуру:
Операционная часть содержит код, задающий вид операции (сложение, умножение, передача и т.д.).
Адресная часть содержит информацию об адресах операндов, результата операции и следующей команды.
Структура команды определяется составом, назначением и расположением полей в команде.
Формат команды – это структура команды с разметкой номеров разрядов, определяющих границы отдельных полей команды.
Возможные структуры машинных команд
Двухадресная структура
используется в вычислительных машинах, построенных так, что результат операции будет всегда помещаться в фиксированный регистр процессора, например на место первого операнда. В этом случае адрес результата может явно не указываться.
Безадресная структура фиксирует адреса обоих операндов и результата операции, например при работе со стековой памятью.
Обычно в вычислительной машине используется несколько форматов команд разной длины (чаще всего безадресные, одноадресные и двухадресные).
Структура машинной команды
Смотрите также страницы справочника:
Содержание
Структура машинной команды
Структура машинной команды для режима «32 бита»
Каждая машинная команда может содержать от одного байта до 16 байт.
Примечание. Есть две машинных команды (CALL, код 9A, JMP, код EA), в которых поле для задания адреса занимает 6 байт.
Структура машинной команды для режима «16 бит»
Примечание. Есть две машинных команды (CALL, код 9A, JMP, код EA), в которых поле для задания адреса занимает 4 байта.
Префиксы перед кодом операции
Вообще-то префиксы перед командами встречаются не часто. Чтобы в этом убедиться, достаточно посмотреть на какую-нибудь распечатку программы в виде машинных команд, например, на результаты работы дизассемблера. Еще более редко можно увидеть сразу два префикса подряд.
Когда перед кодом операции помещаются префиксы, должны соблюдаться следующие два правила:
Если в команде есть более одного префикса, то префиксы должны располагаться в том порядке, в котором они показаны в таблицах, приведенных выше.
В одной команде не могут стоять сразу два префикса одной группы (сразу два префикса команды или сразу два префикса замены сегмента).
Замечено, что процессоры обычно бывают терпимы к нарушению этих правил. Однако, стоит все же считать, что результат таких нарушений может оказаться непредсказуемым.
Префикс действует только в пределах той команды, перед которой он стоит.
Код префикса не может совпадать с кодом операции какой-нибудь команды. Это хорошо видно по таблице Первый байт кода операций. В этой таблице показаны также и коды префиксов.
Префиксы команды
Префиксы команды имеют свои собственные имена на языке ассемблера. И вдобавок, некоторые ассемблеры показывают эти команды в отдельной строке. Поэтому при программировании на ассемблере эти префиксы команды могут восприниматься как самостоятельные команды. (Это еще раз показывает, что мышление на языке ассемблера может сильно отличаться от мышления на языке машинных команд).
Префикс изменения размера адреса
Если общий режим выполнения программы равен «32 бита», то для команды, перед которой есть префикс 67, устанавливается атрибут размера адреса «16» бит.
Если общий режим выполнения программы равен «16 бит», то для команды, перед которой есть префикс 67, устанавливается атрибут размера адреса «32» бита.
Действие префикса зависит от конкретной команды.
Префикс изменения размера операнда
Если общий режим выполнения программы равен «32 бита», то для команды, перед которой есть префикс 66, устанавливается атрибут размера операнда «16» бит.
Если общий режим выполнения программы равен «16 бит», то для команды, перед которой есть префикс 66, устанавливается атрибут размера операнда «32» бита.
Действие префикса зависит от конкретной команды.
Префиксы замены сегмента
Код операции
После всех префиксов (если перед командой есть префиксы) начинается собственно машинная команда. И начинается машинная команда с кода операции.
Поле с кодом операции всегда присутствует в любой машинной команде. Очевидно, что в команде должен быть хотя бы один байт. И тогда этим единственным байтом как раз будет именно код операции.
При обсуждении системы команд удобно использовать понятие «основной байт» кода операции. Если КОП состоит из одного байта, то этот байт и является основным байтом. Если КОП состоит из двух байт, то основным следует считать второй байт кода операции.
В данном справочнике имеются таблицы команд, в которых команды расположены в порядке их кодов операции:
Первый байт кода операций Второй байт кода операцийВ таблицах справочника в колонке «Формат» основной байт кода операции условно показан в виде восьми черточек, соотвествующих восьми разрядам основного байта.
Подобное обозначение основного байта есть для каждой команды, так как у каждой команды есть код операции.
Для многих команд в основном байте есть особые биты или битовые поля. Такие места в байте показаны буквами на фоне черточек.
Разберем какой-нибудь конкретный случай. Пусть это будет команда ADD с кодами 04 и 05, которая выполняет операцию сложения. Двоичная запись для этих кодов операции выглядит так: 00000100 и 00000101, отличие только в самом младшем разряде.
Здесь вариант команды ADD с кодом 04 ( w = 0 ) выполняет операцию сложения для байта (размер операнда 8 бит), а вариант с кодом 05 ( w = 1 ) выполняет ту же операцию для слова (размер 16 бит).
Обозначение ( ——reg ) говорит о том, что прямо в основном байте кода операции задается регистр, для которого эта операция выполняется.
И это значит, что для данной команды имеется восемь разных вариантов с разными кодами операций. Примерами таких команд могут служить однобайтные команды INC и DEC (инкремент и декремент).
Можно посмотреть и с другой стороны, со стороны команд ассемблера. Если для команды INC задается в качестве операнда какой-нибудь регистр, например EAX или EBX, то операнд будет указан прямо в коде операции машинной команды.
Полный список обозначений для особых битов и битовых полей основного байта приведен на странице Пояснения к основным таблицам.
Байт MRM имеется не во всех командах. Это определяется конкретным кодом операции (а говоря точнее, «основным кодом операции»), входит ли байт MRM в состав данной машинной команды или не входит.
Здесь важно заметить, что речь идет не о команде с точки зрения языка ассемблера, а о машинной команде с конкретным основным кодом операции. Например, команда сложения ADD имеет четыре разных варианта с байтом MRM, еще четыре варианта с «сокращенным» байтом MRM, который в нашем справочнике обозначен как NNN, и два варианта вообще без байта MRM. Итого это получается десять разных кодов операции, десять разных вариантов машинной команды. См. страницу Основные команды арифметики.
В таблицах справочника, в колонке «Формат» показано, в составе каких команд есть байт MRM. Причем наличие в колонке «Формат» обозначения MRM или обозначения NNN говорит о том, что в составе команды есть целая группа байтов, относящаяся к MRM. Первым в этой группе идет байт ( mod,reg,r/m ), то есть, собственно байт MRM, затем, если требуется, может идти второй байт режима адресации, это байт SIB, а затем, если требуется, может быть еще и поле для задания адреса.
Байт MRM делится на три битовых поля: двухбитовое поле ( mod ), трехбитовое поле ( reg ), трехбитовое поле ( r/m ).
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
mod | reg | r/m |
Поле ( reg ) определяет первый операнд команды, операнд-приемник (destination). Поле ( r/m ) определяет второй операнд команды, операнд источник (source). Обычно бывает именно такое распределение ролей между ( reg ) и ( r/m ), который из операндов будет источником, а который приемником. Но бывает и наоборот, это зависит от конкретной команды.
Поле ( r/m ) задает либо регистр, либо память. Это поле действует совместно с полем ( mod ), вместе будет пять битов и получается 32 варианта, это дает 8 вариантов для задания регистров и 24 варианта для задания формы и режима адресации памяти.
Обозначение NNN
В системе команд x86 имеются такие команды, в которых байт MRM используется несколько иначе, чем было описано выше. Отличие в том, как трактуется поле ( reg ).
Дело в том, что основной код операции (один байт или два байта) не всегда однозначно определяет, какая это команда. При некоторых значениях основного кода операции к этому коду операции добавляются еще три бита из поля ( reg ) байта MRM. И тогда уже этот рассширенный код операции определяет команду.
Как пример такого случая, можно назвать команды с первым байтом кода операции равным 80, 81, 82, 83. См. страницу Первый байт кода операций.
В таблицах данного справочника для подобных команд ставится обозначение NNN в колонке «Формат» вместо обозначения MRM. Просто нужно было как-то выделить отдельно этот особый случай. Вот и получился «байт NNN» вместо «байта MRM».
Обозначение NNN показывает, что в команде стоит сокращенный вариант байта MRM, который может задавать только один операнд, вместо прежних двух операндов. Этот операнд определяется полями ( mod ) и ( r/m ), так что операнд может быть либо регистром, либо может иметь одну из многих форм задания адреса в памяти.
В системе команд x86 есть случаи, когда байт MRM применяется в сокращенном виде только из-за того, что для данной конкретной команды не требуется, чтобы байт MRM задавал два операнда, так как в этой команде нужен только один операнд. В этом случае поле ( reg ) байта MRM просто не используется, а в документации оговаривается, что всегда должно быть ( reg = 0 ).
Таких случаев совсем немного:
Для этих случаев в таблицах справочника тоже ставится обозначение NNN.
Байт SIB возможен в команде только в режиме 32 бита и только в том случае, когда в команде уже есть байт MRM (в полной форме или в сокращенной форме NNN).
Этот дополнительный байт для задания режима адресации включается в состав команды только при некоторых определенных значениях в полях ( mod ) и ( r/m ) байта MRM.
Аналогично байту MRM, байт SIB делится на три битовых поля:
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
scale | index | base |
Байт SIB позволяет применять еще более сложные формы задания адреса в памяти.
Поле для задания адреса
В этом поле из 1, или 2, или 4 байт, расположенном внутри команды, может быть задан либо полный адрес, либо смещение относительно некоторого адреса.
С точки зрения терминологии, не всегда можно отличить «смещение» от «полного адреса». Например, как называть полный адрес внутри сегмента, если такой адрес всегда задается смещением от начала сегмента.
Поле задания адреса может по-разному использоваться в разных командах. Однако, рассматривая общую структуру команды, важно различать следующие два случая:
Эти два разных случая по-разному отражаются в таблицах справочника в колонке «Формат».
Если в формате команды есть обозначение MRM (или обозначение NNN), то дополнительные байты, относящиеся к байту MRM никак не показываются. Так что поле для задания адреса в этом случае показано не будет.
Если в формате команды нет байта MRM, но есть поле для задания адреса, то в колонке «Формат» будет стоять обозначение «addr (..)«, где в скобках указывается количество байт.
В системе команд x86 невозможен случай, чтобы в некоторой команде оказалось сразу два поля для задания адреса. Поэтому в таблицах справочника невозможен случай, чтобы в колонке «Формат» стояло обозначение MRM (или NNN), а затем еще и обозначение «addr (..)».
Поле для задания адреса есть не во всех машинных командах.
Непосредственный операнд
Форматы многих команд предусматривают возможность задавать константу непосредственно внутри команды. На языке ассемблера это соответствует заданию для операнда конкретного численного значения вместо имени переменной.
В таблицах справочника в колонке «Формат» наличие непосредственного операнда показано обозначением «data (..)«, где в скобках указывается количество байт.
Поле для непосредственного операнда есть не во всех машинных командах.
Если в формате команды есть поле для задания непосредственного операнда, то это поле в команде всегда будет последним.