dementiy 18.07.2010 00:14
Coding — Ассемблер в Linux. Использование системных вызовов
«Мастер ФУ! А зачем нужны системные вызовы? - Затем же, зачем тебе нужен твой сосудКакой сосуд? - решил уточнить ученик - А вот какой! - крикнул мастер, ударяя ученика палкой»
Системные вызовы это интерфейс для взаимодействия ядра ОС и внешних приложений. В данной заметке мы не будем рассматривать, как устроены системные вызовы, мы рассмотрим только использование некоторых из них (предназначенных для работы с файлами). Итак начнем:
Системный вызов OPEN
1 |
|
Системный вызов OPEN принимает три аргумента:
*pathname — путь к файлу;
flags — флаги, которые указывают способ открытия файла. Основные флаги (все флаги можно найти в файле include/asm-generic/fcntl.h) :
0 (O_RDONLY) — открыть файл только для чтения;
1 (O_WRONLY) — открыть файл только для записи;
2 (O_RDWR) — открыть файл для чтения и записи.
mode — права доступа к файлу, учитываются, если задан флаг O_CREAT. Права доступа задаются для владельца, группы и отсальных:
0700 — Владелец файла имеет право на чтение, запись и выполнение;
0400 — Владелец файла имеет право на чтение;
0200 — Владелец файла имеет право на запись
0100 — Владелец файла имеет право на выполнение;
0070 — Группа файла имеет право на чтение, запись и выполнение;
0040 — Группа файла имеет право на чтение;
0020 — Группа файла имеет право на запись;
0010 — Группа файла имеет право на выполнение;
0007 — Остальные пользователи имеют право на чтение, запись и выполнение;
0004 — Остальные пользователи имеют право на чтение;
0002 — Остальные пользователи имеют право на запись
0001 — Остальные пользователи имеют право на выполнение.
В %eax возвращается файловый дескриптор (целое неотрицательное значение) в случае успеха или отрицательное значение, если произошла ошибка.
Системный вызов CREAT
1 |
|
Системный вызов CREAT принимает два аргумента: путь к создаваемому файлу (*pathname) и права на файл (mode). При успешном выполнении возвращает дескриптор созданного файла в регистр %eax. Функция CREAT в действительности представляет из себя обертку для вызова OPEN:
1 |
fs/open.c:
|
Пример создания файла:
Системный вызов WRITE
1 |
|
Системный вызов WRITE приниммает три параметра:
fd — файловый дескриптор:
0 — STDIN (стандартный ввод);
1 — STDOUT (стандартный вывод);
2 — STDERR (стандартный вывод ошибок).
*buf — указатель на буфер (данные подлежащие выводу);
count — количество символов подлежащих выводу.
И возвращает количество выведенных символов в регистр %eax. Пример использования:
Системный вызов READ
1 |
|
Системный вызов READ аналогично WRITE принимает три аргумента, которые описаны выше. Количество прочитанных символов возвращается в %eax. Пример использования:
Системный вызов LSEEK
1 |
|
Системный вызов LSEEK предназначен для чтения/записи в произвольное место файла. Он принимает следующие аргументы:
fd — файловый дескриптор;
offset — количество байт, на которые нужно сместиться относительно whence;
whence — устаналивает позицию в файле, принимает следующие значения (определены в include/linux/fs.h):
1 (SEEK_SET) — начало файла;
2 (SEEK_CUR) — текущая позиция в файле;
3 (SEEK_END, SEEK_MAX) — конец файла.
Возвращает новую позицию в файле относительно его начала в %eax, либо номер ошибки в случае неудачи.
1 |
|
Системный вызов CLOSE
1 |
|
Cистемный вызов CLOSE принимает только один аргумент — файловый дескриптор (fd) и возврщает в %eax 0 в случае успеха или номер ошибки в случае неудачи.
1 |
...
|
Пример вывода текста из файла с использованием системных вызовов OPEN, WRITE, READ и CLOSE:
Системный вызов UNLINK
1 |
|
Системный вызов UNLINK принимает всего лишь один аргумент — путь к удаляемому файлу. В %eax возвращается 0 в случае успеха или номер ошибки в случае неудачи.
1 |
|
Системные вызовы TRUNCATE и FTRUNCATE
1 |
|
1 |
|
Системный вызов TRUNCATE принимает два аргумента: путь к файлу (*path) и новый размер файла (length), и возвращает в %eax 0 в случае успеха или номер ошибки в случае неудачи. Создадим файл «test.txt» и напишем в нем «Some text before truncate». Его размер составляет 26 байт. Теперь выполним следующую программу:
Она урезает файл до 9 байт и после ее исполнения в файле останется надпись «Some text». Если указать размер файла больше текущего размера, то в файле образуются дырки. Системный вызов FTRUNCATE полностью аналогичен TRUNCATE, за исключением того, что вместо пути указывается файловый дескриптор, FTRUNCATE имеет номер 0x5d.
Системный вызов UTIME
1 |
|
Системный вызов UTIME принимает два параметра: имя файла, которому следует изменить время доступа и модификации и указатель на структуру utimebuf. Структура utimebuf включает в себя два поля:
1 |
include/linux/utime.h:
|
Время доступа и модификации указывается в секундах от 1 января 1970 года. Рассмотрим небольшой пример, создадим файл «test.txt», чтобы просмотреть его время доступа и модификации можно воспользоваться командой ls (для отображения времени доступа используется параметр --time=atime). Изменим эти значения, время доступа выставим равным 1 января 1970 года, а время модификации 1 января 2011 года:
После запуска программы можете проверить время доступа и модификации, они должны были измениться. Для того, чтобы установить текущее время доступа и модификации необходимо передать 0 (NULL) вместо адреса структуры (movl $0, %ecx).
Замечания
В системных вызовах в случае ошибки возвращается отрицательное значение в регистр %eax. Например в системном вызове LSEEK, если задан файловый дескриптор не открытого файла, то в %eax будет значение 0xfffffff7, что соответсвует -9 (коды ошибок можно посмотреть в файле include/asm-generic/errno-base.h), а не 4294967287. Поэтому для обработки ошибок следует использовать условные конструкции для знаковых чисел.
Системные вызовы можно просмотреть используя трассировщик strace. Например для программы utime.s:
Таким образом можно проверить себя на правильность заданных аргументов. Если системный вызов возвращает ошибку, то strace отобразит ее в удобочитаемом виде:
Общая концепция работы с системными вызовами я думаю должна быть ясна, в %eax всегда помещается номер системного вызова, в %ebx, %ecx, %edx, %esi, %edi с первого по пятый аргументы соответственно.
Вместо шлюза $0x80 можно использовать библиотеку языка С и инструкцию CALL. У такого подхода есть свои плюсы и недостатки. Главный плюс состоит в том, что будут использовать разделяемые библиотеки, а минус, как следствие, в увеличении размера исполняемого файла.
Ну и наконец, справку по системным вызовам можно получить на страницах справочного руководства man, во втором и третьем разделах.
P.S. Данная заметка не является второй частью цикла (которая появится скорее всего уже только в августе), скорее это приложение к первой части, чтобы немного пролить свет на использование системных вызовов в ассемблере. Как всегда, если заметите неточности или ошибки сообщите о них. И наконец pdf'ка (возможно, что pdf со временем будет пополняться, но это не точно).
На счет документации. Есть документация по системным вызовам для С, а для ассемблера можно найти примеры (и то не много), которые разбросаны по всей сети, а документации нет. Хорошо это или плохо я не знаю, с одной стороны дублировалась бы информация, которая есть в документации к С, с другой стороны было бы неплохо иметь описание всех системных вызовов с примерами на ассемблере.
короче реально подбирать параметры в регистры...
но я не отстану ;)..
вот что можно такое зафигачить на асме, что тяжелее или просто нельзя на сях?
самогенерирующийся код? а это сильно сложно, чтоб хотя бы понять, сейчас?
но я не отстану ;)..
вот что можно такое зафигачить на асме, что тяжелее или просто нельзя на сях?
самогенерирующийся код? а это сильно сложно, чтоб хотя бы понять, сейчас?
Нет, подбирать-то ничего не надо, я же в конце написал "... в %eax всегда помещается номер системного вызова, в %ebx, %ecx, %edx, %esi, %edi с первого по пятый аргументы соответственно.", а номера системных вызовов можно взять тут. На счет сложности, всегда все зависит от алгоритма.
Зафигарить можно оптимизацию. Да, если у вас конечно на запасных путях стоит N товарных поездов, заполненных свободным временем, то можете написать какое-нибудь приложение.
И да, hello world заработал (хз, че в пролый раз было)
так:
так:
$ as -s -o hello.o hello.s
$ ld -s -o hello hello.o
Крошка-сын к отцу пришел,
и спросила кроха:
Что такое "хорошо"
И что такое "плохо"
...
Это только у меня вызывает омерзение этот, с позволения сказать, -- "мастер", которого вообще следовало бы изолировать?
И ушла рыдая кроха,
Вытирая кровь рубашкой.
Нет, не ждите от ребенка
Уважения к "папашке".
и спросила кроха:
Что такое "хорошо"
И что такое "плохо"
...
Мастер ФУ! А зачем нужны системные вызовы? - Затем же, зачем тебе нужен твой сосуд
Какой сосуд? - решил уточнить ученик - А вот какой! - крикнул мастер, ударяя ученика палкой
Какой сосуд? - решил уточнить ученик - А вот какой! - крикнул мастер, ударяя ученика палкой
Это только у меня вызывает омерзение этот, с позволения сказать, -- "мастер", которого вообще следовало бы изолировать?
И ушла рыдая кроха,
Вытирая кровь рубашкой.
Нет, не ждите от ребенка
Уважения к "папашке".
А чем Вам не нравится вступление? Метафора, как метафора, и ничего в ней плохого я не вижу.
Ай, не обращайте внимание!
Жаль, что Вы не видите в ней агрессии сумасшедшего идиота. Если это так, то я не смогу Вам объяснить, что мне там не нравиться. Это как слепому от рождения рассказать какого цвета небо, какого цвета трава, снег, одуванчики?
Как говориться, ничего личного. Просто не люблю когда проявляют жестокость. Даже иносказательно.
Куда ходит ваша энергия? -- Она уходит в след за вашими мыслями. Думайте позитивно, созидательно и мир вокруг вас начнет меняться в эту же сторону.
Извините за лишнюю мораль. И в мыслях не было -- учить кого-то! Моя реплика -- это всего лишь моя позиция, но не правила для всех.
Жаль, что Вы не видите в ней агрессии сумасшедшего идиота. Если это так, то я не смогу Вам объяснить, что мне там не нравиться. Это как слепому от рождения рассказать какого цвета небо, какого цвета трава, снег, одуванчики?
Как говориться, ничего личного. Просто не люблю когда проявляют жестокость. Даже иносказательно.
Куда ходит ваша энергия? -- Она уходит в след за вашими мыслями. Думайте позитивно, созидательно и мир вокруг вас начнет меняться в эту же сторону.
Извините за лишнюю мораль. И в мыслях не было -- учить кого-то! Моя реплика -- это всего лишь моя позиция, но не правила для всех.
и еще на той же странице wasm`а есть нехилая, но грустная метафора:
когда только начинаешь писать на асме под *nix то возникает интересное ощущение: вроде бы ты попал в грязный пятибаксовый мотель (из тех, возле которых обязательно проходит метро и когда едет поезд на потолке дрожит дешевая люстра и мигает свет); здесь давно нет горячей воды, обои уродливыми клочьями свисают со стен, с потолка капает какая то мерзкая гадость и пахнет плесенью, все удобства – во дворе... На мотеле (подпертые кем-то неизвестным) стоят уже давно покосившиеся со временем неоновые буквы «*NIX для ассемблерщиков» (половина букв давно не горит, а половина с треском догорает). У мотеля нет своих постояльцев. Сюда заезжают лишь переночевать, чтобы на следующее утро убраться подальше...
Самое мерзкое во всем этом то, что через единственное окно в этой конуре, через дорогу, как будто специально, вырос семизвездочный отель, весь в рекламе, бассейнах и пальмах... Прямо над входом (к которому то и дело поминутно подъезжают все более и более крутые тачки) сверкает золотом надпись: “*NIX для сишников”. Вон видно как по террасам ходят пузатые мужики в обнимку с дорогими бабами, потягивая коктейли и куря сигары, им прислуживает армия официантов и слуг; все они смеются и живут.
И еще интересно, правда, что до сих пор