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

Материал из Википедии — свободной энциклопедии
Это старая версия этой страницы, сохранённая 89.249.18.214 (обсуждение) в 11:57, 15 декабря 2011. Она может серьёзно отличаться от текущей версии.
Перейти к: навигация, поиск
Язык ассемблера 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и. Проверено 1 июня 2010. Архивировано 22 августа 2011 года.
  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