Реклама:

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

Таблица В,4, Некоторые системные вызовы и подпрограммы UNIX, поддерживаемые интерпретатором

Имя

Аргументы

Возвращаемое значение

Описание

_OPEN

*name, 0/1/2

Дескриптор файла

Открытие файла

_CREAT

*name, *mode

Дескриптор файла

Создание файла

_READ

fd, buf, nbytes

# байт

Чтение п байт (пЬ^еэ) из буфера Ь^

_WRITE

fd, buf, nbytes

# байт

Запись п байт (пЬуіез) из буфера Ь^

_CLOSE

fd

0 в случае успешного выполнения

Закрытие файла с дескриптором fd

_LSEEK

fd, offset(long), 0/1/2

Положение (long)

Перемещение указателя файла

_EXIT

status

 

Закрытие файлов, остановка процесса

_GETCHAR

 

Чтение символа

Чтение символа в файле стандартного ввода

_PUTCHAR

char

Запись байта

Запись символа в файл стандартного вывода

_PRINTF

*format, arg

 

Запись с форматированием в файл стандартного вывода

_SPRINTF

but, *format, arg

 

Запись в буфере Ь^ с форматированием

_SSCANF

buf, *format, arg

 

Чтение аргументов из буфера Ь^

Все эти двенадцать программ запускаются в стандартном порядке вызова: в первую очередь, в стеке в обратном порядке размещаются все необходимые аргументы; затем в стек вводится номер вызова; наконец, выполняется команда системного исключения SYS без операндов. Все необходимые данные, в том числе номер вызова той или иной системной службы, системная программа извлекает из стека. Возвращаемые значения записываются либо в регистр АХ, либо в комбинацию регистров DX : АХ (если они соответствуют длинному слову).

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

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

Файлы открываются вызовом OPEN или CREAT. В обоих случаях первым аргументом является адрес начала строки, содержащей имя файла. Вторым аргументом в вызове OPEN могут быть 0 (если файл нужно открыть для чтения), 1 (если файл открывается для записи) или 2 (если файл открывается для чтения и записи). Если при наличии прав записи указанный файл не существует, в процессе вызова он создается. Во время вызова CREAT создается пустой файл с полномочиями, заданными на основании второго аргумента. Вызовы OPEN и CREAT возвращают двухбайтовое целое и помещают его в регистр АХ, который называется дескриптором файла и с помощью которого этот файл можно прочесть, записать или закрыть. Отрицательное возвращенное значение свидетельствует о том, что вызов завершился ошибкой. Перед началом выполнения программы открываются три файла с дескрипторами: 0 для стандартного ввода, 1 для стандартного вывода и 2 для стандартного вывода ошибок.

У вызовов READ и WRITE три аргумента: дескриптор файла, буфер, в котором хранятся данные, и число передаваемых байтов. Поскольку аргументы размещаются в стеке в обратном порядке, сначала в стек вводится число байтов, затем - адрес начала буфера, далее - дескриптор файла, и наконец - номер вызова (READ или WRITE). Этот порядок размещения аргументов в стеке аналогичен стандартной последовательности вызова в языке С:

read(fd, buffer, bytes);

Эта команда реализуется путем введения в стек параметров в следующем порядке: bytes, buffer, fd.

У вызова CLOSE один аргумент - дескриптор файла. При успешном закрытии файла он возвращает значение 0 в регистре АХ. Вызов EXIT требует сохранения в стеке статуса выхода и не возвращает значение.

Вызов LSEEK изменяет указатель чтения-записи в открытом файле. Первым аргументом здесь выступает дескриптор файла. Поскольку второй аргумент является длинным словом, в стек сначала помещается старшее слово, а затем младшее - даже в том случае, если смещение умещается в одном слове. Третий аргумент определяет метод вычисления нового значения указателя чтения-записи: относительно начала файла (0), текущего положения (1) или конца файла (2). Возвращаемое значение определяет новое положение указателя относительно начала файла; в формате длинного слова оно сохраняется в комбинации регистров DX : АХ.

Перейдем к функциям, не являющимся системными вызовами. Функция GETCHAR считывает один символ из файла стандартного ввода и помещает его в регистр AL; при этом значение АН обнуляется. При ошибке слово в регистре АХ целиком приравнивается к значению -1. Вызов PÜTCHAR записывает один байт в файл стандартного вывода. Выводимым значением при успешной записи является именно этот байт; при ошибке выводится -1.

Вызов PRINTF выводит отформатированные данные. Первым аргументом служит адрес форматной строки, задающей формат выводимых данных. Строка Ы указывает на то, что следующим аргументом является целое число в стеке, которое при выводе преобразуется в десятичное представление. Аналогичным образом, строка °4х осуществляет преобразование в шестнадцатеричное, а Хо - в восьмеричное представление. Строка Xs определяет следующий аргумент как строку с завершающим нулем, которая при вызове передается с помощью адреса в стеке. Количество дополнительных аргументов в стеке должно соответствовать количеству указателей преобразования в форматной строке.

Например:

printf(??x = %6 and у = *d\n??. х, у);

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

Первым аргументом вызова SPRINTF является буфер, в который направляется выходная строка (в отличие от PRINTF, где строка попадает в файл стандартного вывода). Остальные аргументы аналогичны тем, что применяются в PRINTF. Вызов SSCANF в определенном смысле противоположен PRINTF - первым аргументом здесь является строка, которая может содержать целые числа в десятичном, восьмеричном или шестиадцатеричном представлении, а вторым - форматная строка с указателями преобразования. Могут быть и другие аргументы - адреса слов памяти, принимающие преобразованные данные. Все упомянутые системные подпрограммы весьма разносторонне но подробный анализ их возможностей мы проводить не будем. В разделе "Примеры" есть несколько примеров, демонстрирующих Pix применение в различных ситуациях.

Вызовы подпрограмм || Оглавление || Заключительные замечания о наборе команд