СДЕЛАЙТЕ СВОИ УРОКИ ЕЩЁ ЭФФЕКТИВНЕЕ, А ЖИЗНЬ СВОБОДНЕЕ

Благодаря готовым учебным материалам для работы в классе и дистанционно

Скидки до 50 % на комплекты
только до

Готовые ключевые этапы урока всегда будут у вас под рукой

Организационный момент

Проверка знаний

Объяснение материала

Закрепление изученного

Итоги урока

Введение в Ассемблер

Категория: Информатика

Нажмите, чтобы узнать подробности

Просмотр содержимого документа
«Введение в Ассемблер»


Тема : Введение в Ассемблер


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

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

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


Что такое ассемблер? Ассемблер - это программа, преобразовывающая исходный текст программы, написанной на языке ассемблера, в машинный код. Дополнительно ассемблер может создавать листинг программы с номерами строк, адресами переменных, операторами исходного языка и таблицей перекрестных ссылок символов и переменных, используемых в программе. Совместно с ассемблером используется программа, называемая компоновщиком (linker) или редактором связей (linkage editor). Она объединяет отдельные файлы, созданные ассемблером, в единую исполняемую программу. В блок базовых программ входит также отладчик (debugger) позволяющий программисту пошагово выполнять программу, проверять и изменять содержимое памяти.

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

16-разрядные программы для реального режима адресации. Эти программы предназначены для выполнения в системе MS DOS либо в среде эмулятора DOS под Linux. Большинство примеров из этой книги можно адаптировать для выполнения в реальном режиме адресации. О программировании для реального режима адресации речь пойдет в многочисленных примечаниях книги. Кроме того, две главы полностью посвящены выводу текстовой и графической информации на экран монитора в режиме MS DOS.

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

Как язык ассемблера связан с машинным кодом? Во-первых, машинный код - это набор чисел, которые интерпретируются центральным процессором компьютера и определяют выполняемые им действия. Например, все процессоры Intel семейства IA-32 имеют совместимый между собой машинный код. Машинный код состоит исключительно из двоичных чисел. Во-вторых, язык ассемблера состоит из набора операторов, понятных человеку. Каждый оператор начинается с короткого мнемонического обозначения выполняемых процессором действий, например ADD (сложить), MOV (переслать), SUB (вычесть) или CALL (вызвать). Язык ассемблера однозначно связан с машинным кодом. Это значит, что каждый оператор языка ассемблера соответствует одной команде машинного кода.

Какое отношение имеет язык ассемблера к языкам высокого уровня, таким как C++ или Java? Языки высокого уровня, такие как C++ или Java, не имеют однозначного соответствия с языком ассемблера и, следовательно, с машинным кодом. Например, один оператор языка C++ транслируется в несколько операторов языка ассемблера или несколько машинных команд. Давайте посмотрим, как происходит процесс трансляции оператора языка C++ в машинный код. Поскольку анализировать двоичный машинный код очень трудно, вместо него мы рассмотрим эквивалентные операторы языка ассемблера. В приведенном ниже операторе языка C++ выполняются две арифметические операции и полученный результат присваивается переменной. Предположим, что существуют целочисленные переменные X и Y:


X = (У + 4) 3;


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

mov еах, У; Загрузить значение переменной Y в регистр ЕАХ

add eax,4; Прибавить число 4 к регистру ЕАХ

mov ebx,3; Загрузить число 3 в регистр ЕВХ

imul ebx; Умножить содержимое регистра ЕАХ на содержимое ЕВХ

mov Х, еах; Переслать содержимое регистра ЕАХ в переменную X

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

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

Являются ли программы на языке ассемблера переносимыми? Важным отличием языка ассемблера от языков высокого уровня является то, что написанные на нем программы не являются переносимыми. Говорят, что язык программирования является переносимым {portable), если написанные на нем программы можно скомпилировать и запустить на разных компьютерных платформах. Например, программы, написанные на языке C++, Moгyr быть скомпилированы и запушены практически на любом компьютере и п любой операционной системе при условии, что в них не используются вызовы библиотечных функций, характерные для конкретной операционной системы. Основным отличием языка Java является то, что написанные на нем программы после компиляции могут выполняться в любой компьютерной системе, для которой существует реализация виртуальной машины Java.

Учитывая изложенные выше моменты, язык ассемблера не может быть переносимым по определению, поскольку он тесно связан с архитектурой процессоров определенного семейства. Таким образом, на сегодняшний день существует несколько совершенно разных языков ассемблера. Каждый из них привязан либо к конкретному семейству процессоров, либо к конкретной архитектуре компьютера. Среди них можно выделить семейство процессоров Motorola 68x00, Intel IA-32, SUN Sparc, VAX и IBM-370. Команды в языке ассемблера соответствуют командам конкретного процессора. Например, язык ассемблера, рассмотренный в этой книге, предназначен для программирования только процессоров Intel, принадлежащих семейству 1А-32.

Зачем изучать язык ассемблера? А если взять хорошую книгу, в которой описана архитектура конкретного компьютера и структура его процессора? Неужели она не заменит это описание программирования на языке ассемблера?

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

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

Для прикладного программиста язык ассемблера поможет преодолеть ограничения, накладываемые используемым ими языком высокого уровня в плане выполнения определенных типов операций. Например, в языке Microsoft Visual Basic обработка строковых данных выполняется крайне неэффективно. Поэтому для выполнения операций со строками, такими как шифрование данных и обработка битовых строк, программисты обычно используют подпрограммы, написанные на языке C++ или ассемблере и размешенные в DLL (Dynamic Link Libraries, или динамически загружаемые библиотеки).

Если вы связаны с разработкой специализированного оборудования, то наверняка вам придется написать драйвер устройства, управляющий работой того оборудования, которое выпускает ваша фирма. Драйверы устройств (device drivers) - это низкоуровневые системные программы, напрямую взаимодействующие с обслуживаемыми ими устройствами. В задачу драйвера входит преобразование обобщенных запросов, посылаемых операционной системой на конкретное устройство, в последовательность низкоуровневых команд, характерных для данного конкретного устройства. Например, производители принтеров комплектуют каждое выпускаемое ими устройство отдельными драйверами для каждой из поддерживаемых операционных систем, таких как Microsoft Windows, Mac OS, Linux и др.

Существуют ли какие-либо правила в языке ассемблера? Да, конечно, в языке ассемблера приняты несколько правил, обусловленные внутренней физической структурой самого процессора и его системой команд. Например, два операнда, используемые в одной команде, должны иметь одинаковый размер. Тем не менее, в языке ассемблера гораздо меньше правил, чем, например, вС++.

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

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

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

Программы (или хотя бы некоторые из них) для работы с ассемблером:

1. Emu8086. Хорошая программа, особенно для новичков. Включает в себя редактор исходного кода и некоторые другие полезные вещи. Работает в Windows, хотя программы пишутся под DOS. К сожалению, программа стоит денег (но оно того стоит))). Подробности см. на сайте http://www.emu8086.com.

2. TASM – Турбо Ассемблер от фирмы Borland. Можно создавать программы как для DOS так и для Windows. Тоже стоит денег и в данный момент уже не поддерживается (да и фирмы Borland уже не существует). А вообще вещь хорошая.

3. MASM – Ассемблер от компании Microsoft (расшифровывается как МАКРО ассемблер, а не Microsoft Assembler, как думают многие непосвящённые). Пожалуй, самый популярный ассемблер для процессоров Intel. Поддерживается до сих пор. Условно бесплатная программа. То есть, если вы будете покупать её отдельно, то она будет стоить денег. Но она доступна бесплатно подписчикам MSDN и входит в пакет программ Visual Studio от Microsoft.

4. WASM – ассемблер от компании Watcom. Как и все другие, обладает преимуществами и недостатками.

5. Debug - обладает скромными возможностями, но имеет большой плюс - входит в стандартный набор Windows. Поищите ее в папке WINDOWS\COMMAND или WINDOWS\SYSTEM32. Если не найдете, тогда в других папках каталога WINDOWS. 6. Желательно также иметь какой-нибудь шестнадцатеричный редактор. Не помешает и досовский файловый менеджер, например Волков Коммандер (VC) или Нортон Коммандер (NC). С их помощью можно также посмотреть шестнадцатеричные коды файла, но редактировать нельзя. Бесплатных шестнадцатеричных редакторов в Интернете довольно много. Вот один из них: McAfee FileInsight v2.1. Этот же редактор можно использовать для работы с исходными текстами программ. Однако мне больше нравится делать это с помощью следующего редактора:

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


Исполняемая программа

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

Какие файлы являются текстовыми, а какие - «исполняемыми» программами: primer.срр, primer ехе, primer.bat, primer.pas, primer.com, primer.asm ? Из перечисленных - это primer.exe и primer.com.

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

Запись команды в двоичном коде называют «машинный код команды». В коды команд преобразуются любые «операторные действия», в коды данных - сами данные.

Пример 1. Программа, увеличивающая каждый элемент массива данных на 2

В исходном тексте primer, срр

void main ()

{

short mt х[5] = 11,5, -3, 23, 1 2};

for (int k -=0; k

}

И исполняемом модуле

-

-

коды данных в памяти

последовательность команд процессора

Объем исходного текста primer срр составляет 98 байт, исполняемой программы после компиляции в Borland C++ v.3 - 6356 байт.

Язык ассемблера

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

Преобразование записанных на языке ассемблера команд и данных в машинные коды называется трансляция (ассемблирование) Трансляцию в машинные коды выполняет программа - транслятор («ассемблер»)

Программы - дизассемблеры выполняют обратную задачу: переводят машинные коды в символические ассемблерные команды.

Запись команды в ассемблере


add al, bl

mov ah, 4ch

Машинный код команды (в hex) после трансляции

8ED8

B44C

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

Пример 2. Программа примера 1 на ассемблере

Исходный текст программы (primer. asm)

code segment

assume cs code ; директивы транслятора

al: mov bx, ds ; команды

mov ds, bx

xor si, si

mov cx,5

a2: add cs:x[si], 2

inc si

inc si

loop a2

mov ah,4ch

int 21 h

x db 1,5,-3,23,12 ; данные

code ends

end al

Объем исходного текста ассемблерной программы - 212 байт. Объем исполняемого модуля primer.exe, полученного в Borland TASM, составляет 539 байт. Сравните с C++ !

Язык ассемблера — машинно-зависимый язык

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

Отличие ассемблеров от компиляторов

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

• Транслятор преобразует одну символическую команду ассемблера в одну машинную команду - преобразование «один к одному»

• Компилятор с ЯВУ преобразует один символический оператор языка в последовательность из нескольких машинных команд - преобразование «один к нескольким»

Компиляция одного оператора for (int k =0; k

mov сх,5

а2: add ds:x[si],2

me si

ine si

loop a2

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

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

Язык ассемблера и языки программирования высокого уровня

В отличии от языков высокого уровня:

  1. Язык ассемблера не является универсальным

Ассемблеры являются «машинно-зависимыми». Получаемый после трансляции машинный код уникален для процессоров данной архитектуры и не будет понят процессором другой платформы

  1. Ассемблер не является алгоритмическим языком

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

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

  1. Иной подход к освоению языка ассемблера

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

- иметь четкое представление об архитектуре и системе команд процессора, форматах данных, их кодировании и других реалиях,

- знать не столько конструкции символического языка (они крайне просты), а механизм выполнения процессором различных команд;

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

Места языка ассемблера в программировании

  1. Ассемблер - там, где нужен прямой программный доступ к памяти и аппаратуре.

  2. Ассемблер - для создания минимальный по размеру и/или минимальный по времени исполнения программы

С помощью ассемблерных вставок часто оптимизируют отдельные фраг менты программ на ЯВУ

Пример ассемблерной вставки в языке С:

asm {

mov al, disk

mov cx, Offffh

mov bx,p

int 25h

pop cx

}

  1. Ассемблер - это инструмент анализа исполняемых программ при отсутствии их исходных текстов.

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


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

5