Форум программистов, компьютерный форум, киберфорум
Наши страницы

Assembler, MASM, TASM

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 2, средняя оценка - 5.00
Mikl___
Заблокирован
Автор FAQ
10.11.2013, 16:55  [ТС] #2
ПРЕДИСЛОВИЕ

Ассемблер (Assembler) — язык программирования, понятия которого отражают архитектуру электронно-вычислительной машины. Язык ассемблера — символьная форма записи машинного кода, использование которого упрощает написание машинных программ. Для одной и той же ЭВМ могут быть разработаны разные языки ассемблера. В отличие от языков высокого уровня абстракции, в котором многие проблемы реализации алгоритмов скрыты от разработчиков, язык ассемблера тесно связан с системой команд микропроцессора. Для идеального микропроцессора, у которого система команд точно соответствует языку программирования, ассемблер вырабатывает по одному машинному коду на каждый оператор языка. На практике для реальных микропроцессоров может потребоваться несколько машинных команд для реализации одного оператора языка.

Язык ассемблера обеспечивает доступ к регистрам, указание методов адресации и описание операций в терминах команд процессора. Язык ассемблера может содержать средства более высокого уровня абстракции: встроенные и определяемые макрокоманды, соответствующие нескольким машинным командам, автоматический выбор команды в зависимости от типов операндов, средства описания структур данных. Главное достоинство языка ассемблера — «приближенность» к процессору, который является основой используемого программистом компьютера, а главным неудобством — слишком мелкое деление типовых операций, которое большинством пользователей воспринимается с трудом. Однако язык ассемблера в значительно большей степени отражает само функционирование компьютера, чем все остальные языки.

И хотя драйвера и операционные системы сейчас пишут на Си, но Си при всех его достоинствах — язык высокого уровня абстракции, скрывающий от программиста различные тонкости и нюансы железа, а ассемблер — язык низкого уровня абстракции, прямо отражающий все эти тонкости и нюансы. Для успешного использования ассемблера необходимы сразу три вещи:
  1. знание синтаксиса транслятора ассемблера, который используется (например, синтаксис MASM, FASM и GAS отличается), назначение директив языка ассемблер (операторов, обрабатываемых транслятором во время трансляции исходного текста программы);
  2. понимание машинных инструкций, выполняемых процессором во время работы программы;
  3. умение работать с сервисами, предоставляемыми операционной системой — в данном случае это означает знание функций Win32 API. При работе с языками высокого уровня очень часто к API системы программист прямо не обращается; он может даже не подозревать о его существовании, поскольку библиотека языка скрывает от программиста детали, зависящие от конкретной системы. Например, и в Linux, и в Windows, и в любой другой системе в программе на Си/Си++ можно вывести строку на консоль, используя функцию printf() или поток cout, то есть для программиста, использующего эти средства, нет разницы, под какую систему делается программа, хотя реализация этих функций будет разной в разных системах, потому что API систем очень сильно различается. Но если человек пишет на ассемблере, он уже не имеет готовых функций типа printf(), в которых за него продумано, как "общаться" с системой, и должен делать это сам.
В итоге получается, что для написания даже простой программы на ассемблере требуется весьма большое количество предварительных знаний — "порог вхождения" здесь намного выше, чем для языков высокого уровня.

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

На языке ассемблера пишут программы или их фрагменты в тех случаях, когда критически важны:
  1. объем используемой памяти (программы-загрузчики, встраиваемое программное обеспечение, программы для микроконтроллеров и процессоров с ограниченными ресурсами, вирусы, программные защиты и т.п.)
  2. быстродействие (программы написанные на языке ассемблера выполняются гораздо быстрее, чем программы-аналоги, написанные на языках программирования высокого уровня абстракции. В данном случае быстродействие зависит от понимания того, как работает конкретная модель процессора, реальный конвейер на процессоре, размер кэша, тонкостей работы операционной системы. В результате программа начинает работать быстрее, но теряет переносимость и универсальность)
Кроме того, знание языка ассемблера облегчает понимание архитектуры компьютера и работы его аппаратной части, то, чего не может дать знание языков высокого уровня абстракции (ЯВУ). В настоящее время большинство программистов разрабатывает программы в средах быстрого проектирования (Rapid Application Development) когда все необходимые элементы оформления и управления создаются с помощью готовых визуальных компонентов. Это существенно упрощает процесс программирования. Однако, нередко приходится сталкиваться с такими ситуациями, когда наиболее мощное и эффективное функционирование отдельных программных модулей возможно только в случае написания их на языке ассемблера (ассемблерные вставки). В частности, в любой программе, связанной с выполнением многократно повторяющихся циклических процедур, будь это циклы математических вычислений или вывод графических изображений, целесообразно наиболее времяемкие операции сгруппировать в программируемые на языке ассемблера субмодули. Это допускают все пакеты современных языков программирования высокого уровня абстракции, а результатом всегда является существенное повышение быстродействия программ.

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

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

Автор придерживается мнения, что программирование на языке ассемблера — это искусство, которое основано на нескольких основных законах и включает в себя большое количество практических приемов и правил. Математических выкладок вы встретите очень мало, зато приводятся разнообразные примеры программ и всячески пропагандируется быстрая прикидочная оценка параметров и характеристик, которую желательно производить «в уме».
Вы не будете читать введение, не понимая языка, на котором оно написано. Это замечание относится к любой книге (исключая книжки-картинки). Чтобы получить от пособия максимум полезного, у Вас должны быть определенные знания, и Вы уже должны уметь делать нечто большее, чем просто читать. Данное пособие отнюдь не предназначено служить введением в программирование для ЭВМ. Предполагается, что читатель имеет некоторый опыт в этой области. Читатель должен:
  1. иметь представление о том, как работает компьютер с заложенной в него программой: не столько о том, как работает электроника, сколько о том, как команды могут сохраняться в памяти машины и затем последовательно выполняться. Было бы полезно предварительное знакомство с любым из языков программирования;
  2. знать хоть отчасти общепринятый компьютерный жаргон, например такие слова, как «память», «регистры», «биты», «плавающая точка», «переполнение», «кодировка ASCII», «файлы», «листинг»;
  3. самостоятельно написать и отладить хотя бы две программы.

Введение в язык ассемблера

Язык программирования — это система обозначений для описания данных и алгоритмов их обработки на компьютере. Программы для первых вычислительных машин составлялись на простейшем из языков программирования — машинном коде, при помощи только двух символов: нуля и единицы. Первое время программы писали в двоичном коде, но вскоре, программисты придумали себе облегчение — программы стали писать не в двоичной, а в шестнадцатеричной системе счисления. Для перевода из двоичной в шестнадцатеричную систему счисления каждые четыре двоичные цифры заменяют одной шестнадцатеричной цифрой (глава «Представление данных»). Например, (1010 0010 0000 0111)2 = (A207)16.

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

Например, команда перемещения для микропроцессора Intel x86 выглядит так: C605EF00400005. C605 — опкод операции перемещения. По такой команде компьютер помещает число 05 (две последние цифры 05) в ячейку памяти с номером 004000EF (цифры EF004000).


Концепция Джона фон Неймана

Джон фон Нейман (John von Neumann) — профессор математики в Принстонском Институте сложных исследований — помогал проектировать компьютер EDVAC (Electronic Discrete Variable Automatic Computer — Электронный автоматический компьютер с дискретными переменными). В статье «Предварительное обсуждение логической конструкции электронной вычислительной машины», опубликованной в 1946 в соавторстве с Артуром Берксом (Arthur Burks) и Германом Гольдстайном (Herman Goldstine), он описал некоторые особенности компьютеров. Впоследствии оказалось, что концепция Джона фон Неймана настолько мощна и универсальна, что используется и по сей день в современных компьютерах:
  • компьютер должен состоять из следующих модулей: управляющий блок, арифметико-логический блок, оперативная память, блоки ввода/вывода;
  • строение компьютера не должно зависеть от решаемой задачи, программа должна храниться в памяти компьютера;
  • команды и данные должны храниться в одной и той же памяти;
  • память делится на ячейки одинакового размера, порядковый номер ячейки считается ее адресом;
  • программа состоит из серии элементарных инструкций, которые обычно не содержат прямого значения операнда (указывается только его адрес), поэтому программа не зависит от обрабатываемых данных. Инструкции выполняются одна за другой в том порядке, в котором они находятся в памяти;
  • для изменения порядка выполнения инструкций используются инструкции условного и безусловного перехода;
  • инструкции и данные (то есть операнды, результаты или адреса) представляются в виде двоичных сигналов и в двоичной системе счисления.
Двоичная система счисления используется в цифровых устройствах по следующим причинам:
  • наименьшее количество возможных состояний элемента ведет к упрощению конструкции в целом, а также повышает помехоустойчивость и скорость работы;
  • двоичная система счисления позволяет упростить операции сложения и умножения — основных действий над числами.
Компьютер, на котором Вы сейчас работаете, представляет собой реализацию фон-неймановской архитектуры вычислительных машин. Так же, как и машина предсказанная Джорджем фон-Нейманом в 1945 году, Ваш компьютер состоит из блока управления, арифметико-логического устройства (АЛУ), памяти и устройств ввода/вывода. В ней реализуется концепция хранимой программы: программы и данные хранятся в одной и той же памяти. Выполняемые действия определяются блоком управления и АЛУ, которые вместе являются основой центрального процессора. Центральный процессор выбирает и исполняет команды из памяти последовательно, адрес очередной команды задается «счетчиком адреса» в блоке управления. Этот принцип исполнения называется последовательной передачей управления. Данные, с которыми работает программа, могут включать переменные — именованные области памяти, в которых сохраняются значения с целью дальнейшего использования в программе. Фон-неймановская архитектура — не единственный вариант построения ЭВМ, есть и другие, которые не соответствуют указанным принципам. Однако подавляющее большинство современных компьютеров основано именно на этих принципах, включая и сложные многопроцессорные комплексы.
Центральный процессор (АЛУ с блоком управления) реализуется микропроцессором семейства х86 — от 8086/88 до Pentium 4. При всей своей внутренней суперскалярности, суперконвейеризированности и спекулятивности, внешне процессор соблюдает вышеупомянутый принцип последовательной передачи управления. Набор арифметических, логических и прочих инструкций насчитывает несколько сотен, а для потоковой обработки придуман принцип SIMD — множество комплектов данных, обрабатываемых одной инструкцией (расширения ММХ, 3DNow!, SSE). Процессор имеет набор регистров, часть которых доступна для хранения операндов, выполнения действий над ними и формирования адреса инструкций и операндов в памяти. Другая часть регистров используется процессором для служебных (системных) целей, доступ к ним может быть ограничен (есть даже программно-невидимые регистры).
Память распределена по нескольким компонентам:
  1. Оперативная память (ОЗУ) — массив ячеек памяти со смежными адресами — реализуется на микросхемах динамической памяти. Для повышения производительности обмена данными (включая и считывание команд) оперативная память кэшируется сверхоперативной памятью. Первый и второй уровень кэширования располагается в микропроцессоре. Оперативная память вместе с кэшем всех уровней (до трех уровней) представляет собой единый массив памяти, непосредственно доступный процессору для записи и чтения данных, а также считывания программного кода.
  2. В любом компьютере обязательно есть постоянная память(ПЗУ, ROM), в которой хранится программа начального запуска компьютера и минимальный необходимый набор сервисов (ROM BIOS)
    Из постоянной памяти можно только считывать команды и данные
  3. Некоторые виды специальной памяти (например, видеопамять).
Вся эта память вместе с оперативной располагается в едином пространстве с линейной адресацией. Память дополняется устройствами хранения данных, например, дисковыми. Эти устройства предназначены для записи данных с целью последующего считывания (возможно, и на другом компьютере). От рассмотренной выше памяти, называемой также внутренней, устройства хранения отличаются тем, что процессор не имеет непосредственного доступа к данным по линейному адресу. Доступ к данным на устройствах хранения выполняется с помощью специальных программ, обращающихся к контроллерам этих устройств.
Устройства ввода/вывода (УВВ) служат для преобразования информации из внутреннего представления в компьютере (биты и байты) в форму, доступную окружающим, и обратно. К устройствам ввода относятся клавиатура, мышь, джойстик, микрофон, сканер, видеокамера, различные датчики; к устройствам вывода — дисплей, принтер, плоттер, акустические системы, исполнительные механизмы. Устройства хранения вместе с УВВ можно объединить общим понятием периферийные устройства. Существует также класс коммуникационных устройств, предназначенных для передачи информации между компьютерами и (или) их частями. Эти устройства обеспечивают, например, соединение компьютеров в локальные сети или подключение терминала (это УВВ) к компьютеру.
Периферийные и коммуникационные устройства (и даже память) снабжаются контроллерами или адаптерами, которые доступны процессору. Все компоненты компьютера представляются для процессора в виде наборов ячеек памяти или (и) портов ввода/вывода. Процессор может адресоваться к ним с точностью до одного байта — набора смежных восьми бит. Каждый байт (ячейка памяти, порт) имеет собственный уникальный физический адрес. Этот адрес устанавливается на системной шине процессором, когда он инициирует обращение к данной ячейке или порту. В семействе х8б и PC-совместимых компьютерах пространства адресов / ячеек памяти и портов ввода/вывода разделены. Это предусмотрено с обеих сторон: процессоры позволяют, а компьютеры используют данное разделение. В принципе, это разделение не обязательно, существуют процессоры, для которых все внешние ячейки рассматриваются только как память. Контроллеры и адаптеры периферийных устройств могут и не использовать порты в пространстве ввода/вывода, если их регистры отображены на пространство памяти. За историю PC типовой объем ОЗУ вырос уже на три порядка и подбирается к гигабайту. Микропроцессор Intel 8086 имел разрядность шины адреса 20 бит, что позволяло адресовать 220=1.048.576 ячеек (1 Мбайт). Сейчас микропроцессоры имеют разрядность физического адреса памяти 32/36 бит, что позволяет адресовать до 4 Гбайт/64 Гбайт соответственно. Пространство ввода/вывода использует только младшие 16 бит адреса, что позволяет адресовать до 216=65.536 однобайтных регистров. Адреса системных устройств копьютеров на базе Intel x86 не меняются. Пространства памяти и ввода/вывода неравнозначны не только по объему, но и по способам обращения. Способов адресации к ячейке памяти в х86 великое множество, в то время как для адресации ввода/вывода их существует только два. При обращении к памяти используется виртуальная адресация, при которой для программиста, программы и пользователя создается иллюзия оперативной памяти гигантского размера. Реальный физический адрес процессор формирует из логического адреса (указанного программистом) под управлением операционной системы, поддерживающей виртуальную память. Иллюзия большого объема создается операционной системой с помощью устройств хранения и специальных аппаратных средств процессора. Возможна реальная адресация к памяти — в этом случае физический адрес совпадает с логическим. К портам ввода/вывода обращаются только по реальным адресам, правда, и здесь возможна виртуализация чисто программными средствами операционной системы. Самое существенное различие пространств памяти и ввода/вывода — процессор может считывать инструкции для исполнения только из пространства памяти. Хотя через порт ввода можно считать фрагмент программного кода (например, при считывании данных с диска), но для того чтобы этот код исполнить, его необходимо записать в память.
Процессор исполняет программный код, находящийся к моменту исполнения в пространстве памяти. Программный код — это последовательность команд, или инструкций, каждая из которых определенным образом закодирована и расположена в целом числе смежных байт памяти. Каждая инструкция обязательно имеет операционную часть, несущую процессору информацию о требуемых действиях. Операндная часть, указывающая процессору, где находятся операнды, может присутствовать в явном или неявном виде или отсутствовать. Операндная часть может описывать от нуля до двух операндов, участвующих в данной инструкции (есть инструкции, в которые кроме двух операндов задается еще и параметр инструкции).
Здесь могут быть
  • сами значения операндов (непосредственные операнды);
  • явные или неявные указания на регистры процессора, в которых находятся операнды;
  • адрес ячейки памяти (или его составная часть);
  • регистры процессора, участвующие в формировании адреса, и разные комбинации этих компонент.
Длина инструкции в семействе х86 может быть от одного до 12 байт и определяется типом инструкции. Сложившийся формат инструкции х86 достаточно сложен, и «понять», сколько байт занимает конкретная инструкция, процессор может, декодировав первые 1-3 байта инструкции. Инструкции могут предшествовать префиксы (всегда однобайтные), указывающие на изменение способа адресации, размера операнда или (и) необходимость многократного (по счетчику и условию) повторения данной инструкции. Адрес (логический) текущей исполняемой инструкции хранится в специальном регистре — указателе инструкций (Instruction Pointer, IP/EIP/RIP), который соответствует счетчику команд фон-неймановской машины. После исполнения так называемой линейной инструкции этот указатель увеличивает свое значение на ее длину, то есть указывает на начало следующей инструкции. Линейная инструкция не нарушает порядок выполнения, определяемый последовательностью расположения инструкций в памяти (по нарастанию адреса). Кроме линейных инструкций, существуют инструкции передачи управления, среди которых различают инструкции переходов и вызовов процедур. Эти инструкции в явном или неявном виде содержат информацию об адресе следующей выполняемой инструкции, который может указывать на относительно произвольную ячейку памяти. Инструкции переходов и вызовов могут быть безусловными (ни от чего не зависящими) и условными. Произойдет условный переход (вызов) или нет, зависит от состояния флагов (признаков) на момент исполнения данной инструкции. Если переход (вызов) не состоится, то исполняется инструкция, расположенная в памяти следом за текущей. Вызов процедуры характерен тем, что перед ним процессор сохраняет в стеке (стек — это область ОЗУ) адрес следующей инструкции, и на этот адрес передается управление после завершения исполнения процедуры (этот адрес извлекается из стека при выполнении инструкции возврата). При переходе в стеке ничего не сохраняется, то есть переход выполняется безвозвратно.
Последовательность исполнения инструкций, предписанная программным кодом, может быть нарушена под воздействием внутренних или внешних (относительно процессора) причин. К внутренним причинам относятся исключения (exceptions) — особые ситуации, возникающие при выполнении инструкций. Наглядным примером исключения является попытка деления на ноль. При возникновении условия исключения процессор автоматически выполняет вызов процедуры обработки исключения, после которой он может вернуться к повторному исполнению инструкции, породившей исключение или следующей за ней. Вариант поведения зависит от типа произошедшего исключения. Исключения широко используются современными операционными системами, на основе обработки исключений строится система виртуальной памяти и реализуются многие функции многозадачных операционных систем. Внешними причинами изменения нормальной последовательности инструкций являются аппаратные прерывания — вызовы процедур под воздействием электрических сигналов, поступающих на специальные выводы процессора. Эти сигналы могут подаваться неожиданно для исполняемой программы, но у программиста есть возможность заставить процессор игнорировать все прерывания или их часть. Злоупотреблять этой возможностью нельзя, поскольку на аппаратных прерываниях строится, синхронизация обращения к памяти и УВУ, а также другие системные и прикладные функции компьютера. Источниками аппаратных прерываний являются контроллеры и адаптеры периферийных устройств, генераторы меток времени, системы управления питанием и т.д. Есть еще так называемые программные прерывания, но они отнюдь не нарушают последовательность инструкций, предписанную программистом. Поэтому прерываниями они по сути не являются — это всего лишь особый способ вызова процедур, широко используемый для вызова системных сервисов BIOS и операционной системы. И наконец, последовательность инструкций может изменяться по сигналу аппаратного сброса или инициализации процессора.


Составление программ на машинном коде — достаточно тяжелая и кропотливая работа, требующая чрезвычайного внимания и высокой квалификации программиста. Программист должен был удержать в своей памяти, где у него находятся переменные, где код программы, взаимосвязь между отдельными частями программ, но и объем памяти машины был не очень большой. Программист должен был помнить двоичные комбинации для каждого кода операции, адреса и константы, ввести их в память компьютера в правильном порядке. В программе на машинном коде очень легко ошибиться и очень трудно отыскать ошибку. Трудно расширять или сокращать уже написанные программы. Чтобы облегчить и повысить производительность труда, были созданы специальные программы ассемблеры (англ. assemble — собирать), которые выполняли рутинную работу по переводу символических команд СЛОЖИТЬ, ВЫЧЕСТЬ, ПЕРЕМЕСТИТЬ в нули и единицы машинного кода, а также разработан язык программирования — ассемблер. Язык ассемблера позволяет составлять программы, используя для обозначения команд и символьных имен легко запоминающуюся мнемонику. Символьные имена выбираются программистом и служат для обозначения ячеек памяти и переменных.

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

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

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

Человеку нелегко пользоваться машинным кодом, поскольку смысл кода команды не ясен без соответствующего справочника. Можно заменить код каждой машинной команды коротким именем, называемым мнемоническим кодом. Например, код 01000000b или 40h для микропроцессора Intel x86 означает «увеличить содержимое регистра EAX на единицу», выглядит как «INC EAX». Мнемонической командой служит трёх- или четырёхбуквенное сокращение английского глагола (см. табл. 1).
Мнемоники команд
Мнемо-
ника
Смысл команды Производное английское слово
jmp продолжать выполнение с нового адреса в памяти to jump — прыгнуть
mov переместить данные to move — переместить
sub получить разность двух значений to subtract — вычесть
xchg обменять значения в регистрах/ ячейках памяти to exchange — обменять
incувеличить значение в регистре/ячейке памяти на единицуto increase — увеличить

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

Язык ассемблера — это не какой-то один конкретный язык программирования, а целый класс языков. Каждый микропроцессор имеет свой собственный машинный код и, следовательно, собственный язык ассемблера (разрабатываемый изготовителем микропроцессора). В данной книге будет рассмотрен язык ассемблера для микропроцессоров семейства IA32/64.

Язык ассемблер для микропроцессоров IA32/64 поддерживают два синтаксиса Intel и AT&T. Под Intel-синтаксис разработаны следующие ассемблеры: MASM (Macro Assembler — Microsoft Corporation), BASM, TASM (Build-in Assembler, Turbo Assembler — Borland Inc), ASM-86 (Intel Corporation), FASM (Flat Assembler — Tomasz Grysztar), LZASM (lazzy assebmler — Степан Половников), WASM (Open Watcom Assembler — фирма Watcom), HLASM, HLA (High Level Assembler — IBM), NASM (NetWide Assembler — Simon Tatham, Julian Hall, Peter Anvin), YASM (Yet Another Assembler — Peter Johnson, Michael Urman), RosAsm (ReactOS Assembler), GoAsm (Jeremy Gordon) и т.д. Синтаксис AT&T используют AS (UNIX assembler) и GAS (GNU assembler).
Все вышеперечисленные ассемблеры включают стандартные мнемонические команды, в том числе команды арифметических операций для чисел с плавающей запятой для сопроцессора. Несмотря на имеющиеся различия между этими ассемблерами, их структуры и форматы команд языков в значительной мере совместимы.

В данном пособии будет рассматриваться программирование на языке Macro Assembler под 32-разрядную операционную систему Windows.

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

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

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

Алфавит языка ассемблера содержит такие символы:
  • все строчные и прописные буквы латинского алфавита;
  • десять арабских цифр: 0, 1, 2, …, 9;
  • специальные знаки: « » (пробел), «?», «!», «.» (точка), «,» (запятая), «;» (точка с запятой), «:» (двоеточие), «@», «_» (знак подчеркивания), «’», «”», скобки полукруглые и квадратные, «/», «\», «>», «<», «*».
Синтаксис — это совокупность правил образования конструкций языка из символов, определенных алфавитом. Например, правило образования одной из конструкций языка ассемблера — идентификатора, или имени, заключается в следующем: идентификатор — это последовательность от одной до двухсот латинских букв, цифр и знаков «?», «.», «@», «_», «$», обязательно начинающаяся не с цифры; точка может быть только первым символом в имени; в зависимости от настроек, строчные и прописные буквы в имени могут не различаться.

Примеры идентификаторов: A, A12345, ALFA, _67890, INDEX.

Словарь — совокупность заранее оговоренных служебных слов: названия команд, названия директив ассемблера, названия регистров микропроцессора; в словарных словах строчные и прописные буквы не различаются.
Семантика — множество правил, позволяющих уточнить синтаксически правильные конструкции языка и определить их смысловое значение. Иными словами, зная и синтаксис, и семантику языка, можно понять, какие последовательности символов алфавита (тексты) имеют смысл, а какие — бессмысленны с точки зрения данного языка.
Программы, написанные на языке ассемблера, представляют собой последовательность приказов (инструкций, операторов). Эти операторы предварительно обрабатываются при помощи транслятора (программы, которая заменит каждый оператор языка ассемблера на соответствующую ему группу машинных кодов).
Однозначное преобразование одной машинной инструкции в одну команду языка ассемблера называется транслитерацией. Так как наборы инструкций для каждой модели процессора отличаются, каждой конкретной компьютерной архитектуре (платформы Intel, Alpha, SPARC, Motorola и т.д.) соответствует свой язык ассемблера, и написанная на нем программа может быть использована только в этой среде.

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

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

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

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

Первым ассемблером и одновременно первым интерпретатором стал псевдокод и набор инструкций Short Code, разработанный в 1949 г. американцами Пресом Экертом и Джоном Мошли для ЭВМ BINAC. Решение любой задачи вначале записывалось математическими уравнениями. Те, в свою очередь, по-символьно транслировались в коды: из «a=b+c» в «S0 03 S1 07 S2». На заключительном этапе коды приобретали двоичный вид, а каждая строка после ввода автоматически выполнялась. Первая практическая задача, которую решил ассемблер, — расчет таблиц артиллерийской стрельбы для американских баллистиков. Ассемблеры на мнемонических кодах («MOV», «ADD») появились только в середине 50-х. Авторы языка ассемблер более известны изобретением вычислительных машин на вакуумных трубках: ENIC (1946 г.), BINAC (1949 г.) и прямого предка современных компьютеров UNIVAC I (1951 г.).
21
Миниатюры
Электронный учебник   Электронный учебник   Электронный учебник  

Электронный учебник   Электронный учебник   Электронный учебник  

Электронный учебник   Электронный учебник   Электронный учебник  

Электронный учебник   Электронный учебник   Электронный учебник  

Изображения
   
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru