Команды языка ассемблера один в один соответствуют командам процессора и, фактически, представляют собой удобную символьную форму записи (мнемокод) команд и их аргументов. Также язык ассемблера обеспечивает базовые программные абстракции: связывание частей программы и данныx через метки с символьными именами (при ассемблировании[1] для каждой метки высчитывается адрес, после чего каждое вхождение метки заменяется на этот адрес) и директивы[2].
Директивы ассемблера позволяют включать в программу блоки данных (описанные явно или считанные из файла); повторить определённый фрагмент указанное число раз; компилировать фрагмент по условию; задавать адрес исполнения фрагмента, отличный от адреса расположения в памяти[уточнить!]; менять значения меток в процессе компиляции; использовать макроопределения с параметрами и др.
Каждая модель процессора, в принципе, имеет свой набор команд и соответствующий ему язык (или диалект) ассемблера.
Имеются процессоры, реализующие базис своих высокоуровневых языков (Forth, Lisp), где ассемблер имеет минимальные отличия от базового языка. В отличие, например, от существующих, ассемблер процессора Java не совместим синтаксически с своим высокоуровневым языком.
Достоинства и недостатки
Достоинства языка ассемблера
Минимальное количество избыточного кода, то есть использование меньшего количества команд и обращений в память, позволяет увеличить скорость и уменьшить размер программы.
Обеспечение полной совместимости и максимального использования возможностей нужной платформы: использование специальных инструкций и технических особенностей данной платформы.
При программировании на ассемблере становятся доступными специальные возможности: непосредственный доступ к аппаратуре, портам ввода-вывода и особым регистрам процессора, а также возможность написания самомодифицирующегося кода (то есть метапрограммирование, причём без необходимости программного интерпретатора).
Последние технологии безопасности, внедряемые в операционные системы, не позволяют делать самомодифицирующегося кода, так как исключают одновременную возможность исполнения инструкций и запись в одном и том же участке памяти (технология W^X в BSD-системах, DEP в Windows).
Недостатки языка ассемблера
Большие объёмы кода и большое число дополнительных мелких задач, что приводит к тому, что код становится очень сложно читать и понимать, а следовательно усложняется отладка и доработка программы, а также трудность реализации парадигм программирования и любых других соглашений, что приводит к сложности совместной разработки.
Меньшее количество доступных библиотек, их малая совместимость между собой.
Поскольку большие программы на ассемблере писать не всегда удобно, их пишут на языках высокого уровня. На ассемблере же пишут небольшие фрагменты или модули, для которых критически важны:
размер кода (загрузочные сектора, программное обеспечение для микроконтроллеров и процессоров с ограниченными ресурсами, вирусы, программные защиты);
специальные возможности: работа напрямую с аппаратурой или машинным кодом, то есть загрузчики операционных систем, драйверы, вирусы, системы защиты.
Легальная сфера деятельности
Оптимизация критичных к скорости участков программ написанных на языке высокого уровня, таком как C++. Это особенно актуально для видеоприставок, у которых фиксированная производительность, и для мультимедийных кодеков, которые стремятся делать менее ресурсоемкими и более популярными.
Создание операционных систем (ОС). ОС часто пишут на Си, языке, который специально был создан для написания одной из первых версий Unix. Аппаратно зависимые участки кода, такие, как загрузчик ОС, уровень абстрагирования от железа - HAL и ядро, частично приходится писать на ассемблере. Ассемблерного кода в Windows или Linux совсем не много, поскольку авторы стремятся к переносимости и надежности. Некоторые любительские ОС, такие, как KolibriOS, целиком написаны на ассемблере. При этом KolibriOS помещается на дискету и содержит графический многооконный интерфейс.
Программирование микроконтроллеров (МК). По мнению профессор Таненбаума, как онтогенез повторяет филогенез, развитие МК повторяет историческое развитие компьютеров новейшего времени.[3] На сегодняшний день для программирования МК весьма часто применяют ассемблер. Применение ассемблера так же во многом обусловлено очень низким уровнем программирования. В МК буквально приходится перемещать отдельные байты и биты между различными ячейками памяти. Программирование МК перспективно, т.к. по мнению Таненбаума в машине и квартире в среднем содержится 50 микроконтроллеров (должно быть имеется ввиду западный дом).[4]
Создание драйверов. Некоторые участки драйверов, взаимодействующие с железом, программируют на ассемблере. Хотя в целом драйверы стараются писать на языке высокого уровня. Поскольку это быстрее и надежнее. Надежность для драйверов играет особую роль, посколько в Windows NT и Linux драйверы работают в режиме ядра. Одна ошибка может привести к краху системы.
Обратная разработка программы с целью создать аналогичную программу. Примером такой обратной разработки может быть деятельность команды разработчиков ReactOS. В процессе работы первая группа исследователей изучает внутренне устройство Windows NT, и описывает человеческим языком. Затем вторая группа программистов, используя отчёт первой, создаёт аналогичную функциональность.
Создание антивирусов и других защитных программ. Для специалистов этой области, по заявлению Ильфака Гильфанова, создателя IDA, он создал этот интерактивный дизассемблер.[5]
Создание микропрограммы т.е. прошивки для микросхем. Микропрограммы используются в CISC процессорах Intel начиная с Intel486. Такой процессор содержит аппаратно реализованную микроархитектуру и софт – микропрограмму. Микропрограмма интерпретирует CISC команды архитектуры процессора во внутренние RISC команды микроархитектуры, которые исполняются непосредственно аппаратной частью процессора. Так же CD приводы, модемы, DVD плееры и другие устройства, созданные на основе микроконтроллеров или специализированных мультипроцессоров, содержат прошивку.
Изучение интерфейсной части ПО с целью создания информационных систем, сопрягающихся с изучаемым ПО. Это значит дизассемблирование библиотек подсистемы окружения, для изучения API функций, или дизассемблирование чего угодно, главное чтоб это было оправдано необходимостью создать железо или софт, который должен взаимодействовать с изучаемой программой через определенный интерфейс, который нужно изучить. Дело в том, что в остальном, для создание аналогичной программы, законы запрещают пользоваться дизассемблером (Разработчики ReactOS стремятся обойти это ограничение).
Нелегальная сфера деятельности
Взлом программ. «Оригинал» ПО, копии которого продаются незаконно, если в нём использовались технические средства защиты авторских прав, вероятно, был взломан с помощью отладчика и знаний языка ассемблера. Специалиста по взлому называют крякером. Крякер, как правило, владеет языком ассемблера x86. Что позволяет при помощи отладчика или дизассемблера найти внутри кода программы функцию, ответственную за ввод кода активации или прекращение работы демонстрационной версии программы. Крякер может изменить исходный код программы при помощи hex редактора (1). Либо создать генератор ключа (2). Первый способ более прост для конечного пользователя. Второй менее наказуем.[6](УКРФ ст. 272 до 2 лет[7])
Создание вирусов и других вредоносных программ. (УКРФ ст. 273 до 3 лет, при тяжких последствиях до 7 лет.[8])
Исследования вирусов. На сайте Лаборатория Касперского описаны «исследователи», которые сами не создают вирусы, но пишут книги о том, как это сделать[9]. Ярким примером российского исследователя является Крис Касперски (не путать с Касперским — это не только два разных человека, но даже не однофамильцы).
Связывание ассемблерного кода с другими языками
Поскольку на ассемблере чаще всего пишут лишь фрагменты программы, их необходимо связывать с остальными частями на других языках. Это достигается 2 основными способами:
На этапе компиляции — вставка в программу ассемблерных фрагментов (англ.inline assembler) специальными директивами языка, в том числе написание процедур на языке ассемблера. Способ удобен для несложных преобразований данных, но полноценного ассемблерного кода, с данными и подпрограммами, включая подпрограммы с множеством входов и выходов, не поддерживаемых высокоуровневыми языками, с помощью него сделать нельзя.
На этапе компоновки, или раздельная компиляция. Для взаимодействия скомпонованных модулей достаточно, чтобы связующие функции[10] поддерживали нужные соглашения вызова (англ.calling conventions) и типы данных. Написаны же отдельные модули могут быть на любых языках, в том числе и на ассемблере.
Синтаксис
Общепринятого стандарта для синтаксиса языков ассемблера не существует. Однако, существуют стандарты, которых придерживается большинство разработчиков языков ассемблера. Основными такими стандартами являются Intel-синтаксис и AT&T-синтаксис.
Набор команд
К командам языка ассемблер относят:
1)Команды пересылания данных (mov, lea т.д.)
2)Арифметичекие команды (add, sub, imul и т.д.)
3)Логические и побитовые операции (or, and, xor, shr т.д.)
4)Команды управления ходом выполнения программы (jmp, loop, ret и т.д.)
5)Команды вызова программных прерываний (иногда относят к командам управления): int, into
Общий формат записи инструкций одинаков для обоих стандартов:
[метка:] кодоп [операнды][;комментарий]
где кодоп(код операции) — непосредственно мнемоника инструкции процессору. К ней могут быть добавлены префиксы (повторения, изменения типа адресации и пр.).
Используемые мнемоники обычно одинаковы для всех процессоров одной архитектуры или семейства архитектур (среди широко известных - мнемоники процессоров и контроллеров Motorola, ARM, x86). Они описываются в спецификации процессоров. Возможные исключения:
Если ассемблер использует кроссплатформенный AT&T-синтаксис (оригинальные мнемоники приводятся к синтаксису AT&T)
Если изначально существовало два стандарта записи мнемоник (система команд была наследована от процессора другого производителя).
Например, процессор Zilog Z80 наследовал систему команд Intel i8080, расширил ее и поменял мнемоники (и обозначения регистров) на свой лад. Например сменил интеловские mov[11] на ld. Процессоры Motorola Fireball наследовали систему команд Z80, несколько её урезав. Вместе с тем, Motorola официально вернулась к мнемоникам Intel. И в данный момент половина ассемблеров для Fireball работает с интеловскими мнемониками, а половина с мнемониками Zilog.
Директивы
Кроме инструкций, программа может содержать директивы: команды, не переводящиеся непосредственно в машинные инструкции, а управляющие работой компилятора. Набор и синтаксис их значительно разнятся и зависят не от аппаратной платформы, а от используемого компилятора (порождая диалекты языков в пределах одного семейства архитектур). В качестве "джентельменского набора" директив можно выделить:
определение данных (констант и переменных)
управление организацией программы в памяти и параметрами выходного файла
задание режима работы компилятора
всевозможные абстракции (т.е. элементы языков высокого уровня) - от оформления процедур и функций (для упрощения реализации парадигмы процедурного программирования) до условных конструкций и циклов (для парадигмы структурного программирования)
.MODELTINYCODESEGMENTASSUMECS:CODE, DS:CODEORG100h
START:
movah,9movdx,OFFSET Msg
int 21h
int 20h
Msg DB'Hello World',13,10,'$'CODEENDSEND START
Происхождение и критика термина «язык ассемблера»
Данный тип языков получил свое название от названия транслятора (компилятора) с этих языков — ассемблера (англ.assembler — сборщик). Название последнего обусловлено тем, что на первых компьютерах не существовало языков более высокого уровня, и единственной альтернативой созданию программ с помощью ассемблера было программирование непосредственно в кодах.
Язык ассемблера в русском языке часто называют «ассемблером» (а что-то связанное с ним — «ассемблерный»), что, согласно английскому переводу слова, неправильно, но вписывается в правила русского языка. Однако, сам ассемблер (программу) тоже называют просто «ассемблером», а не «компилятором языка ассемблера» и т. п.
Использование термина «язык ассемблера» также может вызвать ошибочное мнение о существовании единого языка низкого уровня, или хотя бы стандарта на такие языки. При именовании языка, на котором написана конкретная программа, желательно уточнять, для какой архитектуры она предназначена и на каком диалекте языка написана.