Введение
Привет, Хабр! Сегодня я хочу поделиться своими наблюдениями и опытом по работе с различными ассемблерами. Я сам пишу на языке 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. Однако, из‑за отсутствия информации о памяти для этих ассемблеров, сравнение не может быть полным.
Спасибо за внимание! Надеюсь, статья была полезной и интересной. Пишите в комментариях о вашем опыте работы с ассемблерами и какие ещё малоизвестные инструменты стоит рассмотреть.
Комментарии (15)
Number571
13.09.2024 14:33+3AsmX Foundation реализовали довольно необычную систему, которая больше похожа на JIT‑компилятор, но не является классической виртуальной машиной. Впервые я сталкиваюсь с подобным подходом, и это можно считать своего рода ноу‑хау
Ассемблер на интерпретаторе JS-кода - это и вправду ноу-хау, потому что смысла в этом = 0.
Ассемблер — это низкоуровневый язык программирования, который напрямую взаимодействует с аппаратным обеспечением.
AsmX подходит под данное определение? Вопрос конечно риторический. С учётом того, как автор данной статьи восхищается AsmX - не удивлюсь, что он есть также и автор данного ассемблера. Более подробно про AsmX можно почитать в статье: Обзор языка программирования AsmX.
Alex679 Автор
13.09.2024 14:33Спасибо за ваш комментарий!
Вы абсолютно правы, что традиционный ассемблер - это низкоуровневый язык, напрямую взаимодействующий с аппаратным обеспечением.
AsmX действительно не является классическим ассемблером в привычном понимании этого термина, так как он не взаимодействует напрямую с аппаратным обеспечением. Это ближе к концепции высокоуровневой абстракции или виртуальной платформы, где ассемблерный синтаксис используется для управления кодом в окружении, которое не является "железом" в традиционном смысле. Однако, это не означает, что в этом подходе нет своего рода уникальности или инновации (или даже ноу-хау), особенно если он позволяет решать задачи, которые стандартные виртуальные машины или JIT-компиляторы не закрывают.
Что касается ReLax, я не сказал бы, что он меня "не смутил". Это действительно виртуальная машина, и она, как вы правильно заметили, не является ассемблером в классическом понимании. Однако, оба этих проекта, насколько я понимаю, предлагают свои решения для специфичных задач, и здесь стоит корректно различать архитектурные подходы, которые они используют, хотя и позиционирование некоторых терминов может быть спорным.
Оба проекта, AsmX и ReLax, хоть и используют терминологию ассемблера, не являются классическими ассемблерами в традиционном понимании этого слова. Они скорее представляют собой высокоуровневые абстракции.
Вы справедливо отметили, что использование термина "ассемблер" в данном контексте вводит в заблуждение. Более точным было бы называть их "псевдо-ассемблерами" или "виртуальными низкоуровневыми языками".SerafimArts
13.09.2024 14:33Однако, это не означает, что в этом подходе нет своего рода уникальности или инновации (или даже ноу-хау), особенно если он позволяет решать задачи, которые стандартные виртуальные машины или JIT-компиляторы не закрывают.
И какие задачи он позволяет решать, если даже обычный высокоуровневый JS будет быстрее и читабельнее?
Извиняюсь за циничность, но почему в статью попала эта детсадовская поделка уровня BolgenOS (а учитывая код - никак иначе это назвать нельзя, ну блин, парсер на регулярках, без построения AST, использующий самый грубый и медленный алгоритм разбора -- каждый шаг матчить новое значение -- это даже не смешно), а не, например, LLVM IR, который на выходе может выдавать тот же бинарь под веб или любую существующую платформу. Или почему не WASM, который на порядки быстрее и эффективнее этой поделки? Или почему не AssemblyScript? Или почему... А я напоминаю, что перечисляю только ассемблерные языки на которых можно написать что-то под веб, которые в разы популярнее (28 звёздочек у этого AsmX с 1 контрибьютером, против 3к+ звёздочек только у одной репы спеки WASM, и 7.5к у транспайлера из С/С++), производительнее и качественнее.
Да миллион же всяких более популярных решений. Тот же C# во что собирается? Правильно, в CLR, который фактически является таким же высокоуровневым ассемблером и поддерживает JIT, не?
Какое это блин "ноу-хау"? Это просто шутка, которая слишком сильно затянулась, раз кто-то это пытается оценить серьёзно.
Поддерживаю @Number571, выглядит всё так, что вы и есть автор этой поделки, иначе я даже не знаю как ещё объяснить подобное...
Alex679 Автор
13.09.2024 14:33Спасибо за ваш комментарий! Ваше мнение весьма ценно.
Благодарю за ваше мнение и за то, что поделились информацией о различных ассемблерных языках и технологиях, таких как WASM, AssemblyScript и LLVM IR.
Сравнивать AsmX с такими проектами, как LLVM IR, не совсем корректно. Это как сравнивать самодельный деревянный велосипед с гоночным автомобилем. Оба средства передвижения, но классы разные.
Касательно сравнения по количеству звёзд на GitHub, это действительно не всегда корректный показатель качества или значимости проекта. Звёзды могут отражать популярность, но не всегда дают полную картину о практической ценности и функциональности.
Вопрос о "ноу-хау" в данном случае, вероятно, не стоит воспринимать буквально, как принципиально новое изобретение. Скорее, речь может идти об образовательном или экспериментальном аспекте проекта. В таком контексте, простота реализации и использование менее эффективных методов (например, парсера на регулярных выражениях) могут быть оправданы целью обучения. Важно, что автор попробовал реализовать что-то сложное, пусть и не самым оптимальным способом.
Не исключено, что AsmX был создан школьником. Это не необходимо оценивать как нечто плохое или незначительное. Наоборот, это может быть примером интереса и увлеченности молодого человека.
Наконец, я хочу подчеркнуть, что я не являюсь автором AsmX и выражаю свое мнение исключительно как независимый наблюдатель. Благодарю вас за ваш интерес и конструктивную критику!
SIISII
13.09.2024 14:33В данной статье мы не будем рассматривать ARM, AVR и другие микроконтроллерные архитектуры, а сосредоточимся исключительно на компьютерных ассемблерах.
В порядке придирок.
ARM, AVR -- это, конечно, архитектуры, но не обязательно микроконтроллерные, если говорить об ARM (есть и ПК, и полноценные серверы, да и смартфоны не на микроконтроллерах реализованы). "Персоналочная" архитектура, неофициально обозначаемая как x86 (официально -- IA-32 для 32-разрядных процессоров и AMD64 / Intel64 для 64-разрядных) -- это тоже архитектура (и, в принципе, может быть и микроконтроллерной: технических препятствий нет). Архитектура определяет, как "выглядит" процессор (или вычислительная система в целом) с точки зрения программиста -- в первую очередь, какова его система команд. Эта тема в статье затрагивается, но весьма несильно, что неудивительно: для глубокого погружения в систему команд даже IA-32, без всего, что появилось в 64-разрядных процессорах, потребуется толстенный талмуд.
Но в целом автор рассуждает не о системе команд, а о ассемблерах в узком смысле слова -- о трансляторах языка ассемблера. В спойлере "Программы на разных ассемблерах" можно увидеть примеры одного и того же кода для разных трансляторов.
По сути, эта статья даёт обзор синтаксиса нескольких трансляторов для одного исходного языка, и её название формально является совершенно корректным. Но реальное употребление слова "ассемблер" в жизни куда шире и даже, скорей, обозначает именно язык, а не транслятор (более того, нередко встречается словосочетание "компилятор ассемблера", что не очень-то правильно). Как по мне, лучше б название было изменить на что-нибудь вроде "Знакомимся с трансляторами ассемблера для ПК" -- тогда сразу станет ясно, о чём пойдёт речь.
tolich_the_shadow
13.09.2024 14:33Это не трансляторы ассемблера, а ассемблеры. Ассемблер - не язык, а транслятор мнемокода.
SIISII
13.09.2024 14:33Я выше уже откомментировал название статьи. Раньше там стояло просто "ассемблеры" и формально это было корректно ("ассемблер" -- транслятор, а транслируемый им язык -- "язык ассемблера", assembly language). Но в реальном использовании этого слова под ассемблером почти всегда понимают именно язык, а отнюдь не транслятор. Явное упоминание последнего в названии статьи сразу говорит, что речь пойдёт именно о трансляторах, а не о языке как таковом. Кстати, термин "мнемокод", кажется, давным-давно уже не используется...
Yuri0128
13.09.2024 14:33У меня статья вызвала некоторое недоумение:
ну сравнивать нечто типа "виртуального assembly language" с реальным несколько писец как некорректно;
сам уровень статьи (ну песочница же ведь);
некоторые заявления автора как в статье так и в комментах, причем они иногда не коррелируют;
ну и вишенка - когда-то давным давно я писал на assembly language c компиляцией TASM Borland - так размер в памяти был как-то сильно много меньше при сильно более сложной программе (а для умножения в 3 строки - там наверное до пары десятков байт) и время исполнения было ну буквально единицы тактов. Откудова у автора взялося 256KB на NASM-е? То ли он оптимизацию не делал то еще что-то. И откудова 0,38 секунды времени исполнения 6 строчек в assembly language? Может я что-то не доганяю. Ведь вся программка влезет в кэш первого уровня - там просто моментом все исполнится. Снова я чего-то не догоняю... Старею видать...
SerafimArts
13.09.2024 14:33А то что псевдо-виртуальная машина, написанная на JS и исполняющаяся в браузере оказалось в 2 раза быстрее этих "6 строчек" - вас не смутила?)
Yuri0128
13.09.2024 14:33Не... Если чиста ассемблер на 6 строчек исполняется 0,38 секунды, то все остальное уже точно не смущает :).... В том числе и JS интерпретатор, который оказалси быстрее...
Arenoros
мне больше всего fasm нравился, когда в универе нужно было что то писать, в проде ни когда не приходилось что то писать чисто на asm