...
...

Введение в NASM (низкоуровневое программирование для Windows)

"…Абстрактных, ненужных знаний нет. В жизни может случиться, что только знание того, какой чешский король разбил монголов, спасет твою голову…"
В. Короткевич
"Черный замок Ольшанский"


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

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

Да, компиляторы с языков высокого уровня обеспечивают такую необходимую сегодня скорость разработки конечного продукта. В большинстве случаев, с которыми сталкивается рядовой программист, ему нет необходимости искать эффективный путь решения задачи — микропроцессор сам "вытянет" это решение, за считанные секунды перебрав миллионы вариантов. Но кому-то придется разрабатывать эти компиляторы, включать в них поддержку инструкций новых процессоров, оптимизировать перевод лексем языка высокого уровня в машинный код. Кто-то должен оптимизировать критические участки кода, чтобы дать возможность остальным позабыть о подобных проблемах и стремиться к "более высоким вершинам". В конце концов, кто-то должен написать первый SDK для нового микропроцессорного устройства, будь то мобильный телефон или кофеварка. Конечно, потребность в таких специалистах намного меньше, чем в программистах "1С" и Visual Basic. Но она будет всегда, пока будут микропроцессоры современного типа. И эти же специалисты пойдут в первых рядах, когда (если) будут изобретены принципиально новые вычислительные устройства. И для тех же прикладных программистов никогда не будет лишним знать, во что превращается высокоуровневый код при его исполнении процессором, и где могут возникнуть "узкие места". Естественно, сразу разобраться с принципами программирования на низком уровне не удастся. Нужно "учиться, учиться и еще раз учиться", а потом приобретать опыт, наступать на грабли, работать над ошибками. И начинать лучше всего в привычной среде, каковой для большинства IT-специалистов является персональный IBM-совместимый компьютер. Кроме того, желательно при разработке программного обеспечения ориентироваться сразу на современную операционную систему, а не на DOS, как это зачастую делается в учебниках.





Возможно ли это — низкоуровневое программирование под Windows? На этот вопрос можно с полной уверенностью заявить: да, и процесс этот можно обставить с достаточным комфортом. Речь в этой статье пойдет как раз о выборе инструментария, организации рабочего места и базовых правилах программирования на ассемблере для 32-разрядных операционных систем семейства Windows. Что же нужно смельчаку, рискнувшему погрузиться в мир низкоуровневого программирования? Если он является убежденным аскетом, то абсолютно ничего, кроме операционной системы и горы технической документации. В самом деле, набрать программу в шестнадцатеричном коде можно даже при помощи текстового редактора. И это не просто бравада автора — на сайте [1] заинтригованный читатель может ознакомиться с лучшими образцами "программистского дзэна". Однако такой подход является скорее искусством и требует огромных затрат времени и сил, обладая при этом очень низким коэффициентом полезного действия. Можно ли сделать низкоуровневое программирование продуктивным? Чтобы разработчик мог не только отвести душу, но и конкурировать на рынке программного обеспечения? Ответить однозначно на эти вопросы сложно. Скорее всего, читатель сам получит ответ, если дочитает эту статью, а потом опробует предложенные рекомендации на практике.

Итак, для продуктивного низкоуровневого программирования прежде всего необходим ассемблер — компилятор мнемонических инструкций в машинный код. Действительно, листинг программы на ассемблере при наличии в нем комментариев и осмысленных меток после некоторой практики читается практически так же легко, как и программа, записанная на языке высокого уровня. Какой же компилятор предпочесть? Чтобы остановить свой выбор на конкретном экземпляре, необходимо рассмотреть хотя бы несколько возможных. На первом месте, естественно, стоит Macro Assembler от Microsoft (MASM).

Большинство приверженцев низкоуровневого программирования для Windows используют его в своих проектах и не имеют претензий. Следует отметить, что Macro Assembler как самостоятельный продукт перестал существовать с версии 6.13, зато появились энтузиасты, которые стали формировать пакеты, отбирая необходимые утилиты из SDK, DDK и Visual Studio. Так появился MASM32 [2] — пакет, содержащий все необходимое для низкоуровневого программирования: собственно ассемблер, компоновщик, библиотекарь и даже пакет документации с большим количеством примеров. К числу положительных черт MASM можно отнести его популярность. Огромное количество макроинструкций и отвлеченных понятий, которые не являются необходимыми для записи алгоритма в понятной для процессора форме, вызывает уважение с одной стороны и вносит путаницу с другой. Кажется, что этот язык можно было бы сделать более лаконичным, однако можно и оправдать наличие некоторых атавизмов требованиями обратной совместимости. Второе место традиционно занимает Turbo Assembler от Borland/ Inprise. В чистом виде в настоящее время этот продукт не существует, однако он входит в состав сред разработчика C++ Builder и Delphi. Это чисто коммерческий продукт — программированием на TASM занимаются энтузиасты, сохранившие верность продукции Borland. По возможностям он сродни MASM. Четко разделить места между остальными компиляторами очень сложно. Поэтому просто рассмотрим еще две оригинальные разработки.

Flat Assembler (FASM) [3] — очень интересный проект, который уже несколько лет ведет Tomasz Grysztar. В отличие от большинства представителей семейства ассемблеров, FASM являет собой в одном лице компилятор и компоновщик. То есть из исходного текста после обработки сразу появляется исполняемый файл или динамическая библиотека. Автор этого продукта постоянно следит за деятельностью фирм — производителей процессоров, поэтому FASM поддерживает инструкции самых последних моделей процессоров Intel и AMD. Кроме того, в FASM реализован лаконичный, но очень мощный макроязык. Существует мнение, что FASM наиболее приспособлен к реализации идей объектноориентированного программирования на ассемблере. На FASM можно программировать как под Windows, так и под Linux. Flat Assembler занимает особое место среди ассемблеров, и поэтому мало подходит для знакомства с традиционной схемой низкоуровневого программирования, при которой исходный текст на ассемблере сначала транслируется в объектный код, а уже файлы с объектным кодом и библиотеки компонуются и записываются в файл, готовый к выполнению.

Netwide Assembler (NASM) [4] был разработан для того, чтобы дать программистам бесплатный инструмент написания программ для Windows. NASM в целом поддерживает синтаксис MASM, причем встречающиеся отличия воспринимаются легко и естественно. NASM оснащен небольшим, но достаточно функциональным набором макроинструкций. По сравнению с FASM NASM консервативен, в нем не находят отражения инструкции новых процессоров, однако благодаря своей традиционности именно он и послужит основой для дальнейшего повествования в этой статье. Пакет NASM включает достаточно подробную инструкцию по установке и использованию. К сожалению, как и большая часть действительно достойной технической документации, она доступна лишь на английском языке. Поэтому, чтобы серьезно заниматься низкоуровневым программированием, потребуется освоить хотя бы базовые элементы английского и найти англо-русский словарь. Если в двух словах, то для установки NASM нужно просто распаковать содержимое дистрибутивного архива в какую-нибудь папку на диске и для удобства прописать путь к этой папке в переменной окружения PATH. Для определенности и по аналогии с традиционной схемой размещения инструментальных программных систем можно рекомендовать построить следующую структуру каталогов (рис. 1), которая встречается в некоторых распространяемых подборках инструментов разработчика NASM для Windows [5]:


Рис. 1. Рекомендуемая иерархическая структура среды разработки NASM

В соответствии с этой схемой в каталоге BIN хранятся все исполняемые файлы среды разработчика (сам компилятор, компоновщик, библиотекарь, отладчик и др.), и путь именно к этому каталогу следует прописать в переменной PATH, чтобы инструменты были доступны при любом текущем каталоге. Каталог DOC предназначен для хранения документации. В каталог INC удобно записать подключаемые модули с описаниями констант Win32 API. После этого, чтобы скомпилировать программу на ассемблере, достаточно набрать в командной строке следующее:

nasmw -p C:\W32NASM\INC\ win32n.inc -f win32 hello.asm

При выполнении этой команды NASM скомпилирует файл hello.asm, предварительно ознакомившись с описаниями констант и типов данных Win32 API, которые хранятся в файле win32n.inc. Результатом компиляции станет объектный файл hello.obj в формате Microsoft Win32 Object File. Более подробную информацию о параметрах командной строки компилятора NASMW.EXE можно получить из сопроводительной документации или запустив его с ключом -h. NASM позволяет создавать объектные файлы как формата Microsoft Win32 Object File, так и Microsoft OMF Object File. В исходных файлах первого типа нельзя использовать директивы import и export, и связь с функциями динамических библиотек может быть осуществлена только с использованием библиотек импорта. Зато предопределены идентификаторы для описания секций .text, .data, .bss. Исходный текст в этом случае может иметь следующую структуру:

global main
extern MessageBox
extern ExitProcess

segment .data
...
segment .bss
...
segment .text

main:
...
push dword 0
call [ExitProcess]

Для получения исполняемого файла придется выполнить следующие команды:

C:\> nasmw -f win32 main.asm
C:\> alink -oPE main.obj win32.lib -entry main

Кстати, если при компиляции будет получено сообщение об ошибке типа "attempt to define a local label before any non-local labels", то, скорее всего, в исходном тексте записано нечто вроде ".text" вместо "segment .text".
Если выходной файл должен иметь формат Microsoft OMF Object File, то следует использовать ключ -f obj. В файлах этого типа можно использовать директивы import и export, что позволяет создавать с их помощью библиотеки импорта для DLL-библиотек, которые можно компоновать с win32-файлами. Кроме того, для файлов этого типа предопределена метка ..start, которая отмечает точку входа. Структура исходного файла в этом случае может иметь следующий вид:

SECTION DATA USE32 CLASS=DATA
...
SECTION BSS USE32 CLASS=DATA
...
SECTION CODE USE32 CLASS=CODE
...
..start:
...

и компилироваться он должен так:

C:\> nasmw -f obj main.asm

Традиционная последовательность создания программы на языке ассемблера (опуская такие важные технологические этапы, как постановка задачи, проектирование, тестирование и отладка) состоит из трех основных шагов (рис. 2):


Рис. 2. Этапы создания исполняемого модуля из исходных текстов

Из этой схемы видно, что компилятор нужен только на втором шаге. Как же создать файл с исходным текстом? Использовать "Блокнот"? Можно, конечно, и так, но, чтобы не портить нервы и сразу воспитывать хороший вкус, стоит обратиться к свободно распространяемому продукту ASM Editor for Windows от AV(T) [6]. Что вы получите в этом случае? Кроме приятной цветовой гаммы рабочего пространства — подсветку синтаксиса, настраиваемую контекстную помощь и возможность автоматизировать процесс компиляции. Фактически ASM Editor является интегратором инструментов разработчика, заслуживающим звание IDE. Итак, текст набран и скомпилирован. Как же получить долгожданный EXE-файл? Для этого необходим компоновщик. Для NASM традиционно рекомендуют использовать ALink от Anthony A.J. Williams. Что же, автор этой статьи не имеет возражений против такого предложения. Действительно, ALink прекрасно справляется с компоновкой объектных файлов как формата MS/Intel OMF, так и формата MS-COFF, к Windows-программе без проблем можно подключить необходимые ресурсы. Кстати, о ресурсах. Можно, конечно, было бы обойти этот вопрос стороной, так как программы получаются вполне функциональными и без них. Однако в большинстве случаев использование ресурсов позволяет делать некоторые вещи проще и красивее. Как известно, ресурс может быть описан в обычном текстовом файле. Для преобразования таких файлов в формат, пригодный для компоновки, можно использовать компилятор ресурсов GoRC от Jeremy Gordon. Если же появляется необходимость в правке ресурсов в скомпилированных файлах, то здесь нет равных программе Resource Hacker [7] от Angus Johnson.

Казалось бы, приведен весь перечень необходимых для низкоуровневого программирования инструментов. Но, к сожалению, программы на ассемблере не меньше, а, скорее, больше программ на языках высокого уровня подвержены ошибкам программиста. И для успешной борьбы с этим неприятным явлением необходим мощный инструмент, позволяющий отследить по шагам выполнение программы и найти тот самый проблемный байт. Одним словом, необходим отладчик. В соответствии с договоренностью вести разработку под Windows можно посоветовать Olly Debugger [8] от Oleh Yuschuk. Это действительно стоящая вещь, имеющая встроенный анализатор кода, который графически отображает циклы и переходы. Очень удобен встроенный справочник по функциям Win32 API. Итак, все необходимые инструменты найдены и размещены в каталоге BIN. Можно приступать к обустройству среды разработчика. Как уже было сказано выше, в качестве интегратора будет использоваться ASM Editor. К сожалению, сразу после установки этот пакет настроен на работу с MASM32, но благодаря его гибкости не составит труда эту настройку изменить. Прежде всего нужно спланировать, в каком стиле будет вестись работа. Если предполагается весь исходный текст проекта размещать в единственном ASM-файле — это одно дело. Но такой вариант уже давно признан несостоятельным при реализации больших проектов. Гораздо лучше применить модульный подход, при котором исходные тексты независимых модулей хранятся в отдельных файлах. Автор предлагает оформлять каждый модуль (который условно назовем "name") следующим образом. В файл name.asm записывается исходный текст модуля на языке ассемблера. Так как обычно модуль существует не обособленно, а может обращаться к подпрограммам и областям памяти других модулей, предоставляя, в свою очередь, и им такой же сервис, удобно все идентификаторы импорта-экспорта вынести в файл name.inc. Для того, чтобы не указывать всякий раз параметры компиляции модуля, создается файл name.nsm, в котором описываются подключаемые inc-файлы и параметры, которые обычно указываются в командной строке NASM. Таким образом, каждый модуль проекта будет состоять из трех описанных файлов. Если читатель последует предложенной рекомендации, то для компилирования модуля можно посоветовать написать простой BAT-сценарий следующего содержания:

@echo off
nasmw.exe -E %1.err -@%1.nsm
if errorlevel 1 goto error
goto no_error
:error
notepad.exe %1.err
goto exit
:no_error
del %1.err
:exit

и сохранить его в файле compile.bat в каталоге W32NASM\BIN. После этого, чтобы скомпилировать модуль, достаточно в командной строке набрать:

compile name

и в зависимости от корректности исходного текста будет либо сформирован объектный файл name.obj, либо текстовый файл с описанием ошибок, который, к тому же, будет сразу выведен для просмотра в "Блокноте". Более того: если зайти в настройки ASM Editor через меню Service –> Properties… и в таблице вкладки ASM Editor Properties для команды Assemble ASM file записать:

C:\W32NASM\BIN\compile.bat {b}

то выполнять компиляцию модуля можно не покидая редактора путем вызова через меню команды Assemble ASM file. Главное — не забыть сохранить перед этим изменения, внесенные в исходный текст модуля, иначе будет скомпилирован старый вариант файла с исходным текстом. На этом подготовительные работы по организации рабочего места можно считать завершенными. Все дальнейшие настройки, способствующие комфортной работе, читатель при необходимости выполнит самостоятельно. Пришло время на простом примере показать технику работы в описанных выше условиях.
Здесь необходимо сделать небольшое отступление и вкратце рассказать о специфике разработки приложений для Windows с использованием ассемблера. Дело в том, что каждая операционная система, предоставляя программисту определенный сервис в решении наиболее общих и востребованных задач, как-то: управление памятью, файловый ввод-вывод и интерфейс с пользователем, устанавливает и определенные правила, которым тот должен следовать при написании программ. Практически любая программа, предназначенная для выполнения в среде операционной системы Windows, использует вызовы функций Win32 API. Поэтому так важно ознакомиться с правилами их использования. Разрабатывая Windows, Microsoft придерживалась рекомендаций Intel 80x86 ABI (Application Binary Interface), в которых как раз и описываются правила взаимодействия модулей программ. Отметим только самые ключевые аспекты этих правил.

В процессе своей работы программы на ассемблере активно используют регистры. Для процессоров семейства i386 это 32-разрядные регистры EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP (в использовании сегментных регистров необходимость возникает очень редко). В соответствии с правилами ABI функции должны сохранять значения регистров EBX, ESI, EDI и EBP. Значения регистров EAX, ECX и EDX сохранять не обязательно (рис. 3). Важно понимать, что этому же правилу следуют и функции Win32 API. Поэтому после вызова какой-либо из них нельзя предполагать, что значения регистров EAX, ECX и EDX сохранятся. Если планируется их дальнейшее использование, программист должен сам позаботиться об их сохранности, например, задействовав стек.


Рис. 3. Использование регистров в соответствии с ABI

Передача параметров в функции Win32 API осуществляется через стек, причем помещаться в стек они должны в порядке, обратном тому, что можно увидеть в описании функций. За редким исключением (например, очень удобная функция wsprintf) функции Win32 API сами очищают стек от параметров. Подавляющее большинство, если не все функции Win32 API в качестве параметров принимают 32-битные значения. Если значение параметра не укладывается в указанные границы, используется 32-битный указатель. Функции Win32 API возвращают результат своей работы через регистр EAX. Рассмотрим на примере, как должен осуществляться вызов функции MessageBox, чтобы вывести диалоговое окно с сообщением pszMessage и заголовком pszCaption (предполагается, что владельцем диалога будет окно, манипулятор которого сохранен в 32-битной переменной hwnd):

...
push dword MB_ICONINFORMATION | MB_OK
push dword pszCaption
push dword pszMessage
push dword [hwnd]
call [MessageBox]
...

Здесь нужно заметить, что ассемблер NASM не отслеживает типов переменных даже если они описаны с указанием размера выделяемой памяти. Поэтому в операциях, не затрагивающих регистры, необходимо явное указание на размер операндов — в данном случае dword. Так как в программах для Windows вызовы функций Win32 API встречаются сплошь и рядом, использовать такие громоздкие описания было бы затруднительно. Поэтому хорошим выходом из сложившейся ситуации будет разработка макроса, позволяющего записывать вызов в одну строку. Автор решил использовать синтаксис, подобный обращению к подпрограмме в языках семейства DBASE IV. Макрос для этих целей записывается так:

%imacro DO 1-*
%rep %0 — 1
%rotate -1
push dword %1
%endrep
%rotate -1
call [%1]
%endmacro
%idefine WITH,

а так выглядит вызов функции MessageBox:

DO MessageBox WITH [hwnd], pszMessage, pszCaption, MB_ICONINFORMATION | MB_OK

Как уже было сказано, для NASM существует готовая библиотека импорта функций Win32 API. Однако подобную библиотеку можно создать и самостоятельно. Для этого в NASM имеются директивы extern и import. Их описание приведено в сопроводительной документации, а в этой статье рассмотрим два макроса, которые позволяют оформлять исходные тексты библиотеки импорта в более читаемом виде:

%macro DLL 1
%define __DLL %1
%endmacro

%imacro FUNCT 1-2
extern %1
%if %0 = 1
import %1 __DLL
%else
import %1 __DLL %2
%endif
%endmacro

Эти макросы удобно сохранить в файле import.inc и подключать его при описании библиотек импорта. Используются они следующим образом:

DLL KERNEL32.DLL
FUNCT ExitProcess
FUNCT GetCommandLine, GetCommandLineA
...
DLL USER32.DLL
FUNCT MessageBox, MessageBoxA
FUNCT CreateWindowEx, CreateWindowExA
...
...
Как видно из этого простого примера, макрос DLL начинает блок описания функций, импортируемых из определенной динамической библиотеки. Существенно то, что имя DLL-файла обязательно должно указываться с расширением, иначе программа, вполне работоспособная в Windows 9x/Me, откажется запускаться под Windows NT/2000. Макрос FUNCT служит для описания импортируемых функций. Первый его параметр задает идентификатор функции в том виде, в каком он будет использоваться в программе, а второй соответствует идентификатору, записанному в самой DLL-библиотеке. Если оба идентификатора совпадают, второй параметр можно опустить.

Теперь пришло время продемонстрировать пример простой программы, которая будет выводить на экран диалоговое окно с содержимым командной строки. Сначала нужно набрать исходные тексты макросов DLL, FUNCT, DO и WITH, которые приведены выше, и сохранить их в файле import.inc. Затем следует создать файл import.asm, в котором описать используемые в примере функции Win32 API следующим образом:

DLL KERNEL32.DLL
FUNCT GetCommandLine, GetCommandLineA
FUNCT ExitProcess
DLL USER32.DLL
FUNCT MessageBox, MessageBoxA

Теперь в соответствии с тем, что говорилось о разработке модульных программ, нужно связать INC- и ASM-файлы, создав файл import.nsm следующего содержания:

import.asm
-p import.inc
-f obj

Можно попробовать выполнить компиляцию этого файла так, как было описано выше. В результате должен получиться файл import.obj, который позволит разрабатываемой программе обращаться к описанным функциям Win32 API. Исходный текст самой программы нужно записать в файле test.asm:

segment .data
szCaptiondb "The command line is..."

segment .text

start:

DO GetCommandLine
DO MessageBox WITH 0, eax, szCaption, 0

xor eax, eax
DO ExitProcess WITH eax

а в файл test.inc поместить описания экспорта-импорта в следующей форме:

global start

extern MessageBox
extern GetCommandLine
extern ExitProcess

Увязать оба созданных файла, как и в предыдущем случае, следует с помощью файла test.nsm следующего содержания:

test.asm
-p test.inc
-p import.inc
-f win32

После того, как оба модуля, IMPORT и TEST, будут успешно скомпилированы, т.е. появятся объектные файлы import.obj и test.obj, можно переходить к созданию исполняемой программы с помощью следующей команды:

C:\> alink test.obj import.obj -oPE -entry start]

Если все было проделано правильно, то в каталоге появится файл test.exe, который можно запустить. Если в командной строке ничего не указывать, на экран будет выведено окно с полным путем к EXE-файлу. Если при запуске написать в командной строке какой-нибудь текст, он будет выведен на экран следом за путем к файлу. Так работает функция GetCommandLine.

В заключение обобщим то, о чем шла речь в этой статье. Вначале была рассмотрена область применения микропроцессорной техники, чем аргументирована важность навыков низкоуровневого программирования. Было предложено осуществить знакомство с этим процессом в привычной операционной среде IBM-совместимого компьютера. Далее в целях облегчения старта для новичков в области программирования был рассмотрен спектр инструментальных средств и предложен конкретный набор, включающий в себя компилятор исходных текстов и ресурсов, компоновщик объектных и библиотечных файлов, отладчик и текстовый редактор. Были даны рекомендации по технике модульного программирования, рассмотрены основные правила использования функций Win32 API в программах на ассемблере, приведен пример простейшего приложения, разработанного с учетом предложенных рекомендаций. Если читатель дошел до этих последних строк статьи, он уже может сделать предварительный вывод о том, насколько продуктивно заниматься низкоуровневым программированием под Windows. В любом случае стоит отметить тот замечательный факт, что большинство инструментов, описанных в этой статье, являются абсолютно бесплатными и могут легально использоваться в том числе и в коммерческих разработках.

Конечно, в одной статье невозможно рассказать обо всех аспектах низкоуровневого программирования. Заинтересовавшемуся читателю придется перечитать многие страницы технических руководств и других статей, прежде чем он будет вознагражден реально работающей программой собственной разработки. Можно посоветовать ознакомиться со статьями Iczelion [9], в которых подробно описаны теория и практика программирования на ассемблере под Windows (русский перевод можно найти на [1]). Обязательно придется обзавестись справочником по функциям Win32 API (файл win32.hlp входит в комплект поставки сред разработки — например, Borland C++ 5.0). Ну, и никуда не удастся уйти от изучения работы микропроцессора и управляющих им инструкций, которые можно найти на сайтах производителей микропроцессоров. Стоит ли полученный результат затраченных усилий? Вопрос риторический, и ответ на него в большой степени зависит от таланта и усердия разработчика. В любом случае полученные навыки и умения могут оказаться полезными в самой неожиданной ситуации, которыми в избытке одаривает динамичная современная жизнь программистов.

Игорь Орещенков, 2004

[1] http://www.wasm.ru
[2] http://www.masm32.com/masmdl.htm
[3] http://flatassembler.net
[4] http://sourceforge.net/projects/nasm
[5] ftp://ftp.szif.hu/pub/demos/tool/w32nasm.zip
[6] http://www.avtlab.ru
[7] http://delphi.icm.edu.pl/ftp/tools/ResHack.zip,
http://www.users.on.net/johnson/resourcehacker/reshack.zip
[8] http://home.t-online.de/home/Ollydbg
[9] http://www.win32asm.cjb.net/




© Компьютерная газета

полезные ссылки
Корпусные камеры видеонаблюдения
IP камеры видеонаблюдения