Как *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 выбор метода обращения к функциям ОС не совсем понятен. Перед каждым системным вызовом приходится сохранять все регистры в стеке, затем производить системный вызов, а после этого восстанавливать прежнее содержимое регистров. С точки зрения производительности это накладно. |