Машинный кодилимашинный язык– это язык, на котором записываются программы для данной машины или данного семейства машин. Этот код определяется набором кодов операций и форматом команд процессора, типом адресации ячеек, форматом представления данных в памяти и пр.
Для примера рассмотрим программу, которая выводит на консоль текст «Hello,world!», для процессора архитектуры x86 фирмыIntelc16-разрядной адресацией. В этой архитектуре адресуемой ячейкой памяти является каждый 8‑разрядный байт. Поле КОП команды занимает первый байт (т.е. допускается не более 2 8 = 256 различных команд), поле адреса – 2 байта (т.е. можно адресовать 2 16 байтов = 65536 байтов = 64 КБ – длинный адрес) или 1 байт (можно адресовать только 256 байт – короткий адрес).
Первая команда этой программы занимает 3 байта и выглядит в двоичном коде следующим образом:
Для удобства чтения программ программисты записывают их в шестнадцатеричном(16-ричном) коде, заменяя каждую четвёрку битов одной 16-ричной цифрой (всего этих цифр 16), как показано в следующей таблице:
Почему МАШИНЫ говорят на ДВОИЧНОМ КОДЕ? — Научпок #shorts
16-ричная цифра
Двоичное число
Десятичное число
В любой системе счисления число, следующее за последней цифрой, равно 10, т.е. изображается двумя цифрами (см. в таблице 102, 1010и 1016).
Таким образом, эта команда в 16-ричной системе имеет вид ВВ 11 01. Байты 11 01 образуют здесь двухбайтовое поле адреса. Адрес, указанный в этом поле, – 011116, а не 110116. Чтобы записать правильный адрес, нужно поменять местами байты адресного поля! В десятичной системе этот адрес равен 273.
Вся программа в 16-ричном коде выглядит следующим образом (за программой последует её комментарий):
Адрес первого байта
Команды и данные 25
8A 07
CD 10
E2 F9
48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21
Программа размещена, начиная с ячейки с адресом 010016, и состоит из 8 команд, занимающих первые 17 байтов. После команд в неё включена выдаваемая строка текста «Hello,world!» – 13 символов (включая пробел). Каждый символ представлен своим 8‑разряднымASCII-кодом (см. любую таблицу символов). Вся строка занимает 1310=D16байтов:
Таким образом, вся программа с данными занимает 30 байтов.
Команды с номерами 4 – 7 (выделены жирным шрифтом) повторяются столько раз, сколько символов в выводимой строке (13 раз). Это – цикл.
Комментарии к программе
В программе для передачи данных используются регистры: 8-разрядные – AL,AH(это байты 16-разрядного регистра АХ), 16‑разрядные –BX,CX. РегистрыCXиIP(адрес следующей команды) используются для организации цикла. Команды «знают», какие регистры они используют.
Вывод символа на консоль осуществляется операционной системой (BIOS) с помощью прерывания с номером 1016. Останов программы (возврат управления операционной системеMSDOSпосле завершения программы) осуществляется с помощью прерывания 2016. Команда останова необходима, иначе процессор начнёт следующий байт (4816– символ «Н») рассматривать как код операции, и это может привести к тяжёлым последствиям.
G-, M-КОДЫ — #25 — БАЗОВЫЕ G-КОДЫ: G00 И G01 / Программирование обработки на станках с ЧПУ
Команды и данные
Комментарии
Поместить в BX адрес строки (байт с символом «Н» становится текущим)
Поместить в CX длину строки (000D)
Поместить в AH номер функции 0E16 прерывания 1016
8A 07
Поместить в AL значение ячейки памяти, адрес которой находится в BX (т.е. текущий символ)
CD 10
Вызов прерывания 1016, которое с помощью регистра АХ выведет текущий символ
Увеличить значение ВХ на 1 (сделать текущим следующий байт)
E2 F9
Если CX≠0, то уменьшить CX на 1 и увеличить IP (равный 010F) на F9 (равносильно уменьшению на 7, т.к. F9 – дополнительный код числа -7), т.е. перейти по адресу 010816 – на начало цикла
Вызвать прерывание 2016: завершить программу
48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21
Этот пример показывает, насколько сложно писать, читать (понимать) и отлаживать программу в машинном коде. Производительность программиста, программирующего в цифровом машинном коде, – всего несколько команд в день. В первых ЭВМ архитектура процессоров была гораздо проще, но пользоваться самим компьютером было значительно сложнее. Но именно такие языки позволяют максимально использовать возможности конкретной машинной архитектуры при создании максимально эффективных программ.
Поэтому уже в начале 1950-х годов стали появляться языки программирования, позволявшие записывать машинные команды и данные не в цифровом виде, в символическом, используя мнемонические имена команд, регистров, ячеек памяти. Эти языки называют языками символического кодирования.Для них создавались программы-трансляторы, преобразующие команды из символической записи в цифровую. Эти трансляторы, а вместе с ними и языки символического кодирования, назывались сначалаавтокодами, а позже ассемблерами(по-русски – «сборщиками»). Появление таких языков и трансляторов стало возможным лишь на машинах с архитектурой фон Неймана благодаря принципу хранимой программы (они и были созданы для первых таких машин 26 ).
Приведём код той же программы на языке ассемблера:
mov bx, HW ; move — переместить
L: mov al, [bx]
int 10h ; interruption — прерывание
inc bx ; increment – увеличить на 1
loop L ; loop — цикл
HW: db ‘Hello, World!’
Кроме расшифровки смысла команд, здесь происходит автоматическое определение адресов команд и данных с помощью меток (LиHW). В целом, использование языков символического кодирования увеличило производительность программистов на порядок, сохраняя возможность использования всех особенностей архитектуры вычислительной системы. Таким образом, языки символического кодирования и программы-трансляторы автокоды и ассемблеры стали первым шагомавтоматизации программирования– одной из важнейших составляющих технологии программирования.
Однако, языки ассемблера и написанные на них программы привязаны к конкретной архитектуре вычислительной системы и не годятся для других систем. Кроме того, производительность программистов на ассемблере слишком низкая для написания того объёма программного кода, который требуется в современных условиях. Для удовлетворения этой потребности разрабатываются языки программирования высокого и сверхвысокого уровня – следующие шаги автоматизации программирования. На таких языках предыдущая программа превращается в один простой оператор:
Источник: studfile.net
Машинный код как язык программирования. Язык ассемблера
Язык сборки (или ассемблера) представляет собой низкоуровневый язык программирования для компьютера или иного программируемого оборудования, в котором существует корреляция между языком и инструкцией машинного кода архитектуры. Каждый машинно-ориентированный язык (в профессиональной терминологии — «сборщик») относится к конкретной компьютерной архитектуре. Напротив, большинство высокоуровневых языков программирования кроссплатформенны, но требуют интерпретации или компиляции.
Платформенно-ориентированный код также можно назвать символическим языком или набором инструкций, выполняемых непосредственно центральным процессором компьютера. Каждая программа, выполняемая процессором, состоит из серии инструкций. Машинный код по определению является самым низким уровнем программирования, видимым для программиста.
Использование
Для многих операций требуется один или несколько операндов, способных построить полную инструкцию, и многие ассемблеры могут принимать выражения чисел и константы, а также регистры и метки в качестве операндов. Это освобождает специалиста при программировании на языке машинного кода от утомительных повторяющихся вычислений. В зависимости от архитектуры эти элементы также могут быть объединены для конкретных инструкций или режимов адресации с использованием смещений или других данных, а также фиксированных адресов. Многие «сборщики» предлагают дополнительные механизмы для облегчения разработки программы, контроля процесса сборки и поддержки отладки.
Историческая перспектива
Первый ассемблерный язык был разработан в 1947 году Кэтлин Бут для ARC2 в Биркбекском лондонском университете в процессе работы с Джоном фон Нейманом и Германом Голдстином в Институте перспективных исследований. SOAP (Symbolic Optimal Assembly Program) была языком ассемблера для ПК IBM 650, созданного Стэном Поули в 1955 году.
Исторически многие программные решения были написаны только на ассемблере. ОС писались исключительно на этом языке до введения Burroughs MCP (1961 г.), который был написан на языке Executive Systems Problem Oriented Language (ESPOL). Многие коммерческие приложения были написаны на машинно-ориентированном языке, в том числе большое количество программного обеспечения мэйнфреймов IBM, созданного ИТ-гигантами. COBOL и FORTRAN в конечном итоге вытеснили большую часть наработок, хотя многие крупные организации сохранили ассемблерные прикладные инфраструктуры в 1990-х годах.
Большинство ранних микрокомпьютеров основывались на языке ассемблера с ручной кодировкой, включая большинство ОС и масштабных приложений. Это связано с тем, что эти машины имели серьезные ограничения ресурсов, нагружали индивидуальную память и архитектуру дисплеев и предоставляли ограниченные системные службы с ошибками. Возможно, более важным было отсутствие первоклассных высокоуровневых компиляторов языка, подходящих для использования в микрокомпьютере, что осложняло обучение машинному коду.
Область применения
Языки сборки устраняют большую часть проблемного, утомительного и трудоемкого программирования на ассемблерах первого поколения, необходимого на самых ранних компьютерах. Это освобождает программистов от рутины в виде запоминания числовых кодов и вычисления адресов. На начальных этапах «сборщики» широко использовались для всех разновидностей программирования.
Однако к концу 1980-х гг. их применение в значительной степени было вытеснено языками более высокого уровня в поисках повышения производительности программирования. Сегодня язык ассемблера по-прежнему используется для прямой аппаратной манипуляции, доступа к специализированным инструкциям процессора или для решения критических проблем с производительностью. Типичной областью применения являются драйверы устройств, низкоуровневые встроенные системы и параметры реального времени.
Образцы применения
Типичными примерами крупных программ на языке ассемблера являются операционные системы IBM PC DOS, компилятор Turbo Pascal и ранние приложения, такие как программа электронных таблиц Lotus 1-2-3.
Машинно-ориентированный язык — основной язык разработки для многих востребованных домашних ПК 1980-х и 1990-х годов (таких как MSX, Sinclair ZX Spectrum, Commodore 64, Commodore Amiga и Atari ST). Это обусловлено тем, что интерпретированные диалоги BASIC на этих системах обеспечивали низкую скорость выполнения, а также ограниченные возможности для полного использования имеющегося оборудования. Некоторые системы даже имеют интегрированную среду разработки (IDE) с высокоразвитыми средствами отладки и макрообъектов. Некоторые компиляторы, доступные для Radio Shack TRS-80 и его преемников, имели возможность комбинировать встроенный источник сборки с программами высокого уровня. После компиляции встроенный ассемблер создал встроенный двоичный код.
Машинный код для чайников. Терминология
Программа ассемблера создает коды операций путем перевода комбинаций мнемоники и синтаксических правил для операций и режимов адресации в их числовые эквиваленты. Это представление обычно включает в себя код операции, а также другие управляющие биты и данные. Ассемблер также высчитывает постоянные выражения и определяет символьные имена для мест памяти и других объектов.
Машинные коды команд ассемблера также могут выполнять некоторые простые типы оптимизации, зависящей от набора команд. Одним из конкретных примеров этого могут быть популярные «сборщики» x86 от разных поставщиков. Большинство из них могут выполнять замены команд перехода в любом количестве проходов, по запросу. Также способны выполнять простую перегруппировку или вставку инструкций, таких как некоторые сборщики для архитектур RISC, которые могут помочь оптимизировать разумное планирование команд, чтобы максимально эффективно использовать конвейер CPU.
Подобно ранним языкам программирования, таким как Fortran, Algol, Cobol и Lisp, сборщики были доступны с 1950-х годов, как и первые поколения текстовых компьютерных интерфейсов. Однако сначала появились сборщики, поскольку их намного проще писать, чем компиляторы для высокоуровневых языков. Это связано с тем, что каждая мнемоника, а также режимы адресации и операнды инструкций транслируются в числовые представления каждой конкретной инструкции без большого контекста или анализа. Также был ряд классов переводчиков и полуавтоматических генераторов кода со свойствами, аналогичными как сборкам, так и языкам высокого уровня, причем скоростной код, возможно, является одним из наиболее известных примеров.
Количество проходов
Существует два вида программирования на ассемблере, основанные на количестве проходов через источник (по количеству попыток прочтения) для создания объектного файла.
Однопроходные ассемблеры проходят через исходный код один раз. Любой символ, используемый до его определения, потребует errata в конце объектного кода.
Многопроходные ассемблеры создают таблицы со всеми символами и их значениями в первых проходах, а затем применяют таблицу в последующих проходах для генерации кода.
Первоначальной причиной использования однопроходных сборщиков была скорость сборки — часто второй проход требовал перемотки и перечитывания источника программы на ленту. Более поздние компьютеры с гораздо большими объемами памяти (особенно для хранения дисков) имели пространство для выполнения всей необходимой обработки без повторного чтения. Преимущество многопроходного ассемблера заключается в том, что отсутствие ошибок приводит к тому, что процесс связывания (или загрузка программы, если ассемблер непосредственно создает исполняемый код) проходит быстрее.
Что такое двоичный код?
Программа, написанная на языке ассемблера, состоит из ряда мнемонических команд процессора и мета-операторов (известных как директивы, псевдо-инструкции и псевдооперации), комментарии и данные. Инструкции по языку ассемблера обычно состоят из мнемоники кода операции. За ней следует список данных, аргументов или параметров. Они переводятся ассемблером в инструкции машинного языка, которые загружаются в память и выполняются.
Например, приведенная ниже инструкция сообщает процессору x86/IA-32 переместить 8-битное значение в регистр. Двоичный код для этой команды — 10110, за которым следует 3-битный идентификатор, для которого используется регистр. Идентификатором AL является 000, поэтому следующий код загружает регистр AL с данными 01100001.
Возникает вопрос: что такое двоичный код? Это система кодирования с использованием двоичных цифр «0» и «1» для представления буквы, цифры или другого символа на компьютере или другом электронном устройстве.
Пример машинного кода: 10110000 01100001.
Технические особенности
Преобразование языка сборки в машинный код — это задание ассемблера. Обратный процесс выполняется с помощью дизассемблера. В отличие от языков высокого уровня существует взаимно однозначное соответствие между множеством простых операторов сборки и инструкциями машинного языка. Однако в некоторых случаях ассемблер может предоставлять псевдоинструкции (макросы).
Они распространяются на несколько инструкций машинного языка для обеспечения обычно необходимой функциональности. Большинство полнофункциональных ассемблеров также предоставляют богатый макроязык, который используется поставщиками и программистами для генерации более сложных кодов и последовательностей данных.
Каждая компьютерная архитектура имеет свой собственный машинный язык. Компьютеры отличаются количеством и типами операций, которые они поддерживают, в разных размерах и числе регистров, а также в представлениях данных в хранилище. В то время как большинство ПК общего назначения способны выполнять практически ту же функциональность, способы, которыми они это делают, различаются. Соответствующие языки ассемблера отражают эти различия.
Множество наборов мнемоники или синтаксиса на ассемблере могут существовать для одного набора команд, обычно создаваемого в разных программах. В этих случаях наиболее популярным является, как правило, тот, который предоставляется изготовителем и используется в его документации.
Язык дизайна
Существует большая степень разнообразия в том, как авторы сборщиков классифицируют заявления и номенклатуру, которые они используют. В частности, некоторые описывают все, что отличается от машинной или расширенной мнемоники, как псевдооперацию. Базовый словарь сборки состоит из системы команд — трех основных разновидностей инструкций, которые используются для определения программных операций:
- мнемоника опкода;
- определения данных;
- директивы сборщика.
Мнемоника опкода и расширенная мнемоника
Инструкции, написанные на языке ассемблера, элементарны, в отличие от высокоуровневых языков. Как правило, мнемоника (произвольные символы) является символьным обозначением для одной исполняемой инструкции кода. Каждая команда обычно состоит из кода операции плюс ноль или более операндов. Большинство команд относятся к одному или двум значениям.
Расширенная мнемоника зачастую применяется для специализированной эксплуатации инструкций — для целей, не очевидных из названия мануала. Например, многие процессоры не имеют явной инструкции NOP, но имеют встроенные алгоритмы, которые используются для этой цели.
Многие сборщики поддерживают элементарные встроенные макрокоманды, способные сгенерировать две или более машинных инструкций.
Директивы данных
Существуют инструкции, используемые для определения элементов для хранения данных и переменных. Они определяют тип данных, длину и выравнивание. Эти инструкции также могут определять доступность информации для внешних программ (собранных отдельно) или только для программы, в которой определен раздел данных. Некоторые ассемблеры определяют их как псевдооператоры.
Директивы сборки
Директивы сборщика, также называемые псевдокодами или псевдооперациями, являются командами, предоставленными ассемблеру, и направляющих его на выполнение операций, отличных от инструкций по сборке. Директивы влияют на работу ассемблера и могут влиять на объектный код, символьную таблицу, файл листинга и значения параметров внутреннего ассемблера. Иногда термин псевдокода зарезервирован для директив, которые генерируют объектный код.
Имена псевдоопераций часто начинаются с точки, чтобы отличаться от машинных команд. Другим распространенным использованием псевдоопераций является резервирование областей хранения для данных времени выполнения и, возможно, инициализация их содержимого до известных значений.
Самодокументирующийся код
Символьные ассемблеры позволяют программистам связывать произвольные имена (метки или символы) с ячейками памяти и разными константами. Зачастую каждой постоянной величине и переменной присваивается собственное имя, поэтому инструкции могут ссылаться на эти местоположения по имени, тем самым способствуя самодокументирующему коду. В исполняемом коде имя любой подпрограммы соотносится с ее точкой входа, поэтому любые вызовы подпрограммы могут использовать ее имя. Внутри подпрограмм назначаются метки GOTO. Многие сборщики поддерживают локальные символы, которые лексически отличаются от обычных символов.
Ассемблеры типа NASM обеспечивают гибкое управление символами, позволяя программистам управлять разными пространствами имен, автоматически вычислять смещения в структурах данных и назначать метки, которые ссылаются на литеральные значения или результат простых вычислений, выполняемых ассемблером. Ярлыки также могут использоваться для инициализации констант и переменных с помощью перемещаемых адресов.
Языки ассемблера, как и большинство других языков компьютера, позволяют добавлять комментарии к исходному коду программы, которые будут игнорироваться во время процесса сборки. Судебное комментирование имеет важное значение в программах ассемблерного языка, поскольку определение и назначение последовательности двоичных машинных команд трудно определить. «Необработанный» (без комментирования) язык ассемблера, созданный компиляторами или дизассемблерами, довольно сложно прочитать, когда необходимо внести изменения.
Источник: autogear.ru
Программирование в машинных кодах и ассемблере
Любая программа для ЭВМ — системная или прикладная — воспринимается (распознается) процессором только в том случае, если она состоит из специальных команд, коды которых известны процессору определенного типа. Команды записаны в памяти компьютера в специальном формате. Каждая команда состоит из операционной и адресной частей.
В первой из них находится позиционный двоичный код, определяющий требуемое от процессора действие (сложение, вычитание и т.д.). Во второй – адресной части команды, также в виде двоичного позиционного кода, находятся адреса данных (операндов), над которыми это действие необходимо выполнить, либо сами операнды. В вольном переводе на русский язык некоторую команду можно, например, интерпретировать так: сложить два числа, находящиеся в памяти по адресам 100 и 120.
Разные типы ЭВМ имеют отличные друг от друга способы кодировки команд. Так, на персональных IВМ-совместимых компьютерах некоторая команда сложения в двоичном коде может иметь вид: 0000001111000011D или в шестнадцатиричном коде 03С3H. А на «древних» компьютерах типа М-220 команда сложения двух чисел могла выглядеть так:
001 00000001100100 00000001111000 00000001111011.
Поэтому программа в кодах компьютера (машинных кодах) является машинно-зависимойи непереносимой,т.е. подготовленная для компьютера одного типа, она не сможет выполняться на других. Этот факт определяет основной недостаток программирования в машинных кодах.
Вторым недостатком программирования в кодах является сильное дробление программы. Дело в том, что логически команды процессора достаточно примитивны и обуславливают выполнение простейших операций. Так, программирование несложной формулы x=(a+b)(c+d) требовало задания серии команд типа:
— сложить а и b, промежуточный результат записать в ,
— сложить c и d, промежуточный результат записать в ,
— умножить на , результат записать в х.
При программировании в кодах визуально каждая программа состояла из большого количества команд-строк, похожих на приведенные выше двоичные коды. Это определяло третий недостаток программирования в кодах — затрудненную читаемость программы и, как следствие, сложность исправления (отладки) или доработки программы.
Однако программированию в кодах присущи и значительные плюсы. Программист управляет всеми ресурсами компьютера, полностью контролирует текущее состояние ЭВМ, выбирает наиболее оптимальный код команды. Самые короткие по объему и наиболее быстрые по выполнению программы или их фрагменты разрабатываются и сегодня в кодах.
Для облегчения наглядности программы в кодах разработаны специальные символические языки — ассемблеры. В них каждой команде компьютера сопоставляется определенный символьный код, являющийся сокращением «родных» для человека слов. Специальная программа (она также называется ассемблером) переводит (транслирует)«непонятную» для компьютера (но более понятную для человека) символьную строку в коды компьютера. Так, приведенные выше коды команд сложения на ассемблере могли выглядеть так: ADD АХ, BX (сложить числа из регистров АХ и ВХ и результат запомнить в АХ). При программировании на ассемблере программист может оперировать не с адресами памяти, в которых хранятся данные, а с их символическим представлением. Например, вначале ассемблеру специальной инструкцией сообщается, что по такому-то адресу хранится число, названное для программиста как . Далее программист не задумывается над тем, по какому адресу находится соответствующее число, но просто использует его имя .
Ассемблер является машинно-зависимым языком программирования, так как его инструкции соответствуют кодам команд компьютера. Поэтому ассемблерная программа может выполняться только на тех ЭВМ, для которых она разрабатывалась. Кроме того, для работы на ассемблере требуется детальное знание особенностей конкретной ЭВМ.
Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:
Источник: studopedia.ru