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

Язык ассемблераязык программирования низкого уровня. Язык получил свое название от слова ассемблер (англ. assembler — сборщик) — названия транслятора (компилятора) c языка ассемблера. Язык ассемблера, в некоторых случаях, для краткости, называют «ассемблером» (а что-то связанное с ним — «ассемблерный»), но в общем случае это неправильно. Также, сам ассемблер (программу) никогда не называют «компилятором языка ассемблера» или «компилятором ассемблера» (разве что в редких случаях).

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

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

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

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

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

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

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

Содержание

Синтаксис

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

Каждая инструкция записывается в отдельной строке.

Полный формат каждой строки инструкций следующий:

label: code       ; comment

где label — название метки; code — собственно, инструкция языка ассемблера; commentкомментарий .

При этом один или два компонента строки могут отсутствовать, то есть строка может состоять, к примеру, только из комментария, или содержать только метку или инструкцию.

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

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

jmp — продолжать выполнение с нового адреса памяти (от англ. jump - прыжок)
mov — переместить данные (от англ. move - передвинуть)
sub — получить разность двух значений (от англ. substract - вычесть)
xchg — обменять значения в регистрах/ячейках памяти (от англ. exchange - обмен)

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

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

Например процессор Zilog Z80 наследовал ситему команд Intel i8080, расширил ее и поменял мнемоники (и обозначения регистров) на свой лад. Например сменил интеловские «mov» на «ld» (команда перемещения данных). Процессоры Motorola FireBall наследовали систему команд Z80, несколько ее урезав. Вместе с тем, Motorola официально вернулась к мнемоникам Intel. И в данный момент половина ассемблеров для Fireball работает с интеловскими мнемониками, а половина с мнемониками Zilog.

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

Каждый ассемблер имеет собственные директивы.

Для упрощения и ускорения написания программ на языке ассемблера служат макросы.

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

  • Максимально оптимальное использование средств процессора, использование меньшего количества команд и обращений в память, и как следствие — большая скорость и меньший размер программы
  • Использование расширеных наборов инструкций процессора (ММХ, SSE, SSE2, SSE3)
  • Доступ к портам ввода-вывода и особым регистрам процессора (в большинстве ОС эта возможность доступна только на уровне модулей ядра и драйверов)
  • Возможность использования самомодифицирующегося (в том числе перемещаемого) кода (под многими платформами эта возможность недоступна, так как запись в страницы кода запрещена, в том числе и аппаратно, однако в большинстве общедоступных систем из-за их врожденных недостатков имеется возможность исполнения кода содержащегося в сегменте (секции) данных, куда запись разрешена)
  • Максимальная «подгонка» для нужной платформы

NB: Последние технологии безопасности, внедряемые в операционные системы и компиляторы, не позволяют делать самомодифицирующего кода, так как исключают одновременную возможность исполнения программы и запись в одном и том же участке памяти (технология W^X).

Технология W^X используется в OpenBSD (где и появилась), в других BSD-системах, в Linux, в Microsoft Windows (начиная с Windows XP SP2) используется схожая технология DEP.

Недостатки

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

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

Пример программы, выдающей на экран приветствие (написан на TASM для процессоров семейства Intel x86, операционной системы DOS или совместимой):

 
TITLE Пример программы, выдающей на экран приветствие 

 STACK 256
DATASEG SEGMENT PARA 'DATASEG'
    Msgstr DB 'Hello, World!'
DATASEG ENDS
CODESEG SEGMENT PARA 'CODESEG'   ;Вот так правильно описываются сегменты памяти        
 start:    
    mov ax,DATASEG         ; занести в регистр AX смещение блока данных        
    mov ds,ax              ; установить регистр DS равным AX
    mov bx,1               ; указание направления вывода (на экран)
    mov cx,13              ; указание количества символов строки
    mov dx,offset Msgstr   ; поместить в регистр DX смещение строки
    mov ah,40h             ; выбор функции вывода строки
    int 21h                ; вызов прерывания DOS (вывод строки)
    mov ax, 04C00h         ; выбор функции завершения программы
    int 21h                ; вызов прерывания DOS (завершение программы)
 
CODESEG ENDS
end start    

Здесь всё записанное между строками 'start:' и 'end start' — это символические записи инструкций процессора,
(после знака ; и до конца строки — комментарии)

MODEL 
STACK
SEGMENT
ENDS

— это директивы ассемблера (TASM),

DB 'Hello, World!'

— это непосредственные данные (строка для вывода);
Msgstr — метка (идентификатор), упрощающая доступ к данным.

Ассемблеры для x86

  • Borland Turbo Assembler (TASM)
  • Microsoft Macro Assembler (MASM)
  • MASM32
  • FASM (http://flatassembler.net)
  • NASM
  • Unix Assembler (AS) и GNU Assembler (GAS) (Unix-подобные системы)

Ссылки

  • WASM.ru — русскоязычный сайт, посвящённый программированию на языке ассемблера
  • SYSBIN.com — русскоязычный портал по низкоуровневому программированию


 
Начальная страница  » 
А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ы Э Ю Я
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9 Home