Введение
Привет, Хабр! Сегодня я хочу поделиться своими наблюдениями и опытом по работе с различными ассемблерами. Я сам пишу на языке C и относительно редко касался темы ассемблера. Но недавно решил восполнить этот пробел в знаниях и посмотреть на различные ассемблеры. В данной статье мы не будем рассматривать ARM, AVR и другие микроконтроллерные архитектуры, а сосредоточимся исключительно на компьютерных ассемблерах. Давайте не будем судить строго, ведь это скорее исследовательский опыт, чем глубокое погружение.
Введение в ассемблеры
Ассемблер — это низкоуровневый язык программирования, который напрямую взаимодействует с аппаратным обеспечением. Он предоставляет возможность детального управления ресурсами компьютера, что полезно для задач, требующих высокой производительности или специфического доступа к аппаратуре.
Классика жанра: NASM и GAS
NASM (Netwide Assembler) — это свободный ассемблер для архитектуры Intel x86, известный своей простотой и мощью. Он поддерживает 16-, 32- и 64-разрядные программы и предлагает богатый набор макросов. NASM часто используется для написания высокопроизводительных участков кода, драйверов устройств и операционных систем.
Автор: Simon Tatham и Julian Hall.
Репозиторий: NASM GitHub
Инструкции: NASM поддерживает порядка 700+ инструкций, включая различные расширения и специфические команды.
GAS (GNU Assembler) — ассемблер проекта GNU, используемый компилятором GCC. Это кроссплатформенный инструмент, поддерживающий множество архитектур. GAS отличается мощными возможностями по работе с макросами и директивами, что делает его незаменимым инструментом для разработки системного программного обеспечения.
Автор: Проект GNU.
Репозиторий: GAS в составе GNU Binutils
Инструкции: Поддерживает более 1000 инструкций, так как покрывает множество процессорных архитектур
ReLax и AsmX
Relax — не является традиционным ассемблером, но его автор позиционирует его как язык программирования, который компилируется в байт‑код. Сложно назвать его полноценным компилятором, так как он больше похож на виртуальную машину.
Автор: Данил
Статья на Habr: Habr Article
Репозиторий: GitHub RVM, GitHub IRasm
Лицензия: Open Source
AsmX — это язык программирования на основе NodeJS. AsmX G2 является вторым поколением этой платформы. AsmX пытается предложить ассемблер для разработчиков, знакомых с веб‑технологиями.
Автор: Tai Husk
Репозиторий: AsmX GitHub, AsmX G2 GitHub
Лицензия: Open Source
Relax и AsmX: Первые впечатления
Relax, несмотря на заявления о компиляции, вызвал у меня больше вопросов, чем ответов. Отсутствует понятная документация, а сам процесс компиляции неясен. Хоть автор и позиционирует Relax как компилятор, по факту его реализация больше напоминает байт‑машину. Я не нашел информации о конкретных инструкциях компиляции, что показалось мне странным, ведь продукт должен быть готов к использованию. На страницах GitHub‑репозиториев RVM и IRasm присутствует лицензия, но документации по использованию языка я не нашел.
AsmX, в отличие от Relax, обладает более структурированным подходом. На GitHub доступна документация, позволяющая разобраться с установкой и использованием. AsmX Foundation реализовали довольно необычную систему, которая больше похожа на JIT‑компилятор, но не является классической виртуальной машиной. Впервые я сталкиваюсь с подобным подходом, и это можно считать своего рода ноу‑хау. Автор в README‑файлах репозиториев подробно описывает обновления и новые возможности языка.
Оценка Relax и AsmX
Relax:
Плюсы:
Автор пытается создать свой язык программирования на C++.
Написан на C++.
Минусы:
Отсутствие технической документации.
Сложно понять, что можно писать на Relax.
AsmX:
Плюсы:
Доступна техническая документация.
Установку и использование легко понять благодаря мануалам.
Минусы:
Написан на NodeJS.
Таблицы сравнения
Сравнение синтаксиса комментариев в различных ассемблерах
Для удобства чтения и сопровождения кода, ассемблеры предоставляют возможность добавлять комментарии — текст, который игнорируется компилятором. Рассмотрим, как это делается в разных ассемблерах:
GAS | NASM | ReLax | AsmX | AsmX G2 |
| | |
|
|
Как видно из таблицы, большинство ассемблеров используют символ #
или ;
для обозначения комментариев. Однако AsmX G2 использует два символа ;;
для комментариев.
Сравнение наличия и определения точки входа
Точка входа — это место в программе, с которого начинается её выполнение. В различных ассемблерах подход к определению точки входа может различаться. Рассмотрим, как это реализовано в каждом из ассемблеров.
GAS | Нужно определять вручную (например, |
NASM | Нужно определять вручную (например, |
ReLax | |
AsmX | Не имеет явной точки входа |
AsmX G2 | |
В GAS и NASM разработчику необходимо явно указать точку входа, что дает гибкость, но требует дополнительной настройки. ReLax использует объектно‑ориентированный подход, где точка входа — это метод MainClass.Main
. AsmX, в свою очередь, не имеет явно определенной точки входа, что может быть необычно для традиционных ассемблеров. AsmX G2 возвращается к более традиционному подходу, используя main
как точку входа, что может облегчить переход для разработчиков, привыкших к C‑подобным языкам.
Наличие инструкций SIMD в разных ассемблерах
Теперь давайте посмотрим, как обстоят дела с поддержкой SIMD‑инструкций (Single Instruction, Multiple Data) в разных ассемблерах. Эти инструкции играют важную роль в высокопроизводительных вычислениях, например, в мультимедийных приложениях или обработке больших массивов данных. В таблице ниже представлены поддерживаемые наборы SIMD‑инструкций, такие как MMX, AVX, SSE и другие.
Assembler | MMX | AVX | SSE | AVX2 | SSE2 | SSE3 | SSE4 | AVX-512 | SSE4.1 | SSE4.2 |
GAS | + | + | + | + | + | + | + | + | + | + |
NASM | + | + | + | + | + | + | + | + | - | - |
ReLax | - | - | - | - | - | - | - | - | - | - |
AsmX | - | - | - | - | - | - | - | - | - | - |
AsmX G2 | + | - | + | - | - | - | - | - | - | - |
+
означает, что ассемблер поддерживает соответствующий набор инструкций SIMD.-
означает, что ассемблер не поддерживает соответствующий набор инструкций SIMD.
Анализ поддержки SIMD-инструкций
GAS и NASM показывают полную или почти полную поддержку современных SIMD инструкций, что делает их предпочтительными для разработки высокопроизводительных приложений. Однако, NASM не поддерживает SSE4.1 и SSE4.2, что может быть ограничением для некоторых специфических задач.
ReLax и AsmX не поддерживают никакие SIMD инструкции, что может ограничить их применение в задачах, требующих высокой производительности.
AsmX G2 поддерживает базовые MMX и SSE, что может быть достаточно для некоторых задач, но отсутствие поддержки более новых инструкций, таких как AVX или AVX-512, может ограничить его использование в современных вычислениях.
Итоги
Если вам нужны мощные SIMD‑инструкции для работы с мультимедийными данными или высокопроизводительными вычислениями, GAS и NASM — это ваши лучшие друзья. GAS лидирует по поддержке SIMD, включая самые современные наборы инструкций, такие как AVX-512. NASM также хорош, но с небольшими ограничениями. ReLax и AsmX не подходят для программ, требующих инструкций SIMD. AsmX G2 может быть использован для программ, требующих только MMX и SSE.
Важно отметить, что поддержка инструкций SIMD может зависеть от конкретной версии ассемблера и целевой платформы. Перед использованием SIMD инструкций, рекомендуется ознакомиться с документацией выбранного ассемблера.
Пример кода для вычисления квадрата числа
Для сравнения я написал простую программу на разных ассемблерах: вычисление квадрата числа. Это не «Hello, World!» (он слишком прост), но и не факториал (он слишком сложен для первого знакомства с ассемблером).
Программа на разных ассемблерах
GAS:
.section .data
number: .int 500
result: .int 0
.section .text
.global main
main:
movl number, %eax # Загрузить число в регистр eax
imull %eax, %eax # Вычислить квадрат числа
movl %eax, result # Сохранить результат в переменную result
# Завершение программы
movl $1, %eax # Системный вызов для выхода
xorl %ebx, %ebx # Код возврата 0
int $0x80 # Вызов ядра
NASM:
section .data
number dd 500
result dd 0
section .text
global _start
_start:
mov eax, [number] ; Загрузить число в регистр eax
imul eax, eax ; Вычислить квадрат числа
mov [result], eax ; Сохранить результат в переменную result
; Завершение программы
mov eax, 1 ; Системный вызов для выхода
xor ebx, ebx ; Код возврата 0
int 0x80 ; Вызов ядра
AsmX:
@mul 500 500 # Вычислить квадрат числа
AsmX G2:
@function main { ;; Точка входа C/C++
@mul 500 500 ;; Вычислить квадрат числа
}
Бенчмарк: Вычисление квадрата числа
Я решил посмотреть, как ведут себя эти ассемблеры с точки зрения производительности и потребления памяти, написав простую программу для вычисления квадрата числа. Для этого я запустил программы и замерил время выполнения и использование памяти.
Assembler | memory | min | avg | max |
GAS | 1024kb | 0.38s | 0.4s | 0.587s |
NASM | 256kb | 0.36s | 0.38s | 0.505s |
AsmX | ????? | 0.17s | 0.21s | 0.262s |
AsmX G2 | ????? | 0.15s | 0.19s | 0.259s |
К сожалению, провести бенчмарки для Relax оказалось невозможным из‑за отсутствия возможности запуска.
Примечание: Бенчмарки носят ориентировочный характер и могут варьироваться в зависимости от аппаратного обеспечения и конфигурации системы.
Итоги
GAS и NASM — это классические ассемблеры, прекрасно подходящие для работы с языками программирования C/C++ и другими.
AsmX — интересный проект, который может быть полезен для бэкенд и фронтенд разработчиков, благодаря использованию NodeJS.
NASM показал себя более экономичным в плане потребления памяти по сравнению с GAS.
AsmX G2 имеет синтаксис, напоминающий смесь C++ и ассемблера.
Бенчмарки удивили нас, демонстрируя высокую производительность AsmX и AsmX G2. Однако, из‑за отсутствия информации о памяти для этих ассемблеров, сравнение не может быть полным.
Спасибо за внимание! Надеюсь, статья была полезной и интересной. Пишите в комментариях о вашем опыте работы с ассемблерами и какие ещё малоизвестные инструменты стоит рассмотреть.