Как *nix-системы потеряли портируемость j1m (j1m@list.ru) Спецвыпуск: Хакер, номер #051, стр. 051-092-2 movb var, %al # поместить в al байт по адресу var movl %eax, %ebx # поместить в ebx содержимое eax 4. Адресация - это единственное, что в AT&T-синтаксисе сделано нелогично. В общем случае она выглядит так: смещение (базовый регистр, индексный регистр, множитель). movl base_addr(%ebx,%edi,2),%еах # mov eax,base_addr[ebx+edi*2] Запятые сохраняются даже в случае отсутствия какого-либо элемента адресации. 5. Директивы ассемблера начинаются с точки. .string "Это строка" 6. Специальный символ '.' - это ссылка на текущий адрес. 7. Комментарии начинаются со знака '#' или заключаются в "/* */". Делаем вскрытие пингвину Что нужно знать об устройстве *nix-системы, чтобы писать программы на ассемблере? Как известно, всеми ресурсами ПК управляет операционная система. Она контролирует распределение оперативной памяти, управляет файловой системой и различными устройствами, такими как жесткий диск и звуковая карта. Поэтому любая программа, пожелавшая вывести на экран что-либо, создать файл, сменить текущий каталог или выполнить какое либо другое, внешнее по отношению к ней действие, должна просить об этом операционную систему. Запрос к операционной системе называется системным вызовом (Syscall). Существует множество различных системных вызовов (более 200), позволяющих открывать и читать файлы (Open, Read), создавать и уничтожать процессы (Fork, Kill), ходить по каталогам (Chdir) и делать еще множество разных полезных вещей. На С системный вызов выглядит как обращение к функции, например, чтобы открыть файл File.txt, достаточно одной строки: handle = open("file.txt", O_RDWR); Как же будет выглядеть системный вызов на ассемблере? Это зависит от ядра ОС. В случае с Linux номер системного вызова помещается в регистр eax, а аргументы - в остальные регистры общего назначения. Далее необходимо выполнить запрос на прерывание с номером 80h. Приведу пример: movl $5, %eax # номер 5 (open - открыть файл) в eax movl $file_name, %ebx # адрес строки, содержащей имя файла в ebx movl $02, %ecx # 02 (числовое обозначение O_RDWR) в ecx int $0x80 # системный вызов В случае с BSD номер системного вызова опять же помещается в %eax, но аргументы кладутся в стек, затем необходимо выполнить все тот же int $0x80. Пример: movl $5, %eax # номер 5 (open - открыть файл) в eax pushl $02 # 02 (числовое обозначение O_RDWR) в стек pushl $file_name # адрес строки, содержащей имя файла в стек int $0x80 # системный вызов В обоих случаях дескриптор файла вернется в eax. Почему же *nix-системы несовместимы друг с другом на низком уровне? На самом деле это только Linux несовместим со всеми остальными *nix’ами (Solaris, BSD и др.) :). Все остальные *nix’ы, вышедшие из оригинального UNIX (System 5) используют классическую конвенцию вызова, похожую на вызов функции в языке C. Linux же был написан с нуля (у Линуса даже стандарта POSIX на руках не было), Торвальдс получил большую свободу выбора и почему-то остановился на Fastcall конвенции вызова, свойственной продуктам от MS :). В Linux номера системных вызовов можно посмотреть в файле /usr/include/asm/unistd.h, а в BSD - в файле /usr/include/sys/syscall.h. Описание самих системных вызовов можешь почитать в man’ах. Также советую заглянуть на страничку www.lxhp.in-berlin.de/lhpsyscal.html: там лежит описание работы с системными вызовами на низком уровне. |