Your AI powered learning assistant

ЯЗЫК АССЕМБЛЕРА С НУЛЯ | #1 НАЧАЛО

Введение

00:00:00

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

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

Набор инструкций

00:03:23

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

Что будет в этом видео

00:04:27

Переход с других языков После изучения любого другого языка здесь все может показаться немного странным. То, к чему мы привыкли, больше не работает по-старому. Раньше за нас все делали компиляторы; теперь, прежде чем бездумно писать код типа "hello world", нам нужно больше понимать процесс выполнения программ.

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

Ассемблер - это

00:05:08

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

Семейства процессоров

00:05:56

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

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

Регистры

00:08:00

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

Эволюция размеров регистров Регистры общего назначения, такие как CX, выполняют различные функции, такие как циклы подсчета или арифметические операции. С увеличением разрядности процессора 16-разрядные регистры расширились до 32 разрядов без потери совместимости с программным обеспечением, разработанным для 16-разрядных систем.

Режимы работы процессоров

00:10:24

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

Компиляторы

00:12:03

Компилятор Microsoft под названием MSDS управляет процессом компиляции, гарантируя, что созданные исполняемые файлы подходят для конкретных операционных систем. Каждая операционная система имеет свой уникальный способ загрузки программ в память и взаимодействия с внешними устройствами, для чего требуются различные форматы исполняемых файлов. Различия в компиляторах и ассемблерах приводят к различной совместимости кода между системами Windows и Linux.

Формат записи команд (mov)

00:13:22

Понимание формата записи команд Формат записи команд в документации существенно различается из-за двух разных синтаксисов, предложенных компаниями Intel и Kent. Команды состоят из названия, указывающего на действие, за которым следуют операнды, разделенные запятыми. Операнды могут варьироваться от одного до ни одного в зависимости от конкретной команды. Например, "mov" - это обычная команда ассемблера для передачи данных с двумя операндами, указывающими источник и место назначения.

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

Установка ms-dos

00:15:05

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

Сегменты программы

00:19:41

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

Адреса

00:20:32

Использование адресов для взаимодействия с сегментами Использование адресов в коде позволяет сегментам взаимодействовать друг с другом. Для доступа к данным из сегмента в памяти формируется адрес, состоящий из двух чисел: значения адреса сегмента и его смещения внутри сегмента. Логические адреса используются для программного формирования и хранения адресов сегментов.

Понимание адресации сегмента Сегментная адресация включает в себя 16-разрядные регистры, представляющие различные сегменты, такие как код, стек и данные. Комбинация этих регистров формирует логические адреса, которые могут указывать на любое местоположение внутри сегмента. За счет сдвига логического адреса, оставленного на 20-битной шине, на 4 бита, обеспечивается эффективный доступ к физическим ячейкам памяти объемом до одного мегабайта без ограничений.

Создание сегментов

00:23:48

Создание сегментов Maya Создание сегмента в Maya зависит от различных факторов. В коде для создания сегментов используются два метода: с помощью специальных директив 1, которые являются базовыми, и с помощью директив segment и NDS. Сначала мы присваиваем сегменту имя для последующего использования при получении сегментированного адреса.

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

Выравнивание размера регистра "U16" означает, что все регистры внутри этого сегмента по умолчанию будут 16-разрядными; однако, если вместо этого указано "I32" или когда указаны процессоры выше 386 моделей (которые используют выравнивание по I32), это влияет на размер создаваемых сегментов и формирование внутренних адресов.

Загрузка адресов в сегментные регистры

00:28:06

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

Группы

00:28:29

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

ASSUME

00:29:09

При работе с сегментами в группе компиляторы, по сути, не знают назначения каждого сегмента. Чтобы явно информировать компилятор о связях сегментов с кодом, данными или регистрами стека, в сегментах перед первой командой используется специальная директива в качестве руководства. При указании того, какой сегментный регистр "DS" указывает на какой сегмент (например, "D1" или "D2"), значения в регистре не перезаписываются, а доступны на основе меток, представляющих смещения внутри этих сегментов.

Директива .model

00:30:32

Директива .model используется для определения модели памяти для программы, позволяющей создавать несколько сегментов. Эта модель памяти определяет, как компилятор автоматически объединяет сегменты памяти. Различные модели, такие как flat и tiny, используются в зависимости от требований программы, с ограничениями на размер сегмента в зависимости от выбранной модели.

Упрощенные сегменты

00:32:06

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

Организация сегментов данных и кода Сегменты, подобные данным, соответствуют инициализированным данным в виде глобальных переменных, которым присваиваются значения при инициализации. Различие между ближними и дальними данными заключается в логической адресации с использованием 16-разрядных адресов для любой ячейки памяти (far) или только 16-разрядного смещения без указания сегмента (near). Директивы Data определяют внешние сегменты данных, в то время как 'const' используется для обозначения констант.

Исполняемые файлы

00:35:47

Исполняемые файлы позволяют группе избежать использования директивы ISU, поскольку определение используемой модели памяти влияет на то, какой исполняемый файл будет скомпилирован. Исполняемые файлы Windows широко известны своим расширением .exe, но MS-DOS поддерживает два типа исполняемых файлов: COM и EXE-структуры, которые существенно различаются. COM-файлы используют модель малой памяти, содержащую только скомпилированный код без дополнительной программной информации, в отличие от EXE-файлов неограниченного размера, обычно использующих модели малой памяти.

Загрузка программы в память

00:36:43

Понимание загрузки программы и распределения памяти Загрузка программ в память требует понимания того, как операционная система выделяет блоки памяти для выполнения программы. Для обозначения адресов в шестнадцатеричной системе создаются специальные структуры данных, такие как префиксы сегментов. Директива org определяет начальный адрес программы относительно PSP и сегмента.

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

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

Процесс компиляции

00:41:30

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

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

Написание первой программы

00:44:49

Создание первой программы с сообщением "Hello World" Написание первой программы предполагает применение всех рассмотренных знаний для создания базовой программы "Hello World". Это знаменует собой начало многих руководств по этому языку, восходящих ко времени, когда программисты имели полный контроль над компьютерами. Используя специальные команды и директивы, мы можем создать и скомпилировать простую программу.

Выделение памяти и объявление переменных Чтобы написать код, который компилируется в исполняемый файл, мы объявляем переменные, такие как message, с выделенными объемами памяти, указанными ключевыми словами, такими как db для байт. Адрес данных управляется с помощью сегментных регистров и смещений внутри сегментов для эффективного распределения памяти.

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

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

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