Применение языка Ассемблера
Общеизвестно, что программировать на Ассемблере трудно. Как Вы знаете, сейчас существует много различных языков высокого уровня, которые позволяют затрачивать много меньше усилий при написании программ. Естественно, возникает вопрос, когда у программиста может появиться необходимость использовать Ассемблер при написании программ. В настоящее время можно указать две области, в которых использование языка Ассемблера оправдано, а зачастую и необходимо.
Во-первых, это так называемые машинно-зависимые системные программы, обычно они управляют различными устройствами компьютера (такие программы называются драйверами). В этих системных программах используются специальные машинные команды, которые нет необходимости применять в обычных (или, как говорят прикладных) программах. Эти команды невозможно или весьма затруднительно задать в языке высокого уровня.
Вторая область применения Ассемблера связана с оптимизацией выполнения программ. Очень часто программы-переводчики (компиляторы) с языков высокого уровня дают весьма неэффективную программу на машинном языке. Обычно это касается программ вычислительного характера, в которых большую часть времени выполняется очень небольшой (порядка 3-5%) участок программы (главный цикл). Для решения этой проблемы могут использоваться так называемые многоязыковые системы программирования, которые позволяют записывать части программы на различных языках. Обычно основная часть программы записывается на языке программирования высокого уровня (Фортране, Паскале, С и т.д.), а критические по времени выполнения участки программы – на Ассемблере. Скорость работы всей программы при этом может значительно увеличиться. Часто это единственный способ заставить программу дать результат за приемлемое время.
При дальнейшем изучения архитектуры компьютера нам придётся писать как фрагменты, так и полные программы на машинном языке. Для написания этих программ мы будем использовать одну из версий языка Ассемблера, так называемый Макроассемблер версии 4.0 (MASM-4.0). Достаточно полное описание этого языка приведено в учебнике [5], изучения этого учебника (или аналогичных учебников по языку Ассемблера [6-8]) является обязательным для хорошего понимания материала по нашему курсу. На лекциях мы подробно будем изучать только те особенности и тонкие свойства языка Ассемблера, которые недостаточно полно описаны в указанных учебниках.
Изучение языка Ассемблера начнём с рассмотрения общей структуры программы на этом языке. Программа на языке Ассемблера состоит из одного или более независимых модулей. В каком смысле модуль является независимой единицей языка Ассемблер, мы выясним несколько позже, когда будем изучать тему "Модульное программирование". Наши первые программы будут содержать всего один модуль, но позже будут рассмотрены и многомодульные программы.
Каждый модуль обычно содержит описание одного или нескольких сегментов памяти. Напомним, что в нашей архитектуре для работы программы каждая команда и каждое данное должны располагаться в каких-либо сегментах памяти. Как мы уже знаем, в младшей модели нашего семейства ЭВМ в каждый момент времени определены четыре активных (или текущих) сегмента памяти, на которые указывают соответствующие сегментные регистры CS, DS, SS и ES.
Таким образом, перед непосредственной работой с содержимым любого сегмента требуется установить на его начало определённый сегментный регистр, до этого нельзя ни писать в этот сегмент, ни читать из него. С другими сегментами, кроме этих четырёх текущих (если они есть в программе), работать в этот момент нельзя, при необходимости доступа к ним нужно менять (перезагружать) содержимое соответствующих сегментных регистров.
Стоит заметить, что сегменты могут перекрываться в памяти ЭВМ и даже полностью совпадать (накладываться друг на друга). Однако максимальный размер сегмента в младшей модели нашего семейства ЭВМ равен 64К, и, если сегменты будут перекрываться, то одновременно для работы будет доступно меньшее количество оперативной памяти. Заметим, что пересечение сегментов никак не влияет на логику работы центрального процессора.[11]
В соответствии с принципом фон Неймана, мы имеем право размещать в любом из сегментов памяти как числа, так и команды. Но такой подход ведёт к плохому стилю программирования, программа перестаёт легко читаться и пониматься программистами. Будем поэтому стараться размещать команды программы в одним сегментах, а данные – в других. Весьма редко программисту будет выгодно размещать данные среди команд, один такой случай будет рассмотрен позже в нашем курсе.
На текущий сегмент команд должен указывать регистр CS, а на сегмент данных – регистр DS. Дело в том, что эти регистры специализированные. В частности, устройство управления может выбирать команды для выполнения только из сегмента, на который указывает регистр CS. Производить арифметические операции можно над числами из любого сегмента, однако в соответствии с принципом умолчания все переменные, если прямо не указано противное, сегментируются по регистру DS. Явное указание необходимости выбирать аргументы команды по другому сегментному регистру увеличивает длину команды на один байт (перед такой командой вставляется специальная однобайтная команда, которая называется префиксом сегмента).
Итак, модуль состоит из описаний сегментов. В сегментах находятся все команды и области памяти, используемые для хранения переменных. Вне сегментов могут располагаться только так называемые директивы языка Ассемблер, о которых мы будем говорить немного ниже. Пока лишь отметим, что чаще всего директивы не определяют в программе ни команд, ни переменных (поймите, что именно поэтому они и могут стоять вне сегментов). [12]
Описание каждого сегмента, в свою очередь, состоит из предложений (statement) языка Ассемблера. Каждое предложение языка Ассемблера занимает отдельную строчку программы, исключение из этого правила будет отмечено особо. Далее рассмотрим различные классы предложений Ассемблера.
Дата добавления: 2015-10-05; просмотров: 4721;