Язык ассемблер: Почему Ассемблер — это круто, но сложно

Содержание

Лекция 4. Основы языка Ассемблер. Синтаксис языка Ассемблер. Ассемблерные вставки в языке C/C++.

4.1. Назначение языков
ассемблера.

Ассемблер (от англ. assemble — собирать) —
компилятор с языка ассемблера в команды машинного языка.

Сейчас
разработка программ на ассемблере применяется в основном в программировании
небольших микропроцессорных систем (микроконтроллеров), как правило,
встраиваемых в какое-либо оборудование. Очень редко возникает потребность
использования ассемблера в разрабатываемых программах в тех случаях, когда
необходимо, например, получить наивысшую скорость выполнения определенного
участка программы, выполнить операцию, которую невозможно реализовать
средствами языков высокого уровня, либо уместить программу в память
ограниченного объема (типичное требование для загрузчиков операционной
системы).

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

Язык ассемблера — тип языка программирования
низкого уровня. Команды языка ассемблера один в один соответствуют командам
процессора и представляют собой удобную символьную форму записи (мнемокод)
команд и аргументов. Язык ассемблера обеспечивает связывание частей программы и
данных через метки, выполняемое при ассемблировании (для каждой метки
высчитывается адрес, после чего каждое вхождение метки заменяется на этот
адрес).

Каждая
модель процессора имеет свой набор команд и соответствующий ему язык (или
диалект) ассемблера.

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

Связывание ассемблерного кода с
другими языками.

Большинство современных компиляторов позволяют комбинировать в одной программе
код, написанный на разных языках программирования. Это дает возможность быстро
писать сложные программы, используя высокоуровневый язык, не теряя
быстродействия в критических ко времени задачах, применяя для них части,
написанные на языке ассемблера. Комбинирование достигается несколькими
приемами:

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

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

Достоинства языков ассемблера.

1.
Максимально оптимальное использование средств процессора, использование
меньшего количества команд и обращений в память и, как следствие, большая
скорость и меньший размер программы.

2.
Использование расширенных наборов инструкций процессора (MMX, SSE, SSE2, SSE3).

3.
Доступ к портам ввода-вывода и особым регистрам процессора (в большинстве ОС
эта возможность доступна только на уровне модулей ядра и драйверов)

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

5.
Максимальная адаптация для нужной платформы.

Однако
следует отметить, что последние технологии безопасности, внедряемые в
операционные системы и компиляторы, не позволяют делать самомодифицирующего
кода, так как исключают одновременную возможность исполнения программы и запись
в одном и том же участке памяти (технология W^X).X используется в OpenBSD , в других BSD-системах, в Linux. В Microsoft
Windows (начиная с Windows XP SP2) применяется схожая технология DEP.

Недостатки языков ассемблера.

1.
Большие объемы кода, большое число дополнительных мелких задач, меньшее
количество доступных для использования библиотек по сравнению с языками
высокого уровня.

2.
Трудоемкость чтения и поиска ошибок (хотя здесь многое зависит от комментариев
и стиля программирования).

3.
Часто компилятор языка высокого уровня, благодаря современным алгоритмам
оптимизации, даёт более эффективную программу (по соотношению качество/время
разработки).

4.
Непереносимость на другие платформы (кроме совместимых).

5.
Ассемблер более сложен для совместных проектов.

4.2. Синтаксис ассемблера.

Синтаксис
общих элементов языка. В отличие от языков программирования высокого уровня,
где основным элементом языка является оператор, синтаксически программа на
ассемблере состоит из последовательности строк. Строка – основная единица
ассемблерной программы.

Синтаксис
строки имеет следующий общий вид:

<метка:>
<команда или директива> <операнды> <;комметарий>

Все
эти четыре поля необязательны, в программе вполне могут присутствовать и
полностью пустые строки для выделения каких либо блоков кода. Метка может быть
любой комбинацией букв английского алфавита, цифр и символов _, $, @, ?, но
цифра не может быть первым символом метки, а символы $ и ? иногда имеют
специальные значения и обычно не рекомендуются к использованию. Большие и
маленькие буквы по умолчанию не различаются, но различие можно включить, задав
ту или иную опцию в командной строке ассемблера. Во втором поле, поле команды,
может располагаться команда процессора, которая транслируется в исполняемый
код, или директива, которая не приводит к появлению нового кода, а управляет
работой самого ассемблера. В поле операндов располагаются требуемые командой
или директивой операнды (то есть нельзя указать операнды и не указать команду
или директиву). И наконец, в поле комментариев, начало которого отмечается
символом ; (точка с запятой), можно написать все что угодно — текст от символа
«;» до конца строки не анализируется ассемблером.

4.3. Ассемблерные вставки в
языках высокого уровня.

Языки
высокого уровня поддерживают возможность вставки ассемблерного  кода. 
Последовательность  команд  Ассемблера 
в  С-программе размещается в
asm-блоке:

asm

{

команда_1 //комментарий_1

команда_2 /* комментарий_2 */

————————

команда_n ; комментарий_n

}

Язык ассемблера — всё по этой теме для программистов

Как компилятор преобразует код на C в Assembler?

Видео, в котором подробно разбирается преобразование программы на языке C в машинный код.

Битва языков программирования 2020 продолжается!

Первый день голосования закончился. По его итогам Swift уверенно обошёл PHP, а Kotlin немного не дотянул до Java. Смотрите результаты здесь. Сегодня соревнуются следующие две пары языков: Assembler/Pascal и С++/Cobol.…

Примите участие в баттле языков программирования 2020. Старт уже завтра!

В то время как Java и язык Си меняются местами на вершине рейтинга TIOBE, мы решили выяснить, какие языки программирования, наши подписчики любят больше всего. Завтра начинается баттл языков программирования…

Курс «Программирование с нуля»

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

Курс «Основы программирования встраиваемых систем»

Русскоязычный курс, открывающий своим слушателям удивительный мир микроконтроллеров. Среди окружающих нас приборов все сложнее встретить такие, в которых их нет. Часы и светофоры, системы освещения, электронные игрушки и роботы, телевизоры…

Компилятор Си в одну инструкцию: обзор инструмента M/o/Vfuscator

M/o/Vfuscator компилирует программы в инструкции mov, и только в них. Инструмент ориентирован на язык Си и архитектуру процессора x86, но адаптивен и легко настраивается под другие языки и архитектуры.

Руководство по созданию ядра для x86-системы. Часть 2. Система ввода / вывода

Рассказывает Arjun Sreedharan  В прошлой статье я писал о том, как создать простейшее x86-ядро, использующее GRUB, работающее в защищённом режиме и выводящее на экран строку. В этот раз мы подключим к ядру драйвер…

Руководство по созданию ядра для x86-системы. Часть 1. Просто ядро

Рассказывает Arjun Sreedharan  Давайте напишем простое ядро, которое можно загрузить при помощи бутлоадера GRUB x86-системы. Это ядро будет отображать сообщение на экране и ждать. 

В Сети появилась серия статей-руководств по созданию собственной ОС на ассемблере и Rust

Предлагаем вашему вниманию серию англоязычных статей, опубликованную в блоге Филиппа Опперманна. В ней подробно разбирается процесс разработки собственной 64-битной ОС на ассемблере и Rust. Серия пополняется, но на основе уже написанных статей можно написать достаточно функциональную операционную…

Основы Just In Time компиляции, используемой в динамических языках, на примере программы на C

Я был сильно вдохновлен, когда узнал о динамической компиляции (JIT — Just In Time) из различных виртуальных машин Ruby и JavaScript. Я мог бы рассказать вам все о том, как…

Бесплатные материалы для программистов

Огромная база ссылок на книги, статьи, туториалы, онлайн-курсы, интерактивные обучалки, подкасты — всё только бесплатное.

Как создавался редактор ассемблерного кода SASM

Рассказывает создатель SASM, Дмитрий Манушин Здравствуйте! Хочу немного рассказать о разработке проекта SASM — среды разработки для языков ассемблера. Чтобы сразу было понятно о чём речь: Сайт: http://dman95.github.io/SASM/ Репозиторий с…

Самоизменяющаяся программа на C под x86_64

Зачем вообще может понадобиться писать программу, которая меняет свой код во время выполнения? Это ужасно! Да, да, я знаю. И все-таки, зачем? Ну, например, это хороший учебный пример. Но главная…

Обычно main — это функция. Но всегда ли это так?

Идея написать эту статью пришла мне в голову, когда одного из моих коллег заставили пройти начальный курс по CS в моем университете. Мы с ним искали способ написать корректную программу…

Язык ассемблера Языки и методы программирования. Теория…

Привет, мой друг, тебе интересно узнать все про язык ассемблера, тогда с вдохновением прочти до конца. Для того чтобы лучше понимать что такое
язык ассемблера , настоятельно рекомендую прочитать все из категории Языки и методы программирования. Теория трансляции

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

Язык ассемблера позволяет программисту пользоваться текстовыми мнемоническими (то есть легко запоминаемыми человеком) кодами, по своему усмотрениюприсваивать символические имена регистрам компьютера и памяти, а также задавать удобные для себя способы адресации. Кроме того, он позволяет использовать различные системы счисления (например, десятичную или шестнадцатеричную) для представления числовых констант, использовать в программе комментарии и др.

Программы, написанные на языке ассемблера, требуют значительно меньшего объема памяти и времени выполнения. Знание программистом языка ассемблера и машинного кода дает ему понимание архитектуры машины. Несмотря на то, что большинство специалистов в области программного обеспечения разрабатывают программы на языках высокого уровня, таких, как Object Pascal или C, наиболее мощное и эффективное программное обеспечение полностью или частично написано на языке ассемблера.

Языки высокого уровня были разработаны для того, чтобы освободить программиста от учета технических особенностей конкретных компьютеров, их архитектуры. В противоположность этому, язык ассемблера разработан с целью учесть конкретную специфику процессора. Сдедовательно, для того, чтобы написать программу на языке ассемблера для конкретного компьютера, важно знать его архитектуру [57].

В качестве примера приведем программу на языке ассемблера для IBM PC. Программа вычисляет значение a = b + c для целых a, b и c:


            .MODEL SMALL 
            .DATA 
b         DW     5 
c         DW     3 
a         DW     ? 
          .CODE 
begin   MOV   AX,@DATA 
          MOV     DS,AX 
          MOV     AX,B 
          ADD     AX,C 
          MOV     A,AX 
          MOV     AH,4CH 
          INT       21H 
          END     begin
Директива   .MODEL   задает механизм распределения памяти под данные и команды. 
Директива   .DATA   определяет начало участка программы с данными. 
Директивы   DW  задают типы переменных и их значения. 
Директива   .CODE   определяет начало участка программы с командами. 
Команды   MOV   AX,@DATA   и   MOV     DS,AX записывают адрес сегмента данных в регистр   DS   (Data Segment). 
Для вычисления a используются команды   MOV     AX, B,   ADD     AX,C   и   MOV     A,AX. 
В директиве   END   задана метка первой выполняемой программы программы begin.

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

Понятие об ассемблере

Сегменты программы, сегменты подпрограммы

Кодовое представление команд

Адресация памяти

 

Ассемблер

Существует несколько версий программы ассемблер. Одним из наиболее часто используемых является пакет Turbo Assembler, водящий в состав комплекса программ Borland Pascal 7.0. Рассмотрим работу с этим пакетом более подробно.

Входной информацией для ассемблера (TASM.EXE) является исходный файл — текст программы на языке ассемблера в кодах ASCII. В результате работы ассемблера может получиться до 3-х выходных файлов:

  1. объектный файл – представляет собой вариант исходной программы, записанный в машинных командах;
  2. листинговый файл – является текстовым файлом в кодах ASCII, включающим как исходную информацию, так и результат работы программы ассемблера;
  3. файл перекрестных ссылок – содержит информацию об использовании символов и меток в ассемблерной программе (перед использованием этого файла необходима его обработка программой CREF).

Существует много способов указывать ассемблеру имена файлов. Первый и самый простой способ — это вызов команды без аргументов. В этом случае ассемблер сам поочередно запрашивает имена файлов: входной (достаточно ввести имя файла без расширения ASM), объектный, листинговый и файл перекрестных ссылок. Для всех запросов имеются режимы, применяемые по умолчанию, если в ответ на запрос нажать клавишу Enter:

  • объектному файлу ассемблер присваивает то же имя, что и у исходного, но с расширением OBJ;
  • для листингового файла и файла перекрестных ссылок принимается значение NUL — специальный тип файла, в котором все, что записывается, недоступно и не может быть восстановлено.

Если ассемблер во время ассемблирования обнаруживает ошибки , он записывает сообщения о них в листинговый файл. Кроме того, он выводит их на экран дисплея.

Другой способ указать ассемблеру имена файлов — это задать их прямо в командной строке через запятую при вызове соответствующей программы, например:

 

TASM Test, Otest, Ltest, Ctest

 

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

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

Входной информацией для программы TLINK являются имена объектных модулей (файлы указываются без расширение OBJ). Если файлов больше одного, то их имена вводятся через разделитель «+». Модули связываются в том же порядке, в каком их имена передаются программе TLINK. Кроме того, TLINK требует указания имени выходного исполняемого модуля. По умолчанию ему присваивается имя первого из объектных модулей, но с расширением ЕХЕ . Об этом говорит сайт https://intellect.icu . Вводя другое имя, можно изменять имя файла, но не расширение. Далее можно указать имя файла, для хранения карты связей (по умолчанию формирование карты не производится). Последнее, что указывается программе TLINK – это библиотеки программ, которые могут быть включены в полученный при связывании модуль. ; , ` «

 

Конструкции языка ассемблера формируются из идентификаторов и ограничителей. Идентификатор представляет собой набор букв, цифр и символов «_», «.», «?», «$» или «@» (символ «.» может быть только первым символом идентификатора), не начинающийся с цифры. Идентификатор должен полностью размещаться на одной строке и может содержать от 1 до 31 символа (точнее, значимым является только первый 31 символ идентификатора, остальные игнорируются). Друг от друга идентификаторы отделяются пробелом или ограничителем, которым считается любой недопустимый в идентификаторе символ. Посредством идентификаторов представляются следующие объекты программы:

  • переменные;
  • метки;
  • имена.

Переменные идентифицируют хранящиеся в памяти данные. Все переменные имеют три атрибута:

  1. СЕГМЕНТ, соответствующий тому сегменту, который ассемблировался, когда была определена переменная;
  2. СМЕЩЕНИЕ, являющееся смещением данного поля памяти относительно начала сегмента;
  3. ТИП, определяющий число байтов, подвергающихся манипуляциям при работе с переменной.

Метка является частным случаем переменной, когда известно, что определяемая ею память содержит машинный код. На нее можно ссылаться посредством переходов или вызовов. Метка имеет два атрибута: СЕГМЕНТ и СМЕЩЕНИЕ.

Именами считаются символы, определенные директивой EQU и имеющие значением символ или число. Значения имен не фиксированы в процессе ассемблирования, но при выполнении программы именам соответствуют константы.

Некоторые идентификаторы, называемые ключевыми словами, имеют фиксированный смысл и должны употребляться только в соответствии с этим. Ключевыми словами являются:

  • директивы ассемблера;
  • инструкции процессора;
  • имена регистров;
  • операторы выражений.

В идентификаторах одноименные строчные и заглавные буквы считаются эквивалентными. Например, идентификаторы AbS и abS считаются совпадающими.

 

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

Целые числа имеют следующий синтаксис (xxxx – цифры):

 

[+|-]xxxx

[+|-]xxxxB

[+|-]xxxxQ

[+|-]xxxxO

[+|-]xxxxD

[+|-]xxxxH

 

Латинский символ (в конце числа), который может кодироваться на обоих регистрах, задает основание системы счисления числа: B – двоичное, Q и O – восьмеричное, D – десятичное, H – шестнадцатеричное. Шестнадцатеричные числа не должны начинаться с буквенных цифр (например, вместо некорректного ABh следует употреблять 0ABh). Шестнадцатеричные цифры от A до F могут кодироваться на обоих регистрах. Первая форма целого числа использует умалчиваемое основание (обычно десятичное).

Символьные и строковые константы имеют следующий синтаксис:

 

‘символы’

«символы»

 

Символьная константа состоит из одного символа алфавита языка. Строковая константа включает в себя 2 или более символа.  В отличие от других компонент языка, строковые константы чувствительны к регистру. Символы «’» и «»» в теле константы должны кодироваться дважды.

Кроме целых и символьных типов ассемблер содержит еще ряд типов (например, вещественные числа, двоично-десятичные числа), однако их рассмотрение выходит за рамки данного пособия.

 

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

Достоинством такого метода является возможность разработки программ значительно большего объема небольшими функционально законченными частями. Кроме того, эти подпрограммы можно использовать в других программах, не прибегая к переписыванию частей программного кода. В довершение ко всему, так как размер сегмента не может превышать 64К, то при разработке программ с объемом кода более 64К, просто не обойтись без модульного принципа.

Язык программирования Ассемблера поддерживает применение процедур двух типов – ближнего (near) и дальнего (far).

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

При вызове процедуры в стеке сохраняется адрес возврата в вызывающую программу:

  • при вызове ближней процедуры – слово, содержащее смещение точки вызова относительно текущего кодового сегмента;
  • при вызове дальней процедуры – слово, содержащее адрес сегмента, в котором расположена точка возврата, и слово, содержащее смещение точки возврата в этом сегменте.

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

 

<имя_процедуры>  PROC <параметр>

   <тело_процедуры>

<имя_процедуры>  ENDP

 

Следует обратить внимание, что в директиве PROC после имени не ставится двоеточие, хотя имя и считается меткой.

Параметр, указываемый после ключевого слова PROC, определяет тип процедуры: ближний (NEAR) или дальний (FAR). Если параметр отсутствует, то по умолчанию процедура считается ближней.

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

 

        
Рис. 1. Варианты размещения подпрограммы в теле программы.

 

Передавать фактические параметры процедуре можно несколькими способами. Простейший способ – передача параметров через регистры: основная программа записывает параметры в какие-либо регистры, а процедура по мере необходимости извлекает их из этих регистров и использует в своей работе. Такой способ имеет один основной недостаток: передавать параметры через регистры можно если их немного (если много, то просто не хватит регистров). Решить это проблему можно, передавая параметры через стек. В этом случае основная программа записывает параметры в стек и вызывает подпрограмму, подпрограмма работает с параметрами и, возвращая управление, очищает стек.

Для работы с подпрограммами в систему команд процессора включены специальные команды, это вызов подпрограммы CALL и возврат управления RET.

Все команды вызова CALL безусловны. Внутрисегментный вызов NEAR CALL используется для передачи управления процедуре, находящейся в том же сегменте. Он указывает новое значение регистра IP и сохраняет старое значение счетчика команд (IP) в стеке в качестве адреса возврата. Межсегментный вызов FAR CALL используется для передачи управления процедуре, находящейся в другом сегменте или даже программном модуле. Он задает новые значения сегмента CS и смещения IP для дальнейшего выполнения программы и сохраняет в стеке как регистр IP, так и регистр CS.

Все возвраты RET являются косвенными переходами, поскольку извлекают адрес перехода из вершины стека. Внутрисегментный возврат извлекает из стека одно слово и помещает его в регистр IP, а межсегментный возврат извлекает из стека два слова, помещая слова из меньшего адреса в регистр IP, а слово из большего адреса – в регистр CS. Команда RET может иметь операнд, который представляет собой значение, прибавляемое микропроцессором к содержимому указателя стека SP после извлечения адреса возврата (очистка стека).

 

Команда микропроцессора — это команда, которая выполняет требуемое действие над данными или изменяет внутреннее состояние процессора.

Существует две основные архитектуры процессоров. Первая называется RISC (Reduced Instruction Set Computer) — компьютер с уменьшенным набором команд. Архитектура RISC названа в честь первого компьютера с уменьшенным набором команд — RISC I. Идея этой архитектуры основывается на том, что процессор большую часть времени тратит на выполнение ограниченного числа инструкций (например, переходов или команд присваивания), а остальные команды используются редко.

Разработчики RISC-архитектуры создали «облегченный» процессор. Благодаря упрошенной внутренней логике (меньшему числу команд, менее сложным логическим контурам), значительно сократилось время выполнения отдельных команд и увеличилась общая производительность. Архитектура RISC подобна «архитектуре общения» с собакой — она знает всего несколько команд, но выполняет их очень быстро.

Вторая архитектура имеет сложную систему команд, она называется CISC (Complex Instruction Set Computer) — компьютер со сложной системой команд. Архитектура CISC подразумевает использование сложных инструкций, которые можно разделить на более простые. Все х86-совместимые процессоры принадлежат к архитектуре CISC.

Давайте рассмотрим команду «загрузить число 0x1234 в регистр АХ». На языке ассемблера она записывается очень просто — MOV АХ, 0x1234. К настоящему моменту вы уже знаете, что каждая команда представляется в виде двоичного числа (пункт 7 концепции фон Неймана). Ее числовое представление называется машинным кодом. Команда MOV АХ, 0x1234 на машинном языке может быть записана так:

 

0x11хх: предыдущая команда

0х1111:0хВ8, 0x34, 0x12

0x1114: следующие команды

 

Мы поместили команду по адресу 0x1111. Следующая команда начинается тремя байтами дальше, значит, под команду с операндами отведено 3 байта. Второй и третий байты содержат операнды команды MOV. А что такое 0хВ8? После преобразования 0хВ8 в двоичную систему мы получим значение 10111000b.

Первая часть — 1011 — и есть код команды MOV. Встретив код 1011, контроллер «понимает», что перед ним — именно MOV. Следующий разряд (1) означает, что операнды будут 16-разрядными. Три последние цифры определяют регистр назначения. Три нуля соответствуют регистру АХ (или AL, если предыдущий бит был равен О, указывая таким образом, что операнды будут 8-разрядными).

Чтобы декодировать команды, контроллер должен сначала прочитать их из памяти. Предположим, что процессор только что закончил выполнять предшествующую команду, и IP (указатель команд) содержит значение 0x1111. Прежде чем приступить к обработке следующей команды, процессор «посмотрит » на шину управления, чтобы проверить, требуются ли аппаратные прерывания.

Если запроса на прерывание не поступало, то процессор загружает значение, сохраненное по адресу 0x1111 (в нашем случае — это 0хВ8), в свой внутренний (командный) регистр. Он декодирует это значение так, как показано выше, и «понимает», что нужно загрузить в регистр АХ 16-разрядное число —- два следующих байта, находящиеся по адресам 0x1112 и 0x1113 (они содержат наше число, 0x1234). Теперь процессор должен получить из памяти эти два байта. Для этого процессор посылает соответствующие команды в шину и ожидает возвращения по шине данных значения из памяти.

Получив эти два байта, процессор запишет их в регистр АХ. Затем процессор увеличит значение в регистре IP на 3 (наша команда занимает 3 байта), снова проверит наличие запросов на прерывание и, если таких нет, загрузит один байт по адресу 0x1114 и продолжит выполнять программу.

Если запрос на прерывание поступил, процессор проверит его тип, а также значение флага IF. Если флаг сброшен (0), процессор проигнорирует прерывание; если же флаг установлен (1), то процессор сохранит текущий контекст и начнет выполнять первую инструкцию обработчика прерывания, загрузив ее из таблицы векторов прерываний.

К счастью, нам не придется записывать команды в машинном коде, поскольку ассемблер разрешает использо

 

Мы уже знаем, что адрес, как и сама команда, — это число. Чтобы не запоминать адреса всех «переменных», используемых в программе, этим адресам присваивают символические обозначения, которые называются переменными (иногда их также называют указателями).

При использовании косвенного операнда адрес в памяти, по которому находится нужное значение, записывается в квадратных скобках: [адрес]. Если мы используем указатель, то есть символическое представление адреса, например, [ESI], то в листинге машинного кода мы увидим, что указатель был заменен реальным значением адреса. Можно также указать точный адрес памяти, например, [0x594F].

Чаще всего мы будем адресовать память по значению адреса, занесенному в регистр процессора. Чтобы записать такой косвенный операнд, нужно просто написать имя регистра в квадратных скобках. Например, если адрес загружен в регистр ESI, вы можете получить данные, расположенные по этому адресу, используя выражение [ESI].

Теперь рассмотрим фрагмент программы, в которой регистр ESI содержит адрес первого элемента (нумерация начинается с 0) в массиве байтов. Как получить доступ, например, ко второму элементу (элементу, адрес которого на 1 байт больше) массива? Процессор поддерживает сложные способы адресации, которые очень нам пригодятся в дальнейшем. В нашем случае, чтобы получить доступ ко второму элементу массива, нужно записать косвенный операнд [ESI + 1].

Имеются даже более сложные типы адресации: [адрес + ЕВХ + 4]. В этом случае процессор складывает адрес, значение 4 и значение, содержащееся в регистре ЕВХ. Результат этого выражения называется эффективным адресом (ЕА, Effective Address) и используется в качестве адреса, по которому фактически находится операнд (мы пока не рассматриваем сегментные регистры). При вычислении эффективного адреса процессор 80386 также позволяет умножать один член выражения на константу, являющуюся степенью двойки: [адрес + ЕВХ * 4]. Корректным считается даже следующее «сумасшедшее» выражение:

 

[число — б + ЕВХ * 8 + ESI]

 

На практике мы будем довольствоваться только одним регистром [ESI] или суммой регистра и константы, например, [ESI + 4]. В зависимости от режима процессора, мы можем использовать любой 16-разрядный или 32-разрядный регистр общего назначения [ЕАХ], [ЕВХ],… [ЕВР].

Процессор предыдущего поколения 80286 позволял записывать адрес в виде суммы содержимого регистра и константы только для регистров ВР, SI, DI, и ВХ.

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

 

ES:[ESI]

 

Некоторые ассемблеры требуют указания регистра внутри скобок:

 

[ES:ESI]

 

В наших примерах мы будем считать, что все сегментные регистры содержат одно и то же значение, поэтому мы не будем использовать их при адресации.

Тебе нравиться язык ассемблера? илиу тебя есть полезные советы и дополнения? Напиши другим читателям ниже. Надеюсь, что теперь ты понял что такое язык ассемблера
и для чего все это нужно, а если не понял, или есть замечания,
то нестесняся пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории
Языки и методы программирования. Теория трансляции

Язык ассемблера

Язык программирования низкого уровня

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

Код сборки преобразуется в исполняемый машинный код с помощью служебная программа упоминается как ассемблер. Процесс преобразования называется сборка, как в сборка то исходный код. В языке ассемблера обычно есть один оператор на машинную инструкцию (1: 1), но Комментарии и операторы ассемблера директивы,[5]макросы,[6][1] и символический этикетки программы и места в памяти часто также поддерживаются.

Термин «ассемблер» обычно относят к Уилкс, Уиллер и Gill в своей книге 1951 года Подготовка программ для ЭЦП.,[7] которые, однако, использовали этот термин для обозначения «программы, которая собирает другую программу, состоящую из нескольких разделов, в единую программу».[8]

Каждый язык ассемблера специфичен для определенного компьютерная архитектура а иногда и Операционная система.[9] Однако некоторые языки ассемблера не предоставляют конкретных синтаксис для вызовов операционной системы, и большинство языков ассемблера могут универсально использоваться с любой операционной системой, поскольку язык обеспечивает доступ ко всем реальным возможностям процессор, на котором все системный вызов механизмы в конечном итоге отдыхают. В отличие от языков ассемблера, большинство языки программирования высокого уровня обычно портативный через несколько архитектур, но требует устный перевод или же составление, задача гораздо более сложная, чем сборка.

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

Синтаксис языка ассемблера

В языке ассемблера используется мнемонический представлять каждый нижний уровень машинная инструкция или же код операции, обычно также каждый архитектурный регистр, флаги т. д. Многие операции требуют одного или нескольких операнды чтобы сформировать полную инструкцию. Большинство ассемблеров допускают именованные константы, регистры и этикетки для программ и ячеек памяти, и может вычислить выражения для операндов. Таким образом, программисты освобождаются от утомительных повторяющихся вычислений, а программы на ассемблере гораздо более читабельны, чем машинный код. В зависимости от архитектуры эти элементы также могут быть объединены для конкретных инструкций или режимы адресации с помощью смещения или другие данные, а также фиксированные адреса. Многие ассемблеры предлагают дополнительные механизмы для облегчения разработки программ, управления процессом сборки и помощи отладка.

Терминология

  • А макроассемблер включает макрокоманда возможность, чтобы (параметризованный) текст на языке ассемблера мог быть представлен именем, и это имя можно было использовать для вставки расширенного текста в другой код.
  • А кросс-ассемблер (смотрите также кросс-компилятор) — это ассемблер, запускаемый на компьютере или Операционная система (в хозяин system) другого типа, нежели система, в которой должен выполняться полученный код ( целевая система). Кросс-сборка облегчает разработку программ для систем, не имеющих ресурсов для поддержки разработки программного обеспечения, таких как Встроенная система или микроконтроллер. В таком случае результирующий объектный код должны быть переданы в целевую систему через только для чтения памяти (ПЗУ, EPROMи др.), программист (когда постоянная память интегрирована в устройство, как в микроконтроллерах), или канал передачи данных, использующий либо точную побитовую копию объектного кода, либо текстовое представление этого кода (например, Intel шестнадцатеричный или же Motorola S-рекорд).
  • А ассемблер высокого уровня — это программа, которая предоставляет языковые абстракции, чаще связанные с языками высокого уровня, такие как расширенные управляющие структуры (ЕСЛИ / ТО / ИНАЧЕ, DO CASE и т. Д.) И абстрактные типы данных высокого уровня, включая структуры / записи, объединения, классы и множества.
  • А микросборщик это программа, которая помогает подготовить микропрограмма, называется прошивка, для управления низкоуровневой работой компьютера.
  • А мета-ассемблер это «программа, которая принимает синтаксическое и семантическое описание языка ассемблера и генерирует ассемблер для этого языка».[10] Ассемблеры «Meta-Symbol» для SDS 9 серии и SDS Sigma серии компьютеров являются мета-ассемблерами.[11][nb 1]Сперри Юнивак также предоставил мета-ассемблер для UNIVAC серии 1100/2200.[12]
  • встроенный ассемблер (или же встроенный ассемблер) — это код ассемблера, содержащийся в программе на языке высокого уровня.[13] Это чаще всего используется в системных программах, которым требуется прямой доступ к оборудованию.

Ключевые идеи

Ассемблер

An ассемблер программа создает объектный код к Идет перевод комбинации мнемоники и синтаксис для операций и режимов адресации в их числовые эквиваленты. Это представление обычно включает код операции («код операции»), а также другие элементы управления биты и данные. Ассемблер также вычисляет константные выражения и разрешает символические имена для ячеек памяти и других объектов.[14] Использование символических ссылок — ключевая особенность ассемблеров, позволяющая избежать утомительных вычислений и обновления адресов вручную после модификации программы. Большинство ассемблеров также включают макрос средства для выполнения текстовой замены — например, для генерации общих коротких последовательностей инструкций как в соответствии, вместо называется подпрограммы.

Некоторые ассемблеры также могут выполнять некоторые простые типы Набор инструкций-специфический оптимизации. Одним из конкретных примеров этого может быть повсеместная x86 монтажники от различных производителей. Называется размер скачка,[14] большинство из них могут выполнять замену инструкций перехода (длинные переходы заменяются короткими или относительными переходами) за любое количество проходов по запросу. Другие могут даже выполнять простую перестановку или вставку инструкций, например, некоторые ассемблеры для RISC архитектуры что может помочь оптимизировать разумный планирование инструкций использовать Конвейер процессора максимально эффективно.[нужна цитата]

Ассемблеры были доступны с 1950-х годов как первый шаг по сравнению с машинным языком и до языки программирования высокого уровня Такие как Фортран, Алгол, Кобол и Лисп. Так же было несколько классов переводчиков и полуавтоматических генераторы кода со свойствами, аналогичными языкам ассемблера и языков высокого уровня, с Speedcode как, возможно, один из наиболее известных примеров.

Сборщиков может быть несколько с разными синтаксис для конкретного ЦПУ или же архитектура набора команд. Например, инструкция по добавлению данных из памяти в регистр в x86-семейный процессор может быть добавить eax, [ebx], в оригинале Синтаксис Intel, тогда как это будет написано addl (% ebx),% eax в Синтаксис AT&T используется Ассемблер GNU. Несмотря на разный внешний вид, разные синтаксические формы обычно генерируют одни и те же числовые Машинный код. У одного ассемблера также могут быть разные режимы для поддержки вариаций синтаксических форм, а также их точных семантических интерпретаций (например, FASM-синтаксис, ТАСМ-синтаксис, идеальный режим и т. д., в частном случае сборка x86 программирование).

Количество проходов

Есть два типа ассемблеров в зависимости от того, сколько проходов через исходный код необходимо (сколько раз ассемблер читает исходный код) для создания объектного файла.

  • Сборщики за один проход пройтись по исходному коду один раз. Для любого символа, использованного до его определения, потребуется «опечатка» в конце объектного кода (или, по крайней мере, не ранее точки, где определен символ), сообщая компоновщик или загрузчик, чтобы «вернуться» и перезаписать местозаполнитель, который был оставлен там, где использовался еще не определенный символ.
  • Многопроходные сборщики создайте таблицу со всеми символами и их значениями на первых проходах, а затем используйте таблицу в последующих проходах для генерации кода.

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

Первоначальной причиной использования однопроходных ассемблеров был размер памяти и скорость сборки — часто второй проход требовал сохранения таблицы символов в памяти (для обработки пересылка ссылок), перематывая и перечитывая исходник программы на Лента, или перечитывая колоду открытки или же перфорированная бумажная лента. В более поздних компьютерах с гораздо большей памятью (особенно на дисках) было достаточно места для выполнения всей необходимой обработки без повторного чтения. Преимущество многопроходного ассемблера заключается в том, что отсутствие ошибок делает процесс связывания (или загрузка программы если ассемблер напрямую создает исполняемый код) быстрее.[15]

Пример: в следующем фрагменте кода однопроходный ассемблер сможет определить адрес обратной ссылки BKWD при сборке заявления S2, но не сможет определить адрес прямой ссылки ВПЕРЕД при сборке оператора ветки S1; в самом деле, ВПЕРЕД может быть неопределенным. Двухпроходный ассемблер определит оба адреса на проходе 1, поэтому они будут известны при генерации кода на проходе 2.

S1   B ВПЕРЕД  ...ВПЕРЕД   EQU * ...BKWD  EQU * ...S2    B BKWD
Сборщики высокого уровня

Более сложный ассемблеры высокого уровня предоставить языковые абстракции, такие как:

  • Объявления и вызовы процедур / функций высокого уровня
  • Расширенные структуры управления (IF / THEN / ELSE, SWITCH)
  • Абстрактные типы данных высокого уровня, включая структуры / записи, объединения, классы и множества.
  • Сложная обработка макросов (хотя доступна на обычных ассемблерах с конца 1950-х годов, например, для IBM 700 серии и IBM 7000 серии, а с 1960-х годов для IBM System / 360 (S / 360), среди других машин)
  • Объектно-ориентированного программирования такие функции, как классы, объекты, абстракция, полиморфизм, и наследование[16]

Видеть Языковой дизайн ниже для более подробной информации.

язык ассемблера

Программа, написанная на языке ассемблера, состоит из ряда мнемонический инструкции процессора и мета-утверждения (известные также как директивы, псевдо-инструкции и псевдооперации), комментарии и данные. Инструкции на языке ассемблера обычно состоят из код операции мнемоника, за которой следует список данных, аргументов или параметров.[17] Они переведены ассемблер в машинный язык инструкции, которые можно загрузить в память и выполнить.

Например, инструкция ниже сообщает x86/IA-32 процессор для перемещения немедленное 8-битное значение в регистр. Двоичный код этой инструкции — 10110, за которым следует 3-битный идентификатор регистра, который следует использовать. Идентификатор для AL регистр 000, поэтому следующие Машинный код загружает AL зарегистрируйтесь с данными 01100001.[17]

10110000 01100001

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

B0 61

Здесь, B0 означает «Переместить копию следующего значения в AL, и 61 является шестнадцатеричным представлением значения 01100001, что составляет 97 в десятичный. Ассемблер для семейства 8086 обеспечивает мнемонический MOV (сокращение от двигаться) для таких инструкций, поэтому приведенный выше машинный код может быть написан на языке ассемблера следующим образом, с пояснительным комментарием, если требуется, после точки с запятой. Это намного легче читать и запоминать.

MOV AL, 61ч       ; Загрузить AL с 97 десятичным (61 шестнадцатеричным)

В некоторых языках ассемблера (включая этот) одна и та же мнемоника, такая как MOV, может использоваться для семейства связанных инструкций для загрузки, копирования и перемещения данных, будь то непосредственные значения, значения в регистрах или ячейки памяти, на которые указывает значения в регистрах или по непосредственным (a / k / a прямым) адресам. Другие ассемблеры могут использовать отдельные мнемоники кода операции, такие как L для «перемещения памяти в регистр», ST для «перемещения регистра в память», LR для «перемещения регистра в регистр», MVI для «немедленного перемещения операнда в память» и т. Д.

Если одна и та же мнемоника используется для разных инструкций, это означает, что мнемоника соответствует нескольким различным двоичным кодам инструкций, исключая данные (например, 61ч в этом примере), в зависимости от операндов, следующих за мнемоникой. Например, для процессоров x86 / IA-32 синтаксис языка ассемблера Intel MOV AL, AH представляет собой инструкцию, которая перемещает содержимое регистра AH в регистр AL. В[nb 2] шестнадцатеричная форма этой инструкции:

88 E0

Первый байт, 88h, определяет перемещение между регистром байтового размера и другим регистром или памятью, а второй байт, E0h, кодируется (с тремя битовыми полями), чтобы указать, что оба операнда являются регистрами, источником является AH, а пункт назначения AL.

В таком случае, когда одна и та же мнемоника может представлять более одной двоичной инструкции, ассемблер определяет, какую команду генерировать, проверяя операнды. В первом примере операнд 61ч является допустимой шестнадцатеричной числовой константой и недопустимым именем регистра, поэтому только B0 инструкция может быть применима. Во втором примере операнд AH является допустимым именем регистра, а не допустимой числовой константой (шестнадцатеричной, десятичной, восьмеричной или двоичной), поэтому только 88 инструкция может быть применима.

Языки ассемблера всегда разрабатываются таким образом, что такая однозначность повсеместно обеспечивается их синтаксисом. Например, в ассемблере Intel x86 шестнадцатеричная константа должна начинаться с цифровой цифры, чтобы шестнадцатеричное число ‘A’ (равное десятичной десятке) было записано как 0Ач или же 0AH, нет AH, в частности, чтобы оно не могло быть именем регистра AH. (Это же правило также предотвращает двусмысленность имен регистров BH, CH, и DH, а также с любым пользовательским символом, заканчивающимся буквой ЧАС и в противном случае содержит только символы, которые являются шестнадцатеричными цифрами, например слово «ПЛЯЖ».)

Возвращаясь к исходному примеру, в то время как код операции x86 10110000 (B0) копирует 8-битное значение в AL регистр, 10110001 (B1) перемещает его в CL и 10110010 (Би 2) делает это в DL. Примеры для них на языке ассемблера приведены ниже.[17]

MOV AL, 1 час        ; Загрузить AL с немедленным значением 1MOV CL, 2ч        ; Загрузить CL немедленным значением 2MOV DL, 3ч        ; Загрузить DL немедленным значением 3

Синтаксис MOV также может быть более сложным, как показывают следующие примеры.[18]

MOV EAX, [EBX]	  ; Переместите 4 байта памяти по адресу, содержащемуся в EBX, в EAXMOV [ESI+EAX], CL ; Переместить содержимое CL в байт по адресу ESI + EAXMOV DS, DX        ; Переместить содержимое DX в сегментный регистр DS

В каждом случае мнемоника MOV транслируется ассемблером непосредственно в один из кодов операций 88-8C, 8E, A0-A3, B0-BF, C6 или C7, и программисту обычно не нужно знать или запоминать какой.[17]

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

Каждый компьютерная архитектура имеет собственный машинный язык. Компьютеры различаются количеством и типом поддерживаемых ими операций, разным размером и количеством регистров, а также представлением данных в хранилище. Хотя большинство компьютеров общего назначения могут выполнять в основном одни и те же функции, способы их выполнения различаются; соответствующие языки ассемблера отражают эти различия.

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

Два примера процессоров с двумя разными наборами мнемоник — это семейство Intel 8080 и Intel 8086/8088. Поскольку Intel заявила об авторских правах на свою мнемонику на языке ассемблера (по крайней мере, на каждой странице своей документации, опубликованной в 1970-х и начале 1980-х годов), некоторые компании, которые самостоятельно производили процессоры, совместимые с наборами инструкций Intel, изобрели свои собственные мнемоники. В Зилог Z80 CPU, усовершенствование Intel 8080A, поддерживает все инструкции 8080A и многие другие; Zilog изобрел совершенно новый язык ассемблера не только для новых инструкций, но и для всех инструкций 8080A. Например, если Intel использует мнемонику MOV, МВИ, LDA, STA, LXI, LDAX, STAX, LHLD, и SHLD для различных инструкций по передаче данных язык ассемблера Z80 использует мнемонический LD для всех. Похожий случай — это NEC V20 и V30 Процессоры, улучшенные копии Intel 8086 и 8088 соответственно. Как и Zilog с Z80, NEC изобрела новую мнемонику для всех инструкций 8086 и 8088, чтобы избежать обвинений в нарушении авторских прав Intel. (Сомнительно, могут ли такие авторские права быть действительными, и более поздние производители процессоров, такие как AMD[№ 3] и Cyrix переиздал мнемонику инструкций Intel x86 / IA-32 без разрешения и без штрафных санкций.) Сомнительно, что на практике многие люди, которые программировали V20 и V30, действительно писали на ассемблере NEC, а не на языке Intel; поскольку любые два языка ассемблера для одной и той же архитектуры набора инструкций изоморфны (наподобие английского и Pig Latin), нет необходимости использовать собственный опубликованный язык ассемблера производителя с продуктами этого производителя.

Языковой дизайн

Основные элементы

Авторы ассемблеров сильно различаются в способах категоризации операторов и в используемой ими номенклатуре. В частности, некоторые описывают что-либо, кроме машинной мнемоники или расширенной мнемоники, как псевдооперацию (псевдооперацию). Типичный язык ассемблера состоит из 3 типов инструкций, которые используются для определения программных операций:

Мнемоника опкодов и расширенная мнемоника

Инструкции (инструкции) на языке ассемблера, как правило, очень просты, в отличие от инструкций в языки высокого уровня. Как правило, мнемоника — это символическое имя для одной исполняемой инструкции машинного языка ( код операции), и для каждой инструкции машинного языка определен как минимум один мнемонический код операции. Каждая инструкция обычно состоит из операция или же код операции плюс ноль или больше операнды. Большинство инструкций относятся к одному значению или к паре значений. Операнды могут быть непосредственными (значение, закодированное в самой инструкции), регистрами, указанными в инструкции или подразумеваемыми, или адресами данных, расположенными в другом месте в хранилище. Это определяется базовой архитектурой процессора: ассемблер просто отражает, как эта архитектура работает. Расширенная мнемоника часто используются для указания комбинации кода операции с конкретным операндом, например, ассемблеры System / 360 используют B как расширенная мнемоника для до н.э с маской 15 и NOP («NO OPeration» — ничего не делать за один шаг) для до н.э с маской 0.

Расширенная мнемоника часто используются для поддержки специального использования инструкций, часто для целей, не очевидных из названия инструкции. Например, у многих ЦП нет явной инструкции NOP, но есть инструкции, которые можно использовать для этой цели. В процессорах 8086 инструкция xchg топор,топор используется для нет, с нет псевдо-код операции для кодирования инструкции xchg топор,топор. Некоторые дизассемблеры распознают это и расшифруют xchg топор,топор инструкция как нет. Аналогичным образом ассемблеры IBM для Система / 360 и Система / 370 использовать расширенную мнемонику NOP и НЕТ ПР за до н.э и BCR с нулевыми масками. Для архитектуры SPARC они известны как синтетические инструкции.[19]

Некоторые ассемблеры также поддерживают простые встроенные макрокоманды, которые генерируют две или более машинных инструкции. Например, у некоторых ассемблеров Z80 инструкция ld hl, bc признано генерировать ld l, c с последующим ld h, b.[20] Иногда их называют псевдо-коды операций.

Мнемоника — это произвольные символы; в 1985 г. IEEE опубликовал Стандарт 694 для унифицированного набора мнемоник, который будет использоваться всеми ассемблерами. С тех пор стандарт был отменен.

Директивы данных

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

Директивы сборки

Директивы сборки, также называемые псевдоопкодами, псевдооперациями или псевдооперациями, представляют собой команды, данные ассемблеру, «предписывающие ему выполнять операции, отличные от инструкций сборки».[14] Директивы влияют на то, как работает ассемблер, и «могут влиять на объектный код, таблицу символов, файл листинга и значения внутренних параметров ассемблера». Иногда термин псевдо-код операции зарезервирован для директив, генерирующих объектный код, например тех, которые генерируют данные.[21]

Имена псевдоопераций часто начинаются с точки, чтобы отличить их от машинных инструкций. Псевдооперации могут сделать сборку программы зависимой от параметров, вводимых программистом, так что одна программа может быть собрана разными способами, возможно, для разных приложений. Или псевдооперация может использоваться для управления представлением программы, чтобы ее было легче читать и поддерживать. Другое распространенное использование псевдоопераций — резервирование областей хранения для данных времени выполнения и, при необходимости, инициализация их содержимого известными значениями.

Символьные ассемблеры позволяют программистам ассоциировать произвольные имена (этикетки или же символы) с ячейками памяти и различными константами. Обычно каждой константе и переменной дается имя, поэтому инструкции могут ссылаться на эти местоположения по имени, тем самым продвигая самодокументирующийся код. В исполняемом коде имя каждой подпрограммы связано с ее точкой входа, поэтому любые вызовы подпрограммы могут использовать ее имя. Внутри подпрограмм, ИДТИ К адресатам присвоены ярлыки. Некоторые ассемблеры поддерживают местные символы которые часто лексически отличаются от обычных символов (например, использование «10 $» в качестве пункта назначения GOTO).

Некоторые ассемблеры, такие как NASM, обеспечивают гибкое управление символами, позволяя программистам управлять различными пространства имен, автоматически рассчитать смещения в пределах структуры данных, и присвоить метки, которые относятся к буквальным значениям или результату простых вычислений, выполненных ассемблером. Метки также можно использовать для инициализации констант и переменных с перемещаемыми адресами.

Языки ассемблера, как и большинство других компьютерных языков, позволяют добавлять комментарии к программе. исходный код это будет проигнорировано во время сборки.Разумное комментирование важно в программах на ассемблере, поскольку значение и цель последовательности двоичных машинных инструкций может быть трудно определить. «Необработанный» (раскомментированный) язык ассемблера, созданный компиляторами или дизассемблерами, довольно трудно читать, когда необходимо внести изменения.

Макросы

Многие ассемблеры поддерживают предопределенные макросы, и другие поддерживают определяется программистом (и многократно переопределяемые) макросы, включающие последовательности текстовых строк, в которые встроены переменные и константы. Определение макроса чаще всего[№ 4] смесь операторов ассемблера, например директив, символических машинных инструкций и шаблонов для операторов ассемблера. Эта последовательность текстовых строк может включать коды операций или директивы. После определения макроса его имя может использоваться вместо мнемоники. Когда ассемблер обрабатывает такой оператор, он заменяет его текстовыми строками, связанными с этим макросом, а затем обрабатывает их, как если бы они существовали в файле исходного кода (включая, в некоторых ассемблерах, раскрытие любых макросов, существующих в тексте замены) . Макросы в этом смысле относятся к IBM автокодеры 1950-х годов.[22][№ 5]

На языке ассемблера термин «макрос» представляет собой более всеобъемлющую концепцию, чем в некоторых других контекстах, таких как препроцессор в Язык программирования C, где его директива #define обычно используется для создания коротких однострочных макросов. Инструкции макроса ассемблера, такие как макросы в PL / I и некоторые другие языки сами по себе могут быть длинными «программами», выполняемыми ассемблером путем интерпретации во время сборки.

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

Макроассемблеры часто позволяют макросам принимать параметры. Некоторые ассемблеры включают в себя довольно сложные макроязыки, включающие такие элементы языка высокого уровня, как необязательные параметры, символьные переменные, условные выражения, манипуляции со строками и арифметические операции, которые можно использовать во время выполнения данного макроса и позволяющие макросам сохранять контекст или обмениваться информацией. . Таким образом, макрос может генерировать множество инструкций на языке ассемблера или определений данных на основе аргументов макроса. Это может быть использовано для создания структур данных в стиле записи или «развернутый»циклы, например, или могут генерировать целые алгоритмы на основе сложных параметров. Например, макрос» sort «может принимать спецификацию сложного ключа сортировки и генерировать код, созданный для этого конкретного ключа, не требуя тестов времени выполнения, которые потребуется для общей процедуры интерпретации спецификации. Организация, использующая язык ассемблера, который был сильно расширен с помощью такого набора макросов, может считаться работающей на языке более высокого уровня, поскольку такие программисты не работают с компьютером самого низкого уровня концептуальные элементы. Подчеркивая этот момент, макросы использовались для реализации первых виртуальная машина в СНОБОЛ4 (1967), который был написан на языке реализации SNOBOL (SIL), ассемблере для виртуальной машины. Целевая машина переведет это в свой собственный код, используя макроассемблер.[23] В то время это обеспечивало высокую степень портативности.

Макросы использовались для настройки крупномасштабных программных систем для конкретных клиентов в эпоху мэйнфреймов, а также использовались персоналом клиентов для удовлетворения потребностей своих работодателей путем создания конкретных версий операционных систем производителя. Это было сделано, например, системными программистами, работающими с IBMсистема мониторинга разговоров / виртуальная машина (ВМ / CMS) и с надстройками IBM для «обработки транзакций в реальном времени», Система управления информацией о клиентах CICS, и ACP/TPFавиакомпания / финансовая система, которая началась в 1970-х и до сих пор управляет многими крупными компьютерные системы бронирования (CRS) и системы кредитных карт сегодня.

Также возможно использовать исключительно возможности обработки макросов ассемблера для генерации кода, написанного на совершенно разных языках, например, для генерации версии программы на КОБОЛ использование программы на чистом макросе на ассемблере, содержащей строки кода COBOL внутри операторов времени ассемблера, инструктирующих ассемблер генерировать произвольный код. IBM OS / 360 использует макросы для выполнения генерация системы. Пользователь указывает параметры, кодируя серию макросов ассемблера. Сборка этих макросов генерирует поток работы построить систему, в том числе язык управления работой и полезность контрольные заявления.

Это связано с тем, что, как было реализовано в 1960-х годах, концепция «обработки макросов» не зависит от концепции «сборки», первая из которых, говоря современным языком, представляет собой больше текстовую обработку, обработку текста, чем создание объектного кода. Концепция обработки макросов появилась и появляется в языке программирования C, который поддерживает «инструкции препроцессора» для установки переменных и выполнения условных тестов на их значениях. В отличие от некоторых предыдущих макропроцессоров внутри ассемблеров, препроцессор C не Полный по Тьюрингу потому что ему не хватает возможности либо зацикливаться, либо «переходить», последний позволяет программам зацикливаться.

Несмотря на мощь обработки макросов, она вышла из употребления во многих языках высокого уровня (за исключением C, C ++ и PL / I), оставаясь неизменным для сборщиков.

Подстановка параметров макроса строго по имени: во время обработки макроса значение параметра текстуально заменяется его именем. Самым известным классом возникающих ошибок было использование параметра, который сам был выражением, а не простым именем, когда писатель макроса ожидал имя. В макросе:

foo: макрос aload a * b

Намерение состояло в том, что вызывающий должен предоставить имя переменной, а «глобальная» переменная или константа b будет использоваться для умножения «a». Если foo вызывается с параметром а-с, макрорасширение загрузить a-c * b происходит. Чтобы избежать возможной двусмысленности, пользователи макропроцессоров могут заключать в скобки формальные параметры внутри определений макросов, или вызывающие программы могут заключать в скобки входные параметры.[24]

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

Написаны пакеты макросов, обеспечивающие структурное программирование элементы для кодирования потока выполнения. Самый ранний пример этого подхода был в Набор макросов Concept-14,[25] первоначально предложенный Харлан Миллс (Март 1970 г.) и реализован Марвином Кесслером из подразделения IBM Federal Systems, которое предоставило IF / ELSE / ENDIF и аналогичные блоки потока управления для программ ассемблера OS / 360. Это был способ уменьшить или исключить использование ИДТИ К операций в ассемблерном коде, что является одним из основных факторов, вызывающих код спагетти на языке ассемблера. Этот подход был широко принят в начале 1980-х (последние дни широкомасштабного использования языка ассемблера).

Любопытный дизайн был Натуральный, «поточно-ориентированный» ассемблер для 8080 /Z80, процессоры[нужна цитата] из Whitesmiths Ltd. (разработчики Unix-подобно Идрис операционной системы, и то, что, как сообщалось, было первым коммерческим C компилятор). Язык был классифицирован как ассемблер, потому что он работал с необработанными машинными элементами, такими как коды операций, регистры, и ссылки на память; но он включал синтаксис выражения, чтобы указать порядок выполнения. Скобки и другие специальные символы, наряду с конструкциями блочно-ориентированного структурного программирования, управляют последовательностью генерируемых инструкций. A-natural был создан как объектный язык компилятора C, а не для ручного кодирования, но его логический синтаксис завоевал некоторых поклонников.

После упадка крупномасштабной разработки языков ассемблера очевидного спроса на более сложные ассемблеры не было.[26] Несмотря на это, они все еще разрабатываются и применяются в случаях, когда ограничения ресурсов или особенности в архитектуре целевой системы препятствуют эффективному использованию языков более высокого уровня.[27]

Ассемблеры с мощным механизмом макросов позволяют структурированное программирование с помощью макросов, таких как макрос переключателя, поставляемый с пакетом Masm32 (этот код представляет собой полную программу):

включают masm32включаютmasm32rt.inc	; использовать библиотеку Masm32.коддемомен:  ПОВТОРЕНИЕ 20	выключатель rv(случайный, 9)	; создать число от 0 до 8	mov ecx, 7	дело 0		Распечатать "дело 0"	дело ecx				; в отличие от большинства других языков программирования,		Распечатать "дело 7"		; переключатель Masm32 допускает "переменные случаи"	дело 1 .. 3		.если eax==1			Распечатать "Случай 1"		.elseif eax==2			Распечатать "случай 2"		.еще			Распечатать «случаи с 1 по 3: другое»		.endif	дело 4, 6, 8		Распечатать "корпуса 4, 6 или 8"	дефолт		mov ebx, 19		     ; распечатать 20 звезд		.Повторение			Распечатать "*"			декабрь ebx		.До того как Sign?		 ; цикл, пока не будет установлен флаг знака	конец	Распечатать chr $(13, 10)  ENDM  выходконец демомен

Использование языка ассемблера

Историческая перспектива

Языки ассемблера не были доступны в то время, когда компьютер с хранимой программой был представлен. Кэтлин Бут «приписывают изобретение языка ассемблера»[28][29] на основе теоретической работы она начала в 1947 году, работая над ARC2 в Биркбек, Лондонский университет после консультации с Эндрю Бут (позже ее муж) с математиком Джон фон Нейман и физик Герман Голдстайн на Институт перспективных исследований.[29][30]

В конце 1948 г. Электронный автоматический калькулятор запоминания задержки (EDSAC) имел ассемблер (названный «начальные заказы»), интегрированный в его бутстрап программа. В нем использовалась однобуквенная мнемоника, разработанная Дэвид Уиллер, который признан компьютерным сообществом IEEE создателем первого «ассемблера».[14][31][32] В отчетах об EDSAC введен термин «сборка» для процесса объединения полей в командное слово.[33] МЫЛО (Символьная оптимальная программа сборки) был языком ассемблера для IBM 650 компьютер, написанный Стэном Поли в 1955 году.[34]

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

Когда-то языки ассемблера широко использовались для всех видов программирования. Однако к 1980-м годам (1990-е годы по микрокомпьютеры), их использование было в значительной степени вытеснено языками более высокого уровня в поисках улучшенных продуктивность программирования. Сегодня ассемблер по-прежнему используется для прямого управления оборудованием, доступа к специализированным инструкциям процессора или для решения критических проблем с производительностью. Типичное использование: драйверы устройств, низкий уровень встроенные системы, и в реальном времени системы.

Исторически многие программы были написаны полностью на ассемблере. В Берроуз MCP (1961 г.) был первым компьютером, для которого операционная система не была полностью разработана на языке ассемблера; это было написано в Проблемно-ориентированный язык исполнительных систем (ESPOL), диалект Алгола. Многие коммерческие приложения также были написаны на языке ассемблера, в том числе большое количество Мэйнфрейм IBM программное обеспечение, написанное крупными корпорациями. КОБОЛ, FORTRAN и некоторые PL / I в конечном итоге вытеснили большую часть этой работы, хотя ряд крупных организаций сохраняли инфраструктуры приложений на ассемблере и в 1990-е годы.

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

В более коммерческом контексте основными причинами использования языка ассемблера были минимальный раздут (размер), минимальные накладные расходы, большая скорость и надежность.

Типичными примерами больших программ на ассемблере того времени являются IBM PC. ДОС операционные системы, Турбо Паскаль компилятор и ранние приложения, такие как электронная таблица программа Лотос 1-2-3. Язык ассемблера использовался для обеспечения максимальной производительности Sega Saturn, консоль, для которой было очень сложно разрабатывать и программировать игры.[35] Аркадная игра 1993 года NBA Jam другой пример.

Ассемблер долгое время был основным языком разработки для многих популярных домашних компьютеров 1980-х и 1990-х годов (таких как MSX, Sinclair ZX Spectrum, Коммодор 64, Коммодор Амига, и Atari ST). Это было во многом потому, что интерпретированный Диалекты BASIC в этих системах предлагали недостаточную скорость выполнения, а также недостаточные возможности для использования всех преимуществ доступного оборудования в этих системах. В некоторых системах даже есть интегрированная среда развития (IDE) с расширенными возможностями отладки и макросов. Некоторые компиляторы, доступные для Radio Shack TRS-80 и его преемники имели возможность комбинировать встроенный исходный код ассемблера с программными операторами высокого уровня. После компиляции встроенный ассемблер произвел встроенный машинный код.

Текущее использование

Всегда есть[36] Были споры о полезности и производительности языка ассемблера по сравнению с языками высокого уровня.

Хотя язык ассемблера имеет специфические ниши, где это важно (см. Ниже), есть и другие инструменты для оптимизации.[37]

По состоянию на июль 2017 г.[Обновить], то Индекс TIOBE по популярности языков программирования ассемблер занимает 11 место, опережая Visual Basic, Например.[38] Ассемблер можно использовать для оптимизации по скорости или для оптимизации по размеру. В случае оптимизации скорости современные оптимизация компиляторов заявлены[39] чтобы преобразовать языки высокого уровня в код, который может работать так же быстро, как рукописная сборка, несмотря на контрпримеры, которые можно найти.[40][41][42] Сложность современных процессоров и подсистем памяти затрудняет эффективную оптимизацию как для компиляторов, так и для программистов на ассемблере.[43][44] Более того, повышение производительности процессора привело к тому, что большинство процессоров большую часть времени простаивают,[45] с задержками, вызванными предсказуемыми узкими местами, такими как промахи кеша, Ввод / вывод операции и пейджинг. Это сделало скорость выполнения исходного кода не проблемой для многих программистов.

Есть несколько ситуаций, в которых разработчики могут использовать ассемблер:

  • Написание кода для систем со старыми процессорами, которые имеют ограниченные языковые возможности высокого уровня, такие как Atari 2600, Коммодор 64, и графические калькуляторы.[46]
  • Код, который должен напрямую взаимодействовать с оборудованием, например, в драйверы устройств и обработчики прерываний.
  • Во встроенном процессоре или DSP прерывания с большим числом повторений требуют наименьшего количества циклов на прерывание, например прерывание, которое происходит 1000 или 10000 раз в секунду.
  • Программы, которым необходимо использовать специфические для процессора инструкции, не реализованные в компиляторе. Типичным примером является побитовое вращение инструкция, лежащая в основе многих алгоритмов шифрования, а также запрос четности байта или 4-битного переноса добавления.
  • Требуется автономный исполняемый файл компактного размера, который должен выполняться без обращения к время выполнения компоненты или библиотеки ассоциируется с языком высокого уровня. Примеры включают прошивку для телефонов, автомобильных топливных систем и систем зажигания, систем управления кондиционированием воздуха, систем безопасности и датчиков.
  • Программы с внутренними циклами, зависящими от производительности, в которых язык ассемблера предоставляет возможности оптимизации, которые трудно реализовать на языке высокого уровня. Например, линейная алгебра с BLAS[40][47] или же дискретное косинусное преобразование (например. SIMD версия сборки от x264[48]).
  • Программы, которые создают векторизованные функции для программ на языках более высокого уровня, таких как C. На языке более высокого уровня этому иногда помогает компилятор. внутренние функции которые отображаются непосредственно в мнемонику SIMD, но тем не менее приводят к преобразованию сборки один к одному, специфичному для данного векторного процессора.
  • В реальном времени такие программы, как моделирование, системы навигации и медицинское оборудование. Например, в по проводам системы, телеметрия должна интерпретироваться и действовать в строгие сроки. Такие системы должны устранять источники непредсказуемых задержек, которые могут быть созданы (некоторыми) интерпретируемыми языками, автоматически вывоз мусора, операции подкачки или вытесняющая многозадачность. Однако некоторые языки более высокого уровня включают компоненты времени выполнения и интерфейсы операционной системы, которые могут вызывать такие задержки. Выбор сборки или языки нижнего уровня для таких систем дает программистам большую наглядность и контроль над деталями обработки.
  • Криптографические алгоритмы, которые всегда должны выполняться строго в одно и то же время, предотвращая время атаки.
  • Изменяйте и расширяйте унаследованный код, написанный для мэйнфреймов IBM.[49][50]
  • Ситуации, когда требуется полный контроль над окружающей средой, в ситуациях с чрезвычайно высокой степенью безопасности, когда ничего нельзя принимать как должное.
  • Компьютерные вирусы, загрузчики, определенный драйверы устройств, или другие элементы, очень близкие к оборудованию или операционной системе нижнего уровня.
  • Симуляторы с инструкциями для мониторинга, отслеживания и отладка где дополнительные накладные расходы сведены к минимуму.
  • Ситуации, когда не существует языка высокого уровня, на новом или специализированном процессоре, для которого нет кросс-компилятор доступен.
  • Разобрать механизм с целью понять, как это работает и изменение программных файлов, таких как:
    • существующий двоичные файлы которые могут быть или не могут быть изначально написаны на языке высокого уровня, например, при попытке воссоздать программы, исходный код которых недоступен или был утерян, или при взломе защиты от копирования проприетарного программного обеспечения.
    • Видеоигры (также называемый ROM взлом), что возможно несколькими способами. Наиболее широко используемый метод — изменение программного кода на уровне языка ассемблера.

Ассемблер по-прежнему преподается в большинстве Информатика и электроинженерия программы. Хотя сегодня немногие программисты регулярно работают с языком ассемблера в качестве инструмента, основные концепции остаются важными. Такие фундаментальные темы, как двоичная арифметика, выделение памяти, обработка стека, набор символов кодирование прерывать обработка и компилятор Было бы трудно изучить дизайн в деталях без понимания того, как компьютер работает на аппаратном уровне. Поскольку поведение компьютера в основном определяется его набором инструкций, логическим способом изучения таких концепций является изучение языка ассемблера. Большинство современных компьютеров имеют аналогичные наборы команд. Следовательно, изучения единственного языка ассемблера достаточно, чтобы усвоить: I) основные понятия; II) распознавать ситуации, когда использование ассемблера может быть уместным; и III) чтобы увидеть, как эффективный исполняемый код может быть создан из языков высокого уровня.[16]

Типичные области применения

  • Язык ассемблера обычно используется в системе ботинок code, низкоуровневый код, который инициализирует и тестирует оборудование системы перед загрузкой операционной системы и часто хранится в ПЗУ. (BIOS на IBM-совместимом ПК системы и CP / M это пример.)
  • Язык ассемблера часто используется для низкоуровневого кода, например для ядра операционной системы, который не может полагаться на доступность ранее существовавших системных вызовов и действительно должен реализовывать их для конкретной архитектуры процессора, на которой будет работать система.
  • Некоторые компиляторы переводят языки высокого уровня в сборку перед полной компиляцией, что позволяет просматривать код сборки для отладка и в целях оптимизации.
  • Некоторые компиляторы для языков относительно низкого уровня, такие как Паскаль или же C, позволяют программисту встраивать язык ассемблера непосредственно в исходный код (так называемый встроенная сборка). Программы, использующие такие средства, могут затем создавать абстракции, используя разные языки ассемблера на каждой аппаратной платформе. Система портативный код может затем использовать эти зависящие от процессора компоненты через единый интерфейс.
  • Ассемблер полезен в разобрать механизм с целью понять, как это работает. Многие программы распространяются только в виде машинного кода, который легко перевести на язык ассемблера с помощью дизассемблер, но труднее перевести на язык более высокого уровня через декомпилятор. Такие инструменты, как Интерактивный дизассемблер широко использовать разборку для этой цели. Этот метод используется хакерами для взлома коммерческого программного обеспечения, а конкурентами — для создания программного обеспечения с аналогичными результатами от конкурирующих компаний.
  • Язык ассемблера используется для повышения скорости выполнения, особенно в ранних персональных компьютерах с ограниченной вычислительной мощностью и ОЗУ.
  • Ассемблеры могут использоваться для генерации блоков данных без накладных расходов на языке высокого уровня из отформатированного и прокомментированного исходного кода для использования в другом коде. Пол, Матиас Р. (13 мая 2002 г.). «[fd-dev] mkeyb». freedos-dev. В архиве из оригинала на 2018-09-10. Получено 2018-09-10.
  • дальнейшее чтение

    • Бартлетт, Джонатан (2004). Программирование с нуля — введение в программирование с использованием языка ассемблера Linux. Bartlett Publishing. ISBN 0-9752838-4-7. В архиве из оригинала 2020-03-24. Получено 2020-03-24.[4]
    • Бриттон, Роберт (2003). Программирование на языке ассемблера MIPS. Prentice Hall. ISBN 0-13-142044-5.
    • Калингарт, Питер (1979) [1978-11-05]. Написано в Университет Северной Каролины в Чапел-Хилл. Горовиц, Эллис (ред.). Ассемблеры, компиляторы и перевод программ. Серия «Компьютерное программное обеспечение» (1-е изд., 1-е изд.). Потомак, Мэриленд, США: Computer Science Press, Inc. ISBN 0-914894-23-4. ISSN 0888-2088. LCCN 78-21905. Получено 2020-03-20. (2 + xiv + 270 + 6 страниц)
    • Дантеманн, Джефф (2000). Пошаговое описание языка ассемблера. Wiley. ISBN 0-471-37523-3.
    • Канн, Чарльз В. (2015). «Введение в программирование на языке ассемблера MIPS». В архиве из оригинала 2020-03-24. Получено 2020-03-24.
    • Нортон, Питер; Соха, Джон (1986). Книга Питера Нортона по языку ассемблера для IBM PC. Нью-Йорк, США: Брэди Букс.
    • Певец, Майкл (1980). PDP-11. Программирование на языке ассемблера и организация машин. Нью-Йорк, США: Джон Уайли и сыновья.
    • Sweetman, Доминик (1999). См. MIPS Run. Издательство Morgan Kaufmann. ISBN 1-55860-410-3.
    • Уолдрон, Джон (1998). Введение в программирование на языке ассемблера RISC. Эддисон Уэсли. ISBN 0-201-39828-1.
    • Юричев, Денис (2020-03-04) [2013]. «Понимание языка ассемблера (обратный инжиниринг для начинающих)» (PDF). В архиве (PDF) из оригинала 2020-03-24. Получено 2020-03-24.
    • «Книга сообщества ASM». 2009. Архивировано с оригинал на 2013-05-30. Получено 2013-05-30. («Электронная книга, полная полезной информации по ASM, руководств и примеров кода» от сообщества ASM, заархивированная в интернет-архиве.)

    внешняя ссылка

    3.1. Машинный язык и ассемблер

    На своем рабочем уровне микропроцессор реагирует на список операций, называемый машинной программой. На рис. 3.1, а приведено содержимое памяти, являющееся программой на машинном языке. Эта программа начинается с адреса 2000Н с содержимым КОП ОО11 11102 и оканчивается адресом 2006Н с содержимым 0111 01102. Человеку практически невозможно понять программу, представленную в такой форме.

    Программа на машинном языке на рис. 3.1, а становится несколько проще для восприятия, когда она представлена в шестнадцатеричном коде (Н-коде), как показано на рис. 3.1, б. Однако, хотя двоичные данные приведены в шестнадцатеричном коде, эта часть программы всегда рассматривается как заданная на машинном языке и оказывается трудной для понимания.

    В более приемлемой форме записанная на машинном языке она могла бы выглядеть так:

    1. Загрузить двоичное число (1011 0100) в аккумулятор.

    Инвертировать каждый двоичный бит содержимого аккумулятора.

    Поместить результаты   инверсии  в  ячейку памяти данных 2100Н.

    В этой части осуществляется перевод двоичного 8-разрядного числа в его эквивалент в инверсной форме.

    Возникает вопрос: как перейти от этой формы человеческого языка, иногда длинной и сложной, к машинному языку? Ответ состоит в использовании языка простого программирования от самого высокого уровня до машинного, представленного на рис. 3.1. Ассемблер использует слова и фразы, преобразуя их в машинный код микропроцессора.

    Обычно фраза или заданная величина на ассемблере будет соответствовать выражению длиной от одного до трех байт машинного языка. Суть и процедура ассемблирования показаны на рис. 3.2, где, например, вторая команда программы представлена единственной мнемоникой из трех букв СМА (инвертировать содержимое аккумулятора). Сначала три буквы переведены в их эквивалент в коде ASCI , затем три кода AS СI преобразованы в оп­ределенный порядок специальной программой ассемблера, которая выдает код инверсии содержимого аккумулятора на машинном языке, т.е. 0010 11112 в данном случае или 2FH. Мнемоника преобразована в один единственный байт машинного языка.

    Программа на языке ассемблер, записанная человеком, могла бы быть представлена в виде табл. 3.1.

    Число различных команд микропроцессора равно 78 и для них предложено         78 имен команд. Многие базовые команды порождают несколько различных кодов операций, поэтому общее число кодов команд равно 244.

    Запомнить 244 восьмиразрядных двоичных кода очень трудно, и поэтому каждому коду ставится в соответствие мнемоническое название (мнемоника) команды, которое является сокращением от английских слов, описывающих ее действие. Например, IN 25 – input data at accumulator from port 25. На русский язык переводится так – ввести данные в аккумулятор из порта с адресом 25.

    Мнемонический код команд позволяет легче запомнить их функции и значительно упрощает написание программ.

    Такой язык написания программ называется языком ассемблера.

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

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

    При работе микропроцессор реагирует на список команд, называемый машинной программой. На рис. 3.1 показаны программы: а) в двоичном машинном коде; б) в шестнадцатеричном машинном коде.

    Программа на рис. 3.1, а начинается с адреса 2000Н с содержимым КОП 001111100 и оканчивается адресом 2006 с содержимым 01110110. Человеку практически невозможно понять программу, представленную в таком виде. Хотя любая микропроцессорная система будет работать только с такой программой.

    Программа, представленная на рис. 3.1, б, несколько проще для восприятия, так как она представлена в шестнадцатеричном коде, но все равно она трудна для понимания. Обе эти программы написаны на машинном языке.

    А как программа, записанная на машинном языке, могла быть описана человеком?

    1 загрузить двоичное число 10110100 в аккумулятор;

    2 инвертировать каждый дв
    оичный бит содержимого аккумулятора;

    3 поместить результат инверсии в ячейку памяти данных 2100Н;

    4 остановить микропроцессор.

    Здесь осуществляется инвертирование двоичного восьмиразрядного числа.

    Возникает вопрос: как перейти от этой формы человеческого языка, иногда длинной и сложной, к машинному языку.

    Язык ассемблер использует слова и фразы, преобразуя их в машинный код микропроцессора.

    Суть и процедура ассемблирования показаны на рис. 3.2, где вторая команда программы представлена единственной мнемоникой из трех букв CMA – complement accumulator – инвертировать содержимое аккумулятора.

    Ход ассемблирования. Сначала три буквы переведены в их эквивалент в коде АСКИ, затем эти три кода АСКИ преобразованы в определенный порядок специальной программой ассемблера, которая выдает код инверсии содержимого аккумулятора на машинном языке – 2FH.

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

    Программа разделена на 4 поля:

    1 поле метки; используется не всегда;

    2 поле мнемоники, содержит точную мнемонику, установленную разработчиком. Указывает программе ассемблера операцию для выполнения;

    3 поле операнда, содержит информацию о регистрах, данных и адресах, объединенных соответствующей операцией;

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

    Таблица 3.1 Программа на языке ассемблер

    Метка

    Мнемоника

    Операнд

    Комментарий

    MVI

    CMA

    STA

    HLT

    A, B4H

    2100H

    Загрузить в аккумулятор данные, следующие непосредственно: В4

    Инвертировать содержимое аккумулятора

    Разместить содержимое аккумулятора в ячейке памяти с адресом 2100

    Остановить МП

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

    Тогда наиболее полная программа в машинных кодах и на языке ассемблера выглядит так, как показано в табл. 3.2.

    Таблица 3.2

    Адрес,

    Н-код

    Содержимое, Н-код

    Метка

    Мнемоника

    Операнд

    Комментарий

    2000

    2001

    2002

    2003

    2004

    2005

    2006

    3E

    B4

    2F

    32

    00

    21

    76

    MVI

    CMA

    STA

    HLT

    Загрузить аккумулятор данными, следующими непосредственно за КОП, В4Н

    Инвертировать содержимое аккумулятора

    Поместить содержимое аккумулятора в ячейку памяти 2100Н

    Остановить МП

    Состав команд микропроцессора включает следующие группы: 1 операций передачи данных, 2 арифметических действий, 3 логических операций, 4 операций ветвления, 5 вызова подпрограмм и возврата в основную программу, 6 прочих операций.

    РАЗНИЦА МЕЖДУ МАШИННЫМ ЯЗЫКОМ И ЯЗЫКОМ АССЕМБЛЕРА | СРАВНИТЕ РАЗНИЦУ МЕЖДУ ПОХОЖИМИ ТЕРМИНАМИ — ТЕХНОЛОГИЯ

    Языки программирования позволяют людям создавать инструкции для компьютера для выполнения задач. Есть три категории языков программирования, такие как языки программирования высокого уровня, язык ассе

    Ключевое отличие — машина

    Язык против языка ассемблера
     

    Языки программирования позволяют людям создавать инструкции для компьютера для выполнения задач. Есть три категории языков программирования, такие как языки программирования высокого уровня, язык ассемблера и машинный язык. Языки программирования высокого уровня легче понять людям. Язык, распознаваемый компьютером, известен как машинный язык. Ассемблер — это язык между языками высокого уровня и машинным языком. В ключевое отличие между машинным языком и языком ассемблера заключается в том, что, машинный язык выполняется непосредственно компьютером, а язык ассемблера требует, чтобы ассемблер преобразовал в машинный код или объектный код для выполнения центральным процессором.

    1. Обзор и основные отличия
    2. Что такое машинный язык
    3. Что такое язык ассемблера
    4. Сходства между машинным языком и языком ассемблера
    5. Параллельное сравнение — машинный язык и язык ассемблера в табличной форме
    6. Резюме

    Что такое машинный язык?

    Люди могут понимать языки программирования высокого уровня. Для программирования с использованием языков высокого уровня необязательно иметь глубокое понимание внутреннего процессора. Они следуют синтаксису, аналогичному английскому языку. Java, C, C ++, Python — это некоторые языки программирования высокого уровня. Компьютер распознает машинный язык, но не понимает языки высокого уровня. Следовательно, эти программы следует преобразовать на понятный для компьютера машинный язык. Этот перевод выполняется с помощью компилятора или интерпретатора.

    Машинный язык состоит из двоичных цифр, которые являются нулями и единожды. Компьютер — это цифровое электронное устройство, поэтому для операций он использует двоичный код. Один указывает на истинное состояние / состояние включения, а ноль указывает на ложное состояние / состояние выключения. Способ преобразования программы с языка высокого уровня на машинный язык зависит от ЦП.

    Что такое язык ассемблера?

    Ассемблер — это промежуточный язык между языками программирования высокого уровня и машинным языком. Это на один уровень выше машинного языка. Язык ассемблера легче понять, чем машинный, но сложнее, чем языки программирования высокого уровня. Этот язык также известен как язык низкого уровня, потому что он близок к аппаратному уровню. Чтобы писать эффективные программы с использованием ассемблера, программист должен хорошо разбираться в архитектуре компьютера и структуре регистров. Для преобразования инструкций на языке ассемблера в машинный или объектный код используется специальный компилятор, известный как ассемблер.

    Инструкции на языке ассемблера состоят из четырех разделов. Это метка, мнемоника, операнд, комментарий. Ярлык и комментарии не являются обязательными. Мнемоника — это инструкция для выполнения, а операнды — это параметры команды. Язык ассемблера также поддерживает макросы. Макрос можно определить как набор инструкций с именем. Его можно использовать в любом месте программы.

    Ниже приведены некоторые примеры операторов языка ассемблера.

    MOV SUM, 50 — Эта инструкция копирует значение 50 в переменную SUM.

    ADD VALUE1,20 — добавляет 20 к переменной VALUE1.

    ADD AH, BH — Эта инструкция предназначена для копирования содержимого регистра AH в регистр BH.

    INC COUNT — увеличивает значение переменной COUNT на единицу.

    AND VALUE1,100 — для выполнения операции AND над переменными VALUE1 и 100.

    MOV AL, 20 — Это для копирования значения 20 в регистр AL

    Набор операторов Assembly — это программа Assembly. Видно, что язык ассемблера проще, чем машинный. Он имеет синтаксис, аналогичный английскому языку. В языке ассемблера около тридцати инструкций. Требуемая память и время выполнения минимальны по сравнению с языками высокого уровня.

    В системах реального времени могут возникать события, требующие немедленного действия ЦП. Эти события представляют собой специальные подпрограммы, называемые программой обработки прерываний (ISR). Язык ассемблера полезен для программирования ISR.

    В чем сходство между машинным языком и языком ассемблера?

    • И машинный язык, и язык ассемблера связаны с аппаратным уровнем.

    В чем разница между машинным языком и языком ассемблера?

    Машинный язык против языка ассемблера

    Машинный язык — это язык программирования самого низкого уровня, где инструкции выполняются непосредственно ЦП.Язык ассемблера — это язык программирования низкого уровня, для которого требуется, чтобы ассемблер преобразовывал в машинный код / ​​объектный код.
    Понятность
    Машинный язык понятен только компьютерам.Язык ассемблера понятен людям.
    Синтаксис
    Машинный язык состоит из двоичных цифр.Синтаксис языка ассемблера аналогичен синтаксису английского языка.
    Зависимость
    Машинный язык зависит от платформы.Ассемблер состоит из стандартного набора инструкций.
    Приложения
    Машинный язык — это машинный код.Ассемблер используется для микропроцессорных систем реального времени.

    Резюме — машина

    Язык против языка ассемблера

    Разница между машинным языком и языком ассемблера заключается в том, что машинный язык непосредственно выполняется компьютером, а язык ассемблера — это язык программирования низкого уровня, который требует от ассемблера преобразования в объектный код или машинный код. Ассемблер на шаг впереди машинного языка. Язык ассемблера — идеальный язык для программирования систем на базе микроконтроллеров. Этот язык также дает хорошее представление о том, как работает ЦП, и о внутренних компонентах компьютера.

    Скачать PDF-версию машинного языка и языка ассемблера

    Вы можете скачать PDF-версию этой статьи и использовать ее в автономных целях в соответствии с примечанием к цитированию. Загрузите PDF-версию здесь. Разница между машинным языком и языком ассемблера.

    Изображение предоставлено:

    1. «Машинный язык» от Turkei89 — Собственная работа, (CC BY-SA 3.0) через Commons Wikimedia
    2. Сборка zstr count x86 от OldCodger2, (Public Domain) через Commons Wikimedia.

    Что такое язык ассемблера? — ИТ-знания

    Язык ассемблера один язык программирования низкоуровневый, предназначенный для конкретного типа процессора. Мы можем произвести это исходный код из языка программирования высокого уровня (например, C / C ++). Но мы также можем сами писать программы на этом языке. Мы, в свою очередь, можем преобразовать код ассемблера в машинный код с помощью ассемблера.

    Ассемблер — это программа, которая запускает компьютер и преобразует инструкции в набор битов. Процессор может использовать его для выполнения основных операций. Некоторые люди называют эти инструкции языком ассемблера, а другие используют термин язык ассемблера .

    Где мы используем ассемблер в IT?

    Каждый компьютер имеет процессор, который выполняет арифметические, логические и контрольные действия компьютера.

    Каждое семейство процессоров имеет собственный набор инструкций для обработки различных операций, таких как ввод с клавиатуры, отображение информации на экране и выполнение различных других задач. Мы называем эту последовательность инструкций «инструкциями машинного языка».

    Een процессор понимает только инструкции машинного языка, которые представляют собой строки из единиц и нулей. Однако машинный язык слишком непонятен и сложен для использования при разработке программного обеспечения. Таким образом, язык ассемблера разработан для определенного семейства процессоров, которые представляют различные инструкции в символьном коде и в более понятной форме.

    Так работает ассемблер

    • Компьютеры поставляются с определенным набором основных инструкций, которые соответствуют основным операциям, которые может выполнять компьютер. Например, инструкция «Load» заставляет процессор перемещать последовательность битов из места в памяти процессора в специальный репозиторий, называемый регистром.
    • Программист может написать программу, используя любую из этих инструкций ассемблера.
    • Эта последовательность операторов ассемблера, известная как исходный код или исходная программа, затем указывается в программе на ассемблере при запуске программы.
    • Программа на ассемблере берет каждую программную инструкцию в исходной программе и генерирует соответствующий битовый поток или шаблон (серию нулей и единиц определенной длины).
    • Выходные данные программы на ассемблере называются объектным кодом или объектной программой по отношению к исходной программе ввода. Серии нулей и единиц, составляющие объектную программу, также называют машинным кодом.
    • Затем мы можем запустить объектную программу в любое время.

    Как мы применяем ассемблерный код?

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

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

    • MOV — перемещать данные из одного места в другое.
    • ДОБАВИТЬ — сложите два значения.
    • SUB — вычесть одно значение из другого.
    • PUSH — поместить данные в стек.
    • POP — извлечь данные из стека.
    • JMP — перейти в другое место.
    • INT — прервать процесс.

    Мы можем использовать следующий простой ассемблерный код для добавления чисел 3 и 4:

    mov eax, 3 — загружает 3 в регистр «eax».
    mov ebx, 4 — загружает 4 в реестр «ebx».
    добавить eax, ebx, ecx — добавить «eax» и «ebx» и сохранить результат (7) в «ecx».

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

    Преимущества языка ассемблера

    Знание этого базового языка помогает вам понять, как:

    • Программы взаимодействуют с ОС, процессором и BIOS.
    • Данные отображаются в памяти.
    • Процессор выполняет инструкции.
    • Обрабатывать данные инструкции.
    • Программа получает доступ к внешним устройствам.

    Преимущества использования языка ассемблера:

    • Требует меньше памяти и времени выполнения.
    • Ассемблер упрощает выполнение сложных аппаратных задач.
    • Подходит для срочных задач.
    • Лучше всего подходит для написания программ обработки прерываний и других программ, находящихся в памяти.

    Нужно ли учить ассемблер?

    От нашей работы зависит, стоит ли нам изучать язык ассемблера. Для большинства разработчиков ответ — «нет».

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

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

    Подавляющее большинство разработчиков программного обеспечения, включая практически всех разработчиков приложений, используют языки программирования высокого уровня и не используют ассемблерный код. Однако некоторые конкретные области, в которых мы действительно используем язык ассемблера:

    • Операционные системы
    • Firmware.
    • Программы оборудования.
    • Проектирование языков программирования.
    • Проектирование компиляторов.
    • Встроенные системы.
    • Аппаратный дизайн.
    • утонченный криптография.
    • Теоретическая информатика.

    Другая причина изучить ассемблер — лучше понять, что происходит глубоко внутри компьютера. (Вот почему почти всех ИТ-специалистов учат этому языку во время обучения.)

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

    Другие вещи, чтобы учиться

    Есть языки, на которых, если мы что-то о них знаем, мы можем многое. Python и Ruby похожи на них, мы можем узнать о них достаточно за выходные, чтобы создать что-то стоящее. Ассемблер не такой.

    Мы никогда не используем язык ассемблера сам по себе, а всегда на определенной платформе. Инженер, которому нужно знать ассемблер, вероятно, работает в той области, где вам нужно знать и другие навыки, чтобы быть эффективным. Скорее всего, они включают:

    • Аппаратные языки, такие как VHDL и Verilog, а также понимание микропроцессоров и электротехники.
    • Языки операционных систем низкого уровня, такие как C и его производные: C ++, C # и D.
    • Древние языки, такие как Фортран и Кобол.
    • Языки платформы, такие как Java и Objective-C.
    • Алгоритмы.

    ITpedia Technology, телекоммуникации и инфраструктура рекомендации

    Программное обеспечение искусственного интеллекта ПредложитьЛучшее программное обеспечение искусственного интеллекта вы можете найти. Более чем программные решения 100 на выбор!
    Cisco Systems IncCCNA и CCNP Электронное обучение. Cisco Virtual Internet Routing Lab Personal Edition (VIRL PE) 20 узлов.
    Иоло технологии, ОООЕсли ваш компьютер не загружается и не загружает приложения с той же скоростью, что и при первой распаковке, загрузите Iolo System Mechanic 18.7. Эта отличная утилита настройки значительно улучшает производительность вашего ПК за счет дефрагментации жесткого диска, восстановления проблемного реестра Windows, настройки использования ЦП и ОЗУ в реальном времени и т. Д. Начиная с версии 18.7, Iolo System Mechanic включает специальные инструменты конфиденциальности для Windows 10. Это выбор нашей редакции для платных приложений для настройки. Получите скидку 50% на iolo’s Phoenix 360; Полная защита, конфиденциальность и производительность для вашей цифровой жизни.
    Mobile Advance Inc.Ноутбуки, планшеты, ASUS RTX — сэкономьте $ 50 на моделях RTX 2080 и получите БЕСПЛАТНУЮ игровую связку — включает игровые коды Battlefield V + Anthem + аксессуары
    Операционная система Программное обеспечение ПредложитьЛучшие компьютерные операционные системы для бизнеса. Windows, Linux, Oracle и т. Д.
    Защищенный траст— Microsoft Surface Go для бизнеса. — Meraki Security и SD-WAN. Устройства Cisco Meraki Security могут быть развернуты удаленно за считанные минуты с помощью облачного обеспечения без необходимости касания. Настройки безопасности просты для синхронизации на тысячах сайтов с использованием шаблонов. Технология Auto VPN надежно соединяет филиалы в 3 клика через интуитивно понятную веб-панель управления. — Шифрование электронной почты, созданное для обеспечения конфиденциальности и соответствия требованиям. Простейшее на рынке совместимое шифрование электронной почты. Безопасная отправка из Microsoft Outlook и многих медицинских приложений. Управляемый сообществом, вы решаете, что мы будем показывать дальше!

    Обсудить с нами LinkedIn.

    резюме

    статья

    Что такое язык ассемблера?

    Описание

    Язык ассемблера — это низкоуровневый язык программирования, разработанный для определенного типа процессора. Мы можем создать Assembler, скомпилировав исходный код из языка программирования высокого уровня (такого как C / C ++). Но мы также можем сами писать программы на этом языке. В свою очередь, мы можем преобразовать ассемблерный код в машинный код, используя ассемблер.

    Автор

    Wim Hoogenraad

    Имя издателя

    ITpedia

    Издательство Логотип

    Язык ассемблера — обзор

    13.1.1 Язык ассемблера

    Язык ассемблера (или Ассемблер) — это скомпилированный компьютерный язык низкого уровня. Он зависит от процессора, поскольку в основном переводит мнемонику Ассемблера непосредственно в команды, понятные конкретному процессору, на взаимно однозначной основе. Эти мнемоники ассемблера представляют собой набор инструкций для этого процессора. Кроме того, Ассемблер предоставляет команды, которые управляют процессом сборки, обрабатывают инициализацию и позволяют использовать переменные и метки, а также управлять выводом.

    На ПК Ассемблер обычно используется только под MS-DOS. При работе в 32-битной операционной системе с защищенным режимом (включая Windows 95 / NT и выше) низкоуровневые программы, которые напрямую обращаются к регистрам или ячейкам памяти, вызывают нарушения защиты. Весь низкоуровневый доступ должен осуществляться через соответствующие драйверы программного обеспечения.

    Для ПК с MS-DOS самым популярным языком ассемблера был Microsoft Macro Assembler или MASM. Как и большинство популярных компиляторов, MASM регулярно обновлялся.Большая часть этого обсуждения относится к версии 5.0 или более поздней, которая упростила использование определенных директив и включила поддержку инструкций, доступных только на процессорах 80286 и 80386.

    Директива — это команда ассемблера, которая не преобразуется в исполняемую инструкцию, но предписывает MASM выполнить определенную задачу, облегчающую процесс сборки. Исполняемая инструкция иногда называется операционным кодом, в то время как директива ассемблера может называться псевдооперационным кодом.Директивы могут сообщать MASM много разных вещей, в том числе о том, какой сегмент памяти упоминается, каково значение переменной или ячейки памяти и где начинается выполнение программы.

    Одна из важных директив MASM — это .MODEL, которая определяет максимальный размер программы. Помните, что для ЦП семейства 80 × 86 память адресуется как сегменты длиной до 64 Кбайт. Если используется 16-битная адресация (для кода или данных), будет доступен только один сегмент размером 64 КБ. Модель памяти программы определяет, как различные части этой программы (код и данные) обращаются к сегментам памяти.MASM поддерживает пять моделей памяти для программ DOS: Small, Medium, Compact, Large и Huge. В модели Small все данные помещаются в один сегмент размером 64 КБ, а весь код (исполняемые инструкции) помещается в другой сегмент размером 64 КБ. В модели Medium все данные помещаются в один сегмент размером 64 КБ, но код может быть больше 64 КБ (многосегментный, требующий 32-разрядной адресации для сегмента: смещение). В модели Compact весь код помещается в один сегмент размером 64 КБ, но данные могут занимать более 64 КБ (но ни один массив не может быть больше 64 КБ).В большой модели и код, и данные могут быть больше 64 КБ (при этом ни один массив данных не может превышать 64 КБ). Наконец, в модели Huge размер кода и данных может превышать 64 КБ, а массивы данных также могут превышать 64 КБ.

    Поскольку для более крупных моделей требуются более крупные адреса, они производят более крупные и медленные программы, чем для моделей меньшего размера. Выбирая модель для программы, постарайтесь оценить максимальный объем хранилища данных, который вам понадобится. Допустим, вы пишете программу БПФ, используя 16-битную целочисленную математику и максимальный размер выборки 2048 точек.Поскольку для каждой точки требуется два целых числа (действительное и мнимое), а каждое целое число имеет длину 2 байта, вам нужно 8096 байтов только для хранения входных (или выходных) данных. Даже если бы у вас были отдельные массивы для входных и выходных данных, это все равно было бы всего 16 192 байта. В качестве запаса прочности для временного хранилища мы удвоим это число до 32 384 байта, что составляет лишь половину сегмента размером 64 КБ. Размер кода оценить сложнее. В этом примере мы начнем с модели Small. Если бы размер кода оказался больше 64 КБ (что непросто сделать на языке ассемблера), мы бы перешли к модели Medium.Эти же модели памяти также применимы к компиляторам языка DOS высокого уровня от Microsoft. Если вы пишете программу MASM для работы с другим языком высокого уровня, вы должны использовать одну и ту же модель памяти для обоих.

    Вот пример простой программы MASM, которая отображает на экране текстовую строку («Это простая программа MASM») с помощью функции DOS. 09h:

    Здесь используются несколько директив. DOSSEG сообщает MASM о необходимости позаботиться о порядке различных сегментов (кода, данных, стека) — деталь, которую мы предпочли бы игнорировать.Директива .DATA указывает начало сегмента данных, а .CODE указывает начало сегмента кода. Сообщение обозначается меткой text, , где директива DB (Defines Bytes) указывает, что это байтовые данные (кавычки обозначают текст ASCII). Строка должна заканчиваться символом ASCII 24h («$») для функции DOS 09h. Исполняемые инструкции помещаются в сегмент кода. Ярлык go, указывает на начало программы. Адрес текстовой строки загружается в регистры DS: DX.Затем вызывается функция DOS 09h для отображения строки. Наконец, вызывается функция DOS 4Ch для выхода из программы и возврата в DOS. Последняя директива END указывает MASM начать выполнение программы с метки (адреса) go.

    MASM называется Macro Assembler, потому что он поддерживает использование макросов. Макрос — это блок программных операторов, которому дано символическое имя, которое затем можно использовать в нормальном программном коде. Макрос также может принимать параметры, когда он вызывается в программе.Когда исходный файл собирается с помощью MASM, любые макросы расширяются (переводятся) в исходный текст определения. Это очень удобно, если один и тот же фрагмент кода, например функция, определяемая программистом, используется повторно. Часто предопределенные макросы могут храниться в отдельном файле вместе с другой информацией, такой как инициализация переменных. Директива INCLUDE может читать этот файл во время сборки.

    Этот краткий обзор MASM едва коснулся поверхности языка ассемблера. Проверьте библиографию для других книг по этой теме.Опять же, вам следует писать программу на языке ассемблера, только если вы работаете в DOS и язык высокого уровня не подходит для вашей задачи. Даже в этом случае обычно можно обойтись простым написанием наиболее важных разделов в MASM и их вызовом с языка высокого уровня. Далее мы рассмотрим популярный интерпретируемый язык высокого уровня: BASIC.

    Книги по информатике @ Amazon.com

    Профессиональный язык ассемблера

    Каждая программа на языке высокого уровня (например, C и C ++) преобразуется компилятором в язык ассемблера перед ее компоновкой в ​​исполняемую программу.В этой книге показано, как просмотреть код языка ассемблера, созданный компилятором, и понять, как он создается. Обладая этими знаниями, вы можете настроить код языка ассемблера, сгенерированный компилятором, или создать свои собственные процедуры на языке ассемблера.

    Это руководство с интенсивным использованием кода разделено на три раздела — основы среды разработки программ на языке ассемблера, программирование на языке ассемблера и передовые методы языка ассемблера. В нем показано, как расшифровать код языка ассемблера, созданный компилятором, и как сделать функции в ваших программах более быстрыми и эффективными, чтобы повысить производительность приложения.

    Что вы узнаете из этой книги:

    • Преимущества изучения кода языка ассемблера, сгенерированного из вашей программы на языке высокого уровня
    • Как создать автономные программы на языке ассемблера для среды Linux Pentium
    • Способы включения расширенные функции и библиотеки в программах на языке ассемблера
    • Как включить подпрограммы языка ассемблера в ваши приложения C и C ++
    • Способы использования системных вызовов Linux в программах на языке ассемблера
    • Как использовать функции Pentium MMX и SSE в ваших приложениях

    Профессиональный язык ассемблера

    Каждая программа на языке высокого уровня (например, C и C ++) преобразуется компилятором в язык ассемблера перед ее компоновкой в ​​исполняемую программу.В этой книге показано, как просмотреть код языка ассемблера, созданный компилятором, и понять, как он создается. Обладая этими знаниями, вы можете настроить код языка ассемблера, сгенерированный компилятором, или создать свои собственные процедуры на языке ассемблера.

    Это руководство с интенсивным использованием кода разделено на три раздела — основы среды разработки программ на языке ассемблера, программирование на языке ассемблера и передовые методы языка ассемблера. В нем показано, как расшифровать код языка ассемблера, созданный компилятором, и как сделать функции в ваших программах более быстрыми и эффективными, чтобы повысить производительность приложения.

    Что вы узнаете из этой книги:

    • Преимущества изучения кода языка ассемблера, сгенерированного из вашей программы на языке высокого уровня
    • Как создать автономные программы на языке ассемблера для среды Linux Pentium
    • Способы включения расширенные функции и библиотеки в программах на языке ассемблера
    • Как включить подпрограммы языка ассемблера в ваши приложения C и C ++
    • Способы использования системных вызовов Linux в программах на языке ассемблера
    • Как использовать функции Pentium MMX и SSE в ваших приложениях

    Об авторе

    Ричард Блюм работал в большом U.Государственная организация С. более 15 лет. За это время он имел возможность программировать служебные программы на различных языках программирования: C, C ++, Java, а также Microsoft VB.NET и C #. Благодаря этому опыту Рич часто находил преимущество в просмотре кода языка ассемблера, сгенерированном компиляторами, и использовании подпрограмм на языке ассемблера для ускорения программ на языке более высокого уровня.
    Рич имеет степень бакалавра электротехники в Университете Пердью, где он работал над многими проектами на языке ассемблера.(Конечно, это было еще во времена восьмибитных процессоров.) У него также есть степень магистра менеджмента в Университете Пердью, специализирующаяся на информационных системах управления.

    Разница между языком ассемблера и языком высокого уровня

    1. Язык уровня ассемблера:
    Это язык низкого уровня, который позволяет пользователям писать программы, используя буквенно-цифровые мнемонические коды вместо числового кода для набора примеров инструкций большие программы на языке ассемблера с этого времени — это IBM PC DOS.

    2. Язык высокого уровня:
    Это машинно-независимый язык. Он позволяет пользователю писать программу на языке, напоминающем английские слова и знакомые математические символы. COBOL был первым языком высокого уровня. Примеры языков высокого уровня: python, c # и т. Д.

    Разница между языком ассемблера и языком высокого уровня:

    ЯЗЫК УРОВНЯ СБОРКИ

    ВЫСОКИЙ УРОВЕНЬ L ЯЗЫК

    • Для преобразования требуется ассемблер
    • Для преобразования требуется компилятор / интерпретатор
    • В этом случае мы преобразуем язык уровня ассемблера в язык машинного уровня
    • Здесь мы конвертируем язык высокого уровня в язык ассемблера в язык машинного уровня
    • Он не зависит от машины
    • В этой мнемонике коды used
    • В этом заявлении на английском языке используется

    901 08

    • Он поддерживает работу на низком уровне
    • Он не поддерживает язык низкого уровня
    • Таким образом, легко получить доступ к аппаратному компоненту
    • При этом затруднен доступ к аппаратной части
    • В этом более компактном коде

    Внимание читатель! Не прекращайте учиться сейчас.Ознакомьтесь со всеми важными концепциями теории CS для собеседований SDE с помощью курса CS Theory Course по приемлемой для студентов цене и будьте готовы к работе в отрасли.

    L10a: язык ассемблера

    L10a: язык ассемблера

    В предыдущей лекции мы разработали набор инструкций.
    архитектура для бета-версии, компьютерной системы, которой мы будем
    построение на протяжении этой части курса. Бета
    включает два типа хранилища или памяти. В ЦП
    datapath есть 32 регистра общего назначения, которые могут быть
    прочитано, чтобы предоставить исходные операнды для ALU, или записано с
    Результат ALU.{30} $ 32-битные слова. В этой памяти хранятся как данные, так и
    инструкции.

    Бета-инструкции — это 32-битные значения, состоящие из различных
    поля. 6-битное поле OPCODE определяет операцию, которая должна быть
    выполненный. 5-битные поля Ra, Rb и Rc содержат регистр
    числа, определяющие один из 32 регистров общего назначения.
    Есть два формата инструкций: один с указанием кода операции и
    три регистра, другой определяет код операции, два регистра,
    и 16-битная константа со знаком.

    Есть три класса инструкций.Инструкции ALU
    выполнить арифметическую или логическую операцию над двумя операндами,
    выдача результата, который сохраняется в регистре назначения.
    Операнды — это либо два значения из универсального
    регистры или одно значение регистра и константа. Желтый
    выделение указывает на инструкции, в которых используется второй
    формат инструкции.

    Инструкции загрузки / сохранения обращаются к основной памяти, либо загружая
    значение из основной памяти в регистр или сохранение регистра
    значение в основной памяти.

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

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

    Используя язык высокого уровня, мы можем подняться еще на один уровень
    абстракции и описать вычисление, которое мы хотим, в терминах
    переменные и математические операции, а не регистры и
    Функции ALU.

    В этой лекции мы опишем язык ассемблера.
    мы будем использовать для программирования бета-версии. И в следующем
    лекцию мы разберемся, как переводить на высоком уровне
    языки, такие как C, на язык ассемблера.

    Слоеный пирог абстракций стал еще выше: мы могли бы написать
    интерпретатор, скажем, Python на C, а затем напишите наш
    прикладные программы на Python. В наши дни программисты часто
    выберите язык программирования, который больше всего подходит для
    выражая свои вычисления, то, возможно, после многих слоев
    перевода, придумайте последовательность инструкций, которые
    Бета-версия действительно может выполняться.

    Хорошо, вернемся к языку ассемблера, который мы будем использовать для
    защищаемся от представлений на битовом уровне
    инструкции и от необходимости знать точное местонахождение
    переменные и инструкции в памяти.Программа под названием
    «Ассемблер» читает текстовый файл, содержащий
    программа на языке ассемблера и производит массив 32-битных слов
    который можно использовать для инициализации основной памяти.

    Мы изучим язык ассемблера UASM, который построен
    в BSim, наш симулятор для бета-версии ISA. UASM действительно просто
    модный калькулятор! Он читает арифметические выражения и
    оценивает их для получения 8-битных значений, которые затем добавляет
    последовательно к массиву байтов, который в конечном итоге будет
    загружается в память бета-версии.UASM поддерживает несколько
    полезные языковые функции, которые упрощают написание ассемблера
    языковые программы. Символы и метки позволяют дать имена
    конкретные значения и адреса. И макросы позволяют нам создавать
    сокращенные обозначения для последовательностей выражений, которые, когда
    оценивается, будет генерировать двоичные представления для
    инструкции и данные.

    Вот пример исходного файла UASM. Обычно мы пишем
    один оператор UASM в каждой строке и может использовать пробелы, табуляции и
    новые строки, чтобы сделать исходный текст максимально читаемым.Мы добавили цветовую кодировку, чтобы помочь в
    объяснение.

    Комментарии (показаны зеленым) позволяют нам добавлять текстовые аннотации к
    программа. Хорошие комментарии помогут напомнить вам, как ваши
    программа работает. Вы действительно не хотите выяснять
    с нуля, что делает часть кода каждый раз, когда вам нужно
    изменить или отладить его! Есть два способа добавить комментарии к
    код. «//» начинает комментарий, который затем занимает
    остальная часть исходной строки. Любые символы после
    «//» игнорируются ассемблером, который запускает
    операторы обработки снова в начале следующей строки в
    исходный файл.Вы также можете заключить текст комментария, используя
    разделители «/ *» и «* /» и
    Ассемблер проигнорирует все, что между ними. Используя этот второй
    типа комментария, вы можете «закомментировать» многие строки
    код, поместив «/ *» в начале и много строк
    позже завершите раздел комментариев символом «* /».

    Символы (показаны красным) — это символические имена для постоянных значений.
    Символы упрощают понимание кода, например, . , мы можем
    использовать N в качестве имени начального значения для некоторых вычислений в
    в данном случае значение 12.Последующие утверждения могут относиться к этому
    значение с использованием символа N вместо ввода значения 12
    напрямую. Читая программу, мы узнаем, что N
    означает это конкретное начальное значение. Итак, если позже мы захотим
    изменить начальное значение, нам нужно только изменить определение
    символа N вместо того, чтобы найти все 12 в нашем
    запрограммируйте и измените их. На самом деле некоторые из других выступлений
    из 12 может не относиться к этому начальному значению, поэтому, чтобы убедиться, что мы
    изменили только те, которые сделали, нам нужно будет прочитать и
    понять всю программу, чтобы убедиться, что мы редактировали только
    право 12-е.Вы можете себе представить, насколько подвержены ошибкам
    быть! Так что использование символов — это практика, которой вы хотите следовать!

    Обратите внимание, что все имена регистров показаны красным. Хорошо
    определите символы от R0 до R31, чтобы иметь значения от 0 до
    31. Затем мы будем использовать эти символы, чтобы помочь нам понять
    какие операнды инструкции предназначены для
    регистры, например , записав R1, и какие операнды
    числовые значения, например , написав цифру 1. Мы могли бы
    просто используйте числа везде, но код будет намного сложнее
    читать и понимать.

    Ярлыки (показаны желтым цветом) — это символы, значение которых
    адрес определенного места в программе. Здесь
    метка «петля» будет нашим названием для местоположения
    инструкция MUL в памяти. В BNE в конце
    код, мы используем метку «цикл», чтобы указать MUL
    инструкция как цель ветвления. Итак, если R1 не равно нулю, мы хотим
    чтобы вернуться к инструкции MUL и запустить другую
    итерация.

    Мы будем использовать отступ для большинства операторов UASM, чтобы
    легко заметить метки, определенные программой.Отступ
    не требуется, это просто очередная сборка привычки
    язык программирования, используемый программистами для обеспечения читабельности своих программ.

    Мы используем вызовы макросов (показаны синим цветом), когда хотим написать
    Бета-инструкции. Когда ассемблер встречает макрос, он
    «Расширяет» макрос, заменяя его строкой
    текст, предоставленный в определении макроса. В течение
    расширение, предоставленные аргументы текстуально вставляются в
    развернутый текст в местах, указанных в макросе
    определение.Думайте о макросе как о сокращении для более длинного текста
    строку, которую мы могли бы ввести. Посмотрим, как все это
    работает в следующем сегменте видео.

    Давайте проследим, как ассемблер обрабатывает наш исходный код.
    файл. Ассемблер поддерживает таблицу символов, которая отображает символы
    имена к их числовым значениям. Изначально таблица символов
    загружен сопоставлениями для всех символов регистров.

    Ассемблер считывает исходный файл построчно, определяя
    символы и метки, раскрывающиеся макросы или вычисляющие выражения
    для генерации байтов для выходного массива.Всякий раз, когда ассемблер
    сталкивается с использованием символа или ярлыка, он заменяется на
    соответствующее числовое значение, найденное в таблице символов.

    Первая строка, N = 12, определяет значение символа N, которое будет
    12, поэтому соответствующая запись сделана в таблице символов.

    Переходя к следующей строке, ассемблер встречает
    вызов макроса ADDC с аргументами
    «R31», «N» и «r1». В качестве
    мы увидим на нескольких слайдах, это вызовет серию
    вложенные расширения макросов, которые в конечном итоге приводят к созданию
    32-битное двоичное значение, которое нужно поместить в ячейку памяти 0.В
    32-битное значение отформатировано здесь, чтобы показать поля инструкции
    а адрес назначения показан в скобках.

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

    В четвертой строке определено, что цикл меток имеет значение
    участка памяти, который собирается заполнить (в этом
    корпус, локация 8). Таким образом, соответствующая запись сделана в
    таблица символов и макрос MUL расширяется до 32-битного слова
    для размещения в локации 8.

    Ассемблер обрабатывает файл построчно, пока не достигнет
    конец файла. Собственно ассемблер делает два прохода
    через файл. На первом проходе загружает таблицу символов
    со значениями из всех определений символов и меток.
    Затем, на втором проходе, он генерирует двоичный вывод. В
    двухпроходный подход позволяет оператору ссылаться на символ или метку
    который определен позже в файле, , например. , переднее отделение
    инструкция может ссылаться на этикетку для инструкции позже в
    программа.

    Как мы видели на предыдущем слайде, здесь нет ничего волшебного
    насчет регистровых символов — это просто символические имена
    для значений от 0 до 31. Таким образом, при обработке ADDC (r31, N, r1),
    UASM заменяет символы их значениями и фактически расширяет
    ADDC (31,12,1).

    UASM очень прост. Он просто заменяет символы их
    values, раскрывает макросы и оценивает выражения. Итак, если вы используете
    символ регистра, где ожидается числовое значение, значение
    символа используется как числовая константа.Возможно нет
    что задумал программист.

    Аналогично, если вы используете символ или выражение, где регистр
    ожидается число, младшие 5 бит значения используются как
    номер регистра, в этом примере, как номер регистра Rb.
    Опять же, вероятно, не то, что задумал программист.

    Мораль истории в том, что при написании сборки UASM
    языковые программы, вы должны быть внимательны и
    признать, что интерпретация операнда определяется
    макрос кода операции, а не то, как вы написали операнд.

    Вспомните из лекции 9, что инструкции ветвления используют 16-битный
    постоянное поле инструкции для кодирования адреса
    цель ветки как смещение слова от местоположения ветки
    инструкция. Ну, на самом деле смещение рассчитывается от
    инструкция, следующая сразу за ветвью, поэтому смещение -1
    будет относиться к самой ветке.

    Расчет смещения вручную немного утомителен.
    и, конечно, изменится, если мы добавим или удалим инструкции
    между инструкцией ветвления и целью ветвления.К счастью
    макросы для инструкций ветвления включают необходимые
    формула для вычисления смещения от адреса ветки и
    адрес целевого филиала. Поэтому мы просто указываем
    адрес целевой ветви, обычно с меткой, и пусть UASM
    делать тяжелую работу.

    Здесь мы видим, что BNE разветвляется в обратном направлении по трем инструкциям.
    (не забудьте считать из инструкции, следующей за веткой), поэтому
    смещение -3. 16-битное дополнение до двух
    представление -3 — это значение, помещенное в постоянное поле
    инструкции BNE.

    Давайте подробнее рассмотрим, как работают макросы в UASM.
    Здесь мы видим определение макроса «консенсус».
    который имеет единственный параметр «n». Тело
    макрос — это последовательность из четырех выражений. Когда есть
    вызов макроса «Concec», в этом примере
    с аргументом 37 тело макроса раскрывается
    заменяя все вхождения «n» аргументом
    37. Полученный текст затем обрабатывается так, как если бы он появился
    вместо вызова макроса. В этом примере четыре
    выражения оцениваются, чтобы дать последовательность из четырех значений, которые
    будет помещен в следующие четыре байта выходного массива.

    Расширения макросов могут содержать другие вызовы макросов, которые
    сами будут расширяться, пока все это
    left — выражения для оценки. Здесь мы видим макрос
    определение слова WORD, которое объединяет свой аргумент в два
    последовательные байты. А для макроса LONG, который собирает свои
    аргумент в четыре последовательных байта, используя макрос WORD для
    обрабатывать младшие 16 бит значения, затем старшие 16 бит
    Значение.

    Эти два оператора UASM приводят к тому, что константа 0xDEADBEEF становится
    конвертируется в 4 байта, которые помещаются в выходной массив
    начиная с индекса 0x100.

    Обратите внимание, что бета-версия ожидает наименее значимый байт
    многобайтовое значение, сохраняемое по младшему байтовому адресу. Так
    младший байт 0xEF размещается по адресу 0x100 и
    старший байт 0xDE помещается по адресу 0x103. Этот
    это соглашение с прямым порядком байтов для многобайтовых
    значения: младший байт идет первым. Intel
    Архитектура x86 также имеет прямой порядок байтов.

    Существует правило симметричного обратного порядка байтов.
    где старший байт идет первым.Обе конвенции
    активно используются, и некоторые ISA могут быть настроены на
    используйте любое соглашение! Нет никакого «права»
    ответ », какое соглашение использовать, но тот факт, что
    там два соглашения означают, что мы должны быть внимательны к
    необходимо преобразовать представление многобайтовых значений, когда
    перемещение значений между одним ISA и другим, например , когда мы
    отправить файл данных другому пользователю.

    Как вы понимаете, есть сильные сторонники обеих схем.
    которые рады подробно отстаивать свою точку зрения.Учитывая накал дискуссии, уместно, чтобы
    названия конвенций были взяты у Джонатана
    «Путешествие Гулливера» Свифта, в котором
    Гражданская война ведется из-за того, открывать ли всмятку в
    его большой конец или его маленький конец.

    Давайте посмотрим на макросы, используемые для сборки бета-версии.
    инструкции. Вспомогательный макрос BETAOP поддерживает 3-регистровый
    формат инструкции, принимая в качестве аргументов значения, которые должны быть помещены
    в полях OPCODE, Ra, Rb и Rc. Файл «.align»
    4-дюймовая директива — это своего рода административная бухгалтерия для
    убедитесь, что у инструкций есть байтовый адрес,
    кратно 4, i.е. , что они охватывают ровно одну 32-битную
    слово в памяти. Затем следует вызов
    Макрос LONG для генерации 4 байтов двоичных данных, представляющих
    значение выражения, показанного здесь. Выражение где
    происходит собственно сборка полей. Каждое поле
    ограничено необходимым количеством бит с использованием оператора по модулю
    (%), затем сдвинут влево (<<) в правильное положение в 32-битное слово.

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

    Давайте проследим сборку инструкции ADDC, чтобы увидеть
    как это работает. Макрос ADDC расширяется до вызова
    вспомогательный макрос BETAOPC, передающий правильное значение для
    код операции ADDC вместе с тремя операндами.

    Макрос BETAOPC выполняет следующие арифметические операции: OP
    аргумент, в данном случае значение 0x30, сдвигается влево, чтобы занять
    старшие 6 бит инструкции. Тогда аргумент РА,
    в этом случае 15 размещается на своем месте.16-битный
    константа -32768 расположена в младших 16 битах
    инструкция. И, наконец, аргумент Rc, в данном случае 0, равен
    помещается в поле Rc инструкции.

    Вы можете понять, почему мы называем эту обработку «сборкой
    инструкция ». Двоичное представление инструкции
    собирается из двоичных значений для каждой инструкции
    поля. Это несложный процесс, но он требует
    много смещения и маскировки, задачи, которые мы с радостью выполним
    компьютерная ручка.

    Вот вся последовательность расширений макросов,
    соберите эту инструкцию ADDC в соответствующий 32-битный двоичный файл
    значение в основной памяти.

    Вы можете видеть, что знание форматов инструкций бета-версии и
    значения кода операции встроены в тела определений макросов.
    Обработка UASM на самом деле довольно общая — с
    другой набор макроопределений, которые он может обрабатывать при сборке
    языковые программы практически для любых ISA!

    Все определения макросов для бета-версии ISA представлены в
    бета.uasm файл, который входит в каждую сборку
    задания языковой лаборатории. Обратите внимание, что мы добавили некоторые удобства
    макросы для определения сокращенных представлений, которые обеспечивают общие
    значения по умолчанию для определенных операндов. Например, кроме
    вызовы процедур, нас не волнует сохраненное значение ПК + 4
    в регистре назначения инструкциями ветвления, так что почти
    всегда будет указывать R31 как регистр Rc, эффективно
    отбрасывая значение ПК + 4, сохраненное ветками. Итак, мы определяем
    макросы ветвления с двумя аргументами, которые автоматически предоставляют R31 как
    регистр назначения.Экономит набор текста и, что более важно,
    упрощает понимание ассемблера
    программа.

    Вот целый набор удобных макросов, предназначенных для
    программы более читабельны. Например, безусловные переходы могут
    быть написанным с использованием макроса BR (), а не более громоздкого
    BEQ (R31, …). И более читабельно использовать ветвь-ложь
    (BF) и макрос истинного ветвления (BT) при тестировании результатов
    сравните инструкцию.

    Обратите внимание на макросы PUSH и POP внизу страницы.Эти
    развернуть в последовательности с несколькими инструкциями, в данном случае, чтобы добавить и
    удалить значения из структуры данных стека, на которую указывает SP
    регистр.

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

    В этом примере мы переписали исходный код, который у нас был
    для факториального вычисления с использованием псевдоинструкций.Для
    Например, CMOVE — это псевдо-инструкция по перемещению небольших
    константы в регистр. Нам легче читать и
    понять цель операции «постоянного перемещения»
    чем операция «добавить значение к 0», предоставляемая
    ADDC расширение CMOVE. Все, что мы можем сделать, чтобы удалить
    когнитивный беспорядок будет очень полезен в долгосрочной перспективе.

    До сих пор мы говорили об инструкциях по сборке. Какие
    о данных? Как мы выделяем и инициализируем хранилище данных и
    как мы помещаем эти значения в регистры, чтобы их можно было
    как операнды?

    Здесь мы видим программу, которая выделяет и инициализирует две памяти
    местоположения с помощью макроса LONG.Мы использовали ярлыки, чтобы
    запомните адреса этих мест на будущее
    ссылка.

    Когда программа собрана, значения метки N и
    factN равны 0 и 4 соответственно, адреса памяти
    местоположения, содержащие два значения данных.

    Для доступа к первому значению данных программа использует LD
    инструкция, в данном случае один из удобных макросов,
    предоставляет R31 как значение по умолчанию для поля Ra. В
    ассемблер заменяет ссылку на метку N ее значением 0
    из таблицы символов.Когда LD выполняется, он вычисляет
    адрес памяти путем добавления константы (0) к значению Ra
    регистр (это R31 и, следовательно, значение 0), чтобы получить
    адрес (0) ячейки памяти, из которой нужно получить значение
    для размещения в R1.

    Константы, необходимые в качестве значений для слов данных и инструкций.
    поля могут быть записаны как выражения. Эти выражения
    оценивается ассемблером при сборке программы и
    полученное значение используется по мере необходимости.Обратите внимание, что выражения
    оцениваются во время работы ассемблера. К тому времени
    программа работает на бета-версии, используется полученное значение. В
    ассемблер НЕ генерирует инструкции ADD и MUL для вычисления
    значение во время выполнения программы. Если значение необходимо для
    поле инструкции или значение начальных данных, ассемблер должен быть
    может самостоятельно выполнять арифметические действия. Если вам нужна программа
    чтобы вычислить значение во время выполнения, вы должны написать
    необходимые инструкции как часть вашей программы.

    И последняя особенность UASM: есть специальный символ
    «.», Называемый «точкой», значением которого является
    адрес следующей ячейки основной памяти, которая должна быть заполнена
    ассемблер, когда он генерирует двоичные данные. Изначально
    «.» равно 0 и увеличивается каждый раз, когда новый
    генерируется байтовое значение.

    Мы можем установить значение «.» сказать ассемблеру
    где в памяти мы хотим разместить значение. В этом примере
    константа 0xDEADBEEF помещается в ячейку 0x100 основного
    объем памяти. И мы можем использовать «.»В выражениях к
    вычислить значения для других символов, как показано здесь, когда
    определение значения символа «k». Фактически
    определение метки «k:» в точности эквивалентно
    Заявление UASM «k =.»

    Мы можем даже увеличить значение «.» пропустить
    местоположения, например , если бы мы хотели оставить место на
    инициализированный массив.

    А это ассемблер! Мы используем язык ассемблера
    как удобное обозначение для генерации двоичного кодирования для
    инструкции и данные.Мы позволяем ассемблеру построить битовый уровень
    необходимых нам представительств и отслеживать адреса, по которым
    эти значения хранятся в основной памяти.

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

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

    Мы используем символы для присвоения значимых имен значениям, чтобы наши
    программы станут более читабельными и их легче модифицировать.
    Точно так же мы используем ярлыки, чтобы давать значимые имена адресам.
    в основной памяти, а затем используйте метки для ссылки на данные
    места в инструкциях LD или ST, или в места инструкций
    в инструкции ветки.

    Макросы скрывают детали того, как собираются инструкции из
    их составляющие поля.

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

    Ассемблер — это программа, которая запускается на нашем компьютере.
    Возникает интересная фраза «курица и яйцо.
    проблема »: как первая программа на ассемблере получила
    собраны в двоичный код, чтобы его можно было запускать на компьютере? Ну это
    был вручную собран в двоичный файл. Я подозреваю, что он обработал очень
    действительно простой язык, с набором символов,
    метки, макросы, оценка выражений и т. д.добавлен только после
    основные инструкции могут быть собраны программой. А также
    Я уверен, что они были очень осторожны, чтобы не потерять двоичный файл, поэтому
    им не пришлось бы делать ручную сборку в секунду
    время!

    Ускоренный курс по языку ассемблера | Мадлен Фарина | Обратное проектирование для чайников

    Основы сборки x86 для обратного проектирования

    Если вы занимаетесь каким-либо видом обратного проектирования — и под этим я имею в виду дизассемблирование скомпилированного исполняемого файла с помощью таких инструментов, как Ghidra, для анализа машинного кода — тогда вы должны стать хорошо осведомленными ассемблера.Если у вас есть интерес к этой области, вы, вероятно, уже слышали о сборке и знаете, что она имеет менее любимую (возможно, даже презираемую) репутацию, но это не обязательно означает, что ей сложно учиться.

    Это не стандартный язык программирования, такой как Python или Java. Оба являются высокоуровневыми языками , а x86 и ARM Assembly — низкоуровневыми . Это означает, что их может быть намного сложнее понять и включать в себя работу с регистрами в памяти для выполнения задач.Программисту легче понять языки высокого уровня, в то время как компьютер может легче интерпретировать язык низкого уровня, также известный как машинный язык. Несоответствий, конечно, больше (о них можно прочитать здесь), но это самое основное различие между ними.

    Когда я впервые изучил сборку на одном из обязательных курсов CS, я нашел это… сложным, мягко говоря. Было чертовски неприятно кодировать простые проекты, такие как четырехфункциональный калькулятор или алгоритм GCD в ARM v8.Мало того, что синтаксис был туманным и ошеломляющим, мне пришлось выполнять все кодирование и тестирование либо с помощью эмулятора, либо работая в терминале, подключенном к компьютерной плате Firefly ROC-RK3328-CC, подключенной к моему ноутбуку. Мне не привыкать работать в командной строке, но когда дело доходит до кодирования проектов, мне легче работать в среде IDE только из-за количества кода, с которым мне приходится работать.

    (оглядываясь назад, я бы использовал функцию ssh в Visual Studio Code для подключения к моему Firefly, но несмотря на это)

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

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

    Источник: http://faculty.cs.niu.edu/~mcmahon/CS241/Images/compile.png

    Если вы занимались разработкой на C ++, вы знаете, что файл .cpp содержит код программиста, и вы должны скомпилировать его, чтобы получить на выходе (.о) файл. Эти файлы имеют объектный код, который представляет собой программы на машинном языке, содержащие код операции (код операции), который является инструкциями для компьютера. Интересно, что вредоносное ПО часто представляется в виде объектного кода, поэтому для понимания кода операции необходима обратная инженерия. Одна из целей RE состоит в том, чтобы преобразовать объектный код в язык ассемблера посредством процесса дизассемблирования.

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

    Если вы заметили, я упомянул как сборку x86, так и ARM v8. На самом деле разница есть, поскольку на самом деле существует несколько разных архитектур (и последующих «разновидностей») сборки. x86 — один из наиболее распространенных языков сборки, его архитектура имеет как 32-разрядные, так и 64-разрядные версии, а его синтаксис основан на AT&T или Intel. Другими словами, большинство компьютеров Intel используют сборку x86. Различия в синтаксисе включают порядок операндов, регистровые и непосредственные префиксы, суффиксы, указывающие размер операнда, и так далее.

    версии ARM похожи (это не похоже на сравнение яблок и апельсинов), но они отличаются тем, что ARM — это архитектура RISC, а x86 — это CISC (подробнее см. Здесь). Инструкции ARM имеют встроенные условные флаги, что позволяет избежать всех этих переходов вокруг одной или двух инструкций, которые вы часто видите в сборке Intel, а ARM не может многое делать с памятью напрямую, кроме загрузки из нее и сохранения в нее. Сборка Intel может выполнять больше операций непосредственно с памятью.

    В оставшейся части этого объяснения мы будем обращаться к сборке x86.

    Источник: http://users.cis.fiu.edu/~prabakar/cda4101/Common/notes/lecture04.html Процессоры

    могут быть с прямым порядком байтов или прямым порядком байтов. байтов в слове памяти. Big endian Системы хранят старший байт (MSB) по наименьшему адресу памяти и младший байт (LSB) по наибольшему. И наоборот, системы с прямым порядком байтов и хранят младший бит по наименьшему адресу памяти и наоборот. Фактически, большинство процессоров имеют прямой порядок байтов, потому что это означает использование меньшего количества цепей, тогда как большинство сетевых протоколов имеют прямой порядок байтов, потому что это лучше для передачи информации по одному биту за раз.

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

    Также забавный факт: полубайтовое (4-битное) значение называется полубайтом!

    Архитектура

    x86 имеет 8 регистров общего назначения (GPR), 6 регистров сегмента, 1 регистр флагов и указатель инструкции для 32-разрядной архитектуры x86.

    Источник: https://www.cs.virginia.edu/~evans/cs216/guides/x86.html

    EAX — Сохраняет возвращаемые значения функции

    EBX — Базовый указатель на раздел данных

    ECX — Счетчик для строковых и циклических операций

    EDX — Указатель ввода / вывода

    ESI — Указатель источника для строковых операций

    EDI — Указатель места назначения для строковых операций

    ESP — Указатель стека

    EBP — Указатель базы кадра стека

    EIP — Указатель на следующую инструкцию для execute («указатель команд»), не может быть изменен напрямую с помощью mov , но может быть изменен косвенно путем обращения к операциям

    Регистры общего назначения используются для основных арифметических и типовых операций. Регистры указателя используются для указания на память для управления программой.

    Флаги и регистры сегментов

    CS — Указатель на сегмент кода, в котором работает ваша программа

    DS — Указатель на сегмент данных, к которому ваша программа обращается

    ES, FS, GS — Дополнительные сегментные регистры доступны для Дальний указатель, адресующийся как видеопамять.

    SS — Указатель на сегмент стека, который использует ваша программа.

    OF — Флаг переполнения, используется, если место назначения не может сохранить весь результат

    SF — Флаг подписи, используется, если последняя операция дала значение с установленным MSB

    ZF — Устанавливается, если результат арифметики операция 0

    Простые инструкции

    mov — перемещает дату из одного места в другое без изменений, в форме:

      mov  назначение, источник 

    lea — загрузка действующего адреса, вычисление косвенного адреса и сохранение адрес (не содержимое памяти) в месте назначения

      lea  destination, значение 

    jmp — сообщает ЦП перейти в новое место, передает поток выполнения, изменяя регистр указателя инструкций

      jmp  назначение 

    добавить — арифметическое сложение, прибавляет указанное значение к значению, хранящемуся в месте назначения, и заменяет пункт назначения с результатом

      добавить  пункт назначения, значение 

    вложенный — арифметическое вычитание, аналогично сложению

      вложенный  пункт назначения, значение 

    вкл — увеличивает пункт назначения на 1

      вкл  пункт назначения 

    dec — уменьшает назначение на 1

      dec  destination 

    Существуют также логические операции, такие как или , и , и xor , которые имеют те же режимы адресации, что и add и sub .

    Адресация

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

    И говоря об адресации, важно знать об адресе возврата , который является параметром , который сообщает функции, где возобновить выполнение после завершения функции. Это необходимо, потому что функции могут быть вызваны для выполнения обработки из множества различных частей программы, и функция должна иметь возможность вернуться туда, откуда она была вызвана.

    Каждый вызов активной функции имеет фрейм, в котором хранятся значения всех локальных переменных, а фреймы всех активных функций хранятся в стеке.Стек — это очень важная структура данных в памяти. Как правило, он используется для хранения временных данных, необходимых во время выполнения программы, таких как локальные переменные и параметры, адреса возврата функций и многое другое. Это статическая память, то есть ее нельзя изменить во время выполнения. Подобная динамическая память, выделенная функциями malloc () или new () , хранится в куче. Я расскажу о стеке и куче в моем следующем посте, а пока мы сосредоточимся только на стеке.

    Как и стопка блинов, стек в памяти имеет порядок «последним пришел — первым ушел» (LIFO), что означает, что объекты на вершине стека выталкиваются первыми. И хотя это странно, но в x86 стек растет вниз от высоких адресов к низким. Что касается сборки, вы можете найти некоторые из наиболее распространенных инструкций по работе с стеком ниже.

    Инструкции стека

      push  value 

    Это уменьшает ESP на количество байтов, занятых значением, и копирует значение по адресу, не связанному с ESP.

      pop  destination 

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

    Теперь перейдем к некоторым необычным инструкциям стека, которые часто используются вредоносными программами (важно, если вы собираетесь обратить вспять любые подозрительные программы):

    pusha — Вставляет 16-битные значения регистров AX, CX, DX, BX, SP, BP, SI, DI в стек

    pushad — проталкивает 32-битные значения регистров EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI в стек

    popa — Обратная операция pusha

    popad — Обратная операция pushad

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

    Ссылки:

    https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture

    Денис Юричев, Обратный инжиниринг для начинающих , https://beginners.re/RE4B-EN.pdf

    Майкл Сикорски, Эндрю Хониг, Практический анализ вредоносных программ: практическое руководство по обнаружению вредоносных программ , (2012)

    Синтаксис строк исходного кода на языке ассемблера

    Все три части исходной строки необязательны.

    символ обычно является этикеткой. В инструкциях и псевдоинструкциях это
    всегда ярлык. В некоторых директивах это символ переменной или константы. В
    описание директивы проясняет это в каждом случае.

    символ должен начинаться в первом столбце. Он не может содержать пробелов
    символ, например пробел или табуляция, если он не заключен в полосы (|).

    Ярлыки — это символические представления адресов.Вы можете использовать ярлыки, чтобы отмечать определенные
    адреса, на которые вы хотите ссылаться из других частей кода. Числовые локальные метки — это
    подкласс меток, которые начинаются с номера в диапазоне 0-99. В отличие от других лейблов,
    числовая локальная метка может быть определена много раз. Это делает их полезными при создании этикеток.
    с макросом.

    Директивы

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

    Инструкции и псевдо-инструкции составляют код, который процессор использует для выполнения
    задания.

    Примечание

    Инструкциям, псевдо-инструкциям и директивам должен предшествовать пробел, например
    как пробел или табуляция, независимо от того, есть ли предыдущая метка или нет.

    Некоторые директивы не разрешают использование этикеток.

    Комментарий — это последняя часть исходной строки. Первая точка с запятой в строке отмечает
    начало комментария, кроме случаев, когда точка с запятой стоит внутри строкового литерала.Конец
    строки — это конец комментария. Только комментарий является допустимой строкой. Ассемблер
    игнорирует все комментарии. Вы можете использовать пустые строки, чтобы сделать ваш код более читабельным.

    Рекомендации при написании исходного кода на языке ассемблера

    Вы должны написать мнемонику инструкций,
    псевдо-инструкции, директивы и символьные имена регистров (кроме a1 a4 , v1 v8 и регистров Wireless MMX) в любом
    все прописные или строчные.Вы не должны использовать смешанный регистр. Ярлыки и комментарии можно в
    прописные, строчные или смешанный регистр.

            ОБЛАСТЬ THUMBex, КОД, ТОЛЬКО ЧТЕНИЕ
                                    ; Назовите этот блок кода THUMBex
            ВХОД                   ; Отметить первую инструкцию для выполнения
            БОЛЬШОЙ ПАЛЕЦ
    Начните
            MOV r0, # 10; Настроить параметры
            MOV r1, # 3
            ДОБАВИТЬ r0, r0, r1; г0 = г0 + г1
    останавливаться
            MOV r0, # 0x18; angel_SWIreason_ReportException
            LDR r1, = 0x20026; ADP_Stopped_ApplicationExit
            SVC # 0x123456; Полухостинг ARM (ранее SWI)
            КОНЕЦ                     ; Отметить конец файла 

    Для облегчения чтения исходных файлов вы можете разделить длинную строку исходного текста на несколько строк.
    поместив символ обратной косой черты ( \ ) в конец строки.Обратная косая черта
    не должны сопровождаться какими-либо другими символами, включая пробелы и табуляции. Ассемблер
    обрабатывает обратную косую черту, за которой следует последовательность конца строки, как пробел. Вы также можете использовать пустой
    строк, чтобы сделать ваш код более читабельным.

    Примечание

    Не используйте обратную косую черту, за которой следует последовательность конца строки в строках в кавычках.

    Ограничение на длину строк, включая любые расширения, использующие обратную косую черту, составляет 4095
    символы.

    Язык ассемблера — Викиверситет

    Язык ассемблера — это набор мнемонических языков с логическим отображением 1 к 1 инструкций в машинный код различных архитектур. Сборка обычно используется, когда задача программирования небольшая и локальная, поскольку она имеет очень небольшую модульность и зависит от платформы, в отличие от языков более высокого уровня. Другое использование сборки — отладка программ (в которой машинные инструкции могут выполняться по одной за раз) и в программах, скомпилированных при обратном проектировании, путем дизассемблирования (в которых нет кода более высокого уровня, с которым можно было бы связываться).

    Архитектура — это самая важная вещь, которую нужно знать при программировании на языке ассемблера. Рассматриваемая архитектура может быть конкретным оборудованием, на котором приложение разработано, или виртуальной машиной. Виртуальная машина является примером абстрактного оборудования и обычно также имеет свою собственную версию машинного кода. Архитектура диктует внутренние представления, используемые типами данных, инструкциями, понятными ЦП, и доступными ресурсами. Поскольку язык ассемблера представляет собой логическое отображение 1: 1 в машинный код, шаги, предпринимаемые для реализации алгоритма, часто намного меньше и многочисленнее, чем на языках более высокого уровня.Типичная аппаратная архитектура содержит ЦП, регистры и память.

    Общие архитектуры:

    • x86
    • ARM
    • КПП
    • MIPS
    • 360/370
    • Виртуальная машина Java
    • Виртуальная машина Python
    • 68000

    ЦП (центральный процессор) действует как мозг компьютерной системы. Обычно он содержит кэш и регистры. Кэш обычно используется для хранения сегментов программного кода, а регистры используются для немедленного доступа к данным.ЦП последовательно выполняет инструкции из кеша, пока не встретит ветвь или прерывание.

    Регистры являются частью ЦП и представляют собой самую быструю доступную память. Количество, размер и использование доступных регистров зависит от рассматриваемой архитектуры. Регистр обычно считается целым числом, но его можно представить как что угодно, от символа до указателя.

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

    Инструкция на языке ассемблера обычно объявляет как расположение этих данных, так и формат ожидаемых данных. Инструкции можно разделить на математические, логические, операции управления потоком или операции с памятью. Общие математические операции включают сложение, вычитание, умножение, деление и сдвиг, в то время как общие логические операции — это побитовые операции И, ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ и НЕ.Операции управления потоком — это чаще всего ветки или сравнения, а память часто загружается, сохраняется или перемещается. Каждая архитектура поставляется с набором инструкций, который представлен в машинном коде (единицы и нули) для машины, но представлен программисту в более удобочитаемой форме. См. Архитектура MIPS — прекрасный пример.

    .

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

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