assembler для чего используется

Что такое ассемблер и нужно ли его изучать

Этому языку уже за 70, но на пенсию он пока не собирается.

Есть традиция начинать изучение программирования с вывода на экран строки «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. Это вакансии реверс-инженеров, специалистов по компьютерной безопасности, разработчиков драйверов и программ для микроконтроллеров/микропроцессоров, системных программистов и другие.

Читайте также:  djvu reader чем открыть

Предлагаемая зарплата — обычная в сфере IT: 80–300 тысяч рублей в зависимости от квалификации и опыта. Вот, например, вакансия реверс-инженера на HeadHunter, где требуется знание ассемблера:

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

Нет, так делать не нужно. Для этого есть несколько причин:

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

обложка: Полина Суворова для Skillbox Media

Микропроцессор, выпущенный компанией Intel в 1979 году. Использовался в оригинальных компьютерах IBM PC.

Данные, которые обрабатываются командой — грамматической конструкцией языка программирования, обозначающей аргумент операции.

Центральная часть операционной системы, координирующая доступ приложений к процессорному времени, памяти, внешним устройствам.

Программа, которая обеспечивает загрузку самой OC сразу после включения компьютера.

Источник

За что я люблю ассемблер?

Этой статье уже почти 3 года. Однако сегодня я решил подредактировать её, дополнить и выложить, наконец, на Хабр.

Оговорочки

Хочу сразу оговориться, что правильно говорить не «ассемблер» (assembler), а «язык ассемблера» (assembly language), потому как ассемблер – это транслятор кода на языке ассемблера (т.е. по сути, программа MASM, TASM, fasm, NASM, UASM, GAS и пр., которая компилирует исходный текст на языке ассемблера в объектный или исполняемый файл). Тем не менее, из соображения краткости многие, говоря «ассемблер» (асм, asm), подразумевают именно «язык ассемблера».

Синтаксис директив, стандартных макросов и пр. структурных элементов различных диалектов (к примеру, MASM, fasm, NASM, GAS), могут отличаться довольно существенно. Мнемоники (имена) инструкций (команд) и регистров, а также синтаксис их написания для одного и того же процессора примерно одинаковы почти во всех диалектах (заметным исключением среди популярных ассемблеров является разве что GAS (GNU Assembler) в режиме синтаксиса AT&T для x86, где к именам инструкций могут добавляться суффиксы, обозначающие размер обрабатываемых ими данных, что бывает довольно удобно, но там есть и другие нюансы, сбивающие с толку программиста, привыкшего к классическому ассемблеру, к примеру, иной порядок указания операндов, хотя всё это лечится специальной директивой переключения в режим классического синтаксиса Intel).

Поскольку ассемблер – самый низкоуровневый язык программирования, довольно проблематично написать код, который корректно компилировался бы для разных архитектур процессоров (например, x86 и ARM), для разных режимов одного и того же процессора (16-битный реальный режим, 32-битный защищённый режим, 64-битный long mode; а ещё код может быть написан как с использованием различных технологий вроде SSE, AVX, FMA, BMI и AES-NI, так и без них) и для разных операционных систем (Windows, Linux, MS-DOS). Хоть иногда и можно встретить «универсальный» код (например, отдельные библиотеки), скажем, для 32- и 64-битного кода ОС Windows (или даже для Windows и Linux), но это бывает нечасто. Ведь каждая строка кода на ассемблере (не считая управляющих директив, макросов и тому подобного) – это отдельная инструкция, которая пишется для конкретного процессора и ОС, и сделать кроссплатформенный вариант можно только с помощью макросов и условных директив препроцессора, получая в итоге порой весьма нетривиальные конструкции, сложные для понимания.

Откуда растут ноги?

Ассемблером я увлёкся лет в 12–13, и он меня изрядно «затянул». Почему?

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

Во-вторых (и это более существенно), на ассемблере можно было делать много того, что сделать на языках высокого уровня (ЯВУ, не путайте с Java) нельзя, затруднительно или не так эффективно. К примеру, мне очень нравилось писать резидентные программы.

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

Вон оно что!

Приведу свои доводы относительно того, чем так хорош ассемблер.

Ассемблер даёт полный контроль над кодом и обладает большей гибкостью, чем любой другой язык программирования (даже C/C++). На асме мы можем конструировать нашу программу, размещая блоки кода и данных как нам вздумается. Каждый генерируемый байт будет таким, каким мы хотим его видеть. Без лишнего runtime-кода стандартных библиотек. Правда, справедливости ради отмечу, что необходимость в этом может возникнуть лишь в весьма специфических случаях. Однако существуют аппаратные платформы с ограниченными ресурсами, где оптимизация кода важна и актуальна и в наши дни.

На ассемблере можно написать ВСЁ, он всемогущ! Вряд ли у вас получится создать MBR-загрузчик полностью на C или на чём-то ещё. Для работы с железом на низком уровне, программирования чипсетов зачастую может потребоваться ассемблер. Для внедрения кода в другие процессы (injection, не только с вредоносными целями), создания различных антиотладочных приёмов тоже необходим ассемблер. Или, скажем, для проделывания чего-то вроде этого. Для C/C++ имеются интринсики – функции для генерации отдельных инструкций процессора (есть ли что-то подобное для других языков программирования – не знаю, не встречал). Но их частое использование загромождает код (не проще ли тогда писать на чистом ассемблере?) А их отсутствие не позволяет нам контролировать генерируемый компилятором код (при этом, к слову говоря, Visual C/C++, GNU C/C++ и Clang будут генерировать разный код; и даже один и тот же компилятор с разными настройками выдаст различный результат).

Читайте также:  ddr 400 что это

Обычно одна строка кода на ЯВУ разворачивается в несколько (или даже десяток) инструкций процессора. А знаете ли вы о том, что некоторые инструкции процессора Intel требуют несколько строк для реализации на ЯВУ (на том же C/C++, если не использовать интринсики)? Если не знаете, просто поверьте на слово, а я, возможно, напишу об этом в одной из следующих статей. Приведу лишь один простой пример: аналоги инструкций rol, ror (существующих ещё в самых ранних процессорах i8086 с конца 70-х годов) появились только в стандарте C++20 в библиотеке bit (как функции std::rotl, std::rotr), а в большинстве других языков они вообще отсутствуют.

Есть такое направление компьютерного искусства: демосцена. Написать intro, уместив исполняемый файл в 256 байт [1, 2, 3, 4] (а то и 128, 64, 32 или даже ещё меньше) на чём-то отличном от ассемблера (ну или по крайней мере, без использования ассемблера для финальной корректировки кода) вы вряд ли сможете.

Ещё одна интересная область применения ассемблера – создание файлов данных с помощью макросов и директив генерации данных. К примеру, fasm позволяет создавать виртуальные данные и генерировать отдельные файлы (директива virtual), а также читать и изменять ранее сгенерированный код (директивы load, store). Есть даже примеры AES-шифрования файлов.

Без ассемблера не обойтись при исследовании (reverse engineering), а зачастую и при отладке программ.

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

На том же C/C++ можно написать практически всё, что можно написать и на ассемблере, причём сразу под десяток платформ и ОС, включая и выключая отдельными опциями компилятора использование различных наборов инструкций, векторизацию, оптимизацию и пр.

Но иногда использование ассемблера действительно оправдано (пример). Часто ассемблер хорошо использовать в виде вставок в код на ЯВУ (посмотрите RTL-модули Delphi, там этого добра в изобилии). Да и использование интринсиков, как правило, не имеет смысла (или даже опасно) без знания ассемблера.

Подытожим…

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

Создание загрузчиков, прошивок устройств (комплектующих ПК, встраиваемых систем), элементов ядра ОС.

Низкоуровневая работа с железом, в т.ч. с процессором, памятью.

Внедрение кода в процессы (injection), как с вредоносной целью, так и с целью защиты или добавления функционала. Системный софт.

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

Оптимизация кода по скорости, в т.ч. векторизация (SSE, AVX, FMA), математические вычисления, обработка мультимедиа, копирование памяти.

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

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

При создании компиляторов и трансляторов исходного кода с какого-либо языка на язык ассемблера (например, многие компиляторы C/C++ позволяют выполнять такую трансляцию). При создании отладчиков, дизассемблеров.

Собственно, отладка, дизассемблирование, исследование программ (reverse engineering).

Создание файлов данных с помощью макросов и директив генерации данных.

Вы не поверите, но ассемблер можно использовать и для написания обычного прикладного ПО (консольного или с графическим интерфейсом – GUI), игр, драйверов и библиотек 🙂

Быть или не быть?

Так, нужно ли изучать ассемблер современному программисту? Если вы уже не новичок в программировании, и у вас серьёзные амбиции, то изучение ассемблера, внутреннего устройства операционных систем и функционирования железа (особенно процессоров, памяти), а также использование различных инструментов для дизассемблирования, отладки и анализа кода полезно тем, кто хочет писать действительно эффективные программы. Иначе будет сложно в полной мере понять, что происходит «под капотом» любимого компилятора (хотя бы в общих чертах), как оптимизировать программы на любом языке программирования и какой приём стоит предпочесть. Необязательно погружаться слишком глубоко в эту тему, если вы пишете на Python или JavaScript. А вот если ваш язык – C или C++, хорошенько изучить ассемблер будет полезно.

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

Это будет полезно

Если вы решили изучить ассемблер и окунуться в низкоуровневое программирование, вам будет полезна следующая литература:

Зубков С.В. Assembler для DOS, Windows и Unix. – ДМК Пресс, 2017. – 638 c., ISBN 978–5–97060–535–6.

Читайте также:  судовая роль что это

Руслан Аблязов. Программирование на ассемблере на платформе x86–64. – ДМК Пресс, 2016. – 302 с., ISBN 978–5–97060–364–2.

Статьи старого WASM’а – кладезь обучающего материала на самые разные низкоуровневые темы (крайне рекомендую!)
Новый WASM (форум по низкоуровневому программированию и сборник статей).

Книги и статьи Криса Касперски (много).

Официальная документация AMD (множество документов) [всё на английском, PDF].

Архитектура и система команд микропроцессоров x86 (староватая документация на русском языке; из описания расширений есть только x87, MMX, 3DNow! и SSE(1)).

Марк Руссинович, Дэвид Соломон, Алекс Ионеску. Внутреннее устройство Microsoft Windows. – 6-е изд., часть 1. – Питер, 2013. – 800 с., ISBN 978–5–496–00434–3, 978–5–459–01730–4 (англ.: 978–0735648739).
Вышло 7-е издание этой части с Павлом Йосифовичем в качестве ещё одного соавтора – Питер, 2018 – 944 с., ISBN 978–5–4461–0663–9 (англ.: 978–3864905384).

Марк Руссинович, Дэвид Соломон, Алекс Ионеску. Внутреннее устройство Microsoft Windows. Основные подсистемы ОС. – 6-е изд., часть 2. – Питер, 2014. – 672 с., ISBN 978–5–496–00791–7 (англ.: 978–0735665873).
7-е издание этой части есть пока только на английском языке (ISBN 978–0135462409).

Джеффри Рихтер. Windows для профессионалов. Создание эффективных Win32-приложений с учётом специфики 64-разрядной версии Windows. – 4-е изд. – Питер, Русская редакция, 2001. – 752 с. (есть вариант книги 2008 г. на 720 с., но она тоже 4-го издания, с переводом 2000 года… в чём разница?), ISBN 5–272–00384–5, 978–5–7502–0360–4 (англ.: 1–57231–996–8).

Джеффри Рихтер, Кристоф Назар. Windows via C&C++. Программирование на языке Visual C++ – 5-е изд. – Питер, 2009 – 896 с., ISBN 978–5–388–00205–1, 978–5–7502–0367–3, 978–0–7356–2424–5 (англ.: 978–0735624245).

Павел Йосифович. Работа с ядром Windows. – Питер, 2021 – 400 c., ISBN 978–5–4461–1680–5 (англ.: 978-1977593375).

Pavel Yosifovich. Windows 10 System Programming, Part 1 – 2020, ISBN 979-8634170381 [англ].

Михаил Гук. Аппаратные средства IBM PC. Энциклопедия. – 3-е изд. – Питер, 2008. – 1072 с., ISBN 978–5–46901–182–8 (2001 г. – 816 с., ISBN 5–88782–290–2).

Владимир Кулаков. Программирование на аппаратном уровне. Специальный справочник (+ дискета). – 2-е изд. – Питер, 2003. – 848 с., ISBN 5–94723–487–4.

Всеволод Несвижский. Программирование аппаратных средств в Windows (+ CD-ROM). – 2-е изд. – БХВ-Петербург, 2008. – 528 с., ISBN 978–5–9775–0263–4.

Компиляторы и инструменты:

MASM32 (Macro Assembler) – наверное, самый популярный пакет самого популярного ассемблера.
MASM64 includes and libs – заголовки и библиотеки для 64-битной версии MASM (информация); файлы ml64.exe, link.exe и прочие потроха можно взять из Visual Studio (путь к папке с нужными файлами примерно такой: C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.12.25827\bin\Hostx64\x64\).

fasm (flat assembler) – современный и удобный компилятор под DOS, Wndows, Linux с очень развитой системой макросов и полным набором инструкций Intel/AMD. Рекомендую в качестве основного!
Там же можно скачать и fasmg (flat assembler g) – универсальный ассемблер под любую платформу (имеются include-модули для создания кода под AVR, i8051, x86/x64, генерации байт-кода JVM, аналогично можно создать свои модули).

NASM (Netwide Assembler) – ещё один современный кроссплатформенный компилятор с хорошей макросистемой и полным набором инструкций Intel/AMD, популярен в зарубежных проектах и при программировании под Linux/BSD.
NASMX – пакет макросов, include’ов, примеров и утилит для NASM под Windows, Linux, BSD, Xbox; включает макрос invoke, символы для работы с OpenGL и пр.

UASM (он же HJWasm) – современный MASM-совместимый мультиплатформенный ассемблер с полным набором инструкций Intel/AMD.

TASM 5.x (Turbo Assembler) – старый, но всё ещё популярный ассемблер, в основном используется для создания программ под DOS.

ALINK, GoLink – компоновщики для программ под DOS и Windows.

objconv – преобразователь форматов объектных файлов (COFF/OMF/ELF/Mach-O).

ResEd – бесплатный редактор ресурсов.

GoRC – компилятор ресурсов (rc → res) [в вышеупомянутом NASMX есть и GoLink, и objconv, и GoRC].

Windows 10 Software Development Kit (SDK) – заголовочные файлы, библиотеки, инструменты (в том числе отладчик WinDbg) для разработчиков Windows.

Fresh IDE – визуальная среда разработки для fasm.

SASM – простая кроссплатформенная среда разработки для NASM, MASM, GAS, fasm с подсветкой синтаксиса и отладчиком (для NASM имеется набор макросов для упрощения работы с консолью).

OllyDbg – популярный 32-битный отладчик (готовится 64-битная версия, но пока ещё не вышла).

x64dbg – хороший отладчик для 32- и 64-битного кода.

IDA Pro – мощный интерактивный дизассемблер (shareware).

VMware Workstation Player – мощный виртуализатор, позволяющий создавать и запускать виртуальные машины (бесплатный для персонального использования).

Oracle VirtualBox – альтернативный бесплатный виртуализатор.

Bochs – эмулятор компьютера IBM PC.

QEMU – эмулятор аппаратного обеспечения различных платформ (QEMU Manager).

Intel Software Development Emulator (SDE) – эмулятор расширений (инструкций) процессоров Intel.

DOSBox – очень популярный эмулятор компьютера для запуска программ под DOS (имеет встроенный замедлитель скорости).

Hiew – редактор двоичных файлов со встроенным дизассемблером, просмотром и редактированием заголовков исполняемых файлов (shareware).

PE Explorer – редактор секций, ресурсов PE, дизассемблер (shareware).

Windows Sysinternals – набор системных утилит для Windows (работа с процессами, мониторы и прочее).

ReactOS – бесплатная Windows-совместимая операционная система с открытым исходным кодом.

KolibriOS – миниатюрная ОС, умещающаяся на дискету 1.44 Mb, с исходниками на fasm.

Все эти ссылки (а также множество других, которые не вошли в эту статью) вы можете найти, кликнув сюда.

Также хочу пригласить вас в наш уютный «ламповый» раздел Assembler Форума на Исходниках.Ру 😉

Кто интересуется демосценой и сайзкодингом, welcome here.

Источник

Сказочный портал