Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
flor_apparato-orientirovnnoe_prog.doc
Скачиваний:
89
Добавлен:
15.06.2014
Размер:
926.72 Кб
Скачать

2.2. Обращения к функциям ос посредством прерываний

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

MOV куда, откуда_или_что

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

MOV cl, bh

MOV edx, esi

переписывает данные из регистра BH в регистр CL, а вторая из приведенных команд пересылает значение из регистра ESI в регистр EDX. В рассматриваемых ассемблерах принято систематическое правило: местонахождение результата (если он только указывается явно в записи команды) всегда задается в самом левом операнде команды. (Для других ассемблеров может применяться другое правило, в частности ассемблер AT&T требует, чтобы место размещения результата команды задавалось в правом ее операнде.)

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

MOV EAX, 1237

MOV DL, 'W'

при выполнении процессором помещают, соответственно, в регистр EAX десятичное число 1237 и в регистр DL код символа W.

Если метка metka (имя области данных) обозначает начало области данных, то команда пересылки

MOV edx, metka

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

Заметим, что только что рассмотренное решение относится только к ассемблеру NASM. В ассемблерах же MASM и TASM для аналогичной цели указания адрес области данных в команде используется запись вида OFFSET имя_области_данных, так что приведенная выше для NASM команда запишется для них в виде

MOV edx, OFFSET metka

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

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

unsigned int write(int handle, char *buffer, unsigned int size)

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

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

В большинстве хорошо спроектированных ОС для доступа к стандартным файлам служат стандартные значения хэндлов, равные 0, 1 и 2. Именно, через хэндл, равный нулю, в дальнейшем обеспечивается доступ к стандартному вводу (по умолчанию, если при запуске программы не сделано соответствующего переназначения, стандартный ввод идет с клавиатуры). Через хэндл, равный единицы, обеспечивается доступ к стандартному выводу (т.е. по умолчанию - вывод на экран). Хэндл со значением два предназначен для оперативного вывода сообщений об ошибках, и также по умолчанию его использование приводит к выводу на экран. Обозначение стандартных ввода и выводов хэндлами со значениями 0, 1, 2 присуще операционным системам Unix, OS/2 и даже старенькой однозадачной MS-DOS, но в ОС типа Windows используется более сложный вариант, который будет рассматриваться значительно позже.

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

Дальше мы рассмотрим особенности обращения к программным функциям операционных систем.

Наиболее эффективным путем доступа к внутренним подпрограммам (функциям по терминологии Си) операционной системы оказалась очень специфическая команда, называемая программным прерыванием. Эта команда в рассматриваемых ассемблерах записывается в виде

INT номер_прерывания

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

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

Для начального изучения возможностей и использования ассемблера сейчас важно лишь то, что к внутренним действиям ряда операционных систем можно обратиться командами INT номер. При этом нужно знать, который номер прерывания задать и как передать аргументы подпрограмме ОС, которая будет выполнять наш запрос. Сразу же обратим внимание, что доступ к внутренним функциям ОС через программные прерывания возможет в ОС Linux и MS-DOS, но скрыт в качестве промежуточного механизма для таких ОС, как Windows и OS/2. Программный интерфейс последних использует доступ к функциям ОС через именованные функции, доступные в свою очередь с помощью специальных библиотек подпрограмм, постоянно находящихся в оперативной памяти и одновременно обслуживающих множество запросов. (Они называются библиотеками динамической компоновки.) Последний вариант доступа будет как более сложный рассмотрен значительно позже - после изучения средств ассемблера, позволяющих описать такие обращения.

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

INT 80H

а какая именно функция нужна - задается числом в регистре eax (это число должно быть занесено в регистр eax перед выполнением команды INT 80H).

Все аргументы, заданные прототипом системной функции на языке Си, должны быть предварительно помещены в регистры ebx, ecx, edx, esi и edi. Причем первый аргумент прототипа функции должен быть помещен в регистр ebx, второй аргумент ее - в регистр ecx, третий - в регистр edx, четвертый - в регистр esi и пятый - в регистр edi. Практически для пользователя такой системы нужно знать только номер, соответствующий базовой системной функции. Эти номера содержатся в файле unistd.h, находящемся в большинстве модификаций Linux в каталоге /usr/include/asm.

Для функции write текущие версии Linux дают число 4, для функции read - число 3, для функции exit - число 1. Этих функций, как ни странно, оказывается достаточно для всех рассматриваемых далее программ, которые предназначены для ознакомления с программированием на ассемблере.

Изученного нами материала уже достаточно для написания простейшей программы, результаты работы которой можно наблюдать. Эта программа, приведенная в листинге 2.2.1, предназначена для вывода на экран текста Privet!

GLOBAL _start

SEGMENT .text

_start:

;--- write(1, txt, 7) == <4>(ebx, ecx, edx)

mov eax,4 ; N function=write

mov ebx,1 ; N handle=1 (stdout)

mov ecx, txt ; address of txt

mov edx,7 ; number of byte

int 80h

mov eax,1 ; N function=exit

int 80h SEGMENT .data

txt db 'Privet!'

Листинг 2.2.1. Простейшая программа вывода текста на ассемблере NASM

В этой программе описано два сегмента со стандартными именами .text и .data, причем в сегменте данных описана именованная область данных с именем txt, которая содержит текст, заданный директивой DB.

Сегмент машинных команд по существу содержит записанные на ассемблере последовательные вызовы системных функций write(1, txt, 7) и exit(0). Каждый такой вызов состоит из занесения в регистры аргументов и обращения к команде INT 80H. Занесение аргументов производится командами пересылки MOV. Первый аргумент этих функций, задаваемый во всех трех данных вызовах константой, заносится в регистр ebx. Второй аргумент для функций write в нашем примере задает адрес области текста, который должен быть выведен, поэтому для его занесения использованы команды вида

MOV ecx, имя_области_текста

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

MOV edx, число

Такой же по виду командой в регистр eax (перед вызовом программного прерывания) заносится системный номер базовой системной функции.

Для наглядности перед командами реализации вызова системной функции приведен ее текст на языке Си, но записанный в виде комментариев. Причем для удобства усвоения запись вызова функции на языке Си сопровождается условной записью вида <номер_функции>(ebx, ecx, edx) или подобной, но с другим числом аргументов в скобках. Последняя форма записи напоминает об используемых в Linux правилах вызова базовых системных функций.

Соседние файлы в предмете Системное программное обеспечение