Ассемблер как двигатель к

Главная » Двигатель

Рейтинг статьи Загрузка…

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

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

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

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

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

Ассемблер как двигатель к

Программист, консультант, специалист по документированию. Легко и доступно рассказывает о сложных вещах в программировании и дизайне.

Ассемблер с нуля — практический подход

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

Будут приводиться ссылки на литературу, позволяющую более глубоко проникнуть в конкретные языки, на примере которых мы стараемся изложить наш подход к программированию.

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

В качестве примеров будет рассмотрено написание конкретных простейших программ «хакерской» направленности, а также изучены основы крекинга (взлома программных защит), использования дизассемблированного кода в сторонних программах.

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

Машины в продаже

Ассемблер как двигатель к

Mitsubishi Pajero, 2011

Ассемблер как двигатель к

Mitsubishi Pajero, 2012

Ассемблер как двигатель к

Mitsubishi Pajero, 2010

Ассемблер как двигатель к

Mitsubishi Pajero, 2006

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

Ассемблер как двигатель к

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

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

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

SMALL 100h HelloMessage DB 'Hello, World!',13,10,'$' 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:

.text _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 .bss
num resb 1

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

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

  1. Одна и та же команда в них выглядит по-разному.
  2. Например, в синтаксисе Intel:
  3. mov eax, ebx — команда перемещает данные из регистра eax в регистр ebx.
  4. В синтаксисе AT&T эта команда выглядит так:
  5. movl %eax, %ebx

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

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

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

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

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

Конечно.

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

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

Ассемблер как двигатель кСкриншот: сайт HeadHunterАссемблер как двигатель кСкриншот: сайт HeadHunterАссемблер как двигатель кСкриншот: сайт HeadHunter

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

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

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

Ассемблер как двигатель к

Главная » Двигатель

Рейтинг статьи Загрузка…

???? 342 просмотров

Ассемблер или другие языки? Xто выбрать? Почему я должен выучить еще один язык, если уже выучил другие языки? Лучший ответ — это следующий аргумент: когда вы знаете английский и живете во Франции и общаетесь там на английском, то чувство неудобства общения никогда вас не покинет. Это потому что во Франции первоочередным и приоритетным будет является французский язык, на котором вас поймут где угодно в пределах страны.

Замечание! Данный курс по программированию микроконтроллеров не распространяется на процессоры ПК с операционными системами Linux/ Windows/Mac, не распространяется на обучение программирование сложных систем на подобие Ethernet, а отвечает только требованиям, которые необходимы для начинающих программировать на языке ассемблер без каких-либо языков высокого уровня.

Много разработчиков, имеющих большой опыт программирования для AVR и которые используют высокоуровневые языки(C/C++. Basic, Pascal…) в повседневной их работе рекомендует начинающим учить AVR на основе языка ассемблер. Причинами этого, чаще всего, являются следующие случаи:

  • если требуется легко анализировать возникающие ошибки;
  • если программа выполняется по другому, чем заранее проектировалась и ожидалась;
  • если высокоуровневый язык не поддерживает управление или команды для какой-то аппаратной части микроконтроллера;
  • если в программе есть критические ко времени выполнения места, где требуется быстрота выполнения.
Читайте также:  Двигатель qvfa технические характеристики

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

Краткий и легкий

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

Эта проблема актуальна при трансляции с языка высокого уровня в язык ассемблера в процессе компиляции.

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

Быстрый и скоростной

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

Критические ко времени программы, такие как измерители сигналов времен без аппаратного таймера, которые должны выполняться превосходно, должны быть написаны на ассемблера.

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

Легок ли ассемблер в изучении?

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

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

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

Некоторые программы требуют до нескольких тысяч линий кода и для его оптимизации требуется много работы.

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

Язык ассемблер. Команды и основы ассемблера

Программирование на ассемблер

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

Ассемблер как двигатель к

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

Регистры

Регистрами в языке ассемблер называют ячейки памяти, расположенные непосредственно на кристалле с АЛУ (процессор). Особенностью этого типа памяти является скорость обращения к ней, которая значительно быстрее оперативной памяти ЭВМ. Она также называется сверхбыстрой оперативной памятью (СОЗУ или SRAM).

Существуют следующие виды регистров:

  1. Регистры общего назначения (РОН).
  2. Флаги.
  3. Указатель команд.
  4. Регистры сегментов.

Ассемблер как двигатель к

Есть 8 регистров общего назначения, каждый размером в 32 бита.

Доступ к регистрам EAX, ECX, EDX, EBX может осуществляться в 32-битовом режиме, 16-битовом — AX, BX, CX, DX, а также 8-битовом — AH и AL, BH и BL и т. д.

Буква «E» в названиях регистров означает Extended (расширенный). Сами имена же связаны с их названиями на английском:

[tchecklist]

  • Accumulator register (AX) — для арифметических операций.
  • Counter register (CX) — для сдвигов и циклов.
  • Data register (DX) — для арифметических операций и операций ввода/вывода.
  • Base register (BX) — для указателя на данные.
  • Stack Pointer register (SP) — для указателя вершины стека.
  • Stack Base Pointer register (BP) — для индикатора основания стека.
  • Source Index register (SI) — для указателя отправителя (источника).
  • Destination Index register (DI) — для получателя.

[/tchecklist]

Специализация РОН языка ассемблер является условной. Их можно использовать в любых операциях. Однако некоторые команды способны применять только определенные регистры. Например, команды цикла используют ESX для хранения значения счетчика.

Регистр флагов. Под этим подразумевается байт, который может принимать значения 0 и 1. Совокупность всех флагов (их порядка 30) показывают состояние процессора. Примеры флагов: Carry Flag (CF) — Флаг переноса, Overflow Flag (OF) — переполнения, Nested Flag (NT) — флаг вложенности задач и многие другие. Флаги делятся на 3 группы: состояние, управление и системные.

Ассемблер как двигатель к

Указатель команд (EIP — Instruction Pointer). Данный регистр содержит адрес инструкции, которая должна быть выполнена следующей, если нет иных условий.

Регистры сегментов (CS, DS, SS, ES, FS, GS). Их наличие в ассемблере продиктовано особым управлением оперативной памятью, чтобы увеличить ее использование в программах. Благодаря им можно было управлять памятью размером до 4 Гб. В архитектуре Win32 необходимость в сегментах отпала, но названия регистров сохранились и используются по-другому.

Это область памяти, выделенная для работы процедур. Особенность стека заключается в том, что последние данные, записанные в него, доступны для чтения первыми. Или иными словами: первые записи стека извлекаются последними. Представить этот процесс себе можно в качестве башни из шашек.

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

Стек постоянно очищается и в каждый момент времени одна процедура использует его.

Ассемблер как двигатель к

Ассемблер как двигатель к

  • В настоящее время компания Faurndau является европейским лидером в разработке и производстве асинхронных, синхронных электродвигателей и электромашин постоянного тока, применяемых в составе испытательных стендов.
  • Выбирая электродвигатели Faurndau клиенту гарантированно полное техническое сопровождение: рекомендаций по выбору электрооборудования в зависимости от сферы применения, индивидуальных подход в проектировании конструкции корпуса и электромагнитной системы электромотора, пусконаладочные работы, поставка запасных частей и расходных материалов.
  • В настоящее время для замены электроприводов постоянного тока производитель предлагает своим партнерам использовать асинхронные электродвигатели переменного тока с короткозамкнутым ротором серии ASM.

2. О компиляторах

Какой ассемблер лучше?

Для процессора x86-x64, имеется более десятка различных ассемблер компиляторов. Они отличаются различными наборами функций и синтаксисом. Некоторые компиляторы больше подходят для начинающих, некоторые ― для опытных программистов.

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

Для некоторых ассемблеров написаны учебные пособия и книги, в которых подробно рассматривается синтаксис, у других нет ничего. Какой ассемблер лучше?

Учитывая множество диалектов ассемблеров для x86-x64 и ограниченное количество времени для их изучения, ограничимся кратким обзором следующих компиляторов: MASM, TASM, NASM, FASM, GoASM, Gas, RosAsm, HLA.

Какую операционную систему вы бы хотели использовать?

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

WindowsDOSLinuxBSDQNXMacOS, работающий на процессоре Intel/AMD
FASM x x x x
GAS x x x x x x
GoAsm x
HLA x x
MASM x x
NASM x x x x x x
RosAsm x
TASM x x

Поддержка 16 бит

Если ассемблер поддерживает DOS, то он поддерживает и 16-разрядные команды. Все ассемблеры предоставляют возможность писать код, который использует 16-разрядные операнды.

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

Читать еще:  Lada granta sport тюнинг двигателя

Поддержка 64 бит

За исключением TASM, к которому фирма Borland охладела в середине нулевых, и, который не поддерживает в полном объеме даже 32-разрядные программы, все остальные диалекты поддерживают разработку 64-разрядных приложений.

Переносимость программ

Очевидно, что вы не собираетесь писать код на ассемблере x86-x64, который запускался бы на каком-то другом процессоре. Однако, даже на одном процессоре вы можете столкнуться с проблемами переносимости.

Например, если вы предполагаете компилировать и использовать свои программы на ассемблере под разными операционными системами. NASM и FASM можно использовать в тех операционных системах, которые они поддерживают.

Предполагаете ли вы писать приложение на ассемблере и затем портировать, это приложение с одной ОС на другую с «перекомпиляцией» исходного кода? Эту функцию поддерживает диалект HLA.

Предполагаете ли вы иметь возможность создавать приложения Windows и Linux на ассемблере с минимальными усилиями для этого? Хотя, если вы работаете с одной операционной системой и абсолютно не планируете работать в какой-либо другой ОС, тогда эта проблема вас не касается.

Поддержка высокоуровневых языковых конструкций

Некоторые ассемблеры предоставляют расширенный синтаксис, который обеспечивает языковые высокоуровневые структуры управления (типа IF, WHILE, FOR и так далее).

Такие конструкции могут облегчить обучение ассемблеру и помогают написать более читаемый код. В некоторые ассемблеры встроены «высокоуровневые конструкции» с ограниченными возможностями.

Читайте также:  139 qmb как снять двигатель

Другие предоставляют высокоуровневые конструкции на уровне макросов.

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

Качество документации

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

Читать еще:  Что такое вакуум в двигателе

В следующей таблице описывается качество справочного руководства ассемблера, которое прилагается к продукту:

Учебники и учебные материалы

Документация на самом ассемблере, конечно, очень важна.

Еще больший интерес для новичков и других, изучающих язык ассемблера (или дополнительные возможности данного ассемблера), ― это наличие документации за пределами справочного руководства для языка.

Большинство людей хотят, чтобы учебник, объясняющий, как программировать на ассемблере, не просто предоставляет синтаксис машинных инструкций и ожидает, что читателю объяснят, как объединять эти инструкции для решения реальных проблем.

MASM является лидером среди огромного объема книг, описывающих, как программировать на этом диалекте. Есть десятки книг, которые используют MASM в качестве своего ассемблера для обучения ассемблеру.

Большинство учебников по ассемблеру MASM/TASM продолжают обучать программированию под MS-DOS. Хотя постепенно появляются учебники, которые обучают программированию в Windows и Linux.

Почему Ассемблер — это круто, но сложно — Журнал «Код» программирование без снобизма

Есть высокоуровневые языки — это те, где вы говорите if — else, print, echo, function и так далее. «Высокий уровень» означает, что вы говорите с компьютером более-менее человеческим языком. Другой человек может не понять, что именно у вас написано в коде, но он хотя бы сможет прочитать слова.

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

Ассемблер — это собирательное название языков низкого уровня: код всё ещё пишет человек, но он уже гораздо ближе к принципам работы компьютера, чем к принципам мышления человека.

Вариантов Ассемблера довольно много. Но так как все они работают по одинаковому принципу и используют (в основном) одинаковый синтаксис, мы будем все подобные языки называть общим словом «Ассемблер».

Как мыслит процессор

Чтобы понять, как работает Ассемблер и почему он работает именно так, нам нужно немного разобраться с внутренним устройством процессора.

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

Регистры бывают разного вида и назначения: одни служат, чтобы хранить информацию; другие сообщают о состоянии процессора; третьи используются как навигаторы, чтобы процессор знал, куда идти дальше, и так далее. Подробнее — в расхлопе ↓

Общего назначения. Это 8 регистров, каждый из которых может хранить всего 4 байта информации. Такой регистр можно разделить на 2 или 4 части и работать с ними как с отдельными ячейками.

Указатель команд. В этом регистре хранится только адрес следующей команды, которую должен выполнить процессор. Вручную его изменить нельзя, но можно на него повлиять различными командами переходов и процедур.

Регистр флагов. Флаг — какое-то свойство процессора. Например, если установлен флаг переполнения, значит процессор получил в итоге такое число, которое не помещается в нужную ячейку памяти. Он туда кладёт то, что помещается, и ставит в этот флаг цифру 1. Она — сигнал программисту, что что-то пошло не так.

Флагов в процессоре много, какие-то можно менять вручную, и они будут влиять на вычисления, а какие-то можно просто смотреть и делать выводы. Флаги — как сигнальные лампы на панели приборов в самолёте. Они что-то означают, но только самолёт и пилот знают, что именно.

Сегментные регистры. Нужны были для того, чтобы работать с оперативной памятью и получать доступ к любой ячейке. Сейчас такие регистры имеют по 32 бита, и этого достаточно, чтобы получить 4 гигабайта оперативки. Для программы на Ассемблере этого обычно хватает.

Так вот: всё, с чем работает Ассемблер, — это команды процессора, переменные и регистры.

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

Команды Ассемблера

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

  • Любая команда на этом языке выглядит так:
  • [<метка>:] <команда> [<операнды>] [;<комментарий>]

Метка — это имя для фрагмента кода. Например, вы хотите отдельно пометить место, где начинается работа с жёстким диском, чтобы было легче читать код. Ещё метка нужна, чтобы в другом участке программы можно было написать её имя и сразу перепрыгнуть к нужному куску кода.

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

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

В этом, собственно, и выражается человечность Ассемблера: команды в нём хотя бы отдалённо напоминают человеческие слова.

Операнды отвечают за то, что именно будут делать команды: какие ячейки брать для вычислений, куда помещать результат и что сделать с ним дополнительно. Операндом могут быть названия регистров, ячейки памяти или служебные части команд.

Комментарий — это просто пояснение к коду. Его можно писать на любом языке, и на выполнение программы он не влияет. Примеры команд:

mov eax, ebx ; Пересылаем значение регистра EBX в регистр EAX mov x, 0 ; Записываем в переменную x значение 0 add eax, х ; Складываем значение регистра ЕАХ и переменной х, результат отправится в регистр ЕАХ

Здесь нет меток, первыми идут команды (mov или add), а за ними — операнды и комментарии.

Пример: возвести число в куб

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

Первый вариант

mov al, x ; Пересылаем x в регистр AL imul al ; Умножаем регистр AL на себя, AX = x * x movsx bx, x ; Пересылаем x в регистр BX со знаковым расширением imul bx ; Умножаем AX на BX. Результат разместится в DX:AX

Второй вариант

mov al, x ; Пересылаем x в регистр AL imul al ; Умножаем регистр AL на себя, AX = x * x cwde ; Расширяем AX до EAX movsx ebx, x ; Пересылаем x в регистр EBX со знаковым расширением imul ebx ; Умножаем EAX на EBX. Поскольку x – 1-байтовая переменная, результат благополучно помещается в EAX

  1. На любом высокоуровневом языке возвести число в куб можно одной строкой. Например:
  2. x = Math.pow(x,3);
  3. x := exp(ln(x) * 3);
  4. на худой конец x = x*x*x.

Хитрость в том, что когда каждая из этих строк будет сведена к машинному коду, этого кода может быть и 5 команд, и 10, и 50, и даже 100. Чего стоит вызов объекта Math и его метода pow: только на эту служебную операцию (ещё до самого возведения в куб) может уйти несколько сотен и даже тысяч машинных команд.

А на Ассемблере это гарантированно пять команд. Ну, или как реализуете.

Почему это круто

Ассемблер позволяет работать с процессором и памятью напрямую — и делать это очень быстро. Дело в том, что в Ассемблере почти не тратится зря процессорное время.

Если процессор работает на частоте 3 гигагерца — а это примерно 3 миллиарда процессорных команд в секунду, — то очень хороший код на Ассемблере будет выполнять примерно 2,5 миллиарда команд в секунду.

Для сравнения, JavaScript или Python выполнят в тысячу раз меньше команд за то же время.

Ещё программы на Ассемблере занимают очень мало места в памяти. Именно поэтому на этом языке пишут драйверы, которые встраивают прямо в устройства, или управляющие программы, которые занимают несколько килобайт.

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

А всё потому, что она написана для конкретного процессора и использует его возможности на сто процентов.

Справедливости ради отметим, что современные компиляторы С++ дают машинный код, близкий по быстродействию к Ассемблеру, но всё равно немного уступают ему.

Почему это сложно

Для того, чтобы писать программы на Ассемблере, нужно очень любить кремний:

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

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

Для чего всё это

Ассемблер незаменим в таких вещах:

  • драйверы;
  • программирование микроконтроллеров и встраиваемых процессоров;
  • куски операционных систем, где важно обеспечить скорость работы;
  • антивирусы (и вирусы).

На самом деле на Ассемблере можно даже запилить свой сайт с форумом, если у программиста хватает квалификации. Но чаще всего Ассемблер используют там, где даже скорости и возможностей C++ недостаточно.

C vs Assembler

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

Читайте также:  Двигатель 1az на каких авто

На Си или на Ассемблере. Выбор не прост, не зря программисты однокристальщики раскололись на два непримиримых лагеря.

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

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

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

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

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

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

C-
А вот с высокими языками, например с Си, ситуация уже куда хуже.

Да, повторить какой нибудь пример из обучалки, вроде вывода строки на дисплей, Сях куда проще, подключил нужную библиотеку, набрал стандартную команду и вот тебе результат. Но это только так кажется.

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

Напомню, что у AVR, как и подавляющего числа МК, память разделена на код и данные и адреса у них в разных адресных пространствах о которых стандарт Си ничего не знает, ведь он расчитан на некий универсальный вычислитель.

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

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

работе на прерываниях, использованию многопоточных процессов, использующих одни и те же ресурсы.

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

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

не можешь найти концы.

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

Ну и такие гадкие вещи как overhead. Программа на Си требует значительно больше оперативной памяти, значительно больше места во flash памяти, работает куда медленней чем ассемблерная программа.

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

Кроме того существуют такие контроллеры как ATTiny 1x у которых либо вообще нет оперативки, либо она такая мизерная, что даже стек там сделан аппаратным. Так что на Си там ничего написать в принципе нельзя.

Assembler+
Представь, что ты прораб, а компилятор это банда джамшутов. И вот надо проделать дырку в стене. Даешь ты джамшутам отвертку и говоришь — ковыряйте. Проковряют они отверткой бетонную стену? Конечно проковыряют, вопрос лишь времени и прочности отвертки.

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

Главное дать задание и проконтроллировать выполнение, а джамшуты все сделают сами.

Задача решается? Да! Эффективно это решение? Совершенно нет! А почему? А потому что прораб не знал, что бетон твердый и отверткой его проковырять сложно. А будь прораб сам когда то рабочим, пусть даже не профи, но своими руками положил плитку, посверлил дырки, то впредь таких идиотских заданий бы не давал.

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

Также и с ассемблером. Хочешь писать эффективные программы на высокоуровневом языке — изучи хотя бы один ассемблер, попиши на нем немного. Чтобы потом, глядя на любую Сишную строку, представлять себе во что это в итоге компилируется и как обрабатывается контроллером. Очень помогает в отладке и написании, а уж про ревесирование чужих программ я вообще не говорю.

Assembler-
Но засиживаться в ассемблерщиках и стараться все сделать на нем далеко не обязательно.

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

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

С+
Си хорош за счет огромного числа готового кода, который можно очень легко и удобно подключать и использовать в своих нуждах. За большую читабельность алгоритмов. За возможность взять и перетащить код, например, с AVR на ARM без особых заморочек. Или с AVR на PIC. Разумеется для этого надо уметь ПРАВИЛЬНО писать на Си, выделяя все аппаратно зависимые части в HAL.

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

Особенно если проект подразумевает не просто мигание светодиодом.

8-16 килобайт тут уже зависит от задачи, а вот пытаться писать на ассемблере прошивку более 16 килобайт можно, но это напоминает прокладку тоннеля под Ла Маншем с помощью зубила.

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

Когда разные трюки и хитрости, вроде игр с адресами возврата из прерываний и процедур, переходами и конечными автоматами на таблицах и всякие извраты будут вызывать лишь интерес, но никак не взрыв мозга из серии «Аааа как это работает??? Не понимаю?!!» Вот тогда и можно изучать Си. Причем, изучать его с дебагером в руках.

Не просто изучить синтаксис (там то как раз все элементарно), а понять ЧТО и КАК делает компилятор из твоего исходника. Поржать над его тупостью или наоборот поудивляться извратам искуственного интелекта. Понять как компилятор делает ветвления, как организует циклы, как идет работа с разными типами данных, как ведется оптимизация.

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

А вот начать изучение ассемблера после Си мало кому удается. Си расслабляет, становится лень и впадлу. Скомпилировалось? Работает? Ну и ладно. А то что там быдлокод, та пофигу… =)

А как же бейсик, паскаль и прочие языки? Они тоже есть на AVR?
Конечно есть, например BascomAVR или MicroPASCAL и во многих случаях там все проще и приятней. Не стоит прельщаться видимой простотой. Она же обернется тем, что потом все равно придется переходить на Си.

Дело в том, что мир микроконтроллеров далеко не ограничивается одним семейством. Постоянно появляются новые виды контроллеров, развиваются новые семейства.

Ведь кроме AVR есть еще и ARM, PIC, STM8 и еще куча прекрасных контроллеров со своими плюсами. И под каждый из этих семейств есть Си компилятор. Ведь Си это, по сути, промышленный стандарт.

Он есть везде и контроллер который не имеет под него компилятора популярным у профессионалов не станет никогда.

А вот на бейсик с паскалем, обычно, всем пофигу.

Если на AVR и PIC эти компиляторы и сделали, то лишь потому, что процы эти стали особо популярны у любителей и там наверняка найдется тот, кто заинтересуется и бейсиками всякими.

С другим семейством контроллеров далеко не факт, что будет также радужно. Например под STM8 или Cortex M3 я видел Pascal в лучшем случае только в виде кривых студенческих поделок. Никак не тянущих на нормальный компилятор.

Такой разный Си
С Си тоже не все гладко. Тут следует избегать компиляторов придумывающих свои диалектные фишки. Например, CodeVision AVR (CVAVR) позволяет обращаться к битам порта с помощью такого кода:

1 PORTB.7 = 1; // Выставить бит 7 порта B в 1

PORTB.7 = 1; // Выставить бит 7 порта B в 1

Удобно? Конечно удобно! Вот только в Си так делать нельзя, стандарт языка не позволяет. И ни один другой Си компилятор такой кусок кода не примет. Т.к. по стандарту корректней будет так:

PORTB |= 1

Ссылка на основную публикацию
Adblock
detector