Assembler, компиляторы и туториалы Iczelion’а

Очередная ссылочная.

Компиляторы:

TASM/TASM32, компилятор для Windows x86 и DOS (Mega.NZ, ZIP, 4.6 Мб)
MASM for DOS (Mega.NZ, ZIP, 4.6 Мб)
MASM32, компилятор для Windows x86: Официальный сайт (копия на Mega.nz)
IMPORT32.LIB (7z, Mega.NZ) (копия на Google.Drive)

Туториалы Iczelion’а (RUS, перевод WASM.RU).

Довольно неплохое руководство по Win32 API для начинающих программистов на ассемблере. Начиная с простейших примеров и до довольно продвинутых программ, включая описание структур и функций Win32 API, структуры PE EXE-файла, простейших VxD-драйверов.

Перевод Aquila.

В комплекте исходники и бинарники примеров программ.

На Old-DOS
На mega.nz

Hello, world на 32-битном ассемблере (Windows x86).

Преамбула

Обещал сделать другу-школьнику, пусть тут описание валяется, не пропадать же.

Листинг

.386
.MODEL FLAT

	extrn	ExitProcess:proc
	extrn	MessageBoxA:proc
	
.DATA

	MSG_TITLE	DB	'Hello, world!',0
	MSG_MESSAGE	DB	'I am running!',0
	MB_INFORMATION	DD 40h

.CODE
Start:
	push	MB_INFORMATION		;Message box style (Icon - Information)
	push	offset MSG_TITLE	;Message box title
	push	offset MSG_MESSAGE	;Message box text
	push	0					;hwndOwner
	call	MessageBoxA
	
	push	0
	call	ExitProcess
end	Start

Что получилось

Начало

1. Прописываем директиву совместимого процессора .386 (больше и не надо), и модель памяти FLAT, стандартную для x86 PE исполняемых файлов.
2. Далее, экспортируем 2 функции WinAPI - ExitProcess, которая позволит программе корректно завершиться, и MessageBoxA, - функция вызовет стандартное диалоговое окно. Эти функции находятся в библиотеке IMPORT32.LIB (есть в комплекте TASM), так что они станут доступны программе на этапе линковки, а директива extrn показывает компилятору, что функции внешние, т.е. компилятор не будет ругаться, что не нашел их в исходнике при компиляции.

Примечание: Кроме функции WinAPI MessageBoxA, есть функция MessageBoxW, параметры у этой функции аналогичные, но используется она, если выводимый текст в кодировке UTF-16.

3. В секции данных (.DATA) определяем константы: MSG_TITLE и MSG_MESSAGE, содержащие, соответственно, строку заголовка и строку, содержащую текст в диалоговом окне. Строки должны оканчиваться символом с кодом 0 (,0)

Примечание: Не строковым символом "0", а нулевым байтом.

4. Также определяем четырехбайтовую (DD) константу, которая будет управлять поведением окна. В данном случае MB_INFORMATION, которой укажем значение 40h, что дополнит окно иконкой "Информация". Полный список констант, управляющих поведением окна, можно увидеть в источнике [1].

5. В секции кода (.CODE) ставим метку Start: (на самом деле, название может быть либо любым, либо зависеть от используемого компилятора, в TASM и MASM любое), это будет указывать компилятору на точку входа в нашу программу, т.е. говорить системе, откуда начинать выполнять код.
6. И ключевое слово end с именем той же метки, между этими конструкциями будет находиться код нашей программы. Поскольку, дополнительных внутренних функций в нашем HelloWorld'е не предполагается - этого хватит, описание функций выходит за рамки данного небольшого урока.

Вызов функции MessageBoxA

Описание функции есть в справочнике по WinAPI, где оно дано в C-подобном стиле:

int MessageBox(
  [in, optional] HWND    hWnd,
  [in, optional] LPCTSTR lpText,
  [in, optional] LPCTSTR lpCaption,
  [in]           UINT    uType
);

И во всех современных компиляторах ассемблера под Windows есть всякие удобняшки, типа готовых макросов, которые ускоряют написание кода, позволяют не париться с параметрами, не писать простыни кода, но, не позволяют осознать, как оно все на самом деле работает. Это или макросы в MASM или режим IDEAL в TASM. Впрочем, все нормальные ассемблеры должны уметь работать и с удобняшками, и без них. А поскольку, пример у нас маленький, то стоит как раз все показать и объяснить, без всяких удобняшек.

Функции WinAPI работают по единому стандартизированному принципу - они достают входные параметры из стека, а результат (конкретное значение или адрес, по которому следует взять данные) пишут в регистр EAX. Значение, возвращаемое функцией, нам в данном примере не понадобится, так что пока это опустим. Разберемся с параметрами.

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

Запись в стек осуществляется командой push, извлечение из стека - командой pop.

Ясно, что человеку такой способ записи параметров интуитивно непонятен, потому в языках высокого уровня, сделали так, чтоб было удобно. Если же писать на чистом ассемблере, мы должны положить параметры в стек в обратном порядке:

push	MB_INFORMATION ;Стиль Message box  (Добавляем иконку "Информация")
push	offset MSG_TITLE    ;Заголовок Message box
push	offset MSG_MESSAGE 	;Текст в Message box
push	0				;ID Вызывающего окна - его нет, устанавливаем в 0.

Далее вызываем саму функцию WinAPI:

call	MessageBoxA

Теперь вызываем функцию, необходимую для корректного завершения программы. На вход она принимает только один параметр - код возврата. Мы ничего не делаем, кроме вывода MessageBox'а, так что отдадим стандартный код нормального завершения - 0.

push 0
call ExitProcess

Под конец, о консольном HelloWorld

Его здесь не будет, потому что написание консольного приложения под Win32, связано с тем, что всегда в определенный момент возникает в ассемблере - "много мелких, суетливых движений", как сказал классик по другому поводу. Написание консольного приложения под Windows усложнено, алгоритм там примерно такой:

1. Получить дескриптор стандартного устройства ввода-вывода
2. Проверить, доступен ли он программе.
3. Если недоступен, значит нас вызвали не из консоли, а из GUI, например, щелчком мыши.
4. Если 3 - неверно
5. Вывести текст на консоль
6. Если 3 - верно
7. Создать новую консоль, вывести текст, закрыть/освободить консоль.

MASM, в отличии от TASM умеет прописывать на этапе линковки флаг IMAGE_SUBSYSTEM_WINDOWS_CUI (3) в заголовок PE-файла, это показывает ОС, что приложение расчитано на консольную подсистему, что, в свою очередь, избавляет программиста от необходимости вручную открывать консоль и устраивать дополнительные проверки. Система откроет консоль за нас. Но вернемся к этому в другой раз.

Ссылки

1. MessageBox function
2. Исходник и откомпилированная версия на GitHub

Assembler: небольшая ссылочная.

Скрипты NppExec

tasm-compile.txt (MEGA.NZ)
tasm-compile.txt (GitHub)
tasm-compile.txt (PasteBin)

tasm-compile-and-run.txt (MEGA.NZ)
tasm-compile-and-run.txt (GitHub)
tasm-compile-and-run.txt (PasteBin)

Обзор и сравнение компиляторов assembler’а на Habr

Как писать на ассемблере в 2018 году
Копия

Программа, которая ничего не делает.

Преамбула

Да, понадобилась мне такая программа под Win32, которая совсем ничего не делает. Запускается, и сразу завершает работу, не открывая окна консоли и не создавая окно GUI. Для чего, расскажу в другой раз. Встал вопрос, на чем писать. .NET не подходит — слишком уж за такой программой Framework таскать, был Lasarus, но, если честно, не понял, как там все правильно сделать. И тут осенило, есть же TASM, идеально подходящий для такой задачи, будет максимально маленький экзешник, требующий только одну функцию из WinAPI — ExitProcess. Самое то! Правда, на ассемблере я кодил в лохматых годах, так что пришлось немного повспоминать.

Листинг

.386
.MODEL FLAT

	extrn ExitProcess:proc

.DATA
	szHelp DB 'This program start and end'
.CODE
Start:
	nop
	nop
	nop
	push	0
	call	ExitProcess
end	Start

На PasteBin

Описание

.386 — директива, позволяющая ассемблировать инструкции i386-го процессора, нам хватит.
.MODEL FLAT — выбор стандартной в Win32 модели памяти (FLAT)

extrn ExitProcess:proc — директива extrn позволяет использовать в программе функцию (тут ExitProcess) из внешней библиотеки, которую подключим на этапе линковки.
Библиотека IMPORT32.LIB, содержащая основные функции WinAPI должна быть в комплекте TASM.

.DATA — начало сегмента данных, в принципе, в этой программе можно его просто определить и не заполнять, но я определю в нем строку, которая будет храниться прямо в в экзешнике, как его описание. Можно открыть экзешник по F3 в Far’е, например, и увидеть ее. При работе программы строка использоваться не будет.

szHelp DB 'This program start and end' — та самая строчка.

.CODE — Сегмент кода.

Start: — метка, обозначающая точку входа в программу. Можно назвать хоть как (Start, Main и т.д.).

nopпустая операция, процессор в буквальном смысле делает ничего. Можно пропустить, но пусть будет.

push 0 — кладем в стек код возврата, который будет использован функцией ExitProcess.

end Start — конец основной функции программы.

Сборка экзешника

Компиляция:

tasm32 /m simple.asm

где:

/ml — учитывать регистр символов при компиляции.
simple.asm — имя файла с исходником.

Получилось:

Assembling file:   simple.asm
Error messages:    None
Warning messages:  None
Passes:            1

Будет создан файл simple.OBJ

Линковка:

tlink32 /Tpe /aa simple.OBJ,,,IMPORT32.LIB

где:

/Tpe — создать на выходе Win32 PE-файл (Стандартный формат 32-х битного экзешника, начиная с Windows 95).
/aa — Использовать WinAPI

Примечание: Библиотека IMPORT32.LIB должна лежать в том же каталоге, где и simple.OBJ, или прописывайте полный путь к файлам

Больше простых примеров с описанием (на буржуйском)

Writing Win32 programs in assembly language using TASM:
Читать на tolik-punkoff.com
Читать на lj.rossia.org
— Скачать с Mega.NZ
Скачать с Google.Drive

Справочники по ассемблеру (assembler) для DOS

Набор интерактивных справочников (запускаются они тоже под DOS)

ASM-HELP — интерактивный справочник по Assembler (DOS)

TECHHELP — интерактивный справочник по прерываниям и структурам данных DOS/BIOS

NG — интерактивный резидентный справочник (вылезает по Shift-F1)
Базы данных:
ASSEMBLER (ENG) — ассемблер
BIOS (ENG) — прерывания BIOS
TC (RUS) — краткая справка по Turbo C
PASCAL (RUS) — справка по Turbo Pascal

Скачать

Питер Абель. Ассемблер и программирование для IBM PC

Скачать (TXT DOS, ZIP)