Ассемблер Материал http://wikipedia.org

Язык ассемблера Motorola MC6800.

Язы́к ассе́мблера — язык программирования низкого уровня, мнемонические команды которого (за редким исключением) соответствуют инструкциям процессора вычислительной системы. Трансляция программы в исполняемый машинный код производится ассемблером (от англ. assembler — сборщик) — программой-транслятором, которая и дала языку ассемблера его название.

Содержание

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

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

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

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

Существуют компьютеры, реализующие в качестве машинного язык программирования высокого уровня (Forth, Lisp, Эль-76). Фактически, в таких компьютерах они выполняют роль языков ассемблера.

  • Язык ассемблера позволяет писать самый быстрый и компактный код, какой вообще возможен для данного процессора.
  • Если код программы достаточно большой, — данные, которыми он оперирует, не помещаются целиком в регистрах процессора, то есть частично или полностью находятся в оперативной памяти, то искусный программист, как правило, способен значительно оптимизировать программу по сравнению с транслятором с языка высокого уровня по одному или нескольким параметрам:
    • скорость работы — за счёт оптимизации вычислительного алгоритма и/или более рационального обращения к ОП, перераспределения данных;
    • объём кода (в том числе за счёт эффективного использования промежуточных результатов). (Сокращение объема кода также нередко повышает скорость выполнения программы.)
  • Обеспечение максимального использования специфических возможностей конкретной платформы, что также позволяет создавать более эффективные программы, — в том числе менее ресурсоемкие.
  • При программировании на языке ассемблера возможен непосредственный доступ к аппаратуре, и, в частности,:
  • Язык ассемблера часто применяется для создания драйверов оборудования и ядра операционной системы (или машинозависимых подсистем ядра ОС).
  • Язык ассемблера используется для создания «прошивок» BIOS.
  • С помощью языка ассемблера часто создаются машинозависимые подпрограммы компиляторов и интерпретаторы языков высокого уровня, а также реализуется совместимость платформ.
  • С помощью дизассемблера позволяет исследовать существующие программы при отсутствии исходного кода.

  • Сложную программу написать на языке ассемблера намного сложнее — вплоть до невозможности, по причине сложности, — чем на языке высокого уровня.
  • В силу машинной ориентации — «низкого» уровня — языка ассемблера человеку сложнее читать и понимать программу на нём по сравнению с программой на языке высокого уровня. А подлежащий редактированию ассемблерный код сравнительно большой, — программа на языке ассемблера состоит из слишком «мелких» элементов — машинных команд. Соответственно, усложняются программирование и отладка, растёт трудоёмкость разработки, сравнительно велика вероятность программных ошибок.
  • Требуется высокая квалификация программиста. Код на ассемблере выполняется быстрее, но написанный неопытным программистом, обычно оказывается хуже сгенерированного компилятором с языка высокого уровня[2]
  • Как правило, меньшее количество доступных библиотек по сравнению с современными индустриальными языками программирования.
  • Программы на языке ассемблера не переносимы на компьютеры с другой архитектурой и системой команд как на уровне машинных команд так и на уровне исходных кодов, что в случае с языками ассемблера одно и то же.

Исторически можно рассматривать язык ассемблера как второе поколение языков программирования ЭВМ. (Если первым считать числовые двоичные коды машинных команд.) Недостатки языка ассемблера, сложность разработки на нём больших программных комплексов привели к появлению языков третьего поколения — языков программирования высокого уровня. В частности: Фортран, Лисп, Кобол, Паскаль, Си и многих др. Именно языки программирования высокого уровня и их наследники в основном используются в настоящее время в индустрии информационных технологий. Однако языки ассемблера сохраняют свою нишу, обусловливаемую их уникальными преимуществами в части эффективности и возможности полного использования специфических средств конкретной платформы.

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

  • быстродействие (драйверы);
  • объем используемой памяти (загрузочные секторы, встраиваемое (англ. embedded) программное обеспечение, программы для микроконтроллеров и процессоров с ограниченными ресурсами, вирусы, программные защиты).

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

  • Оптимизация критичных к скорости подпрограмм в программах на языках высокого уровня, таких как C++ или Pascal. Это особенно актуально для игровых приставок, имеющих фиксированную производительность, и для мультимедиа-кодеков, которые стремятся делать менее ресурсоёмкими и более быстрыми и, следовательно, более популярными.
  • Создание операционных систем (ОС) или машинозависимых компонентов ОС. Причем подавляющее большинство ОС в настоящее время пишут на Си — языке высокого уровня, который специально был создан для написания одной из первых версий UNIX. Небольшие кусочки ОС, такие как загрузчик ОС, уровень абстрагирования от аппаратного обеспечения (hardware abstraction layer) и ядро, часто пишутся с применением ассемблерных вставок или ассемблерных подпрограмм. Фактически, ассемблерного кода в ядрах Windows или Linux совсем немного, поскольку авторы стремятся обеспечить переносимость и надёжность, но, тем не менее, он там присутствует. Некоторые любительские ОС, такие как MenuetOS, целиком написаны на языке ассемблера. При этом MenuetOS помещается на дискету и содержит графический многооконный интерфейс. При этом по причине сложности написания больших программ на ассемблере на MenuetOS не существует имеющего практическую ценность прикладного программного обеспечения, а производительность системы по причине высокой энтропии не столь велика, как можно было бы ожидать от программного обеспечения написанного целиком на ассемблере
  • Программирование микроконтроллеров (МК) и других встраиваемых процессоров. По мнению профессора Таненбаума, развитие МК повторяет историческое развитие компьютеров новейшего времени.[3] На сегодняшний день для программирования МК весьма часто применяются нередко, но уже реже, чем языки высокого уровня. В МК приходится перемещать отдельные байты и биты между различными ячейками памяти. Программирование МК весьма важно, так как, по мнению Таненбаума, в автомобиле и квартире современного цивилизованного человека в среднем содержится 50 микроконтроллеров.[4]
  • Создание драйверов. Некоторые участки драйверов, программируют на языке ассемблера. Хотя в целом в настоящее время драйверы также стараются писать на языках высокого уровня в связи с повышенными требованиями к надёжности и достаточной производительностью современных процессоров и достаточным совершенством компиляторов с языков выского уровня. Надёжность для драйверов играет особую роль, поскольку в Windows NT и UNIX (в том числе в Linux) драйверы работают в режиме ядра. Одна ошибка в драйвере может привести к краху всей системы.
  • Создание антивирусов и других защитных программ.
  • Написание трансляторов языков программирования.

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

Это достигается двумя основными способами:

  • На фазе трансляции — вставка в текст программы на языке высокого уровня ассемблерных фрагментов (англ. inline assembler) с помощью специальных директив языка. В частности, данный способ поддерживается языками программирования Си и Delphi), в том числе написание функций на языке ассемблера. Способ удобен для несложных преобразований данных, но полноценного ассемблерного кода, с данными и подпрограммами, включая подпрограммы со множеством входов и выходов, не поддерживаемых языком высокого уровня, с его помощью сделать невозможно.
  • На этапе компоновки при раздельной трансляции. Для взаимодействия компонуемых модулей достаточно, чтобы импортируемые функции — определённые в одних модулях и используемые в других поддерживали соглашения вызова (англ. calling conventions) и типы данных, применяемые в базовом языке высокого уровня, используемого в качестве основного средства разработки. Написаны же отдельные модули могут быть на любых других языках, в том числе и на языке ассемблера.

Синтаксис языка ассемблера определяется системой команд конкретного процессора.

Типичными командами языка ассемблера являются (большинство примеров даны для Intel-синтаксиса архитектуры x86):

  • Команды пересылки данных (mov и др.)
  • Арифметические команды (add, sub, imul и др.)
  • Логические и побитовые операции (or, and, xor, shr и др.)
  • Команды управления ходом выполнения программы (jmp, loop, ret и др.)
  • Команды вызова прерываний (иногда относят к командам управления): int, into
  • Команды ввода/вывода в порты (in, out)
  • Для микроконтроллеров и микрокомпьютеров характерны также команды, выполняющие проверку и переход по условию, например:
  • cbne — перейти, если не равно
  • dbnz — декрементировать, и если результат ненулевой, то перейти
  • cfsneq — сравнить, и если не равно, пропустить следующую команду

Типичный формат записи команд:

[метка:] опкод [операнды] [;комментарий]

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

В качестве операндов могут выступать константы, адреса регистров, адреса в оперативной памяти и пр. Различия между синтаксисом Intel и AT&T касаются в основном порядка перечисления операндов и указания различных методов адресации.

Используемые мнемоники обычно одинаковы для всех процессоров одной архитектуры или семейства архитектур (среди широко известных — мнемоники процессоров и контроллеров x86, ARM, SPARC, PowerPC, M68k). Они описываются в спецификации процессоров. Возможные исключения:

  • если ассемблер использует кроссплатформенный AT&T-синтаксис (оригинальные мнемоники приводятся к синтаксису AT&T);
  • если изначально существовало два стандарта записи мнемоник (система команд была наследована от процессора другого производителя).

Например, процессор Zilog Z80 наследовал систему команд Intel i8080, расширил её и поменял мнемоники (и обозначения регистров) на свой лад. Процессоры Motorola Fireball наследовали систему команд Z80, несколько её урезав. Вместе с тем, Motorola официально вернулась к мнемоникам Intel и в данный момент половина ассемблеров для Fireball работает с мнемониками Intel, а половина — с мнемониками Zilog.

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

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

Примеры программы Hello, world! для разных платформ и разных диалектов:

Данный тип языков получил своё название от транслятора (компилятора) с этих языков — ассемблера (англ. assembler — сборщик). Название обусловлено тем, что программа «автоматически собиралась», а не вводилась вручную покомандно непосредственно в кодах. При этом наблюдается путаница терминов: ассемблером нередко называют не только транслятор, но и соответствующий язык программирования («программа на ассемблере»).

В СССР язык ассемблера ранее называли «автокод».

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

Три встречающихся варианта употребления термина "ассемблер":

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

2) язык ассемблера для конкретной вычислительной системы, например, для микроконтроллеров семейства AVR (пишется с маленькой буквы);

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

  1. Крис Касперски. Образ мышления IDA. Архивировано из первоисточника 22 августа 2011.
  2. Крис Касперски. Война миров: Ассемблер против Cи. Архивировано из первоисточника 22 августа 2011. Проверено 1 июня 2010.
  3. Эндрю Таненбаум. Архитектура компьютера. 5-е изд.
  4. Эндрю Таненбаум. Архитектура компьютера. 3-е изд.

  • Галисеев Г. В. Ассемблер для Win 32. Самоучитель — М.: Диалектика, 2007. — 368 с. — ISBN 978-5-8459-1197-1.
  • Зубков С. В. Ассемблер для DOS, Windows и UNIX — М. ДМК Пресс; СПб. Питер, 2006. — 608 с. — ISBN 5-94074-259-9.
  • Кип Ирвин. Язык ассемблера для процессоров Intel = Assembly Language for Intel-Based Computers — М.: Вильямс, 2005. — 912 с. — ISBN 0-13-091013-9.
  • Калашников О. А. Ассемблер? Это просто! Учимся программировать — СПб.: БХВ-Петербург, 2007. — 384 с. — ISBN 978-5-94157-709-5.
  • Крис Касперски. Искусство дизассемблирования — СПб.: БХВ-Петербург, 2008. — 896 с. — ISBN 978-5-9775-0082-1.
  • Владислав Пирогов. Ассемблер для Windows — СПб.: БХВ-Петербург, 2007. — 896 с. — ISBN 978-5-9775-0084-5.
  • Владислав Пирогов. Ассемблер и дизассемблирование. — СПб.: БХВ-Петербург, 2006. — 464 с. — ISBN 5-94157-677-3.
  • Ричард Саймон. Microsoft Windows API Справочник системного программиста.
  • Фрунзе А. В. Микроконтроллеры? Это же просто! Т. 1.
  • Юров В., Хорошенко С. Assembler: учебный курс — СПб.: Питер, 1999. — С. 672. — ISBN 5-314-00047-4.

  • WASM.ru — портал, посвящённый информационной безопасности и программированию на языках ассемблера.
  • Assembler & Win64 (англ.) — введение в Ассемблер под х86-64