На чем написан assembler
Что такое ассемблер и нужно ли его изучать
Этому языку уже за 70, но на пенсию он пока не собирается.
Полина Суворова для Skillbox Media
Есть традиция начинать изучение программирования с вывода на экран строки «Hello world!». На языке Python, например, это всего одна команда:
Всё просто, понятно и красиво! Но есть язык программирования, в котором, чтобы получить тот же результат, нужно написать солидный кусок кода:
Это ассемблер. Только не нужно думать, что он плох. Просто Python — это язык высокого уровня, а ассемблер — низкого. Одна команда Python при выполнении вызывает сразу несколько операций процессора, а каждая команда ассемблера — всего одну операцию.
Сложно? Давайте разбираться.
Программист, консультант, специалист по документированию. Легко и доступно рассказывает о сложных вещах в программировании и дизайне.
Немного о процессорах и машинном языке
Чтобы объяснить, что такое язык ассемблера, начнём с того, как вообще работает процессор и на каком языке с ним можно «разговаривать».
Процессор — это электронное устройство (сейчас крошечная микросхема, а раньше процессоры занимали целые залы), не понимающее слов и цифр. Он реагирует только на два уровня напряжения: высокий — единица, низкий — ноль. Поэтому каждая процессорная команда — это последовательность нулей и единиц: 1 — есть импульс, 0 — нет.
Для работы с процессором используется машинный язык. Он состоит из инструкций, записанных в двоичном коде. Каждая инструкция определяет одну простую машинную операцию: арифметическую над числами, логическую (поразрядную), ввода-вывода и так далее.
Например, для Intel 8088 инструкция 0000001111000011B — это операция сложения двух чисел, а 0010101111000011B — вычитания.
Программировать на машинном языке нелегко — приходится работать с огромными цепочками нулей и единиц. Трудно написать или проверить такую программу, а уж тем более разобраться в чужом коде.
Поэтому много лет назад был создан язык ассемблера, в котором коды операций обозначались буквами и сокращениями английских слов, отражающих суть команды. Например, команда mov ax, 6 означает: «переместить число 6 в ячейку памяти AX».
Когда и как был создан ассемблер?
Это произошло ещё в сороковых годах прошлого века. Ассемблер был создан для первых ЭВМ на электронных лампах, программы для которых писали на машинном языке. А так как памяти у компьютеров было мало, то команды вводили, переключая тумблеры и нажимая кнопки. Даже несложные вычисления занимали много времени.
Проблему решили, когда ЭВМ научились хранить программы в памяти. Уже в 1950 году была разработана первая программа-транслятор, которая переводила в машинный код программы, написанные на понятном человеку языке. Эту программу назвали программой-сборщиком, а язык — языком ассемблера (от англ. assembler — сборщик).
Появление ассемблера сильно облегчило жизнь программистов. Они смогли вместо двоичных кодов использовать команды, состоящие из близких к обычному языку условных обозначений. Кроме того, ассемблер позволил уменьшить размеры программ — для машин того времени это было важно.
Как устроен язык ассемблера?
Ассемблер можно считать языком второго поколения, если за первый принять машинный язык. Он работает непосредственно с процессором, и каждая его команда — это инструкция процессора, а не операционной или файловой системы. Перевод языка ассемблера в машинный код называется ассемблированием.
Коды операций в языке ассемблера мнемонические, то есть удобные для запоминания:
Регистрам и ячейкам памяти присваиваются символические имена, например:
EAX, EBX, AX, AH — имена для регистров;
meml — имя для ячейки памяти.
Например, так выглядит команда сложения чисел из регистров AX и BX:
А это команда вычитания чисел из регистров AX и BX:
Кроме инструкций, в языке ассемблера есть директивы — команды управления компилятором, то есть программой-ассемблером.
Вот некоторые из них:
Не думайте, что ассемблер — всего лишь набор инструкций процессора с удобной для программиста записью. Это полноценный язык программирования, на котором можно организовать циклы, условные переходы, процедуры и функции.
Вот, например, код, на ассемблере, выводящий на экран цифры от 1 до 10:
Здесь действие будет выполняться в цикле — как, например, в циклах for или do while в языках высокого уровня.
Единого стандарта для языков ассемблера нет. В работе с процессорами Intel разработчики придерживаются двух синтаксисов: Intel и AT&T. Ни у того ни у другого нет особых преимуществ: AT&T — стандартный синтаксис в Linux, а Intel используется в мире Microsoft.
Одна и та же команда в них выглядит по-разному.
Например, в синтаксисе Intel:
mov eax, ebx — команда перемещает данные из регистра eax в регистр ebx.
В синтаксисе AT&T эта команда выглядит так:
Почему для разных семейств процессоров нужен свой ассемблер?
Дело в том, что у каждого процессора есть набор характеристик — архитектура. Это его конструкция и принцип работы, а также регистры, адресация памяти и используемый набор команд. Если у процессоров одинаковая архитектура, то говорят, что они из одного семейства.
Так как наборы команд для разных архитектур процессоров отличаются друг от друга, то и программы на ассемблере, написанные для одних семейств, не будут работать на процессорах из других семейств. Поэтому ассемблер называют машинно-ориентированным языком.
Кому и зачем нужен язык ассемблера?
Даже из нашего примера «Hello, World!» видно, что ассемблер не так удобен в разработке, как языки высокого уровня. Больших программ на этом языке сейчас никто не пишет, но есть области, где он незаменим:
Если вы хотите разрабатывать новые микропроцессоры или стать реверс-инженером, то есть смысл серьёзно заняться изучением языка ассемблера.
Востребованы ли программисты на ассемблере сегодня?
Конечно. Хотя на сайтах по поиску работу вы вряд ли найдёте заявки от работодателей с заголовками: «Нужен программист на ассемблере», зато там много таких, где требуется знание ассемблера дополнительно к языкам высокого уровня: C, C++ или Python. Это вакансии реверс-инженеров, специалистов по компьютерной безопасности, разработчиков драйверов и программ для микроконтроллеров/микропроцессоров, системных программистов и другие.
Предлагаемая зарплата — обычная в сфере IT: 80–300 тысяч рублей в зависимости от квалификации и опыта. Вот, например, вакансия реверс-инженера на HeadHunter, где требуется знание ассемблера:
Стоит ли начинать изучение программирования с языка ассемблера?
Нет, так делать не нужно. Для этого есть несколько причин:
Поэтому, даже если вы решили заняться профессией, связанной с ассемблером, изучение программирования вам лучше начинать с языка высокого уровня. А уж ассемблер после него будет выучить несложно.
Микропроцессор, выпущенный компанией Intel в 1979 году. Использовался в оригинальных компьютерах IBM PC.
Данные, которые обрабатываются командой — грамматической конструкцией языка программирования, обозначающей аргумент операции.
Центральная часть операционной системы, координирующая доступ приложений к процессорному времени, памяти, внешним устройствам.
Программа, которая обеспечивает загрузку самой OC сразу после включения компьютера.
Уверены, что отличите ассемблер от других языков?
Немногие смело признают, что могут ошибиться в идентификации ассемблера, ведь это по-своему особенный язык. Однако не спешите с выводами, а лучше пройдите небольшой тест, который не просто позволит взгляуть на него в ином свете, но и проверит вашу осведомленность в этой сфере.
Программирование на ассемблере сегодня в лучшем случае занимает нишевое положение и чаще воспринимается как неоправданно педантичное, требовательное и затратное даже для своей ниши.
Ассемблер непрост. Он недружелюбен. Программирование на этом языке происходит медленно и зачастую сопряжено с ошибками — таково общепринятое мнение.
К сожалению, в современной цифровой среде исходит это мнение от людей, которые, как правило, плохо представляют, как реально выглядят современные языки ассемблера. Этот стиль программирования не застрял в 50-х, он развивался вместе с высокоуровневыми языками, вбирая в себя структурные, функциональные и объектно-ориентированные элементы. Он отлично дружит с современными API и DOM. Конечно же, принципиально это низкоуровневый язык, но вы можете с тем же успехом создавать поверх него и высокоуровневые абстракции.
Честно говоря, я даже не уверен, что кто-нибудь сможет легко отличить код ассемблера от какого-нибудь высокоуровневого кода без помощи гугла. Вот вы сможете?
1. GUI
Ниже приведен фрагмент кода. Он создает окно с WinAPI и запускает для него цикл обработки сообщений.
Прошу вас, ознакомьтесь с ним и ответьте, написан ли он на одном из видов ассемблера или же на высокоуровневом языке?
2. Библиотеки
Ниже дан пример функциональной библиотеки. Функция “add” просто складывает два целых числа и возвращает их сумму.
3. Алгоритмы
Это реализация алгоритма TPK. Она содержит функцию, несколько циклов, массив и инструкцию вывода в консоль.
Это не ассемблер. Перед вами разработка Алика Гленни — AUTOCODE– один из первых высокоуровневых языков.
источник: The Early Development Of Programming Languages by Donald E. Knuth, Luis Trabb Pardo, 1976.
Кстати, TPK означает «Typical Pardo Knuth» (типичный Пардо Кнут, от имени его создателя) Это не настоящий алгоритм, и создавался он для демонстрации нескольких языков в одном примере.
4. Структурное программирование
Вот пример вычисления суперскалярной суммы.
5. Еще структурное программирование
Это решение задачи о восьми ферзях с выводом в консоль. Его платформенная зависимость минимальна, но при этом оно не обогащено высокоуровневыми возможностями вроде классов, шаблонов или встроенных контейнеров.
6. ООП (с классами и методами)
7. ООП (с объектами и сообщениями)
Это пример TCP-сервера. В нем есть объекты и методы, а работает он в собственной среде.
Заключение
Современное программирование на ассемблере не обязательно связано с инструкциями процессора и регистрами. Да, код всегда начинается с низов, но его можно оснастить функциями, классами и макросами, сделав до нужной степени высокоуровневым.
Программировать на этом языке не всегда трудно, и он не всегда оказывается чрезмерно педантичен. Просто каждому нужно подобрать подходящий для работы уровень.
Национальная библиотека им. Н. Э. Баумана
Bauman National Library
Персональные инструменты
Ассемблер
Ассе́мблер (от англ. assembler — сборщик) — транслятор исходного текста программы, написанной на языке ассемблера, в программу на машинном языке.
Как и сам язык, ассемблеры, как правило, специфичны для конкретной архитектуры, операционной системы и варианта синтаксиса языка. Вместе с тем существуют мультиплатформенные или вовсе универсальные (точнее, ограниченно-универсальные, потому что на языке низкого уровня нельзя написать аппаратно-независимые программы) ассемблеры, которые могут работать на разных платформах и операционных системах. Среди последних можно также выделить группу кросс-ассемблеров, способных собирать машинный код и исполняемые модули (файлы) для других архитектур и операционных систем.
Ассемблирование может быть не первым и не последним этапом на пути получения исполнимого модуля программы. Так, многие компиляторы с языков программирования высокого уровня выдают результат в виде программы на языке ассемблера, которую в дальнейшем обрабатывает ассемблер. Также результатом ассемблирования может быть не исполняемый, а объектный модуль, содержащий разрозненные блоки машинного кода и данных программы, из которого (или из нескольких объектных модулей) в дальнейшем с помощью редактора связей может быть получен исполнимый файл.
Содержание
История
Когда компьютеры были большими как динозавры, а объем мозгов у них был примерно такой же, как у этих рептилий, и даже меньше, единственным способом программирования было забивание программы в память ЭВМ непосредственно в цифровом виде (иногда даже с помощью щелканья переключателями). Затем человек начал совершенствовать эту технику, постепенно перекладывая труд по генерации кода на плечи самой машины. Ибо заставлять высококвалифицированного человека перебирать биты и помнить кучу шестнадцатеричных (а то и восьмеричных) кодов обходится весьма дорого, как в деньгах, так и во времени.
В целом история языков программирования протекает в направлении от программирования на языке компьютера до манипуляции абстракциями вроде Послать.Лесом(всех(кому не нравится эта статья)) Ну или (послать (лесом (всех (кому-не-нравится «эта-статья»)))) или
На языке ассемблера этот код занял бы более 9000 строк. И потребовал бы долгой и кропотливой работы по своему созданию.
Область применения
Ассемблирование и компилирование
Процесс трансляции программы на языке ассемблера в объектный код принято называть ассемблированием. В отличие от компилирования, ассемблирование — более или менее однозначный и обратимый процесс. В языке ассемблера каждой мнемонике соответствует одна машинная инструкция, в то время как в языках программирования высокого уровня за каждым выражением может скрываться большое количество различных инструкций. В принципе, это деление достаточно условно, поэтому иногда трансляцию ассемблерных программ также называют компиляцией.
Дизассемблер
Дизассе́мблер — транслятор, преобразующий машинный код, объектный файл или библиотечные модули в текст программы на языке ассемблера.
По режиму работы с пользователем делятся на
Архитектуры
Под каждую архитектуру процессора и под каждую ОС или семейство ОС существует свой Ассемблер. Существуют также так называемые «кросс-ассемблеры», позволяющие на машинах с одной архитектурой (или в среде одной ОС) ассемблировать программы для другой целевой архитектуры или другой ОС, и получать исполняемый код в формате, пригодном к исполнению на целевой архитектуре или в среде целевой ОС.
Язык ассемблера
Assembler — язык программирования низкого уровня, представляющий собой формат записи машинных команд, удобный для восприятия человеком.
Команды языка ассемблера один в один соответствуют командам процессора и, фактически, представляют собой удобную символьную форму записи (мнемокод) команд и их аргументов. Также язык ассемблера обеспечивает базовые программные абстракции: связывание частей программы и данных через метки с символьными именами и директивы.
Директивы ассемблера позволяют включать в программу блоки данных (описанные явно или считанные из файла); повторить определённый фрагмент указанное число раз; компилировать фрагмент по условию; задавать адрес исполнения фрагмента, менять значения меток в процессе компиляции; использовать макроопределения с параметрами и др.
Каждая модель процессора, в принципе, имеет свой набор команд и соответствующий ему язык (или диалект) ассемблера.
Достоинства и недостатки
Синтаксис
Общепринятого стандарта для синтаксиса языков ассемблера не существует. Однако, существуют стандарты де-факто — традиционные подходы, которых придерживаются большинство разработчиков языков ассемблера. Основными такими стандартами являются Intel-синтаксис и AT&T-синтаксис.
Общий формат записи инструкций одинаков для обоих стандартов:
`[метка:] опкод [операнды] [;комментарий]`
Опкод — непосредственно мнемоника инструкции процессору. К ней могут быть добавлены префиксы (повторения, изменения типа адресации и пр.). В качестве операндов могут выступать константы, названия регистров, адреса в оперативной памяти и пр.. Различия между стандартами Intel и AT&T касаются, в основном, порядка перечисления операндов и их синтаксиса при различных методах адресации.
Кроме инструкций, программа может содержать директивы: команды, не переводящиеся непосредственно в машинные инструкции, а управляющие работой компилятора. Набор и синтаксис их значительно разнятся и зависят не от аппаратной платформы, а от используемого компилятора (порождая диалекты языков в пределах одного семейства архитектур). В качестве набора директив можно выделить:
Как писать на ассемблере в 2018 году
Статья посвящена языку ассемблер с учетом актуальных реалий. Представлены преимущества и отличия от ЯВУ, произведено небольшое сравнение компиляторов, скрупулёзно собрано значительное количество лучшей тематической литературы.
1. Язык. Преимущества и отличия от ЯВУ
Ассемблер (Assembly) — язык программирования, понятия которого отражают архитектуру электронно-вычислительной машины. Язык ассемблера — символьная форма записи машинного кода, использование которого упрощает написание машинных программ. Для одной и той же ЭВМ могут быть разработаны разные языки ассемблера. В отличие от языков высокого уровня абстракции, в котором многие проблемы реализации алгоритмов скрыты от разработчиков, язык ассемблера тесно связан с системой команд микропроцессора. Для идеального микропроцессора, у которого система команд точно соответствует языку программирования, ассемблер вырабатывает по одному машинному коду на каждый оператор языка. На практике для реальных микропроцессоров может потребоваться несколько машинных команд для реализации одного оператора языка.
Язык ассемблера обеспечивает доступ к регистрам, указание методов адресации и описание операций в терминах команд процессора. Язык ассемблера может содержать средства более высокого уровня абстракции: встроенные и определяемые макрокоманды, соответствующие нескольким машинным командам, автоматический выбор команды в зависимости от типов операндов, средства описания структур данных. Главное достоинство языка ассемблера — «приближенность» к процессору, который является основой используемого программистом компьютера, а главным неудобством — слишком мелкое деление типовых операций, которое большинством пользователей воспринимается с трудом. Однако язык ассемблера в значительно большей степени отражает само функционирование компьютера, чем все остальные языки.
И хотя драйвера и операционные системы сейчас пишут на Си, но Си при всех его достоинствах — язык высокого уровня абстракции, скрывающий от программиста различные тонкости и нюансы железа, а ассемблер — язык низкого уровня абстракции, прямо отражающий все эти тонкости и нюансы.
Для успешного использования ассемблера необходимы сразу три вещи:
Оптимальной можно считать программу, которая работает правильно, по возможности быстро и занимает, возможно, малый объем памяти. Кроме того, ее легко читать и понимать; ее легко изменить; ее создание требует мало времени и незначительных расходов. В идеале язык ассемблера должен обладать совокупностью характеристик, которые бы позволяли получать программы, удовлетворяющие как можно большему числу перечисленных качеств.
На языке ассемблера пишут программы или их фрагменты в тех случаях, когда критически важны:
Языки программирования высокого уровня абстракции разрабатывались с целью возможно большего приближения способа записи программ к привычным для пользователей компьютеров тех или иных форм записи, в частности математических выражений, а также чтобы не учитывать в программах специфические технические особенности отдельных компьютеров. Язык ассемблера разрабатывается с учетом специфики процессора, поэтому для грамотного написания программы на языке ассемблера требуется, в общем, знать архитектуру процессора используемого компьютера. Однако, имея в виду преимущественное распространение PC-совместимых персональных компьютеров и готовые пакеты программного обеспечения для них, об этом можно не задумываться, поскольку подобные заботы берут на себя фирмы-разработчики специализированного и универсального программного обеспечения.
2. О компиляторах
Какой ассемблер лучше?
Для процессора x86-x64, имеется более десятка различных ассемблер компиляторов. Они отличаются различными наборами функций и синтаксисом. Некоторые компиляторы больше подходят для начинающих, некоторые ― для опытных программистов. Некоторые компиляторы достаточно хорошо документированы, другие вообще не имеют документации. Для некоторых компиляторов разработано множеством примеров программирования. Для некоторых ассемблеров написаны учебные пособия и книги, в которых подробно рассматривается синтаксис, у других нет ничего. Какой ассемблер лучше?
Учитывая множество диалектов ассемблеров для x86-x64 и ограниченное количество времени для их изучения, ограничимся кратким обзором следующих компиляторов: MASM, TASM, NASM, FASM, GoASM, Gas, RosAsm, HLA.
Какую операционную систему вы бы хотели использовать?
Это вопрос, на который вы должны ответить в первую очередь. Самый многофункциональный ассемблер не принесет вам никакой пользы, если он не предназначен для работы под ту операционную систему, которую вы планируете использовать.
Windows | DOS | Linux | BSD | QNX | MacOS, работающий на процессоре Intel/AMD | |
---|---|---|---|---|---|---|
FASM | x | x | x | x | ||
GAS | x | x | x | x | x | x |
GoAsm | x | |||||
HLA | x | x | ||||
MASM | x | x | ||||
NASM | x | x | x | x | x | x |
RosAsm | x | |||||
TASM | x | x |
Поддержка 16 бит
Если ассемблер поддерживает DOS, то он поддерживает и 16-разрядные команды. Все ассемблеры предоставляют возможность писать код, который использует 16-разрядные операнды. 16-разрядная поддержка означает возможность создания кода, работающего в 16-разрядной сегментированной модели памяти (по сравнению с 32-разрядной моделью с плоской памятью, используемой большинством современных операционных систем).
Поддержка 64 бит
За исключением TASM, к которому фирма Borland охладела в середине нулевых, и, который не поддерживает в полном объеме даже 32-разрядные программы, все остальные диалекты поддерживают разработку 64-разрядных приложений.
Переносимость программ
Очевидно, что вы не собираетесь писать код на ассемблере x86-x64, который запускался бы на каком-то другом процессоре. Однако, даже на одном процессоре вы можете столкнуться с проблемами переносимости. Например, если вы предполагаете компилировать и использовать свои программы на ассемблере под разными операционными системами. NASM и FASM можно использовать в тех операционных системах, которые они поддерживают.
Предполагаете ли вы писать приложение на ассемблере и затем портировать, это приложение с одной ОС на другую с «перекомпиляцией» исходного кода? Эту функцию поддерживает диалект HLA. Предполагаете ли вы иметь возможность создавать приложения Windows и Linux на ассемблере с минимальными усилиями для этого? Хотя, если вы работаете с одной операционной системой и абсолютно не планируете работать в какой-либо другой ОС, тогда эта проблема вас не касается.
Поддержка высокоуровневых языковых конструкций
Некоторые ассемблеры предоставляют расширенный синтаксис, который обеспечивает языковые высокоуровневые структуры управления (типа IF, WHILE, FOR и так далее). Такие конструкции могут облегчить обучение ассемблеру и помогают написать более читаемый код. В некоторые ассемблеры встроены «высокоуровневые конструкции» с ограниченными возможностями. Другие предоставляют высокоуровневые конструкции на уровне макросов.
Никакой ассемблер не заставляет вас использовать какие-либо структуры управления или типы данных высокого уровня, если вы предпочитаете работать на уровне кодировки машинных команд. Высокоуровневые конструкции ― это расширение базового машинного языка, которое вы можете использовать, если найдете их удобными.
Качество документации
Удобство использования ассемблера напрямую связано с качеством его документации. Учитывая объем работы, который тратится для создания диалекта ассемблера, созданием документации для этого диалекта авторы компиляторов практически не заморачиваются. Авторы, расширяя свой язык, забывают документировать эти расширения.
В следующей таблице описывается качество справочного руководства ассемблера, которое прилагается к продукту:
Учебники и учебные материалы
Документация на самом ассемблере, конечно, очень важна. Еще больший интерес для новичков и других, изучающих язык ассемблера (или дополнительные возможности данного ассемблера), ― это наличие документации за пределами справочного руководства для языка. Большинство людей хотят, чтобы учебник, объясняющий, как программировать на ассемблере, не просто предоставляет синтаксис машинных инструкций и ожидает, что читателю объяснят, как объединять эти инструкции для решения реальных проблем.
MASM является лидером среди огромного объема книг, описывающих, как программировать на этом диалекте. Есть десятки книг, которые используют MASM в качестве своего ассемблера для обучения ассемблеру.
Большинство учебников по ассемблеру MASM/TASM продолжают обучать программированию под MS-DOS. Хотя постепенно появляются учебники, которые обучают программированию в Windows и Linux.
3. Литература и веб ресурсы
Beginners
Advanced
4. Практика
Итак, вы уже знаете, что такое ассемблер и с чем его едят. Вы запаслись парой/тройкой книг и веб мануалами, возможно определились и с компилятором… К сожалению уроки программирования выходят за рамки данной статьи, но для тех чей выбор пал на MASM/FASM можете воспользоваться следующими макетами:
Желаем вам, друзья, значительных достижений и новых знаний в 2018 году!
С уважением
Михаил Смоленцев MiklIrk (Иркутский государственный университет путей сообщения),
Алексей Гриценко expressrus (Донской государственный технический университет).
Ps1: Уважаемый, Хабрахабр! Добавьте в ваш редактор подсветку ассемблера (Intel-синтаксис), это пригодится для будущих статей!