Опубликован: 21.08.2007 | Доступ: свободный | Студентов: 1618 / 143 | Оценка: 4.23 / 3.74 | Длительность: 15:37:00
Лекция 3:

Ассемблер

< Лекция 2 || Лекция 3: 123 || Лекция 4 >

Управление ассемблированием обычно обеспечивает средства авторизации, взаимодействия с отладчиком, выдачей листинга, текстовым редактором, операционной системой и средствами приаппаратного уровня, доступными через BIOS.

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

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

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

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

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

При сравнении императивного и функционального подходов к программированию, П.Лэндин (P.J.Landin) предложил абстрактную машину SECD для спецификации машинно-зависимых аспектов семантики Лиспа. Подробное описание этой машины можно найти в книгах по функциональному программированию [ [ 23 ] , [ 64 ] ]. Рассмотрим технику ассемблерного программирования на примере программ для абстрактной машины (АМ), удобной для определения операционной семантики языка программирования, - машины SECD. Это автомат, работающий над четырьмя структурными регистрами: стек для промежуточных результатов, контекст для размещения именованных значений, управляющая вычислениями программа, резервная память (Stack, Environment, Control list, Dump). Регистры приспособлены к хранению выражений в форме атомов или списков. Состояние машины полностью определяется содержимым этих регистров. Поэтому функционирование машины можно описать достаточно точно в терминах изменения содержимого регистров при выполнении команд, что выражается следующим образом:

s e c d -> s' e' c' d' - переход от старого состояния к новому.

Для характеристики встроенных команд Лисп-интепретатора и результата компиляции программ базового Лиспа понадобятся следующие команды:

LD   - ввод данного из контекста в стек;
LDC  - ввод константы из программы в стек;
LDF  - ввод определения функции в стек;
AP   - применение функции, определение которой уже в стеке;
RTN  - возврат из определения функции к вызвавшей ее программе;
SEL  - ветвление в зависимости от активного (верхнего) значения стека;
JOIN - переход к общей точке после ветвления;
CAR  - первый элемент из активного значения стека;
CDR  - без первого элемента активное значение стека;
CONS - формирование узла по двум верхним значениям стека;
ATOM - неделимость (атомарность) верхнего элемента стека;
EQ  - равенство двух верхних значений стека;
SUB1 - вычитание 1 из верхнего элемента стека;
ADD1 - прибавление 1 к верхнему элементу стека;
STOP - останов.

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

s e (STOP ) d -> s e (STOP ) d

Следуя Хендерсону, для четкого отделения обрабатываемых элементов от остальной части списка будем использовать следующие обозначения: (x . l ) - первый элемент списка - x, остальные в списке l. (x y . l ) - первый элемент списка - x, второй элемент списка - y, остальные в списке l и т.д. Теперь мы можем методично описать эффекты всех перечисленных выше команд.

s e (LDC q . c) d            -> (q . s) e c d 
    (a . s) e (ADD1 . c) d        -> (a+1 . s) e c d 
    (a . s) e (SUB1 . c) d        -> (a-1 . s) e c d 
    (a b . s) e (CONS . c) d      -> ((a . b) . s) e c d
    ((a . b) . s) e (CAR . c) d   -> (a . s) e c d
    ((a . b) . s) e (CDR . c) d   -> (b . s) e c d
    (a . s) e (ATOM . c) d        -> (t . s) e c d 
    (a b . s) e (EQ . c) d        -> (t . s) e c d

где t - логическое значение.

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

(DEFUN N-th (n list ) 
      (IF  (EQ n 0 )(CAR list )
                            (N-th (SUB1 n ) (CDR list ) ))  )

Продолжаем описание команд Лисп-машины.

s e (LD n . c) d -> (x . s) e c d , где x - это значение (N-th n e )

При реализации ветвлений управляющая программа соответствует следующему шаблону:

( ... SEL ( ... JOIN ) ( ... JOIN ) ... )

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

(t . s) e (SEL c1 c0 . c) d  -> s e ct (c . d)

         s  e (JOIN )    (c . d) -> s e c  d

где ct - это c1 или c0 в зависимости от истинностного значения t.

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

s e (LDF f . c) d  > ((f . e) . s) e c d 
       ((f . ef) vf . s) e (AP . c) d > NIL   (vf . ef) f (s e c . d) 
            (x) e (RTN ) (s e c . d) > (x . s)       e c d

где f - тело определения, ef - контекст в момент вызова функции, vf - фактические параметры для вызова функции, x - результат функции.

< Лекция 2 || Лекция 3: 123 || Лекция 4 >
Илья Ардов
Илья Ардов

Добрый день!

Я записан на программу. Куда высылать договор и диплом?

Дарья Федотова
Дарья Федотова