Форум программистов, компьютерный форум, киберфорум
Jin X
Войти
Регистрация
Восстановить пароль
Карта форума Блоги Сообщество Поиск Заказать работу  
Рейтинг: 5.00. Голосов: 4.

За что я люблю Assembler?

Запись от Jin X размещена 27.07.2018 в 17:58
Обновил(-а) Jin X 04.09.2018 в 23:35

За что я люблю Assembler?

Оговорочки

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

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



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

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

  • Во-вторых (и это более существенно), на ассемблере можно было делать много того, что сделать на языках высокого уровня (ЯВУ, на путайте с Java) затруднительно или не так эффективно. К примеру, мне очень нравилось писать резидентные программы в моём любимом формате DOS COM, которые я приносил другу и устраивал ему всякие "сюрпризы" (программы могли инсталлироваться в загрузчик MBR или прописываться в файл autoexec.bat и запускаться при следующей загрузке системы). Про вирусы я больше читал, чем писал (и дальше моего компьютера они не уходили). Немного увлекался демосценой (правда, в демопати так и не участвовал, больше смотрел и пробовал реализовать различные элементы).
Но с тех пор прошло уже больше 2-х десятков лет, и сейчас экономия памяти (особенно дисковой) уже не так актуальна, да и скорости современных процессоров для выполнения повседневных задач вполне хватает (популярность языков сверхвысокого уровня подтверждает это, хотя закон Вирта никто не отменял ). А современные компиляторы зачастую могут оптимизировать код по скорости лучше человека, не так ли? Что же может привлекать программиста в ассемблере, ведь исходники на нём гораздо более объёмные, а на разработку требуется больше времени и внимания (чтобы не наделать ошибок)?

Перейдём к сути!

Приведу свои доводы относительно того, чем так хорош ассемблер.
  1. Ассемблер даёт полный контроль над кодом и обладает большей гибкостью, чем любой другой язык программирования (даже C/C++). И речь тут отнюдь не об "injection" (внедрении кода в адресное пространство другого процесса) и не о вирусах, троянах и пр. нечисти (это всё, кстати, можно написать и на многих ЯВУ). На асме мы можем конструировать нашу программу, размещая блоки кода и данных как нам вздумается. Каждый генерируемый байт будет таким, каким мы хотим его видеть. Без лишнего runtime-кода стандартных библиотек. Что же касается демосцены, то написать, скажем, intro, уместив исполняемый файл в 256 байт [1, 2, 3, 4] (а то и 128, 64, 32 или даже ещё меньше) на чём-то отличном от ассемблера вы вряд ли сможете.

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

  3. Получаемый код даже самого умного и навороченного компилятора, как правило, можно оптимизировать (как по скорости, так и по размеру). А ещё можно изощриться и использовать неочевидные комбинации, сделав код короче и быстрее. Этим можно, конечно, заняться и на других языках, но на ассемблере больше простора для творчества. Это особый кайф, азарт, челлендж в некотором роде! К тому же, разве не прикольно написать программу, выполняющую полезные функции, весом менее 10 Кб? Для сравнения: VCL-программа на Delphi 10.2 Tokyo, создающая пустое окно без какого-либо полезного функционала, весит в release-версии целых 2 Мб (а в debug-версии... кхм, 11 Мб). На C++Builder 10.2 Tokyo release-версия такой же программы, не требующая внешних библиотек, получится размером ≈ 2.7 Мб. Аналогичная программа на fasm будет занимать всего пару килобайт.

  4. Обычно одна строка кода на ЯВУ разворачивается в несколько (или даже десяток) инструкций процессора. А знаете ли вы о том, что некоторые инструкции процессора Intel требуют несколько строк для реализации на ЯВУ (на том же C/C++, если не использовать интринсики)? Если не знаете, просто поверьте на слово, а я напишу об этом в следующей статье
Справедливости ради скажу, что писать всегда на ассемблере – занятие не очень разумное с точки зрения времени, усилий, вероятности допустить ошибку и кроссплатформенности. Не так часто нам требуется полный контроль кода и столь уж жёсткая оптимизация, когда экономия пары тактов процессора имеет критически решающее значение. Но иногда использование ассемблера действительно оправдано (пример). Часто ассемблер хорошо использовать в виде вставок в код на ЯВУ (посмотрите RTL-модули Delphi, там этого добра в изобилии). Да и использование интринсиков, как правило, не имеет смысла (и опасно) без знания инструкций ассемблера.

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

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

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

To be continued...
Всего комментариев 12
Комментарии
  1. Старый комментарий
    64 байта наверно иногда можно и без помощи ассемблера написать.
    Особенно если команды ЭВМ удобно кодируются.
    "Исходный код" поместится в 3-4 строчки.
    Запись от ОС размещена 27.07.2018 в 18:08 ОС вне форума
  2. Старый комментарий
    Аватар для Jin X
    Цитата:
    Сообщение от ОС Просмотреть комментарий
    64 байта наверно иногда можно и без помощи ассемблера написать.
    Особенно если команды ЭВМ удобно кодируются.
    Каким образом? Через HEX-редактор?
    Ну там или будет тот же ассемблер (HIEW) или нужно будет кодировать инструкции "вручную". Но есть ли в этом смысл? Если "чисто по приколу", тогда ок.
    А так ведь наверняка придётся этот код оптимизировать (есть у меня тут самописная 64b intro, исходник которой не сразу получился готовым "как надо", я его ужимал и ужимал, чтобы "сие творение" влезло-таки в 64 байта). В итоге доужимался так, что и на добавление звука место осталось
    Запись от Jin X размещена 27.07.2018 в 18:18 Jin X вне форума
    Обновил(-а) Jin X 27.07.2018 в 18:19
  3. Старый комментарий
    Как люди кодили до ассемблеров и шестнадцатиричных редакторов?
    Запись от ОС размещена 27.07.2018 в 19:23 ОС вне форума
  4. Старый комментарий
    Аватар для ildwine
    Хорошая статья, мне нравится.
    Запись от ildwine размещена 27.07.2018 в 20:33 ildwine вне форума
  5. Старый комментарий
    Ассемблер - это конечно хорошо. Но ассемблер не может заменить язык высокого уровня. Обратное тоже верно. Может лучше Золотая Середина? То есть язык высокого уровня плюс ассемблерные вставки там, где это необходимо.
    Что мне не нравится в ассемблере? ... почему бы в ассемблере не использовать привычную для языков высокого уровня символику? ... например для присвоения можно использовать знак "=". У вас иное мнение?
    Запись от wer1 размещена 27.07.2018 в 20:37 wer1 вне форума
  6. Старый комментарий
    Аватар для Eva Rosalene
    Цитата:
    Сообщение от нтч
    Может лучше Золотая Середина? То есть язык высокого уровня плюс ассемблерные вставки там, где это необходимо.
    С/C++ -- с одной стороны, есть асм-вставки, с другой -- полный контроль над средой исполнения даже без них (к контролю над кодом результирующего файла это не относится).

    Цитата:
    Сообщение от нтч
    Но ассемблер не может заменить язык высокого уровня. Обратное тоже верно
    Золотые слова.
    Запись от Eva Rosalene размещена 27.07.2018 в 22:48 Eva Rosalene вне форума
  7. Старый комментарий
    Аватар для Jin X
    Цитата:
    Сообщение от ildwine Просмотреть комментарий
    Хорошая статья, мне нравится.
    Спасибо!

    Цитата:
    Сообщение от ОС Просмотреть комментарий
    Как люди кодили до ассемблеров и шестнадцатиричных редакторов?
    Раньше много чего по-другому было, биты тумблерами переключали, насколько мне известно . Я ж говорю: если хочется и вы видите в этом смысл – не вопрос. У К.К. даже есть статья про программирование в машинных кодах.

    Цитата:
    Сообщение от нтч Просмотреть комментарий
    Ассемблер - это конечно хорошо. Но ассемблер не может заменить язык высокого уровня. Обратное тоже верно. Может лучше Золотая Середина? То есть язык высокого уровня плюс ассемблерные вставки там, где это необходимо.
    Что мне не нравится в ассемблере? ... почему бы в ассемблере не использовать привычную для языков высокого уровня символику? ... например для присвоения можно использовать знак "=". У вас иное мнение?
    Заменять одно другим не стоит, разумеется. Я примерно об этом и говорю в последних 2-х абзацах. Каждый инструмент должен быть применён к месту и разумно – это касается всего, не только языков программирования. Когда я пишу на чистом асме, то делаю это чаще по приколу, чем по необходимости, потому что в большинстве случаев достаточно вставок.
    Что касается высокоуровневого синтаксиса, то некоторые люди пытаются сделать что-то удобоваримое (HLA, к примеру). Но всё равно большой популярностью это не пользуется. Не могу сказать почему, ведь конструкции вроде .IF и .WHILE есть в том же masm32, и люди их вовсю применяют. Исходники на HLA выглядят вот так:
    Код:
    begin BitCnt_1;
    
    	push( ebx );
    	push( ecx );
    	mov( bits2Cnt, ebx );
    	mov( 0, eax );
    	for( mov( 32, ecx ); ecx > 0; dec( ecx )) do
    	
    		shr( 1, ebx );
    		if( @c ) then
    			
    			inc( eax );
    			
    		endif;
    		
    	endfor;
    	pop( ecx );
    	pop( ebx );
    	
    end BitCnt_1;
    
    . . .
    
    	BitCnt_1( 1234567890 );
    	if( eax <> edx ) then
    	
    		stdout.put
    		( 
    			"BitCnt_1 produced an incorrect result: ",
    			(type uns32 eax),
    			" (Should have been ",
    			(type uns32 edx),
    			")" nl
    		);
    		
    	endif;
    На любителя, конечно...
    Но конструкции вида ax = bx можно написать макросами в нормальных ассемблерах типа MASM, fasm, NASM (правда, выглядеть это будет скорее как @ax = bx или . ax = bx).
    Запись от Jin X размещена 28.07.2018 в 09:13 Jin X вне форума
    Обновил(-а) Jin X 28.07.2018 в 18:36
  8. Старый комментарий
    Цитата:
    Сообщение от нтч Просмотреть комментарий
    Что мне не нравится в ассемблере? ... почему бы в ассемблере не использовать привычную для языков высокого уровня символику? ... например для присвоения можно использовать знак "=". У вас иное мнение?
    На ещё более низком уровне, чем тот, где обычно работают ассемблеры, есть VHDL, Verilog, наверняка есть и другие подобные языки.
    https://upload.wikimedia.org/w... source.svg
    Электронщикам можно использовать привычную для языков высокого уровня символику.
    Со всех сторон наседают на ассемблеры!
    Запись от ОС размещена 29.07.2018 в 10:13 ОС вне форума
  9. Старый комментарий
    Бывают такие задачки, что их легче запрограммировать на языке ассемблера, чем на языке высокого уровня, в частности на С++. Например сцепление строки, с определенной частью другой строки, кода известно индекс первого символа и длина подстроки. При этом подстрока может быть в начале, в середине или в конце второй строки, которая задается в параметрах функции
    Запись от Melamed размещена 30.07.2018 в 14:23 Melamed вне форума
  10. Старый комментарий
    Цитата:
    Сообщение от Jin X Просмотреть комментарий
    Спасибо!

    Раньше много чего по-другому было, биты тумблерами переключали, насколько мне известно . Я ж говорю: если хочется и вы видите в этом смысл – не вопрос. У К.К. даже есть статья про программирование в машинных кодах.

    Заменять одно другим не стоит, разумеется. Я примерно об этом и говорю в последних 2-х абзацах. Каждый инструмент должен быть применён к месту и разумно – это касается всего, не только языков программирования. Когда я пишу на чистом асме, то делаю это чаще по приколу, чем по необходимости, потому что в большинстве случаев достаточно вставок.
    Что касается высокоуровневого синтаксиса, то некоторые люди пытаются сделать что-то удобоваримое (HLA, к примеру). Но всё равно большой популярностью это не пользуется. Не могу сказать почему, ведь конструкции вроде .IF и .WHILE есть в том же masm32, и люди их вовсю применяют. Исходники на HLA выглядят вот так:
    Код:
    begin BitCnt_1;
    
    	push( ebx );
    	push( ecx );
    	mov( bits2Cnt, ebx );
    	mov( 0, eax );
    	for( mov( 32, ecx ); ecx > 0; dec( ecx )) do
    	
    		shr( 1, ebx );
    		if( @c ) then
    			
    			inc( eax );
    			
    		endif;
    		
    	endfor;
    	pop( ecx );
    	pop( ebx );
    	
    end BitCnt_1;
    
    . . .
    
    	BitCnt_1( 1234567890 );
    	if( eax <> edx ) then
    	
    		stdout.put
    		( 
    			"BitCnt_1 produced an incorrect result: ",
    			(type uns32 eax),
    			" (Should have been ",
    			(type uns32 edx),
    			")" nl
    		);
    		
    	endif;
    На любителя, конечно...
    Но конструкции вида ax = bx можно написать макросами в нормальных ассемблерах типа MASM, fasm, NASM (правда, выглядеть это будет скорее как @ax = bx или . ax = bx).
    Вот это классный язык!)
    Запись от Konst2016 размещена 30.07.2018 в 23:06 Konst2016 вне форума
  11. Старый комментарий
    Цитата:
    Что же касается демосцены, то написать, скажем, intro, уместив исполняемый файл в 256 байт [1, 2, 3, 4] (а то и 128, 64, 32 или даже ещё меньше) на чём-то отличном от ассемблера вы вряд ли сможете.
    Это все конечно хорошо, только программы под DOS. Эта система давно не актуальна. Для Windows будет проблематично создать исполняемый файл PE формата такого размера, потому что в нем кроме машинного кода находятся служебные данные. На ЯВУ у меня получилось создать файл PE x86 размером 816 байт. https://www.cyberforum.ru/deve... ost3044634
    На x64 не запускается видимо из-за нестандартного выравнивания секций.
    Запись от locm размещена 19.10.2018 в 21:37 locm вне форума
  12. Старый комментарий
    Аватар для Jin X
    locm, 816 байт – это далеко не предел.
    Вот 97 байт для x86 и 286 байт для x64.
    А demo/intro пишут не только под DOS, но и даже под паяльники
    Запись от Jin X размещена 25.10.2018 в 14:20 Jin X вне форума
    Обновил(-а) Jin X 25.10.2018 в 14:23
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru