Структура команды на языке ассемблера содержит. Структура команды на языке ассемблера программирование на уровне. Формат данных и структура команд языка ассемблер

Команды языка Ассемблер (Лекция)

ПЛАН ЛЕКЦИИ

1. Основные группы операций.

Pentium .

1. Основные группы операций

Микропроцессоры выполняют набор команд,которыереализуютследующиеосновные группыопераций:

Операциипересылки,

Арифметическиеоперации,

Логическиеоперации,

Операциисдвига,

Операциисравненияитестирования,

Битовыеоперации,

Операцииуправления программой;

Операцииуправления процессором.

2. Мнемокоды команд процессора Pentium

При описании команд обычно используются их мнемонические обозначения (мнемокоды), которые служат для задания команды при программировании на языке Ассемблера. Для различных версий Ассемблера мнемокоды некоторых команд могут отличаться. Например, для команды вызова подпрограммы используется мнемокод CALL или JSR (“ Jump to SubRoutine ”). Однако мнемокоды большинства команд для основных типов микропроцессоров совпадают или отличаются незначительно, так как они являются сокращениями соответствующих английских слов, определяющих выполняемую операцию. Рассмотрим мнемокоды команд, принятые для процессоров Pentium .

Команды пересылки. Основной командой этой группы является команда MOV , которая обеспечивает пересылку данных между двумя регистрами или между регистром и ячейкой памяти. В некоторых микропроцессорах реализуется пересылка между двумя ячейками памяти, а также групповая пересылка содержимого нескольких регистровиз памяти. Например, микропроцессоры семейства 68 xxx компании Motorola выполняют команду MOVE , обеспечивающую пересылку из одной ячейки памяти в другую, и команду MOVEM , которая производит запись в память или загрузку из памяти содержимого заданного набора регистров (до 16 регистров). Команда XCHG производит взаимный обмен содержимым двух регистров процессора или регистра и ячейки памяти.

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

Команды арифметических операций. Основными в этой группе являются команды сложения, вычитания, умножения и деления,которыеимеютрядвариантов. Команды сложения ADD и вычитания SUB выполняют соответствующие операции с c одержимым двух регистров, регистра и ячейки памяти или с использованием непосредственного операнда. Команды AD C , SB B производят сложение и вычитание с учетом значения признака C , устанавливаемого при формировании переноса в процессе выполнения предыдущей операции. С помощью этих команд реализуется последовательное сложение операндов, число разрядов которых превышает разрядность процессора. Команда NEG изменяет знак операнда, переводя его в дополнительный код.

Операции умножения и деления могут выполняться над числами со знаком (команды I MUL, I DIV ) или беззнака(команды MUL, DIV ).Одинизоперандоввсегдаразмещаетсяврегистре, второй может находиться в регистре, ячейке памяти или быть непосредственным операндом. Результат операции располагается в регистре. При умножении (команды MUL , IMUL ) получается результат удвоенной разрядности, для размещения которого используется два регистра. При делении (команды DIV , IDIV ) в качестве делимого используется операнд удвоенной разрядности, размещаемый в двух регистрах, а в качестве результата в два регистра записывается частное и остаток.

Команды логических операций . Практически все микропроцессоры производят логические операцииИ , ИЛИ, Исключающее ИЛИ, которые выполняются над одноименными разрядами операндов с помощью команд AND, OR, X OR . Операции выполняются над содержимым двух регистров, регистра и ячейки памяти или с использованием непосредственного операнда. Команда NOT инвертирует значение каждого разряда операнда.

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

Команды сравнения и тестирования . Сравнение операндов обычно производится с помощью команды CMP , которая производит вычитание операндов с установкой значений признаков N, Z, V, C в регистре состояния в соответствии с полученным результатом. При этом результат вычитания не сохраняется, и значения операндов не изменяются. Последующий анализ полученных значений признаков позволяет определить относительное значение (>, <, =) операндов со знаком или без знака. Использование различных способов адресации позволяет производит сравнение содержимого двух регистров, регистра и ячейки памяти, непосредственно заданного операнда с содержимым регистра или ячейки памяти.

Некоторые микропроцессоры выполняют команду тестирования TST , которая является однооперандным вариантом команды сравнения. При выполнении этой командыустанавливаются признаки N, Z в соответствии со знаком и значением (равно или не равно нулю) адресуемого операнда.

Команды битовых операций . Эти команды производят установку значения признака C в регистре состояний в соответствии со значением тестируемого бита bn в адресуемом операнде. В некоторых микропроцессорах по результату тестирования бита производится установка признака Z . Номер тестируемого бита n задаетсялибо содержимым указанного в команде регистра, либо непосредственным операндом.

Команды данной группы реализуют разные варианты изменениятестируемогобита.КомандаBT сохраняет значение этого бита неизменным .КомандаB T S послетестирования устанавливает значениеbn =1, а команда B T C - значение bn =0.Команда B T C инвертирует значение бита bn после его тестирования.

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

- команды безусловной передачи управления;

- команды условных переходов;

- команды организации программных циклов;

- команды прерывания;

- команды изменения признаков.

Безусловная передача управления производится командой JMP , которая загружает в программный счетчик PC новое содержимое, являющееся адресом следующей выполняемой команды. Этот адрес либо непосредственно указывается в команде JMP (прямая адресация), либо вычисляется как сумма текущего содержимого PC и заданного в команде смещения, которое является числом со знаком (относительная адресация). Так как PC содержит адрес очередной команды программы, то последний способ задает адрес перехода, смещенный относительно очередного адреса на заданное число байтов. При положительном смещении производится переход к последующим командам программы, при отрицательном смещении – к предыдущим.

Вызов подпрограммы также производится путем безусловной передачи управления с помощью команды CALL (или JSR ). Однако в этом случае перед загрузкой в PC нового содержимого, задающего адрес первой команды подпрограммы,необходимо сохранить его текущее значение (адрес очередной команды), чтобы после выполнения подпрограммы обеспечить возвращение к основной программе (или к предыдущей подпрограмме при вложении подпрограмм). Команды условных переходов (ветвлений программы) производят загрузку в PC нового содержимого, если выполняются определенные условия, которые обычно задаются в соответствии с текущим значением различных признаков в регистре состояния. Если условие не реализуется, то выполняется следующая команда программы.

Команды управления признаками обеспечивают запись - чтение содержимого регистра состояния, в котором хранятся признаки, а также изменение значений отдельных признаков. Например, в процессорах Pentium реализуются команды LAHF и SAHF , которые выполняют загрузку младшего байта, где содержатся признаки, из регистра состояния EFLAG в младший байт регистра EAX и заполнение младшего байта EFLAGS из регистра E A X .. Команды CLC, STC осуществляют установку значений признака переноса CF=0, CF=1, а команда CMC вызывает инвертирование значения этого признака. Так как признаки определяют ход выполнения программы при условных переходах, то команды изменения признаков обычно используются для управления программой.

Командыуправления процессором . К этой группе относятся команды останова, отсутствия операции и ряд команд, определяющих режим работы процессора или его отдельных блоков. Команда HLT прекращает выполнение программы и переводит процессор в состояние останова, выход из которого происходит при поступлении сигналов прерывания или перезапуска (Reset ). Команда NOP (“пустая” команда), которая не вызывает выполнения каких-либо операций, служит для реализации программных задержек или заполнения пропусков, образовавшихся в программе.

Специальные команды CLI, STI запрещают и разрешают обслуживание запросов прерывания. В процессорах Pentium для этого используется бит управления (флаг) IF в регистре EFLAGS .

Многие современные микропроцессоры выполняют команду идентификации, которая позволяет пользователю или другим устройствам получить информацию о типе процессора, используемого в данной системе. В процессорах Pentuim для этого служит команда CPUID , при выполнении которой необходимые данные о процессоре поступают в регистры EAX , EBX , ECX , EDX и могут затем считываться пользователем или операционной системой.

В зависимости от реализуемых процессором режимов работы и заданных типов обрабатываемых данных набор выполняемых команд может существенно расширяться.

Некоторые процессоры производят арифметические операции с двоично-десятичными числами или выполняют специальные команды коррекции результата при обработке таких чисел. В состав многих высокопроизводительных процессоров входит FPU - блок обработки чисел c “плавающей точкой”.

В ряде современных процессоров реализована групповая обработка нескольких целых чисел или чисел c “плавающей точкой” с помощью одной команды по принципу SIMD (“ Single Instruction – Multiple Data ”) - «Одна команда – Множество данных». Одновременное выполнение операций над несколькими операндами существенно повышает производительность процессора при работе с видео- и аудиоданными. Такие операции широко используются для обработки изображений, звуковых сигналов и в других приложениях. Для выполнения этих операций в состав процессоров введены специальные блоки, реализующие соответствующие наборы команд, которые в различных типах процессоров (Pentium , Athlon ) получили название MMX (“ Milti - Media Extension ”) – Мультимедийное Расширение, SSE (“ Streaming SIMD Extension ”) – Потоковое SIMD – расширение, “3 D Extension – Трехмерное Расширение.

Характерной особенностью процессоров компании Intel , начиная с модели 80286, является приоритетный контроль при обращении к памяти, который обеспечивается при работе процессора в режиме защищенных виртуальных адресов – “ Protected Mode ” (защищенный режим). Для реализации этого режима используется специальные группы команд, которые служат для организации защиты памяти в соответствии с принятым алгоритмом приоритетного обращения.

Структура команды на языке ассемблера Программирование на уровне машинных команд - это тот минимальный уровень, на котором возможно программирование компьютера. Система машинных команд должна быть достаточной для того, чтобы реализовать требуемые действия, выдавая указания аппаратуре машины. Каждая машинная команда состоит из двух частей: операционной, определяющей «что делать» и операндной, определяющей объекты обработки, то есть то «над чем делать» . Машинная команда микропроцессора, записанная на языке Ассемблера, представляет собой одну строку, имеющую следующий вид: метка команда/директива операнд(ы) ; комментарии Метка, команда/директива и операнд разделяются по крайней мере одним символом пробела или табуляции. Операнды команды разделяются запятыми.

Структура команды на языке ассемблера Команда ассемблера указывает транслятору, какое действие должен выполнить микропроцессор. Директивы ассемблера - параметры, заданные в тексте программы, влияющие на процесс ассемблирования или свойства выходного файла. Операнд определяет начальное значение данных (в сегменте данных) или элементы, над которыми выполняется действие по команде (в сегменте кода). Команда может иметь один или два операнда, или не иметь операндов. Число операндов неявно задается кодом команды. Если команду или директиву необходимо продолжить на следующей строке, то используется символ «обратный слеш»: «» . По умолчанию Ассемблер не различает заглавные и строчные буквы в написании команд и директив. Примеры директивы и команды Count db 1 ; Имя, директива, один операнд mov eax, 0 ; Команда, два операнда

Идентификаторы – последовательности допустимых символов, использующиеся для обозначения имен переменных и названий меток. Идентификатор может состоять из одного или нескольких следующих символов: все буквы латинского алфавита; цифры от 0 до 9; спецсимволы: _, @, $, ? . В качестве первого символа метки может использоваться точка. В качестве идентификаторов нельзя использовать зарезервированные имена ассемблера (директивы, операторы, имена команд). Первым символом идентификатора должна быть буква или спецсимвол. Максимальная длина идентификатора 255 символов, но транслятор воспринимает первые 32, остальные игнорирует. Все метки, которые записываются в строке, не содержащей директиву ассемблера, должны заканчиваться двоеточием «: » . Метка, команда (директива) и операнд не обязательно должны начинаться с какой-либо определенной позиции в строке. Рекомендуется записывать их в колонку для большей yдобочитаемости программы.

Метки Все метки, которые записываются в строке, не содержащей директиву ассемблера, должны заканчиваться двоеточием «: » . Метка, команда (директива) и операнд не обязательно должны начинаться с какой-либо определенной позиции в строке. Рекомендуется записывать их в колонку для большей yдобочитаемости программы.

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

Структура программы на языке ассемблера Программа, написанная на языке ассемблера, может состоять из нескольких частей, называемых модулями, в каждом из которых могут быть определены один или несколько сегментов данных, стека и кода. Любая законченная программа на языке ассемблере должна включать один главный, или основной, модуль, с которого начинается ее выполнение. Модуль может содержать программные сегменты, сегменты данных и стека, объявленные при помощи соответствующих директив.

Модели памяти Перед объявлением сегментов нужно указать модель памяти при помощи директивы. MODEL модификатор модель_памяти, соглашение_о_вызовах, тип_ОС, параметр_стека Основные модели памяти языка ассемблера: Модель памяти Адресация кода Адресация данных Операционная система Чередование кода и данных TINY NEAR MS-DOS Допустимо SMALL NEAR MS-DOS, Windows Нет MEDIUM FAR NEAR MS-DOS, Windows Нет COMPACT NEAR FAR MS-DOS, Windows Нет LARGE FAR MS-DOS, Windows Нет HUGE FAR MS-DOS, Windows Нет NEAR Windows 2000, Windows XP, Windows Допустимо FLAT NEAR NT,

Модели памяти Модель tiny работает только в 16 -разрядных приложениях MS-DOS. В этой модели все данные и код располагаются в одном физическом сегменте. Размер программного файла в этом случае не превышает 64 Кбайт. Модель small поддерживает один сегмент кода и один сегмент данных. Данные и код при использовании этой модели адресуются как near (ближние). Модель medium поддерживает несколько сегментов программного кода и один сегмент данных, при этом все ссылки в сегментах программного кода по умолчанию считаются дальними (far), а ссылки в сегменте данных - ближними (near). Модель compact поддерживает несколько сегментов данных, в которых используется дальняя адресация данных (far), и один сегмент кода с ближней адресацией (near). Модель large поддерживает несколько сегментов кода и несколько сегментов данных. По умолчанию все ссылки на код и данные считаются дальними (far). Модель huge практически эквивалентна модели памяти large.

Модели памяти Модель flat предполагает несегментированную конфигурацию программы и используется только в 32 -разрядных операционных системах. Эта модель подобна модели tiny в том смысле, что данные и код размещены в одном сегменте, только 32 -разрядном. Для разработки программы для модели flat перед директивой. model flat следует разместить одну из директив: . 386, . 486, . 586 или. 686. Выбор директивы выбора процессора определяет набор команд, доступный при написании программ. Буква p после директивы выбора процессора означает защищенный режим работы. Адресация данных и кода является ближней (near), при этом все адреса и указатели являются 32 -разрядными.

Модели памяти. MODEL модификатор модель_памяти, соглашение_о_вызовах, тип_ОС, параметр_стека Параметр модификатор используется для определения типов сегментов и может принимать значения: use 16 (сегменты выбранной модели используются как 16 -битные) use 32 (сегменты выбранной модели используются как 32 -битные). Параметр соглашение_о_вызовах используется для определения способа передачи параметров при вызове процедуры из других языков, в том числе и языков высокого уровня (C++, Pascal). Параметр может принимать следующие значения: C, BASIC, FORTRAN, PASCAL, SYSCALL, STDCALL.

Модели памяти. MODEL модификатор модель_памяти, соглашение_о_вызовах, тип_ОС, параметр_стека Параметр тип_ОС равен OS_DOS по умолчанию, и на данный момент это единственное поддерживаемое значение этого параметра. Параметр параметр_стека устанавливается равным: NEARSTACK (регистр SS равен DS, области данных и стека размещаются в одном и том же физическом сегменте) FARSTACK (регистр SS не равен DS, области данных и стека размещаются в разных физических сегментах). По умолчанию принимается значение NEARSTACK.

Пример «ничего не делающей» программы. 686 P. MODEL FLAT, STDCALL. DATA. CODE START: RET END START RET - команда микропроцессора. Она обеспечивает правильное окончание работы программы. Остальная часть программы относится к работе транслятора. . 686 P - разрешены команды защищенного режима Pentium 6 (Pentium II). Данная директива выбирает поддерживаемый набор команд ассемблера, указывая модель процессора. . MODEL FLAT, stdcall - плоская модель памяти. Эта модель памяти используется в операционной системе Windows. stdcall - используемое соглашение о вызовах процедур.

Пример «ничего не делающей» программы. 686 P. MODEL FLAT, STDCALL. DATA. CODE START: RET END START . DATA - сегмент программы, содержащий данные. Данная программа не использует стек, поэтому сегмент. STACK отсутствует. . CODE - сегмент программы, содержащей код. START - метка. END START - конец программы и сообщение компилятору, что начинать выполнение программы надо с метки START. Каждая программа должна содержать директиву END, отмечающую конец исходного кода программы. Все строки, которые следуют за директивой END, игнорируются Метка, указанная после директивы END, сообщает транслятору имя главного модуля, с которого начинается выполнение программы. Если программа содержит один модуль, метку после директивы END можно не указывать.

Трансляторы языка ассемблера Транслятор - программа или техническое средство, выполняющее преобразование программы, представленной на одном из языков программирования, в программу на целевом языке, называемую объектным кодом. Помимо поддержки мнемоник машинных команд, каждый транслятор обладает своим собственным набором директив и макросредств, зачастую ни с чем не совместимых. Основные виды трансляторов языка ассемблера: MASM (Microsoft Assembler), TASM (Borland Turbo Assembler), FASM (Flat Assembler) - свободно распространяемый многопроходной ассемблер, написанный Томашем Грыштаром (польск.), NASM (Netwide Assembler) - свободный ассемблер для архитектуры Intel x 86, был создан Саймоном Тэтхемом совместно с Юлианом Холлом и в настоящее время развивается небольшой командой разработчиков на Source. Forge. net.

Src="https://present5.com/presentation/-29367016_63610977/image-15.jpg" alt="Трансляция программы в Microsoft Visual Studio 2005 1) Создать проект, выбрав меню File->New->Project и"> Трансляция программы в Microsoft Visual Studio 2005 1) Создать проект, выбрав меню File->New->Project и указав имя проекта (hello. prj) и тип проекта: Win 32 Project. В дополнительных опциях мастера проекта указать “Empty Project”.

Src="https://present5.com/presentation/-29367016_63610977/image-16.jpg" alt="Трансляция программы в Microsoft Visual Studio 2005 2) В дереве проекта (View->Solution Explorer) добавить"> Трансляция программы в Microsoft Visual Studio 2005 2) В дереве проекта (View->Solution Explorer) добавить файл, в котором будет содержаться текст программы: Source. Files->Add->New. Item.

Трансляция программы в Microsoft Visual Studio 2005 3) Выбрать тип файла Code C++, но указать имя с расширением. asm:

Трансляция программы в Microsoft Visual Studio 2005 5) Установить параметры компилятора. Выбрать по правой кнопке в файле проекта меню Custom Build Rules…

Трансляция программы в Microsoft Visual Studio 2005 и в появившемся окне выбрать Microsoft Macro Assembler.

Трансляция программы в Microsoft Visual Studio 2005 Проверить по правой кнопке в файле hello. asm дерева проекта меню Properties и установить General->Tool: Microsoft Macro Assembler.

Src="https://present5.com/presentation/-29367016_63610977/image-22.jpg" alt="Трансляция программы в Microsoft Visual Studio 2005 6) Откомпилировать файл, выбрав Build->Build hello. prj."> Трансляция программы в Microsoft Visual Studio 2005 6) Откомпилировать файл, выбрав Build->Build hello. prj. 7) Запустить программу, нажав F 5 или выбрав меню Debug->Start Debugging.

Программирование в ОС Windows Программирование в OC Windows основывается на использовании функций API (Application Program Interface, т. е. интерфейс программного приложения). Их количество достигает 2000. Программа для Windows в значительной степени состоит из таких вызовов. Все взаимодействие с внешними устройствами и ресурсами операционной системы происходит, как правило, посредством таких функций. Операционная система Windows использует плоскую модель памяти. Адрес любой ячейки памяти будет определяться содержимым одного 32 -битного регистра. Возможны 3 типа структур программ для Windows: диалоговая (основное окно - диалоговое), консольная, или безоконная структура, классическая структура (оконная, каркасная).

Вызов функций Windows API В файле помощи любая функция API представлена в виде тип имя_функции (ФА 1, ФА 2, ФА 3) Тип – тип возвращаемого значения; ФАх – перечень формальных аргументов в порядке их следования Например, int Message. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Данная функция выводит на экран окно с сообщением и кнопкой (или кнопками) выхода. Смысл параметров: h. Wnd -дескриптор окна, в котором будет появляться окно-сообщение, lp. Text - текст, который будет появляться в окне, lp. Caption - текст в заголовке окна, u. Type - тип окна, в частности можно определить количество кнопок выхода.

Вызов функций Windows API int Message. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Практически все параметры API-функций в действительности 32 -битные целые числа: HWND - 32 -битное целое, LPCTSTR - 32 -битный указатель на строку, UINT - 32 -битное целое. К имени функций часто добавляется суффикс "А" для перехода к более новым версиям функций.

Вызов функций Windows API int Message. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); При использовании MASM необходимо в конце имени добавить @N N – количество байт, которое занимают в стеке переданные аргументы. Для функций Win 32 API это число можно определить как количество аргументов n, умноженное на 4 (байта в каждом аргументе): N=4*n. Для вызова функции используется команда CALL ассемблера. При этом все аргументы функции передаются в нее через стек (команда PUSH). Направление передачи аргументов: СЛЕВА НАПРАВО - СНИЗУ ВВЕРХ. Первым будет помещаться в стек аргумент u. Type. Вызов указанной функции будет выглядеть так: CALL Message. Box. A@16

Вызов функций Windows API int Message. Box (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Результат выполнения любой API функции - это, как правило, целое число, которое возвращается в регистре EAX. Директива OFFSET представляет собой «смещение в сегменте» , или, переводя в понятия языков высокого уровня, «указатель» начала строки. Директива EQU подобно #define в языке СИ определяет константу. Директива EXTERN указывает транслятору, что функция или идентификатор является внешним по отношению к данному модулю.

Пример программы «Привет всем!» . 686 P. MODEL FLAT, STDCALL. STACK 4096. DATA MB_OK EQU 0 STR 1 DB "Моя первая программа", 0 STR 2 DB "Привет всем!", 0 HW DD ? EXTERN Message. Box. A@16: NEAR. CODE START: PUSH MB_OK PUSH OFFSET STR 1 PUSH OFFSET STR 2 PUSH HW CALL Message. Box. A@16 RET END START

Директива INVOKE Транслятор языка MASM позволяет также упростить вызов функций с использованием макросредства – директивы INVOKE: INVOKE функция, параметр1, параметр2, … При этом нет необходимости добавлять @16 к вызову функции; параметры записываются точно в том порядке, в котором приведены в описании функции. макросредствами транслятора параметры помещаются в стек. для использования директивы INVOKE необходимо иметь описание прототипа функции с использованием директивы PROTO в виде: Message. Box. A PROTO: DWORD, : DWORD Если в программе используется множество функций Win 32 API, целесообразно воспользоваться директивой include C: masm 32includeuser 32. inc

Структуры в языке ассемблер

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

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

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

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

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

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

    Задать шаблон структуры .

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

    Определить экземпляр структуры .

    Этот этап подразумевает инициализацию конкретной переменной заранее определенной (с помощью шаблона) структурой.

    Организовать обращение к элементам структуры .

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

Описать структуру в программе означает лишь указать ее схему или шаблон; память при этом не выделяется.

Этот шаблон можно рассматривать лишь как информацию для транслятора о расположении полей и их значении по умолчанию.

Определить структуру - значит, дать указание транслятору выделить память и присвоить этой области памяти символическое имя.

Описать структуру в программе можно только один раз, а определить - любое количество раз.

Описание шаблона структуры

Описание шаблона структуры имеет следующий синтаксис:

имя_структуры STRUC

имя_структуры ENDS

Здесь представляет собой последовательность директив описания данных db, dw, dd, dq и dt .

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

Как мы уже отметили при описании шаблона, память не выделяется, так как это всего лишь информация для транслятора.

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

Рассмотрим работу со структурами на примере моделирования базы данных о сотрудниках некоторого отдела.

Для простоты, чтобы уйти от проблем преобразования информации при вводе, условимся, что все поля символьные.

Определим структуру записи этой базы данных следующим шаблоном:

Определение данных с типом структуры

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

[имя переменной] имя_структуры

    имя переменной - идентификатор переменной данного структурного типа.

    Задание имени переменной необязательно. Если его не указать, будет просто выделена область памяти размером в сумму длин всех элементов структуры.

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

    Его задание также необязательно.

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

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

    К примеру: victor worker .

Для примера определим несколько переменных с типом описанной выше структуры.

Методы работы со структурой

Идея введения структурного типа в любой язык программирования состоит в объединении разнотипных переменных в один объект.

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

    адресное_выражение - идентификатор переменной некоторого структурного типа или выражение в скобках в соответствии с указанными ниже синтаксическими правилами (рис. 1);

    имя_поля_структуры - имя поля из шаблона структуры.

    Это, на самом деле, тоже адрес, а точнее, смещение поля от начала структуры.

Таким образом оператор ". " (точка) вычисляет выражение

Рис. 5. Синтаксис адресного выражения в операторе обращения к полю структуры

Продемонстрируем на примере определенной нами структуры worker некоторые приемы работы со структурами.

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

Будьте внимательны, так как из-за принципа хранения данных “младший байт по младшему адресу” старшая цифра возраста будет помещена в al , а младшая - в ah .

Для корректировки достаточно использовать команду xchg al,ah :

mov ax,word ptr sotr1.age ;в al возраст sotr1

а можно и так:

Дальнейшая работа с массивом структур производится так же, как и с одномерным массивом. Здесь возникает несколько вопросов:

Как быть с размером и как организовать индексацию элементов массива?

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

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

К примеру:

Как выполнить копирование поля из одной структуры в соответствующее поле другой структуры? Или как выполнить копирование всей структуры? Давайте выполним копирование поля nam третьего сотрудника в поле nam пятого сотрудника:

mas_sotr worker 10 dup ()

mov bx,offset mas_sotr

mov si,(type worker)*2 ;si=77*2

mov di,(type worker)*4 ;si=77*4

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

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

Наличие в языке следующих двух типов данных, наверное, объясняется стремлением “хозяйки” максимально эффективно использовать рабочую площадь стола (оперативной памяти) при приготовлении еды или для размещения продуктов (данных программы).

По назначению можно выделить команды (в скобках приводятся примеры мнемонических кодов операций команд ассемблера ПК типа IBM PC):

l выполнения арифметических операций (ADD и ADC - сложения и сложения с переносом, SUB и SBB - вычитания и вычитания с заемом, MUL и IMUL - умножения без знака и со знаком, DIV и IDIV - деления без знака и со знаком, CMP - сравнения и т. д.);

l выполнения логических операций (OR, AND, NOT, XOR, TEST и т. д.);

l пересылки данных (MOV - переслать, XCHG - обменять, IN - ввести в микропроцессор, OUT - вывести из микропроцессора и т. д.);

l передачи управления (ветвления программы: JMP - безусловного перехода, CALL - вызова процедуры, RET - возврата из процедуры, J* - условного перехода, LOOP - управления циклом и т. д.);

l обработки строк символов (MOVS - пересылки, CMPS - сравнения, LODS - загрузки, SCAS - сканирования. Эти команды обычно используются с префиксом (модификатором повторения) REP;

l прерывания работы программы (INT - программные прерывания, INTO - условного прерывания при переполнении, IRET - возврата из прерывания);

l управления микропроцессором (ST* и CL* - установки и сброса флагов, HLT - останова, WAIT - ожидания, NOP - холостого хода и т. д.).

С полным списком команд ассемблера можно познакомиться в работах .

Команды пересылки данных

l MOV dst, src - пересылка данных (move - переслать из src в dst).

Пересылает: один байт (если src и dst имеют формат байта) или одно слово (если src и dst имеют формат слова) между регистрами или между регистром и памятью, а также заносит непосредственное значение в регистр или в память.

Операнды dst и src должны иметь одинаковый формат - байт или слово.

Src могут иметь тип: r (register) - регистр, m (memory) - память, i (impedance) - непосредственное значение. Dst могут быть типа r, m. Нельзя в одной команде использовать операнды: rsegm совместно с i; два операнда типа m и два операнда типа rsegm). Операнд i может быть и простым выражением:

mov AX, (152 + 101B) / 15

Вычисление выражения выполняется только при трансляции. Флаги не меняет.

l PUSH src - занесение слова в стек (push- протолкнуть; записать в стек изsrc). Помещает в вершину стека содержимое src - любого 16-битового регистра (в том числе и сегментного) или двух ячеек памяти, содержащих 16-битовое слово. Флаги не меняются;

l POP dst - извлечение слова из стека (pop - вытолкнуть; считать из стека в dst). Снимает слово с вершины стека и помещает его в dst - любой 16-битовый регистр (в том числе и сегментный) или в две ячейки памяти. Флаги не меняются.

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

Каждая машинная команда состоит из двух частей:

  • операционной — определяющей, «что делать»;
  • операндной — определяющей объекты обработки, «с чем делать».

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

метка команда/директива операнд(ы) ;комментарии

При этом обязательным полем в строке является команда или директива.

Метка, команда/директива и операнды (если имеются) разделяются по крайней мере одним символом пробела или табуляции.

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

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

Примеры строк кода:

Count db 1 ;Имя, директива, один операнд
mov eax,0 ;Команда, два операнда
cbw ; Команда

Метки

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

  • все буквы латинского алфавита;
  • цифры от 0 до 9;
  • спецсимволы: _, @, $, ?.

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

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

Команды

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

Директивы

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

Операнды

Операнд – объект, над которым выполняется машинная команда или оператор языка программирования.
Команда может иметь один или два операнда, или вообще не иметь операндов. Число операндов неявно задается кодом команды.
Примеры:

  • Нет операндов ret ;Вернуться
  • Один операнд inc ecx ;Увеличить ecx
  • Два операнда add eax,12 ;Прибавить 12 к eax

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

В качестве операндов могут выступать

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

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

Правила записи идентификаторов.

  • Идентификатор может состоять из одного или нескольких символов.
  • В качестве символов можно использовать буквы латинского алфавита, цифры и некоторые специальные знаки: _, ?, $, @.
  • Идентификатор не может начинаться символом цифры.
  • Длина идентификатора может быть до 255 символов.
  • Транслятор воспринимает первые 32 символа идентификатора, а остальные игнорирует.
Комментарии

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

Структура программы на ассемблере

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

Пример «ничего не делающей» программы на языке ассемблера:

686P
.MODEL FLAT, STDCALL
.DATA
.CODE
START:

RET
END START

В данной программе представлена всего одна команда микропроцессора. Эта команда RET . Она обеспечивает правильное окончание работы программы. В общем случае эта команда используется для выхода из процедуры.
Остальная часть программы относится к работе транслятора.
.686P — разрешены команды защищенного режима Pentium 6 (Pentium II). Данная директива выбирает поддерживаемый набор команд ассемблера, указывая модель процессора. Буква P, указанная в конце директивы, сообщает транслятору о работе процессора в защищенном режиме.
.MODEL FLAT, stdcall — плоская модель памяти. Эта модель памяти используется в операционной системе Windows. stdcall
.DATA — сегмент программы, содержащий данные.
.CODE — блок программы, содержащей код.
START — метка. В ассемблере метки играют большую роль, что не скажешь о современных языках высокого уровня.
END START — конец программы и сообщение транслятору, что начинать выполнение программы надо с метки START .
Каждый модуль должен содержать директиву END , отмечающую конец исходного кода программы. Все строки, которые следуют за директивой END , игнорируются. Если опустить директиву END , то генерируется ошибка.
Метка, указанная после директивы END , сообщает транслятору имя главного модуля, с которого начинается выполнение программы. Если программа содержит один модуль, метку после директивы END можно не указывать.




Top