Код
#статьи

Что такое ассемблер и нужно ли его изучать

Этому языку уже за 70, но на пенсию он пока не собирается.

Полина Суворова для Skillbox Media

Есть традиция начинать изучение программирования с вывода на экран строки «Hello world!». На языке Python, например, это всего одна команда:

print("Hello, World!")

Всё просто, понятно и красиво! Но есть язык программирования, в котором, чтобы получить тот же результат, нужно написать солидный кусок кода:

.MODEL SMALL
.STACK 100h
.DATA
    HelloMessage DB 'Hello, World!',13,10,'$'
.CODE
START:
    mov ax,@data
    mov ds,ax
    mov ah,9
    mov dx,OFFSET HelloMessage
    int 21h
    mov ah,4ch
    int 21h
END START

Это ассемблер. Только не нужно думать, что он плох. Просто Python — это язык высокого уровня, а ассемблер — низкого. Одна команда Python при выполнении вызывает сразу несколько операций процессора, а каждая команда ассемблера — всего одну операцию.

Сложно? Давайте разбираться.

Немного о процессорах и машинном языке

Чтобы объяснить, что такое язык ассемблера, начнём с того, как вообще работает процессор и на каком языке с ним можно «разговаривать».

Процессор — это электронное устройство (сейчас крошечная микросхема, а раньше процессоры занимали целые залы), не понимающее слов и цифр. Он реагирует только на два уровня напряжения: высокий — единица, низкий — ноль. Поэтому каждая процессорная команда — это последовательность нулей и единиц: 1 — есть импульс, 0 — нет.

Для работы с процессором используется машинный язык. Он состоит из инструкций, записанных в двоичном коде. Каждая инструкция определяет одну простую машинную операцию: арифметическую над числами, логическую (поразрядную), ввода-вывода и так далее.

Например, для Intel 8088 инструкция 0000001111000011B — это операция сложения двух чисел, а 0010101111000011B — вычитания.

Программировать на машинном языке нелегко — приходится работать с огромными цепочками нулей и единиц. Трудно написать или проверить такую программу, а уж тем более разобраться в чужом коде.

Поэтому много лет назад был создан язык ассемблера, в котором коды операций обозначались буквами и сокращениями английских слов, отражающих суть команды. Например, команда mov ax, 6 означает: «переместить число 6 в ячейку памяти AX».

Когда и как был создан ассемблер?

Это произошло ещё в сороковых годах прошлого века. Ассемблер был создан для первых ЭВМ на электронных лампах, программы для которых писали на машинном языке. А так как памяти у компьютеров было мало, то команды вводили, переключая тумблеры и нажимая кнопки. Даже несложные вычисления занимали много времени.

Проблему решили, когда ЭВМ научились хранить программы в памяти. Уже в 1950 году была разработана первая программа-транслятор, которая переводила в машинный код программы, написанные на понятном человеку языке. Эту программу назвали программой-сборщиком, а язык — языком ассемблера (от англ. assembler — сборщик).

Появление ассемблера сильно облегчило жизнь программистов. Они смогли вместо двоичных кодов использовать команды, состоящие из близких к обычному языку условных обозначений. Кроме того, ассемблер позволил уменьшить размеры программ — для машин того времени это было важно.

Как устроен язык ассемблера?

Ассемблер можно считать языком второго поколения, если за первый принять машинный язык. Он работает непосредственно с процессором, и каждая его команда — это инструкция процессора, а не операционной или файловой системы. Перевод языка ассемблера в машинный код называется ассемблированием.

Команды ассемблера состоят из кодов операций и операндов. Операнды — это адреса, из которых процессор будет брать данные для вычислений и в которые будет помещать результат. Адресами могут быть ячейки оперативной памяти и регистры — память внутри процессора. Процессор работает с регистрами гораздо быстрее, чем с оперативной памятью.

Коды операций в языке ассемблера мнемонические, то есть удобные для запоминания:

  • ADD — сложение (от англ. addition);
  • SUB — вычитание (от англ. subtraction);
  • MUL — умножение (от англ. multiplication) и так далее.

Регистрам и ячейкам памяти присваиваются символические имена, например:

EAX, EBX, AX, AH — имена для регистров;

meml — имя для ячейки памяти.

Например, так выглядит команда сложения чисел из регистров AX и BX:

add ax, bx

А это команда вычитания чисел из регистров AX и BX:

sub ax, bx

Кроме инструкций, в языке ассемблера есть директивы — команды управления компилятором, то есть программой-ассемблером.

Вот некоторые из них:

  • INCLUDE — открыть файл и начать его компиляцию;
  • EXIT — прекратить компиляцию файла;.
  • DEF — назначить регистру символическое имя и т. д.

Не думайте, что ассемблер — всего лишь набор инструкций процессора с удобной для программиста записью. Это полноценный язык программирования, на котором можно организовать циклы, условные переходы, процедуры и функции.

Вот, например, код, на ассемблере, выводящий на экран цифры от 1 до 10:

section  .text
   global _start 	
_start: 	            
   mov ecx,10
   mov eax, '1'
         	
l1:
   mov [num], eax
   mov eax, 4
   mov ebx, 1
   push ecx
            	
   mov ecx, num        
   mov edx, 1        
   int 0x80
            	
   mov eax, [num]
   sub eax, '0'
   inc eax
   add eax, '0'
   pop ecx
   loop l1
            	
   mov eax,1            
   int 0x80            
section  .bss
num resb 1

Здесь действие будет выполняться в цикле — как, например, в циклах for или do while в языках высокого уровня.

Единого стандарта для языков ассемблера нет. В работе с процессорами Intel разработчики придерживаются двух синтаксисов: Intel и AT&T. Ни у того ни у другого нет особых преимуществ: AT&T — стандартный синтаксис в Linux, а Intel используется в мире Microsoft.

Одна и та же команда в них выглядит по-разному.

Например, в синтаксисе Intel:

mov eax, ebx — команда перемещает данные из регистра eax в регистр ebx.

В синтаксисе AT&T эта команда выглядит так:

movl %eax, %ebx

Почему для разных семейств процессоров нужен свой ассемблер?

Дело в том, что у каждого процессора есть набор характеристик — архитектура. Это его конструкция и принцип работы, а также регистры, адресация памяти и используемый набор команд. Если у процессоров одинаковая архитектура, то говорят, что они из одного семейства.

Так как наборы команд для разных архитектур процессоров отличаются друг от друга, то и программы на ассемблере, написанные для одних семейств, не будут работать на процессорах из других семейств. Поэтому ассемблер называют машинно-ориентированным языком.

Кому и зачем нужен язык ассемблера?

Даже из нашего примера «Hello, World!» видно, что ассемблер не так удобен в разработке, как языки высокого уровня. Больших программ на этом языке сейчас никто не пишет, но есть области, где он незаменим:

  • На ассемблере разрабатывают встроенные программы для микроконтроллеров. Это миниатюрные компьютеры, установленные в системах сигнализации, пультах управления, датчиках, бытовой технике, модемах и во многих других устройствах. Микроконтроллеры используются даже в робототехнике и спутниковых навигационных системах. Объём памяти у этих мини-компьютеров ограничен, а ассемблер удобен для их программирования тем, что одна его команда транслируется в одну команду в двоичном коде. По исходному тексту программы можно определить время её исполнения и объём памяти для её хранения.
  • На ассемблере пишут драйверы устройств и некоторые компоненты операционных систем — например, ядро или загрузчик. Любительские операционные системы MenuetOS и KolibriOS полностью написаны на ассемблере. Ассемблерный код есть в программах для игровых приставок и мультимедийных кодеков.
  • Ассемблер применяется в реверс-инжиниринге — обратной разработке программ. Реверс-инжиниринг используют, чтобы понять, как работают программы, какой у них алгоритм. Это нужно в тех случаях, когда создатель по каким-то причинам не хочет публиковать исходный код. Обратной разработкой занимаются антивирусные компании, исследующие вирусы и трояны, создатели драйверов и операционных систем, а также просто любопытные. Ещё её активно применяют компьютерные злоумышленники всех мастей: взламывают программы, ищут уязвимости, пишут вирусы, генераторы ключей и тому подобное.

Если вы хотите разрабатывать новые микропроцессоры или стать реверс-инженером, то есть смысл серьёзно заняться изучением языка ассемблера.

Востребованы ли программисты на ассемблере сегодня?

Конечно. Хотя на сайтах по поиску работу вы вряд ли найдёте заявки от работодателей с заголовками: «Нужен программист на ассемблере», зато там много таких, где требуется знание ассемблера дополнительно к языкам высокого уровня: C, C++ или Python. Это вакансии реверс-инженеров, специалистов по компьютерной безопасности, разработчиков драйверов и программ для микроконтроллеров/микропроцессоров, системных программистов и другие.

Предлагаемая зарплата — обычная в сфере IT: 80–300 тысяч рублей в зависимости от квалификации и опыта. Вот, например, вакансия реверс-инженера на HeadHunter, где требуется знание ассемблера:

Стоит ли начинать изучение программирования с языка ассемблера?

Нет, так делать не нужно. Для этого есть несколько причин:

  • Ассемблер слишком сильно отличается от языков высокого уровня, и переходить с него на другой язык будет сложно.
  • Опыт, полученный при изучении ассемблера, в другом языке вам не пригодится. Изучение высокоуровневых языков после ассемблера придётся начинать с чистого листа.
  • Ассемблер — слишком подробный язык. Все рутинные действия, которые в других языках берёт на себя транслятор, в ассемблере приходится описывать программисту. Это может быстро наскучить.

Поэтому, даже если вы решили заняться профессией, связанной с ассемблером, изучение программирования вам лучше начинать с языка высокого уровня. А уж ассемблер после него будет выучить несложно.


Научитесь: Карьера разработчика: трудоустройство и развитие Узнать больше
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована