Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #51, ФЕВРАЛЬ 2005 г.

Как *nix-системы потеряли портируемость

j1m (j1m@list.ru)

Спецвыпуск: Хакер, номер #051, стр. 051-092-5


main:

pushl %ebp # создаем новый кадр стека

movl %esp,%ebp

pushl $mes1

call puts # выводим сообщение mes1 (puts - вывести строку)

pushl $buf1

call gets # читаем имя файла в буфер buf1 (gets - прочитать строку)

pushl $mes2

call puts # выводим сообщение mes2

pushl $buf2

call gets # читаем новое имя файла в буфер buf2

add $16,%esp # очищаем стек

pushl $buf2 # новое имя файла в стек

pushl $buf1 # старое имя файла в стек

call rename # функция rename (переименование файла)

popl %ebx # очищаем стек

movl %ebp,%esp # возвращаем стек в прежнее состоянее

popl %ebp

ret # выходим...

Перед тобой программа для переименования файлов. После запуска она задает пользователю вопрос о старом и новом имени файла, а затем переименовывает этот файл.

Как она работает? Как видно из исходника, программа представляет собой одну функцию, о чем говорит название метки (Main) и команда Ret в конце программы. Обрати внимание, что теперь экспортируем не метку _start, а метку Main. Почему? Вспомни C - в программе на этом языке обязательно должна присутствовать функция Main. Во время компиляции программа линкуется с некоторыми объектными файлами из Libc, в одном из которых находится (внимание!) метка _start, на которую и передается управление после запуска программы, библиотека выполняет некоторые (весьма полезные, кстати) действия и передает управление функции Main. Так как мы в своей программе пользуемся функциями Libc, то для того, чтобы получить управление, нам нужна функция Main. Как и в прошлой программе, в секции данных у нас находятся две строки и два буфера, заполненные нулями, каждый по 256 байт, созданные при помощи директивы .space. Заметь, что длину строк подсчитывать не надо: за тебя это сделает высокоуровневая функция Puts. Также не нужны переносы - символы переноса строки. Только одно замечание: Rename - это не функция, а системный вызов. Программа не вызывает его напрямую, а использует функцию-обертку, предоставляемую Libc.

Заключение

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

Полезное в сети

www.linuxassembly.org - официальный сайт Linux-ассемблерщиков

www.lowlevel.ru - информация по низкоуровневому программированию в Linux

www.lxhp.in-berlin.de/lhpsyscal.html - работа с системными вызовами на низком уровне

nasm.sourceforge.net - мультиплатформенный ассемблер с Intel-синтаксисом

ald.sourceforge.net - Assembly Language Debugger

www.linice.com - Попытка создать SoftIce под Linux

sources.redhat.com/gdb - The GNU Debugger

Статья рассчитана на тех, кто хотя бы поверхностно знакомых с языком C и ассемблером. Поэтому, если ты не обладаешь необходимыми знаниями, тебе придется поднапрячься, чтобы понять все, о чем здесь рассказано.

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

Назад на стр. 051-092-4  Содержание  Вперед на стр. 051-092-6