Что такое ассемблер: где используется и актуален ли этот язык программирования в 2023 году
Оглавление:
Язык ассемблера (от англ. assembly language) — это императивный язык низкого уровня, который используется для представления команд CPU. При этом команды процессора остаются читабельными для программиста. Под термином "ассемблер" также может подразумеваться ПО, которое преобразует соответствующий исходный код в машинный код. Обратный процесс (конвертация машинного кода в ассемблер-код) выполняет дизассемблер.
Простыми словами, язык ассемблера — это низкоуровневый язык, позволяющий программисту обращаться непосредственно к процессору машины.
Схема функционирования
Как работает язык ассемблера
Это самый низкоуровневый человекочитаемый язык программирования. Сегодня он используется для точного управления процессором и памятью на «голом» железе. Важно отметить: нет единого языка ассемблера. Существует множество таких языков.
Языки разнятся в зависимости от архитектуры, на которой функционирует машина (например, x86, x32, ARM или PowerPC).
Assembly language позволяет работать с читаемым машинным байт-кодом, который выполняется компьютером напрямую.
Оригинальный assembly language для Motorola MC6800
Процессор и память
Компьютеры состоят из множества аппаратных средств. Самым важным из них является процессор (CPU), который способен выполнять вычисления. Процессор состоит из множества компонентов, например, схем для выполнения основных математических операций (ALU и FPU) и регистров. Регистры можно представить как небольшие ячейки, в которых хранится горстка небольших чисел.
Представление программной модели CPU
Помимо процессора, компьютер имеет и другие компоненты, такие как память (ОЗУ) и устройства ввода-вывода (такие как мышь, клавиатура, монитор и динамики). Для работы с этим оборудованием мы также можем использовать язык ассемблера.
Плашки оперативной памяти DDR4
Проблема в том, что процессор не понимает ассемблер. Слова и буквы типа "mov eax, 5" — ничего не значат для него. CPU понимает только двоичные числа, которые показывают ему то, что он должен делать со своим оборудованием. Это и есть машинный код. И у процессоров разных производителей свой набор таких чисел и команд.
Как это работает
Представьте, что у нас простой компьютер: он считывает три числа за один раз и далее решает, что делать. Первое прочитанное число — может сказать процессору, какую команду нужно выполнить. Например,
- 0 — сложить два числа вместе, используя аппаратное обеспечение ALU.
- 1 — поместить некоторое постоянное число в регистр.
- 2 — выполнить следующую команду, только если определенный регистр имеет определенное значение.
- 3 — заставить динамики воспроизвести звуковой сигнал.
- ... и так далее.
Следующие два числа, которые считывает компьютер, могут сообщить ему аргументы команды. Например, когда он видит число 0, которое означает «сложить два числа», следующие два числа могут означать, какие именно два регистра компьютер должен сложить. Помните, регистры — это просто маленькие ячейки, в которых хранятся числа. Например:
0 [команда] 3 [первый аргумент] 1 [второй аргумент] — добавить число в регистре №3 к числу в регистре №1 и поместить ответ в специальный регистр №0
Мы, как создатели компьютера, просто решили, что при сложении — результат попадает в регистр №0 (нам так захотелось).
Запоминание того, какое число что делает — может надоесть, а программа, представляющая собой просто набор чисел — станет очень запутанной. Вместо этого — мы можем создать код на языке ассемблера, который поможет убить всех зайцев сразу. В нашем языке не будут использоваться только нули и единицы, а будут также команды add (добавить) и put (поместить). Например, так:
- add 3 1 = 0 3 1 (сложить регистры 3 и 1).
- put 7 3 = 1 7 3 (поместить число 7 в регистр 3).
- check 4 5 = 2 4 5 (проверить, что регистр 4 равен 5, и только в этом случае запустить следующую строку).
- beep = 3 0 0 — воспроизвести звуковой сигнал. Обратите внимание, что мы не используем вторые два числа: на ассемблере мы можем просто написать "beep". Всё!
Итак, у нас есть слова, соответствующие имеющимся командам. Затем мы используем программу, называемую ассемблером — она читает слова, написанные программистом на языке ассемблера, и преобразует их в числа машинного кода. Позже, программы обязательно станут еще более сложными и захочется писать на еще более читабельном языке. Тут и появится компилятор: он берет более сложный язык программирования и преобразует его в код на языке ассемблера, который затем преобразуется в машинный код ассемблером. Например, так:
- if (3 + 7 == 10) then beep() (код на высокоуровневом языке программирования).
- put 3 1 put 7 3 add 1 3 check 0 10 beep (код на языке ассемблера).
- 1 3 1 1 1 7 3 0 1 3 2 0 10 3 0 0 (машинный код).
Видите, как становится труднее читать код с каждым разом? Да, изначально наш компьютер и сам язык ассемблера были элементарными, но в конечном итоге все языки так усложняются . В них есть сотни команд, каждая из которых использует тот или иной аспект аппаратного обеспечения компьютера. Каждая команда представлена числами, а язык ассемблера — определяет красивый способ записи команд.
Так работает язык ассемблера
Разные производители процессоров по-разному сопоставляют числа с командами и, соответственно, имеют разные машинные коды и язык ассемблера. Эти версии называются различными компьютерными архитектурами.
Шестнадцатеричная система счисления также применяется в этих языках
Зачем нужен язык ассемблера и где он применяется
Этот язык — прямое представление фактического машинного языка, который понимает компьютер. В конечном итоге все, что делает компьютер, сводится к этому машинному языку.
Пример машинного кода программы на языке Java
Обычно разработчики применяют компиляторы или интерпретаторы, чтобы не приходилось осуществлять перевод команд вручную. Но, если вы сами захотите написать компилятор, то без понимания ассемблер-машины, сделать это не удастся.
Если вы работаете с ОС напрямую (либо — напрямую с драйверами устройств), без языка ассемблера не обойтись. Кроме того, переход на язык ассемблера может осуществляться по соображениям скорости / производительности. Сегодняшние компиляторы эффективно справляются с теми задачами для которых они разработаны. Но код во внутреннем цикле непосредственно для процессора, оперативной памяти или другого компонента машины — может быть оптимизирован гораздо эффективнее, чем при использовании компилятора.
Вот еще 5 сценариев, зачем нужен язык ассемблера:
- Доступ к специфическим аппаратным возможностям компьютера, которые являются очень редкими или нестандартными для конкретной платформы, чтобы компилятор выбранного языка мог их использовать или оптимизировать. Такая ситуация может возникать, например, если программирование осуществляется для конкретного оборудования (например, для конкретной модели видеокарты).
- Действительно важна производительность. Трудно превзойти компилятор языка C (например), но когда это необходимо — язык ассемблера действительно может помочь. Кроме того, это как правило единственный способ обогнать компилятор по быстродействию.
- Вы любопытны и хотите узнать, как работает компьютер на самом низком уровне. Assembly language практически напрямую связан с архитектурой аппаратного обеспечения. Поэтому, изучение assembly language — отличный способ узнать о том, как работает компьютер.
- Вы хотите лучше использовать дизассемблирование для отладки скомпилированных языков. Это справедливо для байткода Java и других битовых кодов LLVM.
- Вы самонадеянный новичок и наивно полагаете, что сможете победить хорошо оптимизированную (или даже не очень оптимизированную) программу на C, написав код на языке ассемблера.
Кому нужен язык ассемблера
Если вы заинтересованы в низкоуровневом программировании (в смысле операционных систем и драйверов устройств, а не в смысле "Hello, World"), встроенный ассемблерный код иногда включается в программы на языке C для выполнения тех задач, которые C не смог бы решить самостоятельно.
Этот компилятор языка C имеет графический интерфейс
Если вы интересуетесь проектированием микросхем или высокопроизводительными вычислениями, имея некоторое представление об ассемблере, вам будет гораздо легче понять, что происходит на самом деле (даже если вы не используете этот язык непосредственно для выполнения каких-либо действий).
Как устроен язык ассемблера: команды + пример
В очень упрощенном виде, исполняемый язык во время выполнения может быть приближен к следующему представлению:
[ label ] [ opcode [ operand [ ,operand [ ,operand ] ] ] ] [ ; comment ]
Если перевести на русский язык, то получим такое представление:
[ метка ] [ опкод [ операнд [ , операнд [ , операнд ] ] ] ] [ ; комментарий ]
[ ... ] — это необязательная часть строки.
Большинство ассемблеров допускают гораздо более гибкий синтаксис, в котором все или часть необязательных компонентов являются выражениями, оцениваемыми во время сборки, а также — реализуют более или менее сложные директивы, макросы, библиотеки и так далее. Так что синтаксис может быть довольно сложным.
Часто, opcode обозначает какой-либо стандартный оператор (ADD, OR ...) в трехадресном наборе инструкций. Например, так:
opcode source 1, source 2, destination stands for
или так:
source 1 opcode source 2 => destination
В зависимости от архитектуры целевого процессора и набора инструкций, опкод может иметь от нуля до трех операндов. Вот примеры:
- NOP ; нет операции, не имеет операндов. Неявным является счетчик программы — он указывает на первую инструкцию после NOP.
- CLeaR operand ; 0 => operand.
- ADD D, S ; Destination <= Destination + Source (Место назначения <= Место назначения + Источник).
- ADD S0, S1, D ; Source0 + Source1 => Destination (Источник0 + Источник1 => Место назначения).
Еще примеры команд:
- ADD A, B — добавить число в ячейке памяти B к числу в ячейке A.
- MOVE B, C — переместить число в ячейке C в ячейку памяти B.
- Команды ADD и MOVE называются кодами команд или мнемониками.
Востребован ли сегодня ассемблер
Мы нашли специализированного программиста, который много лет работает с языками этого типа и задали ему простой вопрос: «Стоит ли изучать эти языки сегодня?». Ответ ниже:
«Нет. Как программист на языке ассемблера, я не думаю, что вам нужно его изучать (если только вы не окажетесь одним из немногих, кому он реально нужен). Или, если ваше интеллектуальное любопытство подтолкнет вас к этому языку, в таком случае — добро пожаловать в клуб. Таким образом, язык ассемблера — такой краеугольный навык, жизненно важный — лишь для единиц, интересный — чуть для большего количества программистов. Ну а для подавляющего большинства — он просто не нужен.
Язык ассемблера всегда будет где-то необходим. Является ли это гарантией того, что вы получите хорошую работу? Нет. Но и пустой тратой времени его изучение точно не будет».
Вот ещё несколько сценариев, когда этот язык точно понадобится:
- Когда вы беретесь за написание компилятора.
- Когда вы изучаете устройство процессора.
- При чтении внутренних частей ядра ОС.
- При изучении производительности компьютера.
- Портирование операционных систем на новые архитектуры
- Проектирование атомарных операций и примитивов синхронизации, блокировки и разблокировки и тому подобное.
- Написание генераторов кода компилятора.
- Написание высокопроизводительных математических библиотек и библиотек времени выполнения.
- Некоторые задачи цифровой обработки сигналов и коммуникаций.
- Программы ядра для использования с крайне низким энергопотреблением (AirPods и тому подобное).
Подборка книг и полезные видео
Напоследок — три книги, которые должен прочитать каждый, кто хочет научиться работать на этих языках:
-
Программирование на ассемблере на платформе x86-64, Руслан Аблязов.
Обложка книги «Программирование на ассемблере на платформе x86-64»
-
Профессиональное программирование на ассемблере x64 с расширениями AVX, AVX2 и AVX-512, Куссвюрм Даниэль.
Обложка книги «Профессиональное программирование на ассемблере x64 с расширениями AVX, AVX2 и AVX-512» -
Программирование на ассемблере х64. От начального уровня до профессионального использования AVX. Йо Ван Гуй.
Обложка книги «Программирование на ассемблере х64. От начального уровня до профессионального использования AVX»
Также обязательно посмотрите эти видео:
Assembly Language in 100 Seconds. Изучите основы Ассемблера с NASM за 100 секунд.
What is assembly language?. Краткое введение в язык ассемблера и то, как он может создавать машинный код.
What Is Assembly Language?. Язык ассемблера является основополагающим для работы компьютеров. Вкратце автор видео рассмотрит очень простой язык ассемблера и покажет, какое место он занимает в системе.
Why should I learn assembly language in 2020? (complete waste of time?). В этом видео вы найдёте ещё несколько важных причин изучать язык в 2023 году.
Is it worth learning assembly language today? | One Dev Question. Нужно ли разработчикам знать язык ассемблера в наше время? Ларри Остерман из Microsoft высказывает свое мнение.