Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Программирование на языке Ассемблера



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

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

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

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

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

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

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

Для управления таким устройством для него может быть создан соответствующий язык команд. (Широко известные примеры: MI AS/400, JVM.) Говоря шире, любую программу можно представить себе как виртуальное «железо», решающее конкретную задачу. (Конечный пользователь обычно не видит разницы между программой и аппаратурой и часто говорит не «мне программа выдала то-то», а «мне компьютер выдал то-то»). В некоторых случаях интерфейс программы удобно представить в виде системы команд, а следовательно, нужен соответствующий Ассемблер. (Это, конечно, относится не к программам «для чайников», а к инструментальным средствам программистов, системам моделирования).

Предложения языка Ассемблера

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

Во всех языках Ассемблеров каждое новое предложение языка начинается с новой строки. Каждое предложение, как правило, занимает одну строку, хотя обычно допускается продолжение на следующей строке/строках. Формат записи предложений языка м.б. жесткий или свободный. При записи в жестком формате составляющие предложения должны располагаться в фиксированных позициях строки. (Например: метка должна располагаться в позициях 1-8, позиция 9 — пустая, позиции 10-12 — мнемоника команды, позиция 13 — пустая, начиная с позиции 14 — операнды, позиция 72 — признак продолжения). Обычно для записи программ при жестком формате создаются бланки. Жесткий формат удобен для обработки Ассемблером (удобен и для чтения).

Свободный формат допускает любое количество пробелов между составляющими предложения.

В общих случаях предложения языка Ассемблера состоят из следующих компонент:

u метка или имя;

u мнемоника;

u операнды;

u комментарии.

Метка или имя является необязательным компонентом. Не во всех языках Ассемблеров эти понятия различаются. Если они различаются (например, MASM), то метка — точка программы, на которую передается управление, следовательно, метка стоит в предложении, содержащем команду; имя — имя переменной программы, ячейки памяти, следовательно, имя стоит в предложении, содержащем псевдокоманду резервирования памяти или определения константы. В некоторых случаях метка и имя могут отличаться даже синтаксически, так, в MASM/ TASM после метки ставится двоеточие, а после имени — нет.

Однако, физический смысл и метки, и имени — одинаков, это — адрес памяти. Во всех случаях, когда Ассемблер встречает в программе имя или метку, он заменяет ее на адрес той ячейки памяти, к которую имя/метка именует.

Правила формирования имен/меток совпадают с таковыми для языков программирования. В некоторых Ассемблерах (HLAM S/390) не делается различия между меткой и именем.

В языке должны предусматриваться некоторые специальные правила, позволяющие Ассемблеру распознать и выделить метку/имя, например:

u метка/имя должна начинаться в 1-й позиции строки

u если метки/имени нет, то в 1-й позиции должен быть пробел, или за меткой/именем должно следовать двоеточие, и т.п.

Мнемоника — символическое обозначение команды/псевдокоманды.

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

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

Константы — могут представлять непосредственные операнды или абсолютные адреса памяти. Применяются 10-е, 8-е, 16-е, 2-е, символьные константы.

Непосредственные операнды — записываются в сам код команды.

Имена — адреса ячеек памяти.

При трансляции Ассемблер преобразует имена в адреса. Способ преобразования имени в значение зависит от принятых способов адресации. Как правило, в основным способом адресации в машинных языках является адресация относительная: адрес в команде задается в виде смещения относительно какого-то базового адреса, значение которого содержится в некотором базовом регистре. В качестве базового могут применяться либо специальные регистры (DS, CS в Intel) или регистры общего назначения (S/390).

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

Специальный синтаксис — явное описание способа адресации (например, указание базового регистра и смещения).

Регистры

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

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

 

Биты и байты

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

Группа из девяти битов представляет собой байт; восемь битов которого содержат данные и один бит — контроль на четность. Восемь битов обеспечивают основу для двоичной арифметики и для представления символов, таких как буква A или символ *. Восемь битов дают 256 различных комбинаций включенных и выключенных состояний: от «все выключены» (00000000) до «все включены» (11111111). Например, сочетание включенных и выключенных битов для представления буквы A выглядит как 01000001, а для cимвола * — 00101010 (это можно не запоминать). Каждый байт в памяти компьютера имеет уникальный адрес, начиная с нуля.

 

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

Откуда компьютер «знает», что значения бит 01000001 представляют букву A? Когда на клавиатуре нажата клавиша A, система принимает сигнал от этой конкретной клавиши в байт памяти. Этот сигнал устанавливает биты в значения 01000001. Можно переслать этот байт в памяти и, если передать его на экран или принтер, то будет сгенерирована буква A.

По соглашению биты в байте пронумерованы от 0 до 7 справа налево:

Номера бит: 7 6 5 4 3 2 1 0

Значения бит: 0 1 0 0 0 0 0 0

Число 2 в десятой степени равно 1024, что составляет один килобайт и обозначается буквой К. Например, компьютер с памятью в 512 К содержит 512 х 1024, то есть, 524288 байт. Процессор в PC и в совместимых моделях использует 16-битовую архитектуру, поэтому он имеет доступ к 16-битовым значениям как в памяти, так и в регистрах. 16-битовое (двухбайтовое) поле называется словом. Биты в слове пронумерованы от 0 до 15 справа налево.

ASCII

Для целей стандартизации в микрокомпьютерах используется aмериканский национальный стандартный код для обмена информацией ASCII (American National Standard Code for Information Interchange). Читается как «аски» код. Именно по этой причине комбинация бит 01000001 обозначает букву A.

 

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

Двоичные числа

Так как компьютер может различить только нулевое и единичное состояние бита, то он работает системе исчисления с базой 2 или в двоичной системе. Фактически бит унаследовал cвое название от английского «Binary digit» (двоичная цифра).

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

Самый правый бит имеет весовое значение 1, следующая цифра влево — 2, следующая — 4 и так далее. Общая сумма для восьми единичных битов в данном случае составит 1+2+4+...+128, или 255 (2 в восьмой степени — 1).

Для двоичного числа 01000001 единичные биты представляют значения 1 и 64, то есть, 65. Но 01000001 представляет также букву A! Действительно, здесь момент, который необходимо четко уяснить. Биты 01000001 могут представлять как число 65, так и букву A:

u если программа определяет элемент данных для арифметических целей, то 01000001 представляет двоичное число эквивалентное десятичному числу 65;

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

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

Двоичное число не ограничено только восемью битами. Процессор может использовать 16-битовую архитектуру, в этом случае он автоматически оперирует с 16-битовыми числами. 2 в степени 16 минус 1 дает значение 65535, а немного творческого программирования позволит обрабатывать числа до 32 бит (2 в степени 32 минус 1 равно 4294967295) и даже больше.

Двоичная арифметика

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

0 + 0 = 0

1 + 0 = 1

1 + 1 = 10

1 + 1 + 1 = 11

Отрицательные числа

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

Рассмотрим пример:

Число 65: 01000001

Инверсия: 10111110

Плюс 1: 10111111 (равно -65).

В случае, если прибавить единичные значения к числу 10111111, 65 не получится.

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

Двоичное значение: 10111111

Инверсия: 01000000

Плюс 1: 01000001 (равно +65).

Сумма +65 и -65 должна составить ноль:

01000001 (+65) + 10111111 (-65) = (1) 00000000

 

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

Двоичное вычитание выполняется просто: инвертируется знак вычитаемого и складываются два числа. Вычтем, например, 42 из 65. Двоичное представление для 42 есть 00101010, и его двоичное дополнение: — 11010110:

65 01000001 +(-42) 11010110 = 23 (1) 00010111

Результат 23 является корректным. В рассмотренном примере произошел перенос в знаковый разряд и из разрядной сетки.

В случае, если справедливость двоичного дополнения не сразу понятна, рассмотрим следующие задачи: Какое значение необходимо прибавить к двоичному числу 00000001, чтобы получить число 00000000? В терминах десятичного исчисления ответом будет -1. Для двоичного рассмотрим 11111111:

00000001 11111111 Результат: (1) 00000000

Игнорируя перенос (1), можно видеть, что двоичное число 11111111 эквивалентно десятичному -1 и соответственно:

0 00000000 -(+1) -00000001 -1 11111111

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

+3 00000011

+2 00000010

+1 00000001

0 00000000

-1 11111111

-2 11111110

-3 11111101

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

 

 


Поделиться:



Популярное:

Последнее изменение этой страницы: 2017-03-08; Просмотров: 1382; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.047 с.)
Главная | Случайная страница | Обратная связь