FAQ от FORUM WASM.RU При составлении FAQ были использованы ответы участников форума. 06.01.2010: спустя 5 лет добавлены комментарии, описывающие текущее положение дел Q: Какой компилятор выбрать, если я хочу начать программировать на ассемблере? Где их можно взять? A: В настоящее время наибольшую популярность имеет пакет MASM32. За ним идет молодой, но быстро развивающийся пакет FASM (скачать их можно из раздела "Компиляторы" на сайте WASM.RU). Для любителей ретро, подойдет старенький пакет TASM. А вот какой же из них выбрать - это решать вам! Сейчас (2010г.) FASM уже не такой уж и молодой и уже достаточно популярный. Умеет многое из того, что умеет MASM, + кучу своих фич (самое главное достоинство - макроязык). Рекомендуется, но не так прост в изучении. Q: С какой книги можно начать изучение ассемблера? A: Да с любой. Но в настоящее время наиболее популярными являются: С. В. Зубков "Assembler. Для DOS, Windows и Unix", изд. ДМК. - Книга популярна среди начинающих, но не дает фундаментального понимания языка и его особенностей. В. Юров "Assembler" - Учебник, изд. Питер, 2000 - Также популярна и также не очень хороша. Автор использует не совсем стандартную терминологию, примеры содержат ошибки, способные поставить новичка в тупик. В. Юров "Assembler" - Специальный справочник, изд. Питер, 2000 - Справочник. Изучить по нему ассемблер нельзя, можно подучить синтаксис основных команд и другие базовые моменты, но для этого надо уже понимать язык и уметь на нем писать хоть что-то. Абель "Ассемблер и программирование для IBM PC" - Хорошая, большая книжка. Старое издание изобилует ошибками, насчет более поздних переизданий ничего неизвестно. Вышеперечисленные книги рассматривают непосредственно язык ассемблера, но все они ориентированы на мертвый ныне DOS. Тем не менее, в Windows язык не изменился, а потому для базового знакомства с языком эти книги подойдут. Для основательного изучения потребуется более серьезная литература, которую на русском языке найти будет практически невозможно. Кроме того, для программирования под Windows будет не лишним прочитать туториалы Ichzelion'а (есть перевод by Aquila). Q: Как скомпилировать исходный текст программы в com, exe или dll? A: Итак, все по порядку: КОМПИЛЯЦИЯ В COM(MS DOS) TASM: tasm /m /ml /q /zn file_name.asm tlink /x /t file_name.obj MASM: ml /c file_name.asm link file_name.obj,,NUL,,, exe2bin file_name.exe file_name.com КОМПИЛЯЦИЯ В EXE(MS DOS) TASM: tasm /m /ml /q /zn file_name.asm tlink /x file_name.obj MASM: ml /c file_name.asm link file_name.obj отметим, что для сборки 16-битных программ MASM'ом нужен линкер соответствующей версии, который можно взять здесь или здесь. Более подробно тут. КОМПИЛЯЦИЯ В EXE(MS WINDOWS) TASM: (с файлом ресурса) tasm32.exe /ml /m /q /zn /kh32000 file_name.asm brcc32.exe file_name.rc tlink32.exe /Tpe /aa /c /x file_name.obj,,,,,file_name.res (без файла ресурсов) tasm32.exe /ml /m /q /zn /kh32000 file_name.asm tlink32.exe /Tpe /aa /c /x file_name.obj MASM: (с файлом ресурса) ml /c /coff "file_name.asm" rc file_name.rc Link /SUBSYSTEM:WINDOWS "file_name.obj" file_name.res (без файла ресурсов) ml /c /coff "file_name.asm" Link /SUBSYSTEM:WINDOWS "file_name.obj" КОМПИЛЯЦИЯ В EXE(MS WINDOWS(КОНСОЛЬ)) TASM: tasm32.exe /ml /m /q /zn /kh32000 file_name.asm tlink32.exe /Tpe /ap /c /x file_name.obj MASM: ml /c /coff "file_name.asm" Link /SUBSYSTEM:CONSOLE "file_name.obj" КОМПИЛЯЦИЯ В DLL(MS WINDOWS) TASM: tasm32.exe /ml /m /q /zn /kh32000 file_name.asm implib file_name.lib file_name.dll tlink32 /Tpd /aa /z /c file_name.dll MASM: ml /c /coff file_name.asm Link /SUBSYSTEM:WINDOWS /DLL /DEF:file_name.def file_name.obj КОМПИЛЯЦИЯ В LIB(MS WINDOWS) MASM: ml /c /coff file_name.asm Lib file_name.obj В FASM компиляция предельна проста: FASM.EXE file_name.asm и дальше компилятор сам разберется что делать и как. Или же Ctrl-F9 в редакторе FASMW (входит в пакет). Q: Какой редактор лучше всего подходит для написания листингов программ на ассемблере? A: О, это риторический вопрос, и камень приткновения для многих программистов на ассемблере. Здесь нельзя ответить однозначно. Каждый решает этот вопрос по своему. Кто-то пользуется RadAsm'ом, кто-то AsmEd by AV(t)LAB, кому-то нравиться встроенный редактор Дос Навигатора. Попробуйте несколько наиболее приглянувшихся и выберите свое любимое IDE. Также прочитайте вот эту статью, может быть, она ответит на Ваш вопрос. Q: Каким отладчиком пользоваться при отладке своих и исследовании чужих программ? A: Самый лучший отладчик для операционной системы Windows это, конечно же, SoftIce (сейчас Driver Studio). Самый дЗенный инструмент, после Вашего любимого компилятора. Основная особенность - это возможность поставить бряк на любое событие в системе. Существует, так же, отладчик Win32 приложений под названием OllyDbg. Маленький, быстрый, удобный отладчик, а главное - бесплатный (SoftIce денег стоит, причем немалых). В наборе со своими плагинами может имитировать функции Soft Ice, такие как: бряк на функцию по ее имени и многое другое. Очень хороший инструмент! Увы, сейчас SI уже мертв - работает далеко не на всех машинах, что объясняется его несовместимостью с современными видеокартами и отсутствием поддержки (разработчики на него забили), а так же отсутствием поддержки под новые Windows и вообще отсутствием поддержки Популярность набирает отладчик Syser, который, впрочем, все еще сыроват и лично у меня не запустился, но у других работает. Так же хорошим, годным является WinDbg (как для ядра, так и для юзермода), но он совсем не прост в изучении. Q: Каким инструментом можно воспользоваться для того, чтобы посмотреть какие API функции использует то или иное приложение? Какие есть ресурсы (иконки, диалоги и пр.)? A: Существует множество приблуд позволяющих просматривать внуренности исплняемого файла. Это редакторы ресурсов. Я не возьмусь перечислять их все и определять кто из низ лучше делает свою работу. Лично мне нравиться инструмент под названием EXeScope. Его, а так же еще много других инструментов вы сможете найти на WASM.RU в разделе "Редакторы ресурсов". Q: Какой софт можно использывать для pедактиpования файлов в HEX-виде? A: Лучше всего подойдет HIEW by SEN (кстати, любимый инструмент нашего многоуважаемого критика молодых и неопытных посетителей форума WASM.RU - Володи), QView by Alexander Gazko, WinHex. Но существуют и дpугие pедактоpы. Q: Где можно взять справочник по API функциям? A: Если у Вас быстрый Интернет, то здесь есть почти всё, что надо: Microsoft MSDN Library Если поставить один из продуктов Borland (С++ Builder, Delphi), то с ним идет неплохой хэлп, написанный по MSDN-у. Файл находится: C:\Program Files\Common Files\Borland Shared\MSHelp\win32.hlp. Найти в гугле MSDN также можно купить на дисках, если Вы сможете найти его в Вашем городе. Сейчас можно заказывать MSDN бесплатно вместе с VS 2005 Beta. Q: Можно ли писать на ассемблере в одну строчку? A: Возникает встречный вопрос: "Зачем?". Но если Вам это необходимо, то можно воспользоваться способом описанным на когда-то существовавшем сайте "Assembler.ru". Нам потребуется написать макрос примерно следущего содержания: Код (Text): @ macro p0,p1,p2,p3,...,pX p0 p1 p2 p3 ... ... pX endm Теперь используя макрос "@" мы можем записывать команды в строчку: @,,,..., Q: Как вызвать API функцию из программы на ассемблере? A: При вызове Win32 API функций используется STDCALL-конвенция. В ней параметры помещаются в стек в обратном порядке, а аргумент ы удаляет сама апи-функция. Для некоторых апи (wsprintf, DbgPrint) используется CDECL. Пример: на С: some_proc(a,b,c,d,e) на Ассемблере: (TASM32, MASM32, FASM) push e push d push c push b push a call some_proc либо call some_proc,a,b,c,d,e (TASM32) invoke some_proc,a,b,c,d,e (MASM32 & FASM) cinvoke wsprintf, buffer, format, a, b (FASM: cdecl invoke) Q: Что такое Stub программа? A: ""Stub" в переводе с английского - "пень, обломок, огрызок". Это в литературном переводе. В нелитературный перевод углубляться не будем. Скажем только, что это то самое, что показывает компьютер человеку, попытавшемуся запустить из-под DOS приложение, написанное для Windows. Обычно он показывает сообщение: "This program cannot be run in DOS mode". А вы что подумали?" Это вступление статьи "минимальная stub-программа", которую вы можете найти в OffLine версии сайта Assebmler.ru. Q: Где взять документацию по процессорам ? A: На сайте производителя. Процессоры Intel Процессоры AMD (Раньше можно было заказать бумажные Intel Manuals: http://www.wasm.ru/forum/viewtopic.php?id=27626) Offline версия форума: Документы WASM.RU
Q: Я получаю сообщение unresolved external symbol... Что делать? A: Читать документацию А если серьезно, то многие новички недостаточно четко представляют себе процесс создания исполняемого файла. Предельно упрощая, он происходит в две стадии: Код (Text): .asm -> .obj -> .exe/.dll Из ассемблерного (сишного) файла путем КОМПИЛЯЦИИ получаем объектный файл (при этом могут использоваться дополнительные файлы, такие как *.inc в ассемблере или *.h/*.hpp в С/С++). Если компилятор по какой-либо причине (неверно прописан путь к такому файлу или файл отсутствует) не может найти инклуд-файл, то выдается предупреждение и obj-файл получен не будет. На следующей стадии (.obj -> .exe) инклуд-файлы уже не причем. Эта стадия называется ЛИНКОВКОЙ и служит для замещения символьных имен, используемых программистом на реальные адреса (процесс сложнее, но замнем для ясности). Точно так же как и на стадии КОМПИЛЯЦИИ необходимо соблюдение двух условий: 1) Линкер должен знать какие файлы требуются для того, чтобы получить exe из данного obj (это могут быть либо obj-файлы, либо lib-файлы, которые, по сути, содержат внутри себя множество obj-файлов) 2) Линкер должен знать путь к этим файлам. Ошибка при неудовлетворении №2 узнается и устраняется очень просто. Ошибка при №1 порождает печальное "unresolved external symbol" и устраняется сложнее. Во-первых, вы должны знать какие obj/lib-файлы дополнительно требуются в вашем конкретном случае. Это самая распространенная ошибка. Когда такие файлы найдены, пропишите путь к ним в командной строке линкера и укажите сами файлы. Например: Код (Text): link /LIBPATH:"..\slri\visualbind\asnlib\bindlib\Debug" xncbi.lib xserial.lib bindlib.lib objects_biblio.lib objects_medline.lib objects_pub.lib objects_seq.lib objects_mmdb.lib objects_gbseq.lib xutil.lib xobjmgr.lib Как видим, в данном случае линкеру дано указание использовать xncbi.lib, xserial.lib и т.д., а искать их он будет в ..\slri\visualbind\asnlib\bindlib\Debug. Разумеется, эта ошибка - одна из самых простых. Иногда могут проявлятся куда более коварные случаи. Примером может служить т.н. замангление имен в С++ и использование С++-библиотек в С-программах и т.п. Еще парочку любопытных примеров можно найти тут: http://www.rsdn.ru/article/cpp/crt.xml Q : Ну хорошо, а что делать если я как раз столкнулся с замангленым именем? Как линковать тогда? A: Перед тем как объяснять, что делать, рассмотрим сначала, что такое замангление. Как известно, ЯВУ типа С++ позволяют ПЕРЕГРУЖАТЬ функции и операторы. Т.е. две функции (или больше) могут иметь одинаковые имена. Как в этом случае прикажете выкручиваться компилятору? А компилятор выкручивается тем, что на основе некоторого алгоритма уникально искажает имя функции, так, чтобы избежать коллизии. Алгоритм искажения имен у каждого компилятора разный. Алгоритм MS cl.exe может быть реверсирован, исследовав функцию __unDNameEx из msvcrt.dll. Теперь рассмотрим, что делать. Здесь возможно много вариантов. Рассмотрим два. Вариант первый: автор, написавший программу на С++, знал, что ее будут использовать из других языков, например, из С или ассемблера. В этом случае надо специально готовить исходный код. Например так, как это сделано в ImpRecLite - см. исходники. Весь внутренний код написан на С++, а "наружу" смотрят С-шные обертки вокруг С++-методов классов. Более подробно о самой методике написано в MSDN: "Export C++ Functions for Use in C-Language Executables". Пример: Код (Text): extern "C" __declspec(dllexport ) int MyFunc(long parm1); В этом случае компилятор НЕ БУДЕТ манглить имя функции (т.е. добавлять всякие загогулины, соответствующие типу и кол-ву параметров и т.п.), однако, учтите, что таким образом объявленные функции нельзя будет и перегрузить. Вместо подобных объявлений прямо в исходном коде программы, можно использовать .def-файл. Подробнее о .def-файлах можно глянуть в MSDN. Вариант второй: автор, написавший dll на С++ и не думал, что ее будут использовать из какого-нибудь другого языка программирования. В этом случае MS рекомендует следующее: "However, certain situations require that you specify the name in its decorated form. You must specify the decorated name of C++ functions that are overloaded and special member functions, such as constructor and destructor functions, in order for LINK and other tools to be able to match the name. You must also use decorated names in assembly source files that reference a C or C++ function name." Иными словами, тем или иным образом, замангленое имя придется вставить прямо в текст программы. Пример. Пусть некая core.lib экспортирует функцию Код (Text): ?InitCustomControls@@YAXPAUHINSTANCE__@@@Z. Тогда в ассемблерной программе ее стоит звать, например, так (информацию о параметрах можно взять либо из замангленого имени функции с помощью утилиты undname.exe, либо из документации): Код (Text): externdef _imp_?initCustomControls@@YAXPAUHINSTANCE__@@@Z:PTR InitCustomControls equ <_imp_?InitCustomControls@@YAXPAUHINSTANCE__@@@Z> invoke InitCustomControls,hInst Дополнительно в опциях линекра следует указать core.lib как библиотеку, содержащую код этой функции и путь к этой библиотеке: Код (Text): link /LIBPATH:"C:\3dmaxsdk" core.lib
Q: Я поставил себе Soft-Ice и меня не работают bpx. И вообще у меня и Soft-Ice не работает. И Windows теперь больше не работает A: Форумы переполнены этими вопросами, которые, как правило, задают новички. Необходимо понимать, что айс - это драйвер, довольно часто напрямую работающий с железом и с внутренними структурами OS Windows. Поэтому он НЕВЕРОЯТНО чувствителен к изменениям hardware вашей машины, версиям SP, накатываемых на Windows и т.п. Очень глупы вопросы типа "я поставил Windows 2003, и у меня перестал работать Soft-Ice". Так и тянет ответить: "а ты бы еще Windows 2004 поставил, а лучше - 2005, чтоб обидно не было". Версия 2.7 вообще не предназначена для работы на операционках XP+! Вы бы еще чего-нибудь постарее выбрали бы! Айс опирается на структуры данных Windows, которые очень активно перетряхиваются, стоит ли удивляться, что что-то не работает? Авторы утилиты и так проделали изумительную работу. Точно так же и с железом. Ставите себе самые последние видюхи, а потом с воплями пляшете у экрана, матеря разработчиков почем свет стоит... Они же тоже спать хотят, а не бесконечно апдейты клепать! Теперь по делу. Если столкнулись с такой ситуацией, то действие номер 1: ИДИТЕ НА (хм, В и К) http://frontline.compuware.com/nashua/kb/ и ищите информацию по своему вопросу. Не так давно (с версии 2.7, если мне память не изменяет) разработчики отказались от идеи помещения структур прямо в код айса и вынесли их в отдельный файл - osinfo.dat. Перед тем как плакать на форуме, УБЕДИТЕСЬ, что у вас лежит САМЫЙ ПОСЛЕДНИЙ osinfo.dat: ftp://ftp.compuware.com/pub/driverstudio/outgoing/OsInfo/OSINFO.DAT Очень вероятно, что ваши bpx после этого придут в норму. Если нет - есть еще один трюк, описанный тут: http://frontline.compuware.com/nashua/kb/doc/1591.asp Смысл прост. Айс более не знает адресов внутренних структур Windows. Откуда их взять? Из pdb-файлов от самой MS сугубо для вашей версии OS. Скачиваете себе эти файлы с сайта MS http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx и в соответствии с инструкциями по линку выше, обрабатываете их и переписываете файл конфигурации айса. Все должно работать. Еще одна вещь - ВЕРСИЯ айса. Просто дико раздражает когда версию 2.6 ставят на 2003 и, естественно, получают BSOD. А чего вы еще ждали? Всегда ставьте последнюю версию. На данный момент (июнь 2004 года) - это версия 4.3.1. И еще одна вещь. Многие, скачав 4.3.1 c какого-нибудь варезного сайта в сети, тут же принимаются давить bpx MessageBoxA и это не срабатывает. После этого немедленно бегут в ближайший форум и вываливают на первой странице: "какого икса, игрека и еще какого-то неизвестного у меня не работает bpx?". А ответ прост: README надо читать! И активировать опцию "set BreakInSharedMods on" Также случилось знаменательное событие - выход SP2 под XP. В связи с чем Soft-Ice необходимо проапдейтить. Выглядит это так: Starting SoftICE after installing Windows XP SP2 will cause your machine to crash. This is not a problem with SoftICE but rather an internal layout change of the operating system. In addition the SoftICE universal video display will also need to be "found" again. To get around these issues: 1. Boot your system without SoftICE. This can be done by pressing escape at the appropriate time in the boot process. 2. Get the updated OSI data files as detailed below. 3. Rerun the Settings application, go to the SoftICE Video page and click on both the "Detect" and "Test" buttons. 4. Reboot your machine. Как всегда, сгружаете OSINFO.DAT: Для Visual Soft-Ice апдейты сгружать отсюда: ftp://ftp.compuware.com/pub/driverstudio/outgoing/patch/VSISP2Update.z ip Только если вы опробовали все, что тут написано и искали на сайте compuware, ТОЛЬКО тогда постите свой вопрос в форум!
Q: Как мне перехватить API-функцию? A: Невероятно популярный вопрос на очень многих форумах в последнее время. Ваше первое действие - ВЫПОЛНЯЙТЕ ПОИСК ПО ФОРУМУ. На данном форуме эта тема обсуждалась уже столько раз, что всем успела надоесть. Ключевые слова: "хук, hook, перехват, API, injection" и т.п. Обязательно загляните также на RSDN. Там есть пара очень хороших статей по теме. Также обязательно надо почитать Питрека (папа утилиты BoundsChecker). BC описан в книге Касперски "Техника и философия хакерских атак". Родоначальником BC был API monitor, который Питрек предельно подробно описал в "Win95 system programming secrets". Утилита распространялась с полным исходным кодом. Загляните на wheaty.net. Здесь же я осмелюсь предложить другое очень легкое и приятное решение - detours от Microsoft. detours - это библиотека перехвата API. Описание принципа действия и полный исходный код утилиты лежат на: http://research.microsoft.com/sn/detours/ и дополнительно продублированы на wasm.ru в разделе "Утилиты" (4). Использование detours поначалу может немножко запутать, поэтому поясню подробнее. Как правило, целью является запуск exe-файла и перехват вызова этим exe-файлов тех или иных функций dll. Пусть наш подопытный exe-файл выглядит так: Код (Text): #include <windows.h> void main() { MessageBox(0, "HI", "WOW!", MB_OK); } Код невероятно сложен, поэтому, если кто запутается окончательно, пусть топает и читает http://www.wasm.ru/article.php?article=1001002 Наша цель: перехватить вызов MessageBox и подменить его на свой. Методика: мы создадим собственную dll при помощи detours и при помощи тех же самых detours запихнем эту dll в адресное пространство нашего процесса-жертвы. Теперь более детально. Код dll выглядит так: Код (Text): #include <windows.h> #include <detours.h> #pragma warning(disable:4100) #pragma comment(lib,"detours.lib") /** * int MessageBox(HWND hWnd, * LPCTSTR lpText, * LPCTSTR lpCaption, * UINT uType * ); **/ DETOUR_TRAMPOLINE(VOID WINAPI Real_MessageBox (HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType), MessageBox); BOOL WINAPI DetourMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) { Real_MessageBox(0, "He-he, MessageBox is detoured!", "Detours", MB_OK); Real_MessageBox(hWnd, lpText, lpCaption, uType); return true; } BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) { if ( reason == DLL_PROCESS_ATTACH ) DetourFunctionWithTrampoline ( (PBYTE)Real_MessageBox, (PBYTE)DetourMessageBox ); else if ( reason == DLL_PROCESS_DETACH ) DetourRemove ( (PBYTE)Real_MessageBox, (PBYTE)DetourMessageBox ); return true; } ИЗУЧИТЕ ЭТОТ КОД ОЧЕНЬ ВНИМАТЕЛЬНО! Большинство пояснений можно найти тут: http://codeproject.com/system/KamalDetours01.asp Предельно кратко, DETOUR_TRAMPOLINE падчит нужную функцию - туда передается сигнатура и имя функции, которую необходимо подменить на нащ вызов. Далее, DetourMessageBox будет вызываться вместо MessageBox. При загрузке нашей dll функция DetourFunctionWithTrampoline пропадчит нужную нам API адресом DetourMessageBox. Когда dll будет отгружена, DetourRemove уберет падч. Теперь осталось лишь вставить эту dll в адресное пространство процесса тем или иным образом. Сделать это несложно: либо ключом в реестре, либо с помощью withdll.exe, собранного из примеров, поставляемых вместе с detours (файл приаттачиваю). Кстати, примеры скомпилировать тоже непросто. makefiles, как всегда, не рабочие. Надо править common.mak и удалить там строчку "$(LIBD)\syelog.lib" (или собирать ее первой, если она нужна, что бывает редко) А далее лишь осталось набрать: Код (Text): withdll.exe /d:detours_MessageBox.dll MessageBox.exe Вуаля! Мы использовали DETOURS_TRAMPOLINE для т.н. "статического" перехвата кода. Для специфических dll используется "динамический" перехват кода. Разница несколько прозрачна, т.к. обе техники применяются динамически... Если запутались окончательно - читайте pdf о detours А я просто приведу пример исходного кода. Положим, нам надо перехватить функцию "CompareSerialNumber" в библиотеке "CheckSN.dll". Пусть прототип функции CompareSerialNumber будет таким: Код (Text): void CompareSerialNumber(char *) Делается это так: Код (Text): void MyCompareSerialNumber(char *str) { printf("SN is %s\n", str); } BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) { if ( reason == DLL_PROCESS_ATTACH ) { void *p = DetourFunction((PBYTE)DetourFindFunction("CheckSN.dll", "CompareSerialNumber"), (PBYTE)MyCompareSerialNumber); } return true; } Заметьте, что сигнатура MyCompareSerialNumber должна В ТОЧНОСТИ соответствовать сигнатуре функции CompareSerialNumber. P.S. Detours - это великолепная библиотека. Однако и ей присущи некоторые ограничения. Например, как быть, если вы хотите трейсить не одну функцию API как в примере выше, а ВСЕ функции данной библиотеки или что-нибудь не менее масштабное (вдруг вам второй BC захотелось написать). Тут есть некоторые сложности, однако по этому линку дается решение и этих проблем: http://www.sumbera.com/ustation/research/mdlspy.htm Так же помните, что у движка есть и другие ограничения.
Часто задаваемые вопросы по использованию ассемблера в юниксах Составлено STAKANOV Q: Какие ассемблеры бывают в юникс и где их взять? A: Ассемблер as (GNU AS) считается стандартным, также очень популярен ассемблер NASM. Есть также хороший ассемблер FASM. AS: Во FreeBSD as и все утилиты из пакета binutils присутвуют в системе по умолчанию. В Linux потребуется дополнительно установить пакет binutils (формат пакета зависит от дистрибутива) или скачать его с ftp://ftp.gnu.org/gnu/binutils/ . NASM: Во FreeBSD установите порт /usr/ports/devel/nasm/. В Linux установите из соответвующего пакета или скачайте с сайта http://www.kernel.org/pub/software/devel/nasm/ (или http://sourceforge.net/projects/nasm). FASM: Скачайте с официального сайта http://www.flatassembler.net/ Важно! AS использует синтаксис AT&T, а NASM и FASM синтаксис Intel. Q: У юникса есть API ? A: Да. Называется это системные вызовы (syscalls). Осуществляются они путем вызова прерывания номер 0x80. Кроме того, практически везде действует "lcall $7,$0" ("call 7:0" в синтаксисе интел) как его полный аналог. Так же в системе обязательно присутствует библиотека libc. Q: Как передаются параметры системных вызовов? A: Во FreeBSD параметры передаются через стек, сначала последний, затем предпоследний и первый параметр помещается в стек последним. Так же при испотьзовании прерывания необходимо поместить в стек любое 32-битное значение. В Linux через регистры по порядку первый в EBX, и тд - ECX, EDX, ESI, EDI, EBP. Если количество параметров больше 6, то в памяти формируется структура с параметрами и в EBP помещается адрес этой стурктуры. В EAX в обоих случаях номер системного вызова. Если хотите использовать функции из libc, то передача параметров при этом осуществляется так как принято в Си (в мире Windows такой способ известен как CDECL). Результат всегда возвращается в EAX. Q: Где узнать номера системных вызовов? A: Самый простой способ для FreeBSD(должны быть установлены исходники системы!) - смотреть файл /usr/srs/sys/kern/syscalls.master. Там и номера и параметры. Способ для Linux - /usr/src/linux/arch/i386/kernel/syscall_table.S или файл entry.S из того же каталога для версий 2.4 и 2.6. Предполгается что /usr/src/linux/ это каталог с исходными текстами ядра Linux Q: Где найти описания системный вызовов или функций libc? A: Как обычно в юникс - справочник man (например man 2 write) или info. Q: Покажите маленькую программку типа "Hello,world!" A: Вариант 1 (as,FreeBSD) hello.s: Код (Text): .data msg: .asciz "Hello,world!\n" msg_len= .-msg .text .global _start _start: pushl $msg_len # константа, длинна строки pushl $msg # адрес строки "Hello,world!\n" pushl $1 # дескриптор стандартного вывода movl $4,%eax # 4 - номер системного вызова write push %eax # здесь может быть любое 32х битное int $0x80 # выполнить систменый вызов addl $16,%esp # восстанавливаем стек pushl $0 # код выхода movl $1,%eax # 1 - номер системного вызова sys_exit push %eax int $0x80 Вариант 2 (fasm,FreeBSD) hello.asm: Код (Text): format ELF section '.text' executable public _start _start: push msg_len ; size of message push msg ; offset of message push 1 ; stdout mov eax,4 ; 4 = sys_write push eax int 0x80 add esp,4*4 ; очищаем за собой стэк xor eax,eax push eax ; код выхода inc eax ; 1 = sys_exit int 0x80 section '.data' writeable msg db "Hello world",0 msg_len = $-msg Вариант 3 (as, все платформы, используем libc) hello-world.s: Код (Text): .data msg: .string "Hello world." .text .globl main main: pushl $msg call puts xorl %eax, %eax pushl %eax call exit Вариант 4 (nasm, Linux) hello-nasm.asm: Код (Text): SECTION .data ; секция данных msg: db "Hello World",10 ; строка для вывода, 10=cr len: equ $-msg ; "$" означает "здесь" ; len это значение, не адрес SECTION .text ; секция код global _start ; делаем метку доступной для линкера _start: ; стандартный вход mov edx,len ; arg3, длинна строки для вывода mov ecx,msg ; arg2, адрес строки mov ebx,1 ; arg1, стандартный вывод mov eax,4 ; передаем команду sysout в int 80 hex int 0x80 ; прерываение 80 hex, вызов kernel mov ebx,0 ; код выхода, 0=normal mov eax,1 ; команда выход для kernel int 0x80 ; прерывание 80 hex, вызов kernel Q: Как ее запустить (слинковать, ассемблировать)? A: Вариант 1: Код (Text): as hello.s -o hello.o ld -s hello.o -o hello ./hello Вариант 2: Код (Text): fasm hello.asm hello.o ld -s hello.o -o hello ./hello Вариант 3: Код (Text): as hello-world.s -o hello-world.o gcc -Wl,-s hello-world.o -o hello-world ./hello-world Вариант 4: Код (Text): nasm -f elf hello-nasm.asm ld -s hello-nasm.asm -o hello-nasm ./hello-nasm Q: А покажите "Hello,world!" с GUI A: Простейшие примеры: Вариант 1 (as, все платформы) hello-gui.s: Код (Text): # as hello-gui.s -o hello-gui.o # gcc -Wl,-s hello-gui.o -lX11 -L/usr/X11R6/lib -o hello-gui # ./hello-gui .data prDisplay: .long 0 # указатель на структуру Display nScreenNum: .long 0 # номер экрана nWnd: .long 0 # ID окна rEvent: .space 96,0 # буфер для получения события (сообщения) # вообщето все намного сложней # но длинное слово (32бит)со смещением 0 # обычно содержит тип события prGC: .long 0 msgHello: .asciz "Hello, world!" # какое-то непереводимое ругательство msgHelloLen=.-msgHello-1 .text .global main # без libc мы обойтись не сможем! main: # устанавлиываем связь с сервером pushl $0 call XOpenDisplay addl $4,%esp movl %eax,prDisplay # теперь prDisplay содержит адресс структуры # или равен 0 в случае ошибки # получаем номер основного экрана pushl %eax call XDefaultScreen addl $4,%esp movl %eax,nScreenNum # создаем окно pushl nScreenNum pushl prDisplay call XWhitePixel addl $8,%esp pushl %eax # белый пиксел ) pushl nScreenNum pushl prDisplay call XBlackPixel addl $8,%esp pushl %eax # черный пиксел ) pushl $5 # толщина рамки pushl $100 # высота окна pushl $100 # ширина окна pushl $0 # x pushl $0 # y pushl nScreenNum pushl prDisplay call XRootWindow addl $8,%esp pushl %eax # окно родитель pushl prDisplay # дисплей call XCreateSimpleWindow addl $36,%esp movl %eax,nWnd # номер окна # устанавливаем события обрабатываемые прграммой pushl $(1 | (1 << 15)) # это у нас ExposureMask OR KeyPressMask pushl nWnd pushl prDisplay call XSelectInput addl $12,%esp # показываем окно (проще некуда ;-) ) pushl nWnd pushl prDisplay call XMapWindow addl $8,%esp # самое главное # цикл получения и обработки сообщений wloop: pushl $rEvent # адрес буфера pushl prDisplay # дисплей call XNextEvent addl $8,%esp movl rEvent,%eax # !!! так делать не стоит # но здесь сойдет cmpl $12,%eax je _Expose cmpl $2,%eax je _KeyPress jmp wloop _Expose: # запрос на перерисовку # получаем графический контекст pushl $0 pushl $0 pushl nWnd pushl prDisplay call XCreateGC addl $16,%esp movl %eax,prGC # а кто у на сегодня "черный"? pushl $0 pushl prDisplay call XBlackPixel addl $8,%esp # устанвливаем цвет которым рисуем pushl %eax pushl prGC pushl prDisplay call XSetForeground addl $12,%esp # рисуем текст pushl $msgHelloLen pushl $msgHello pushl $50 pushl $10 pushl prGC pushl nWnd pushl prDisplay call XDrawString addl $28,%esp # освобождаем графический контекст pushl prGC pushl prDisplay call XFreeGC addl $8,%esp jmp wloop _KeyPress: # кто-то нажал на кнопку pushl prDisplay call XCloseDisplay call exit Вариант 2 (fasm, все платформы) gui_fasm.asm: Код (Text): ; fasm gui_fasm.asm ; gcc -Wl,-s gui_fasm.o -lX11 -L/usr/X11R6/lib -o gui_fasm ; ./gui_fasm format ELF public main extrn XOpenDisplay extrn XDefaultScreen extrn XWhitePixel extrn XBlackPixel extrn XRootWindow extrn XCreateSimpleWindow extrn XSelectInput extrn XMapWindow extrn XNextEvent extrn XCreateGC extrn XSetForeground extrn XDrawString extrn XFreeGC extrn XCloseDisplay extrn exit section '.data' writeable prDisplay dd 0 ; указатель на структуру Display nScreenNum dd 0 ; номер экрана nWnd dd 0 ; ID окна prGC dd 0 rEvent rb 96 ;буфер для получения события (сообщения) msg db 'Hello,world!',0x0 msg_size = $-msg section '.text' executable main: ;устанавлиываем связь с сервером push 0 call XOpenDisplay add esp,4 mov [prDisplay],eax ;prDisplay содержит адресс структуры ; получаем номер основного экрана push eax call XDefaultScreen add esp,4 mov [nScreenNum],eax ; создаем окно push [nScreenNum] push [prDisplay] call XWhitePixel add esp,8 push eax ; белый пиксел push [nScreenNum] push [prDisplay] call XBlackPixel add esp,8 push eax ; черный пиксел push 5 ; толщина рамки push 100 ; высота окна push 100 ; ширина окна push 0 ; x push 0 ; y push [nScreenNum] push [prDisplay] call XRootWindow add esp,8 push eax ; окно родитель push [prDisplay] call XCreateSimpleWindow add esp,36 mov [nWnd],eax ; устанавливаем события обрабатываемые прграммой mov eax,1 shl eax,15 or eax,1 push eax push [nWnd] push [prDisplay] call XSelectInput add esp,12 ; показываем окно push [nWnd] push [prDisplay] call XMapWindow add esp,8 ; цикл получения и обработки сообщений wloop: push rEvent ; адрес буфера push [prDisplay] ; дисплей call XNextEvent add esp,8 mov eax,rEvent mov eax,[eax] cmp eax,12 je _Expose cmp eax,2 je _KeyPress jmp wloop _Expose: ; запрос на перерисовку ; получаем графический контекст push 0 push 0 push [nWnd] push [prDisplay] call XCreateGC add esp,16 mov [prGC],eax ; "черный" push 0 push [prDisplay] call XBlackPixel add esp,8 ; устанвливаем цвет которым рисуем push eax push [prGC] push [prDisplay] call XSetForeground add esp,12 ; рисуем текст push msg_size push msg push 50 push 10 push [prGC] push [nWnd] push [prDisplay] call XDrawString add esp,28 ; освобождаем графический контекст push [prGC] push [prDisplay] call XFreeGC add esp,8 jmp wloop _KeyPress: push [prDisplay] call XCloseDisplay call exit Q: Как мне получить аргументы командной строки и переменные окружения? A: В точке входа в программу (_start в стеке содержатся следующие данные <ul type=disc>(%esp) aka dword [esp] - n, количество аргументов командной строки</ul> <ul type=disc>4(%esp) aka dword [esp+4]</ul> - адрес первого аргумента, имя программы <ul type=disc>4*2(%esp) aka dword [esp+4*2]</ul> - адрес второго аргумента <ul type=disc>...</ul> <ul type=disc>4*n(%esp) aka dword [esp+4*n]</ul> - адрес последнено аргумента <ul type=disc>4*n+4(%esp) aka dword [esp+4*n+4] - нулевой адрес (NULL)</ul> <ul type=disc>4*n+8(%esp) aka dword [esp+4*n+8] - ] адрес переменных окружения</ul> Q: Какие порекомендуете ссылки? A: GNU Binutils (англ) - http://www.gnu.org/software/binutils NASM (рус) - http://www.opennet.ru/docs/RUS/nasm GNU AS(рус) - http://www.opennet.ru/docs/RUS/gas FASM (рус) - http://mythrillus.land.ru/tajga-tut/index.html Справочник man (рус, англ) http://man.opennet.ru Тексты примеров можно скачать с http://stakanov.by.ru/articles/unixwasmfaq.zip Оригинальный текст расположен по http://stakanov.by.ru/articles/asm_unix_faq.html