Ассемблер рассматривает любые входные или выходные данные в качестве потока байтов. Есть три стандартных файловых потока:
стандартный ввод (stdin
);
стандартный вывод (stdout
);
стандартная ошибка (stderr
).
Файловый дескриптор
Файловый дескриптор (или «дескриптор файла») — это 16-битное целое число, присваиваемое файлу в качестве идентификатора. Когда создается новый файл или открывается существующий, дескриптор файла используется для доступа к нему.
Файловый дескриптор стандартных файловых потоков:
stdin — 0
;
stdout — 1
;
stderr — 2
.
Файловый указатель
Файловый указатель указывает местоположение для последующей операции чтения/записи в файл. Каждый файл рассматривается как последовательность байтов и ассоциируется с файловым указателем, который задает смещение в байтах относительно начала файла. Когда файл открыт, значением файлового указателя является 0
.
Системные вызовы обработки файлов
В следующей таблице кратко описаны системные вызовы, связанные с обработкой файлов:
%eax | Имя системного вызова | %ebx | %ecx | %edx |
2 | sys_fork | struct pt_regs | — | — |
3 | sys_read | unsigned int | char * | size_t |
4 | sys_write | unsigned int | const char * | size_t |
5 | sys_open | const char * | int | int |
6 | sys_close | unsigned int | — | — |
8 | sys_creat | const char * | int | — |
19 | sys_lseek | unsigned int | off_t | unsigned int |
Необходимые шаги для использования системных вызовов:
поместите номер системного вызова в регистр EAX;
сохраните аргументы системного вызова в регистрах EBX, ECX и EDX;
вызовите соответствующее прерывание (80h
);
результат обычно возвращается в регистр EAX.
Создание и открытие файла
Для создания и открытия файла выполняются следующие шаги:
поместите системный вызов sys_creat() — номер 8
в регистр EAX;
поместите имя файла в регистр EBX;
поместите права доступа к файлу в регистр ECX.
Системный вызов возвращает файловый дескриптор созданного файла в регистр EAX. В случае ошибки, код ошибки также будет находиться в регистре EAX.
Открытие существующего файла
Для открытия существующего файла выполняются следующие шаги:
поместите системный вызов sys_open() — номер 5
в регистр EAX;
поместите имя файла в регистр EBX;
поместите режим доступа к файлу в регистр ECX;
поместите права доступа к файлу в регистр EDX.
Системный вызов возвращает файловый дескриптор открытого файла в регистр EAX. В случае ошибки, код ошибки также будет находиться в регистре EAX.
Среди режимов доступа к файлам чаще всего используются:
только чтение (0
);
только запись (1
);
чтение-запись (2
).
Чтение файла
Для чтения данных из файла выполняются следующие шаги:
поместите системный вызов sys_read() — номер 3
в регистр EAX;
поместите файловый дескриптор в регистр EBX;
поместите указатель на входной буфер в регистр ECX;
поместите размер буфера, т.е. количество байтов для чтения, в регистр EDX.
Системный вызов возвращает количество прочитанных байтов в регистр EAX. В случае ошибки, код ошибки также будет находиться в регистре EAX.
Запись в файл
Для записи в файл выполняются следующие шаги:
поместите системный вызов sys_write() — номер 4
в регистр EAX;
поместите файловый дескриптор в регистр EBX;
поместите указатель на выходной буфер в регистр ECX;
поместите размер буфера, т.е. количество байтов для записи, в регистр EDX.
Системный вызов возвращает фактическое количество записанных байтов в регистр EAX. В случае ошибки, код ошибки также будет находиться в регистре EAX.
Закрытие файла
Для закрытия файла выполняются следующие шаги:
поместите системный вызов sys_close() — номер 6
в регистр EAX;
поместите файловый дескриптор в регистр EBX.
В случае ошибки, системный вызов возвращает код ошибки в регистр EAX.
Обновление файла
Для обновления файла выполняются следующие шаги:
поместите системный вызов sys_lseek() — номер 19
в регистр EAX;
поместите файловый дескриптор в регистр EBX;
поместите значение смещения в регистр ECX;
поместите исходную позицию для смещения в регистр EDX.
Исходная позиция может быть:
началом файла — значение 0
;
текущей позицией — значение 1
;
концом файла — значение 2
.
В случае ошибки, системный вызов возвращает код ошибки в регистр EAX.
Пример на практике
Следующая программа создает и открывает файл с именем myfile.txt, и записывает текст Welcome to Ravesli!
в этот файл. Затем программа считывает данные из файла и сохраняет их в буфере с именем info
. Наконец, программа выводит текст, сохраненный в буфере info
, на экран:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
section .text global _start ; объявляем для использования gcc _start: ; сообщаем линкеру входную точку ; Создаем файл mov eax, 8 mov ebx, file_name mov ecx, 0777 ; читать, писать и выполнять могут все int 0x80 ; вызов ядра mov [fd_out], eax ; Записываем данные в файл mov edx,len ; количество байтов mov ecx, msg ; сообщение для записи в файл mov ebx, [fd_out] ; файловый дескриптор mov eax,4 ; номер системного вызова (sys_write) int 0x80 ; вызов ядра ; Закрываем файл mov eax, 6 mov ebx, [fd_out] int 0x80 ; вызов ядра ; Выводим на экран сообщение, указывающее на конец записи в файл mov eax, 4 mov ebx, 1 mov ecx, msg_done mov edx, len_done int 0x80 ; Открываем файл для чтения mov eax, 5 mov ebx, file_name mov ecx, 0 ; доступ "Только для чтения" mov edx, 0777 ; читать, писать и выполнять могут все int 0x80 mov [fd_in], eax ; Считываем данные из файла mov eax, 3 mov ebx, [fd_in] mov ecx, info mov edx, 26 int 0x80 ; Закрываем файл mov eax, 6 mov ebx, [fd_in] int 0x80 ; Выводим на экран данные из буфера info mov eax, 4 mov ebx, 1 mov ecx, info mov edx, 26 int 0x80 mov eax,1 ; номер системного вызова (sys_exit) int 0x80 ; вызов ядра section .data file_name db 'myfile.txt' msg db 'Welcome to Ravesli!' len equ $-msg msg_done db 'Written to file', 0xa len_done equ $-msg_done section .bss fd_out resb 1 fd_in resb 1 info resb 26 |
Результат выполнения программы:
Written to file
Welcome to Ravesli!
Надо добавить 0 к строке имени файла
63: file_name db 'myfile.txt', 0