Реклама:

Хотя структура ассемблерного оператора отражает структуру соответствующей машинной команды, языки ассемблера для разных машин и разных уровней во многом похожи, что позволяет говорить о языке ассемблера в целом. В листингах 7.1-7.3 показаны фрагменты программ на ассемблерах Pentium 4, Motorola 680x0 и (Ultra)SPARC. Все эти программы выполняют вычисление формулы N = I + J. Во всех трех примерах операторы над пустой строкой выполняют вычисление, а операторы под пустой строкой резервируют память для переменных I, J и N. То есть последние операторы не являются символьными представлениями машинных команд.

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

Pentium 4, все сказанное применимо и к процессорам 386, 486, Pentium и Pentium Pro. Для процессора SPARC мы будем использовать ассемблер Sun, а все сказанное применимо и к более ранним 32-разрядным версиям. В книге коды операций и регистры всегда обозначаются прописными буквами, причем не только для ассемблера Pentium 4, как это обычно принято, но и для ассемблера Sun, где по соглашению буквы строчные.

Листинг 7.1. Вычисление выражения N = I + J на ассемблере Pentium 4

FORMULA: MOV ЕАХ,I ; регистр ЕАХ = I

ADD ЕАХ,J ; регистр ЕАХ = I + J

MOV N,ЕАХ ; N = I + J

I DD 3 ; резервирование 4 байт

; и их инициализация значением 3

J DD 4 ; резервирование 4 байт

; и их инициализация значением 4

N DD 0 ; резервирование 4 байт

; и их инициализация значением О

Листинг 7.2. Вычисление выражения N = I + J на ассемблере Motorola 680x0

FORMULA MOVE.L I,DO ; регистр DO = I

ADD.L J.DO ; регистр DO = I + J

MOVE.L DO.N ; N = I + J

I DC.L 3 ; резервирование 4 байт

; и их инициализация значением 3

J DC.L 4 ; резервирование 4 байт

; и их инициализация значением 4

N DC.L 0 ; резервирование 4 байт

; и их инициализация значением О

Листинг 7.3. Вычисление выражения N = ! + J на ассемблере SPARC

FORMULA: SETHI ЯНКП.Ш ! Rl = старшие биты адреса I

LD [Ш+ШХ1)].Ш ! Rl = I

SETHI %HI(J),%R2 ! R2 = старшие биты адреса J

LD OT2+£L0(J)].*R2 ! R2 = J

NOP ! ожидаем получения J из памяти

ADD *R1.*R2.*R2 ! R2 = Rl + R2

SETHI Ш(М.Ш ! Rl = старшие биты адреса N

ST *R2. [Ш+ШКЮ]

I: .WORD 3 ! резервирование 4 байт

! и их инициализация значением 3

J: .WORD 4 ! резервирование 4 байт

! и их инициализация значением 4

N: .WORD 0 ! резервирование 4 байт

! и их инициализация значением О

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

В каждом из трех примеров есть метки: FORMULA, I, J и N. Отметим, что в ассемблере SPARC после каждой метки нужно ставить двоеточие, а в ассемблере Motorola - нет. В ассемблере компьютеров Intel двоеточие ставится только после меток команд, но не после меток данных. Данное различие вовсе не является чем-то фундаментальным, просто у разработчиков разных ассемблеров разные вкусы. Архитектура машины никак не влияет на тот или иной выбор. Единственное достоинство двоеточия состоит в том, что метку можно написать на отдельной строке, а код операции - на следующей строке с тем же отступом, что и метка. Без двоеточия компилятору невозможно было бы отличить метку от кода операции при их размещении в отдельных строках.

В некоторых ассемблерах длина метки ограничена значением 6 или 8 символов. В то же время в большинстве языков высокого уровня длина имен произвольна. Длинные и хорошо подобранные имена упрощают чтение и понимание программы.

В каждой машине есть несколько регистров, но названия у них совершенно разные. Регистры Pentium 4 называются ЕАХ, ЕВХ, ЕСХ и т. д., регистры Motorola - DO, Dl, D2, регистры SPARC имеют несколько названий. В этой книге для их обозначения мы будем использовать символы Ш и %R2.

В поле кода операции содержится либо символическая аббревиатура этого кода (если оператор является символическим представлением машинной команды), либо команда самого ассемблера. Выбор имени - дело вкуса, и поэтому разные разработчики называют их по-разному. Разработчики ассемблера Intel решили использовать обозначение M0V и для загрузки регистра из памяти и сохранения регистра в память, разработчики ассемблера Motorola выбрали для обеих операций обозначение MOVE, а разработчики ассемблера SPARC решили использовать символы LD для первой операции и ST для второй. Очевидно, что выбор названий в данном случае никак не связан с архитектурой машины.

Напротив, необходимость указывать две машинные команды для доступа к памяти объясняется архитектурой SPARC, поскольку виртуальные адреса могут быть 32-разрядными (как в SPARC версии 8) и 44-разрядными (как в SPARC версии 9), а команды могут содержать максимум 22 бита данных. Следовательно, чтобы передать все биты полного виртуального адреса, всегда требуются две команды. Например:

sethi шш.та

Эта команда обнуляет старшие 32 бита и младшие 10 бит 64-разрядного регистра R1, а затем помещает старшие 22 бита 32-разрядного адреса переменной I в битовые позиции с 10 по 31 регистра R1. Далее:

ld[*r1+*l0(i)] .ш

Эта команда складывает R1 и младшие 10 бит адреса I (в результате получается полный адрес I), вызывает данное слово из памяти и помещает его в регистр R1. Указанные команды, прямо скажем, не слишком элегантны, однако разработчики SPARC не гнались за красотой. Перед ними была поставлена задача обеспечить высокую скорость исполнения, и они успешно ее решили.

Процессоры семейства Pentium, 680x0 и SPARC позволяют работать с операндами разной длины (размером с байт, слово и длинное слово). Каким образом ассемблер определяет, какова длина операндов? И опять разработчики разных ассемблеров приняли разные решения. В Pentium 4 регистры разной длины имеют разные названия. Так, для перемещения 32-разрядных значений используется название ЕАХ, для 16-разрядных - АХ, а для 8-разрядных - AL и АН. Разработчики ассемблера Motorola решили прибавлять к каждому коду операции суффикс .L для типа long, .W - для типа word и .В - для типа byte. В SPARC для операндов разной длины используются разные коды операций, например, для загрузки байта, полуслова и слова в 64-разрядный регистр указываются коды операций LDSB, LDSH и LDSW соответственно. Как видите, природа языков совершенно произвольна.

Три ассемблера, которые мы рассматриваем, различаются способом резервирования пространства для данных. Разработчики ассемблера Intel выбрали для этой операции название DD (Define Double - определить двойное слово), поскольку слово процессора 8088 имело длину 8 бит. В Motorola используется аббревиатура DC (Define Constant - определить константу). Разработчики SPARC с самого начала предпочли название .WORD. И снова различия абсолютно случайны.

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

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

Назначение ассемблера || Оглавление || Директивы