Для чего нужен ассемблер
Для чего нужен ассемблер?
Скажем так: зачем уметь собирать-разбирать двигатель от машины и понимать как он работает?
99% людей это не нужно в принципе. Но если вы это знаете, вы можете легко диагностировать какую-то проблему, понять как её решить. При этом, каждый день вы не производите двигатели на станке.
То же самое с ассемблером: чтобы понимать как работает программа, как её отладить, диагностировать, понять, что не работает — для этого и нужен ассемблер. Писать на нём что-то конкретное и большое сейчас абсолютно бессмысленно. Его надо знать и понимать, этого достаточно.
К вашему сведению драйверы это часть ОС. Их как и всю ОС можно написать на СИ, можно на Assembler, а можно, например, на Pascal. Просто сейчас компьютеры настолько быстрые и имеют так много памяти, что оптимизация кода уходит на второй план. Хотя компиляторы современных языков программирования в плане оптимизации фору дадут большинству современных программистов.
Но все таки в серьезных программах есть много так называемых»узких мест» как правило это связано с нехваткой быстродействия, реже нехваткой памяти, тут на помощь приходит ассемблер.
Хотя чудику который говнокодит на PHP или JS этого не понять
PS Язык программирования это инструмент, а не стихотворение его учить не надо, на нем надо писать программы
Погружение в ассемблер. Зачем учить ассемблер в 2020 году
Содержание статьи
Погружение в ассемблер
Это вводная статья цикла «Погружение в ассемблер», которую мы публикуем в честь его завершения. Ее полный текст доступен без подписки. Прочитав ее, ты можешь переходить к другим статьям этого курса:
Ради чего стоит изучать ассемблер?
Стоит освоить ассемблер, если ты хочешь:
Не стоит осваивать ассемблер, если ты хочешь ускорить другие свои программы. Современные оптимизирующие компиляторы справляются с этой задачей очень хорошо. Ты вряд ли сможешь обогнать их.
Кто выдаст лучший ассемблерный код?
Почему обогнать компилятор практически невозможно? Смотри, для тебя же очевидно, что компьютер в шахматы не обыграть, даже если ты играешь лучше, чем создатель шахматной программы? С оптимизирующими компиляторами та же история. Только оптимизирующий компилятор играет не шахматными фигурами, а контекстными обстоятельствами.
В современных процессорах практически ничто из того, что влияет на производительность, нельзя обсуждать в отрыве от контекста. Одна и та же комбинация из десятка ассемблерных инструкций выполняется с резкими отличиями по скорости (в тысячи или даже миллионы раз), в зависимости от целой кучи самых разнообразных обстоятельств.
И все это только верхушка айсберга, малая часть того, что тебе придется учитывать и анализировать, когда будешь стараться переиграть компилятор.
Есть такой миф, что программы, написанные на ассемблере, работают в десять раз быстрее. Этот миф уходит корнями в семидесятые годы. Компиляторы в те далекие времена генерировали код настолько бездарно, что у каждого уважающего себя программиста был черный список запрещенных языковых конструкций.
Когда наши коллеги из прошлого писали программы, они либо держали в уме этот черный список и не давали своим пальцам набивать проблемные конструкции, либо настраивали специальный препроцессор, который конвертировал исходник в более низкоуровневое беспроблемное представление на том же языке. С тех пор минуло 50 лет. Компиляторы возмужали, но миф остался.
Конечно, даже сегодня можно изредка встретить уникума, который пишет более быстрый код, чем компилятор. Вот только времени у него на это уходит так много, что ни в какие ворота не лезет. Плюс для оптимизации от тебя требуется, чтобы ты назубок знал весь набор инструкций процессора.
Вдобавок, поскольку ты шлифуешь свой код вручную, никакой компилятор не подстрахует тебя, не поможет отловить баги, которые ты неизбежно плодишь, когда пишешь программу.
Кроме того, твой ассемблерный код будет непереносимым. То есть, если ты захочешь, чтобы твоя программа запускалась на другом типе процессора, тебе придется полностью переписать ее, чтобы создать модификацию, заточенную под набор инструкций этого другого процессора. Само собой, тебе эти инструкции тоже надо знать назубок.
В итоге ты потратишь в десятки и сотни раз больше времени, чем если бы доверился оптимизирующему компилятору, — но результат, скорее всего, окажется медленнее, а не быстрее.
При этом иногда оптимизирующий компилятор выплевывает ассемблерный код, логика которого ну совсем непонятна. Однако не спеши обвинять компилятор в глупости. Давай разберем пример.
Размышления подобного рода неизбежно заводят тебя в запутанный лабиринт альтернативных вариантов. Все их нужно просчитать, чтобы выбрать лучший. Но даже когда ты сделаешь это, вариант ассемблерного кода, сгенерированный компилятором, скорее всего, будет работать быстрее, чем твой.
Кстати, если используешь GCC или Clang, активируй опции оптимизации для SSE, AVX и всего остального, чем богат твой процессор. Затем откинься на спинку кресла и удивись, когда компилятор векторизует твой сишный код. Причем сделает это так, как тебе и не снилось.
Какие программы нельзя написать на ассемблере?
Нет таких. Все, что можно сделать на компьютере, можно сделать в том числе и на ассемблере. Ассемблер — это текстовое представление сырого машинного кода, в который переводятся все программы, запущенные на компьютере.
Ты при желании можешь написать на ассемблере даже веб‑сайт. В девяностые С был вполне разумным выбором для этой цели. Используя такую вещь, как CGI BIN, веб‑сервер мог вызывать программу, написанную на С. Через stdin сайт получал запрос, а через stdout отправлял результат в браузер. Ты можешь легко реализовать тот же принцип на ассемблере.
Но зачем? Ты должен быть мазохистом, чтобы проделывать такое. Потому что когда ты пишешь на ассемблере, то сталкиваешься вот с такими проблемами.
Да, все можно написать на ассемблере. Но сегодня это нецелесообразно. Лучше пиши на С. Скорее всего, будет безопаснее, быстрее и более лаконично.
От редакции
Автор статьи — большой поклонник С и настоятельно рекомендует этот язык. Мы не будем лишать его такой возможности. С — отличная штука и помогает как освоить основные концепции программирования, так и прочувствовать принципы работы компьютера. Однако при выборе языка для изучения ты можешь руководствоваться самыми разными соображениями. Например:
И так далее. Ответ на вопрос о том, с какого языка начать, зависит от многих факторов, и выбор — дело индивидуальное.
Конечно, когда ты знаешь ассемблер, у тебя будут значительные преимущества перед теми программистами, которые его не знают. Но прежде чем ознакомиться с этими преимуществами, запомни одну простую вещь: хорошие программисты знают ассемблер, но почти никогда не пишут на нем.
Какие преимущества ассемблер дает программисту?
Чтобы писать эффективные программы (в плане быстродействия и экономии ресурсов), тебе обязательно надо знать ассемблер того железа, для которого ты пишешь. Когда ты знаешь ассемблер, ты не обманываешься внешней простотой и краткостью высокоуровневых функций, а понимаешь, во что в итоге превращается каждая из них: в пару‑тройку ассемблерных инструкций или в длиннющую их последовательность, переплетенную циклами.
Если работаешь с языками высокого уровня, такими как С, научись хотя бы читать и понимать ассемблерный код. Даже если ты в обозримом будущем не видишь себя пишущим на ассемблере (на самом деле мало кто себя так видит), знание ассемблера тебе пригодится.
Если будешь с ассемблером на ты, он сослужит тебе хорошую службу в отладке. Освоив ассемблер, ты будешь понимать, что происходит под капотом языков высокого уровня, как компьютер делает то, что он делает, и почему высокоуровневый компилятор иногда работает не так, как ты ждешь от него. Ты сможешь видеть причину этого и понимать, как ее устранить.
Плюс иногда ты ну никак не можешь понять, что у тебя за баг, пока не пройдешься в отладчике в пошаговом режиме по ассемблерному коду.
И вот еще тонкий намек: некоторые работодатели хотели бы видеть в твоем резюме слово «ассемблер». Это говорит им, что ты не просто по верхам нахватался, а действительно интересуешься программированием, копаешь вглубь.
Стоит ли начинать изучать программирование с ассемблера?
Когда ты осваиваешь программирование, начиная с самых низов, в этом есть свои плюсы. Но ассемблер — это не самый низ. Если хочешь начать снизу, начни с логических вентилей и цифровой электроники. Затем поковыряйся с машинным кодом. И только потом приступай к ассемблеру.
Время от времени тебя будут посещать мысли, что ты занимаешься какой‑то ерундой. Но ты узнаешь много полезного для своей будущей работы, даже если она будет связана только с языками высокого уровня. Ты узнаешь, как именно компьютер делает те вещи, которые он делает.
Однако я бы не советовал начинать с ассемблера и более низких слоев. Во всем том, что перечислено в двух предыдущих абзацах, легче разобраться, когда ты начинаешь с какого‑нибудь языка высокого уровня. Так ты достигнешь желаемого результата быстрее, чем оно тебе наскучит.
Но в какой‑то момент тебе и правда обязательно надо познакомиться с ассемблером, особенно если программируешь на С. Я сомневаюсь, что ты сможешь стать полноценным программистом на С, не зная ассемблера. Но начинать с ассемблера не стоит.
Насколько легче учить другие языки, когда уже знаешь ассемблер?
Ассемблер совершенно не похож на языки высокого уровня. Поэтому народная мудрость «Тот опыт, который ты получил на одном языке, может быть легко сконвертирован на другой язык» с ассемблером не работает.
Если ты начнешь с ассемблера, то после того, как выучишь его и решишь освоить новый язык, тебе придется начинать как с чистого листа. Помню, мой однокашник еще в школе выучил ассемблер, написал на нем игрушку, с которой победил на конференции. Но при этом так и не смог хорошо освоиться в С, когда мы учились в универе.
Есть только память. Причем ты работаешь с ней не так, как на языке высокого уровня. Ты можешь забыть, что в какую‑то область памяти поместил строку, и обратиться к ней как к числу. Программа все равно скомпилируется. Но только обрушится в рантайме. Причем обрушится жестко, без вежливого сообщения об ошибке.
Но! Изучив ассемблер, ты будешь понимать, как реализуются и функции, и циклы, и все остальное. А разница между передачей параметра «по значению» и «по ссылке» станет для тебя самоочевидной. Плюс если ты пишешь на С, но не можешь до конца разобраться, как работают указатели, то, когда ты узнаешь, что такое регистры и относительная адресация, увидишь, что понять указатели совсем нетрудно.
Лучше начинай с С. На нем удобно осваивать основы: переменные, условия, циклы, логические построения и остальное. Опыт, который ты получишь при изучении С, легко сконвертировать на любой другой язык высокого уровня, будь то Java, Python или какой‑то еще. Да и с ассемблером легче разобраться, когда ты уже освоил С.
Насколько доходно уметь программировать на ассемблере?
Если заглянешь на HH.ru, то, скорее всего, не найдешь ни одной вакансии, у которой в заголовке написано слово «ассемблер». Но время от времени какая‑нибудь контора лихорадочно ищет мага‑волшебника, который знает нутро компьютера настолько глубоко, что может полностью подчинить операционную систему своей воле. Мага‑волшебника, который умеет (1) латать систему, не имея на руках исходного кода, (2) перехватывать потоки данных на лету и вмешиваться в них.
Некоторая часть этой глубокой магии — а сейчас потребность в такой магии становится все более редкой — может быть воплощена только на языке очень низкого уровня.
Я слышал о конторе, которая ищет человека на разработку новой платформы для высокочастотного трейдинга. Там идея в том, что если ты получаешь информацию о котировках быстрее своих конкурентов и принимаешь решение быстрее их, то будешь грести баснословные суммы.
«Когда ты получаешь котировки, проходя через весь стек TCP/IP, это слишком медленно», — говорят парни из этой фирмы. Поэтому у них есть примочка, которая перехватывает трафик на уровне Ethernet, прямо внутри сетевой карты, куда залита кастомизированная прошивка.
Но эти ребята пошли еще дальше. Они собираются разработать девайс для фильтрации трафика Ethernet — на ПЛИС. Зачем? Чтобы ловить котировки на аппаратном уровне и тем самым экономить драгоценные микросекунды трейдингового времени и в итоге получать небольшое, очень небольшое преимущество перед конкурентами. Язык С им не подошел. Им даже ассемблер не подошел. Так что эти парни выцарапывают программу прямо на кремнии!
Что такое ассемблер и нужно ли его изучать
Этому языку уже за 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 сразу после включения компьютера.
За что я люблю ассемблер?
Этой статье уже почти 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 будут генерировать разный код; и даже один и тот же компилятор с разными настройками выдаст различный результат).
Обычно одна строка кода на ЯВУ разворачивается в несколько (или даже десяток) инструкций процессора. А знаете ли вы о том, что некоторые инструкции процессора 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.