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

{toc_noshowall}

ИЕРАРХИЯ ЯЗЫКОВ

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

1.«Загрузить» содержимое первой ячейки памяти в регистр общего назначения, используемый в качестве накопителя. По команде загрузки производится выборка содержимого первой ячейки памяти (оставляя содержимое самой ячейки неизменным) и запоминание его в нашем регистре-накопителе, при этом предыдущее содержимое этого регистра теряется.

2.«Сложить» содержимое второй ячейки памяти с содержимым регистра-накопителя. Как мы знаем, содержимое второй ячейки остается неизменным, а результат сложения по окончании выполнения команды оказывается в регистре-накопителе.

3.«Запомнить» результат, находящийся пока в регистре, в некоторой ячейке памяти. Таким образом, третья ячейка памяти, как и регистр, содержит результат сложения содержимых первых двух ячеек.

Предположим, что в рассмотренном примере первое число хранилось в ячейке 256, второе — в ячейке 260, и результат требовалось поместить в ячейку 249- Регистр 6 был выбран в качестве накопителя. Соответствующие команды машинного языка IBM 360 таковы:

В большинстве программ команд значительно больше. Однако и в рассмотренном выше примере для задания необходимых команд на машинном языке потребовалось задать 96 (3x32) нулей и единиц. Ошибка хотя бы в одном бите привела бы к неверному конечному результату. Кроме того, программы на машинном языке очень трудны в составлении и для понимания из-за отсутствия соответствия между языком машины и обычным «человеческим» языком.

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

Это значительное улучшение по сравнению с двоичной формой машинного языка. Для программирования сложения двух чисел вместо 96 двоичных цифр теперь требуется написать всего лишь 3x8=24 шестнадцатеричных. В самом деле, наиболее удобной формой представления двоичной информации является шестнадцатеричная форма. Но все же команды машинного языка независимо от формы их представления лишь очень отдаленно напоминают о действиях, которые в соответствии с, ними выполняются.

Нужно попытаться представить операции машинного языка и адреса в форме более понятной программисту. Этой цели служит язык ассемблера. Символические формы представления, или мнемоники кодов операций, позволяют нам, например, писать Lвместо кода операции «Загрузка» (LOAD), А вместо кода операции «Сложение» (ADD),

STвместо кода операции «Запись в память» (STORE). Применение мнемоник исключает необходимость использования двоичных кодов операций машинного языка.

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

Возвращаясь к нашему примеру, назовем три ячейки памяти NUM- BER1, NUMBER2 и NUMсоответственно и регистр 6 — REGSIX. Теперь мы можем переписать команды так:

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

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

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

Существуют языки, такие, как, например, ФОРТРАН, программы на которых гораздо больше походят на математическое или словесное описание необходимых вычислений. На ФОРТРАНе рассмотренная выше программа будет выглядить так:

NUM=NUMBER1+NUMBER2

 

Рис. 3.1. Иерархия языков.

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

ФОРТРАН, КОБОЛ, АЛГОЛ, ПЛ/1 и многие другие символические языки принадлежат классу языков, называемых компилируемыми языками. Вообще говоря, одно предложение или команда такого языка после обработки программой, называемой компилятором, преобразуется в несколько команд машинного языка. Мы уже видели, что оператор языка ФОРТРАН, задающий сложение двух чисел, эквивалентен трем машинным командам. В этом принципиальная разница между компилируемыми языками и языком ассемблера. Выражаясь математическим языком, между предложениями языка ассемблера и командами машинного языка существует взаимно однозначное соответствие, тогда как между предложениями компилируемых языков и командами машинного языка такого соответствия нет.

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

Использование программы, написанной на одном из символических языков, состоит из двух этапов: 1) программа, написанная на символическом языке, должна быть переведена на язык машины, т. е. исходный код должен быть преобразован в объектный код; 2) под управлением полученного объектного кода работает ЭВМ, иначе говоря, объектный код является выполняемой программой. На этапе трансляции ЭВМ выполняет программу-компилятор или ассемблер, при этом исходный код рассматривается как входные данные. На этапе выполнения выполняется программа в объектном коде, в качестве входных используются данные, определенные программистом.

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

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

Во многих случаях программу для решения конкретной задачи удобнее писать на языке высокого уровня, чем на языке ассемблера, так как большинство языков высокого уровня специально ориентировано на выполнение некоторых видов работ. ФОРТРАН (FORmulaTRANslator) создан главным образом учеными; он соединяет вычислительные возможности с относительной простотой программирования алгебраических выражений, что сделало его наиболее употребимым языком для программирования научных вычислений. КОБОЛ (COmmonBusinessOrientedLanguage) был создан для программирования экономических задач; обработка больших объемов информации, например результатов инвентаризации товаров или списков сотрудников, наиболее легко программируется на КОБОЛе. АЛГОЛ (ALGOrithmicLanguage) является языком для описания алгоритмов, или правил вычислений.

Каждый из перечисленных языков служит вполне определенной цели. Но попытки выйти за пределы области ориентации языка приводят к значительным осложнениям. Обработку экономических данных трудно запрограммировать на ФОРТРАНе; чем больше требуется действий невычислительного типа для решения данной задачи, тем менее пригоден ФОРТРАН. С другой стороны, программирование на КОБОЛе сложных алгебраических выражений по меньшей мере утомительно. Кроме того, в КОБОЛе отсутствуют некоторые существенные особенности языков для научных вычислений, например библиотека стандартных подпрограмм для вычисления математических функций, и он слишком «словесен» для подобных применений. АЛГОЛ — международный язык описания алгоритмов; алгоритмы, написанные на АЛГОЛе, можно найти, например, в таком журнале, как САСМ. Однако большинство программистов согласится, что существует много задач, для которых этот язык неудобен. Язык сам по себе не содержит специальных операторов ввода-вывода, кроме того, синтаксис или структура языка, удобная для описания алгоритмов, затрудняет организацию вычислений. Таким образом, каждый из рассмотренных специализированных языков служит определенной цели, но чем он удобнее для программирования в конкретной области, тем больше теряет он в общности.

ПЛ/I(ProgrammingLanguageI) претендует на общность, которой так не хватает перечисленным выше языкам. Синтаксически этот язык является комбинацией АЛГОЛа, ФОРТРАНа и КОБОЛа и вдобавок обладает некоторыми чертами, которые делают возможным написание на нем полной операционной системы. Платой за эту гибкость является чрезвычайная сложность языка для начинающего программиста. Именно эта сложность не позволила и, вероятно, не позволит этому языку стать универсальным языком программирования для машин фирмы IBM. Для начинающего изучать вычислительную науку студента тот факт, что ПЛ/Iявляется языком высокого уровня, означает, что изучение его не может дать того, что дает изучение ассемблера — знания структуры и функций вычислительной системы.

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

Программисту, пишущему на языке высокого уровня, знание языка ассемблера дает дополнительные возможности. Чем ближе он знаком с ЭВМ и ее возможностями, тем большую выгоду он может извлечь для себя независимо от того, на каком языке он программирует. Например, человеку, знакомому с ассемблером, понятны форматы, используемые в ФОРТРАНе, и предложения определения файлов в КОБОЛе. Ему известно, для чего употребляется знак = в ФОРТРАНе и какова разница между целыми и вещественными переменными. Встретившись с вопросом: «Можно ли это сделать на ФОРТРАНе?», он сможет использовать свои знания возможностей машины для определения, имеет ли смысл этот вопрос с машинной точки зрения. Этого обычно достаточно для получения по крайней мере частичного ответа на вопрос.

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

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

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

Системные программы служат цели освобождения пользователя от выполнения машинно- и системно-ориентированных задач, не представляющих непосредственного интереса для него. Например, программист использует компилятор или ассемблер для трансляции исходной программы на машинный язык; пользователь, который был бы вынужден прежде, чем написать программу на ФОРТРАНе, написать компилятор, вероятно, откажется от такого способа решения своей задачи. Такие необходимые действия, как преобразование исходных данных из символьного кода в двоичное представление, удобное для выполнения арифметических операций, управление периферийными устройствами и управление вычислениями в целом непосредственно не связаны с проблемной программой и выполняются системными программами. Короче говоря, системные программы служат связующим звеном между программистом и аппаратурой вычислительной машины.

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

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

Именно на ассемблере можно составить наиболее эффективную программу. Кроме того, программисту на ассемблере значительно •облегчается проблема использования всех возможностей ЭВМ. Так, он может увеличить скорость вычислений, используя большое количество памяти, и наоборот.

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

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

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

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

 
Статьи раздела