Одной из часто встречающихся задач является работа с файлами. В Linux понятие файла довольно широко, и в данном случае мы будем работать с текстовыми файлами на диске. В языке Си для работы с файлами предназначена структура FILE и ряд функций. В контексте текущей статьи отметим следующие:
fopen: открывает файл и возвращает дескриптор для последующего взаимодействия с файлом
fclose: закрывает файл, получая его дескриптор
fputs: функция записи строки в файл
Я не буду подробно останавливаться на особенностях работы каждой функции, так как это больше относится к сфере программирования на языке Си. Лишь рассмотрим их вызов в коде на ассемблере:
.globl main .data filename: .asciz "myfile.txt" openmode: .asciz "w" message: .asciz "Hello METANIT.COM!\n" .text main: subq $8, %rsp # Открываем файл для записи movq $filename, %rdi movq $openmode, %rsi call fopen # сохраняем полученный дескриптор файла в стек movq %rax, (%rsp) # запись строки movq $message, %rdi # Первый параметр - строка форматирования movq (%rsp), %rsi # Второй параметр - дексриптор файла call fputs # Закрытие файла movq (%rsp), %rdi call fclose addq $8, %rsp ret
Прежде всего в программе определено несколько глобальных переменных. Переменная filename указывает на имя файл, в который мы будем записывать данные:
filename: .asciz "myfile.txt"
Предполагается, что файл будет расположен в текущей папке (если его нет, он будет создан).
Переменная openmode указывает на режим доступа к файлу. Мы будем записывать в файл, поэтому в качестве режима применяется строка "w":
openmode: .asciz "w"
Далее идет строка, которая будет записываться в файл:
message: .asciz "Hello METANIT.COM!\n"
В программе выделяем 8 байт в стеке, с одной строны, обеспечивая место для хранения дескриптора файла, а с другой стороны, гарантируя обеспечение выравнивания по 16-байтной границе.
subq $8, %rsp
Затем открываем файл функцией fopen()
:
movq $filename, %rdi movq $openmode, %rsi call fopen
Первый параметр функции - путь к файлу, а второй - режим открытия. В результате открытия в регистр %rax помещается дескриптор файла.
Затем сохраняем дескриптор файла в стек (так как регистр %rax далее будет изменяться) и записываем в файл строку:
# сохраняем полученный дескриптор файла в стек movq %rax, (%rsp) # запись строки movq $message, %rdi # Первый параметр - строка форматирования movq (%rsp), %rsi # Второй параметр - дексриптор файла call fputs
Первый параметр функции fputs - строка для записи - глобальная переменная message, а второй параметр - дескриптор файла, в который будет идти запись.
После окончания работы нам надо закрыть файл с помощью функции fclose()
:
# Закрытие файла movq (%rsp), %rdi call fclose
Функции передается дескриптор файла, ранее сохраненный в стек.
Допустим, программа находится в файле hello.s. Скомпилируем программу с помощью следующей команды:
gcc hello.s -static -o hello
После компиляции запустим приложение на выполнение, и в папке программы будет создан файл myfile.txt, в который будет записана строка.