No Image

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

СОДЕРЖАНИЕ
1 просмотров
11 марта 2020
Язык ассемблера
Класс языка язык программирования
Появился в 1949
Расширение файлов .asm или .s [1]

Язы́к ассе́мблера (англ. assembly language ) — машинно-ориентированный язык программирования низкого уровня. Его команды прямо соответствуют отдельным командам машины или их последовательностям, также он может предоставлять дополнительные возможности облегчения программирования, такие как макрокоманды, выражения, средства обеспечения модульности программ. Может рассматриваться как автокод (см. ниже), расширенный конструкциями языков программирования высокого уровня [2] [3] . Является существенно платформо-зависимым. Языки ассемблера для различных аппаратных платформ несовместимы, хотя могут быть в целом подобны.

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

Автокод — язык программирования, предложения которого по своей структуре в основном подобны командам и обрабатываемым данным конкретного машинного языка [3] .

Содержание

Общее определение [ править | править код ]

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

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

Содержание языка [ править | править код ]

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

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

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

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

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

Возможности [ править | править код ]

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

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

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

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

    Ограничения [ править | править код ]

    • В силу машинной ориентации («низкого уровня») языка ассемблера человеку сложнее читать и понимать программу на нём по сравнению с языками программирования высокого уровня. Это серьёзно затрудняет сопровождение программ, написанных на языке ассемблера.
    • Программа на языке ассемблера состоит из очень «мелких» элементов — машинных команд, соответственно, объём программы в командах пропорционально больше. Поскольку, как известно, программист за единицу времени может написать и отладить примерно одно и то же число операторов, вне зависимости от языка, на котором он пишет, разработка на ассемблере больших программ оказывается существенно медленнее.
    • Усложняются программирование и отладка, растут трудоёмкость и вероятность внесения ошибок.
    • Требуется повышенная квалификация программиста для получения качественного кода: код, написанный средним программистом на языке ассемблера, обычно оказывается не лучше или даже хуже кода, порождаемого оптимизирующим компилятором для сравнимых программ, написанных на языке высокого уровня [6] . При этом чем больше объём программы, тем меньше выигрыш от использования языка ассемблера.
    • Программа на языке высокого уровня может быть перекомпилирована с автоматической оптимизацией под особенности новой целевой платформы [7] , программа же на языке ассемблера на новой платформе может потерять своё преимущество в скорости без ручного переписывания кода [8][9] .
    • Как правило, меньшее количество доступных библиотек по сравнению с современными индустриальными языками программирования.
    • Отсутствует переносимость программ на компьютеры с другой архитектурой и системой команд.

    Применение [ править | править код ]

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

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

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

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

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

    Связывание программ на разных языках [ править | править код ]

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

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

    Синтаксис [ править | править код ]

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

    Набор команд [ править | править код ]

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

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

    Инструкции [ править | править код ]

    Типичный формат записи команд [ править | править код ]

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

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

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

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

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

    Директивы [ править | править код ]

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

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

    Пример программы [ править | править код ]

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

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

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

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

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

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

    Достоинства и недостатки

    Достоинства

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

    • В силу машинной ориентации («низкого» уровня) языка ассемблера человеку сложнее читать и понимать программу на нём по сравнению с языками программирования высокого уровня; программа состоит из слишком «мелких» элементов — машинных команд, соответственно, усложняются программирование и отладка, растут трудоёмкость и вероятность внесения ошибок.
    • Требуется повышенная квалификация программиста для получения качественного кода: код, написанный средним программистом на языке ассемблера, обыкновенно оказывается не лучше или даже хуже кода, порождаемого оптимизирующим компилятором для сравнимых программ, написанных на языке высокого уровня. [5]
    • Программа на языке высокого уровня может быть перекомпилирована с автоматической оптимизацией под особенности новой целевой платформы [6] , программа же на языке ассемблера на новой платформе может потерять своё преимущество в скорости без ручного переписывания кода. [7][8]
    • Как правило, меньшее количество доступных библиотек по сравнению с современными индустриальными языками программирования.
    • Отсутствует переносимость программ на компьютеры с другой архитектурой и системой команд.

    Применение

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

    Читайте также:  Посмотреть траекторию полета самолета

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

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

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

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

    Связывание программ на разных языках

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

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

    Синтаксис

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

    Набор команд

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

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

    Инструкции

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

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

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

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

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

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

    Директивы

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

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

    Пример программы

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

    Содержание статьи

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

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

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

    В последнее время ассемблер незаслуженно находится в тени других языков. Обусловлено это глобальной коммерциализацией, направленной на то, чтобы в максимально короткие сроки получить как можно большую прибыль от продукта. Иными словами, массовость взяла верх над элитарностью. А ассемблер, по моему мнению, ближе к последнему. Гораздо выгоднее в сравнительно небольшие сроки поднатаскать ученика в таких, например, языках, как С++, С#, PHP, Java, JavaScript, Python, чтобы он был более-менее способен создавать ширпотребный софт, не задаваясь вопросами, зачем и почему он так делает, чем выпустить хорошего специалиста по ассемблеру. Примером тому служит обширнейший рынок всевозможных курсов по программированию на любом языке, за исключением ассемблера. Та же тенденция прослеживается как в преподавании в вузах, так и в учебной литературе. В обоих случаях вплоть до сегодняшнего дня большая часть материала базируется на ранних процессорах серии 8086, на так называемом «реальном» 16-битном режиме работы, операционной среде MS-DOS! Возможно, что одна из причин в том, что, с одной стороны, с появлением компьютеров IBM PC преподавателям пришлось перейти именно на эту платформу из-за недоступности других. А с другой стороны, по мере развития линейки 80х86 возможность запуска программ в режиме DOS сохранялась, что позволяло сэкономить деньги на приобретение новых учебных компьютеров и составление учебников для изучения архитектуры новых процессоров. Однако сейчас такой выбор платформы для изучения совершенно неприемлем. MS-DOS как среда выполнения программ безнадежно устарела уже к середине девяностых годов, а с переходом к 32-битным процессорам, начиная с процессора 80386, сама система команд стала намного более логичной. Так что бессмысленно тратить время на изучение и объяснение странностей архитектуры реального режима, которые заведомо никогда уже не появятся ни на одном процессоре.

    Читайте также:  Mikrotik capsman access list

    Что касается выбора операционной среды для изучения ассемблера, то, если говорить о 32-битной системе команд, выбор сравнительно невелик. Это либо операционные системы Windows, либо представители семейства UNIX.

    Также следует сказать несколько слов о том, какой именно ассемблер выбрать для той или другой операционной среды. Как известно, для работы с процессорами х86 используются два типа синтаксиса ассемблера — это синтаксис AT&T и синтаксис Intel. Эти синтаксисы представляют одни и те же команды совершенно по-разному. Например, команда в синтаксисе Intel выглядит так:

    В синтаксисе же AT&T уже будет иной вид:

    В среде ОС UNIX более популярен синтаксис типа AT&T, однако учебных пособий по нему нет, он описывается исключительно в справочной и технической литературе. Поэтому логично выбрать ассемблер на основе синтаксиса Intel. Для UNIX-систем есть два основных ассемблера — это NASM (Netwide Assembler) и FASM (Flat Assembler). Для линейки Windows популярностью пользуются FASM и MASM (Macro Assembler) от фирмы Microsoft, и также существовал еще TASM (Turbo Assembler) фирмы Borland, которая уже довольно давно отказалась от поддержки собственного детища.

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

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

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

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

    На заре компьютерной эры первые ЭВМ занимали целые комнаты и весили не одну тонну, имея объем памяти с воробьиный мозг, а то и того меньше. Единственным способом программирования в те времена было вбивать программу в память компьютера непосредственно в цифровом виде, переключая тумблеры, проводки и кнопочки. Число таких переключений могло достигать нескольких сотен и росло по мере усложнения программ. Встал вопрос об экономии времени и денег. Поэтому следующим шагом в развитии стало появление в конце сороковых годов прошлого века первого транслятора-ассемблера, позволяющего удобно и просто писать машинные команды на человеческом языке и в результате автоматизировать весь процесс программирования, упростить, ускорить разработку программ и их отладку. Затем появились языки высокого уровня и компиляторы (более интеллектуальные генераторы кода с более понятного человеку языка) и интерпретаторы (исполнители написанной человеком программы на лету). Они совершенствовались, совершенствовались — и, наконец, дошло до того, что можно просто программировать мышкой.

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

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

    Синтаксис

    Общепринятого стандарта для синтаксиса языков ассемблера не существует. Однако большинство разработчиков языков ассемблера придерживаются общих традиционных подходов. Основные такие стандарты — Intel-синтаксис и AT&T-синтаксис.

    Общий формат записи инструкций одинаков для обоих стандартов:

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

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

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

    Директивы

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

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

    Продолжение доступно только участникам

    Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

    Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

    Комментировать
    1 просмотров
    Комментариев нет, будьте первым кто его оставит

    Это интересно
    Adblock detector