Пример программы на ассемблере fasm

В статьях Создание образа диска и Создание загрузочного диска было рассмотрено создание загрузочного сектора и создание образа диска операционной системы. Попробуем создать теперь более сложную конструкцию

Наша операционная система будет состоять из трех файлов. которые займут три сектора по 512 байт, и еще один сектор в 512 байт будет использоваться для хранения данных.

Что будет представлять операционная система? Первый файл само собой будет загрузчик, который будет загружать второй файл — ядро. Хотя, конечно, ядром его назвать нельзя, поскольку в данном случае это будет всего лишь оболочка наподобие Shell, куда будут вводиться команды на выполнение тех или иных приложений. И также у нас будет одно приложение — мини текстовый редактор. В нем мы сможем набирать, редактировать и сохранять данные в четвертом секторе диска.

В качестве инструмента программирования выберем FASM по причине большей компактности программ. Тем более FASM поддерживает прямые переходы jmp 0000:0500h. В MASM для этого нам пришлось создавать бы переменную, которая содержала бы адрес. Это бы вело к увеличению размера программы, который итак ограничен 512 байтами.

// Язык Ассемблера #1 [FASM, Linux, x86-64] //

Немного видоизменим загрузочный сектор, убрав из него все лишнее. Это будет файл fboot.asm.

;===================== Загрузочный сектор. Евгений Попов, 2011===================== ;================================================================================== org 7c00h ;BIOS производит чтение 512 байт первого сектора MBR в ОЗУ по адресу 0x00007C00 ;(0x07C0:0x0000 в формате реального режима), затем прочитанному коду передаётся управление start: cli ;запрещаем прерывания xor ax,ax ;обнуляем регистр ах mov ds,ax ;настраиваем сегмент данных на нулевой адрес mov es,ax ;настраиваем сегмент es на нулевой адрес mov ss,ax ;настраиваем сегмент стека на нулевой адрес mov sp,07C00h ;сегмент sp указывает на текущую вершину стека sti ;разрешаем прерывания mov ax, 0002h ;очищаем экран — функция 00h прерывания 10h int 10h mov dx,0h call SetCursorPos mov bp, msg mov cx, 13 call PrintMes ;Вывод на экран строки msg add dh,1 ;переходим на одну строку ниже call SetCursorPos mov bp, Con ;Вывод на экран строки Con mov cx, 23 call PrintMes mov ah,10h int 16h Continue: cmp al, 0Dh ;Если нажимаем на Enter, то переходим к загрузке ядра jz Kernel jmp Continue ;Если нет, снова ожидаем нажатия клавиши Kernel: mov ax,0000h mov es,ax mov bx,500h mov ch,0 ;номер цилиндра — 0 mov cl,02h ;начальный сектор — 2 mov dh,0 ;номер головки — 0 mov dl,80h ;жесткий диск — 80h mov al,01h ;кол-во читаемых секторов -1 mov ah,02h int 13h jmp 0000:0500h ;переход на 0000:0500h, куда загружен второй сектор ;===================== Подпрограммы =================================== PrintMes: ;в регистре bp — строка, в регистре cx — длина этой строки mov bl,04h ;в регистре bl- атрибут mov ax,1301h функция 13h прерывания 10h int 10h ret ;———————————- SetCursorPos: ;установка курсора : функция 02h прерывания 10h mov ah,2h xor bh,bh int 10h ret ;===================== выводимые сообщения===================== msg db ‘OS Loading. ‘,0 Con db ‘Press Enter to Continue’,0 times(512-2-($-07C00h)) db 0 db 055h,0AAh ;сигнатура, символизирующая о завершении загрузочного сектора

Теперь файл ядра — fkernel.asm. Оболочка будет выводить приглашение к вводу программы. Мы же должны напечатать команду writeи после нажатия клавиши Enter перейти в текстовый редактор

FASM. add, sub, mul, div, neg. Арифметика ассемблер. #3

Последняя часть — создание текстового редактора (файл fwriter.asm). Поскольку создание текстовых редакторов на ассемблере — не самое легкое дело, его функционал будет минимальным. Редактор позволит сохранять текст, редактировать, загружать сохраненный текст. Основной недостаток — макисмальное количество символов текста — 256. Что конечно не очень хорошо, поскольку в этом случае при сохранении текста у нас заполняется всего половина четвертого сектора.

org 700h start: mov ax,0002h ;очищаем экран int 10h xor dx,dx call SetCursorPos ;устанавливаем курсор mov bp, msg mov cx, 24 call PrintMes ;Вывод на экран строки msg mov dl,0 mov dh,1 call SetCursorPos ;переводим курсор на одну строку вниз mov bp, helper mov cx,77 call PrintMes ;Вывод на экран строки helper Option: ;Выбор — загрузить текст из четвертого сектора или начать новый mov ah,10h int 16h cmp ah, 3Bh ;Если нажата клавиша F1 — загружаем текст jz Load_text cmp al, 0Dh ;Если нажата клавиша Enter — печатаем текст jz Print_text jmp Option Load_text: ;Загрузка текста mov ax,0000h mov es,ax mov bx,string mov ch,0 ;номер цилиндра — 0 mov cl,4 ;начальный сектор — 4 mov dh,0 ;номер головки — 0 mov dl,80h ;жесткий диск — 80h mov al,01h ;кол-во читаемых секторов -1 mov ah,02h int 13h xor dl,dl mov dh,3 call SetCursorPos mov bp, string mov cx, 256 call PrintMes mov si,255 add dl, 15 ;256-80*3=16 add dh,3 call SetCursorPos jmp Command Print_text: xor dx,dx add dh,3 call SetCursorPos ;получаем позицию курсора mov si,0 ;Печать символов Command: mov ah,10h int 16h cmp al, 1Bh ;Если нажата клавиша Esc — выход из приложения jz Esc cmp al, 0Dh ;Если нажата клавиша Enter — переход на новую строку jz Caret cmp ah, 0Eh ;Если нажата клавиша BackSpase — удалить символ jz Delete_symbol cmp ah, 3Ch ;Если нажата клавиша F2- сохранить текст jz Save_text cmp si, 256 jz Command mov [string + si],al inc si mov ah,09h mov bx,0004h mov cx,1 int 10h add dl,1 call SetCursorPos jmp Command Caret: ;переход на новую строку add dh,1 xor dl,dl call SetCursorPos jmp Command Save_text: ;запись текста в 4 сектор mov ax,0000h mov es,ax mov ah, 03h mov al,1 mov ch,0 mov cl,4 mov dh,0 mov dl,80h mov bx, string int 13h jmp Command Delete_symbol: ;удаление символа после нажатия BackSpase cmp dl,0 jne Delete cmp dh,3 jz Command sub dh,1 mov dl,79 jmp Cursor_Pos Delete: sub dl,1 ;сдвигаем курсор влево Cursor_Pos: call SetCursorPos mov al,20h ;вместо уже напечатанного символа выводим пробел mov [string + si],al ;стираем символ в строке mov ah,09h mov bx,0004h mov cx,1 int 10h cmp si,0 jz Command dec si ;уменьшаем кол-во напечатанных символов jmp Command Esc: jmp 0000:0500h ;возвращаемся во второй сектор ;===================== Подпрограммы =================================== PrintMes: ;в регистре bp — строка, в регистре cx — длина этой строки mov bl,04h ;в регистре bl- атрибут mov ax,1301h int 10h ret ;———————————- SetCursorPos: ;установка курсора mov ah,2h xor bh,bh int 10h ret ;===================== выводимые сообщения===================== msg db ‘This is a text writer. ‘,0 helper db ‘To print text — press Enter, to load text — press F1, to save text — press F2’,0 string db 256 dup(?) ;буфер для вводимого сообщения

Читайте также:
450000 на 3 ребенка до какого года действует программа

Теперь скомпилируем три файла и создадим из них образ

macro align value < db value-1 — ($ + value-1) mod (value) dup 0 >HEADS = 1 SPT = 4 ;4 сектора по 512 байт Begin: file «fboot.bin»,512 ; загрузчик file «fkernel.bin» ; первый файл, типа оболочка shell align 512 file «fwriter.bin» ; второй файл — текстовый редатор align 512 align HEADS*SPT*512

Загружаем систему через Bochs

Нажимаем Enter и загружаем ядро

Вводим команду write и переходим в текстовый редактор

Источник: metanit.com

Консольная программа для Windows на языке ассемблера

dvsav.ru

В предыдущих заметках я начал писать программы, которые стартуют на ПК без операционной системы, будучи загруженными с дискеты. Программы эти я компилировал ассемблером flat assembler (FASM). В настоящей заметке мне захотелось сделать небольшое отступление и написать о том, как при помощи FASM можно писать программы пользовательского режима для Windows. Знание того, как это делается позволяет изучать программирование на ассемблере как таковое, не заморачиваясь написанием своей собственной операционной системы.

Я преподаю студентам программирование на ассемблере Intel x86 с использованием компилятора Microsoft Macro Assembler (MASM). Чтобы изучать ассемблер, нам нужно писать на нем программы, а чтобы мы могли вводить в эти программы данные и видеть какие-то результаты на экране, нам нужны какие-то средства ввода-вывода. В языках C/C++ для ввода-вывода мы привычно используем стандартные библиотеки этих языков. А в ассемблере? Есть разные варианты.

Вариант 1-й.Использовать функции WinAPI, например WriteConsole, ReadConsole. Согласитесь, не самое приятное средство ввода-вывода — мы все-таки ассемблер хотим изучать, а не WinAPI.

Вариант 2-й.Использовать привычную стандартную библиотеку языка C (CRT — C Runtime Library) — т. е. такие простые и понятные функции, как printfи scanf. Но вызвать их из кода на ассемблере, как выяснилось, не такое простое дело.

Вызываем printf из программы на MASM в Visual Studio 2015+

Прежде всего, оказывается, что в версиях Visual Studio начиная с 2015 функция printf и еще какие-то стандартные функции уже не экспортируются Microsoft’овской реализацией CRT, а являются встроенными (inline) и определены прямо в заголовочных файлах (например, stdio.h). Поэтому если вы напишите на ассемблере код, который вызывает printf и попробуете скомпоновать его с msvcrt.lib, то получите ошибку unresolved external symbol printf . Однако Microsoft оставила нам лазейку в виде ряда статически компонуемых библиотек (см. код ниже), которые экспортируют те функции, которые Microsoft сделала встроенными. Ниже приведен код, который вы можете скомпилировать компилятором ml.exe, который вы можете запустить например из командной строки Developer Command Prompt for VS, если у вас установлена Visual Studio (или можете создать и настроить проект в Visual Studio для программирования на MASM).

; MASM version of HelloWorld program using printf() function

; We have to link to these libraries since Visual Studio 2015
includelib libcmt . lib
includelib libucrt . lib
includelib libvcruntime . lib
includelib legacy_stdio_definitions . lib

. 686P ; Pentium Pro or later
. MODEL flat , stdcall
. STACK 4096

EXTERN printf : NEAR

.data
mytext BYTE «Hello World!» , 0Dh , 0Ah , 0

; «PROC» directive is mandatory here, we can’t write just «main:» (don’t know why)
main PROC C
push offset mytext
call printf
add esp , 4
ret
main ENDP

; it’s important that we use just «END» istead of «END main»
; as we don’t want to set main as the entry point.
END

В процессе отладки вышеприведенного кода я наткнулся не только на ошибки компоновщика unresolved external symbol , но и на ошибки времени выполнения. Например, стоило мне написать в конце файла END main, а не просто END, как во время выполнения программы возникала ошибка Exception thrown at 0x77621DCA (ntdll.dll) in AsmProject.exe: 0xC0000005: Access violation writing location 0x00000014 . Дело в том, что функция mainв данном случае не должна быть точкой входа (директива END задает точку входа), ею должна быть функция mainCRTStartup(), которая инициализирует стандартную библиотеку языка C. Функция mainCRTStartup() в конце концов сама вызовет нашу функцию main.
Если же я пытался не использовать директиву PROCрядом с меткой main, т. е. писал вот так:

main :
push offset mytext
call printf
add esp , 4
ret

Вот еще несколько ресурсов по теме линковки программ со стандартной библиотекой языка C:

  • Dynamically linking with MSVCRT.DLL using Visual C++ 2005
  • Overview of potential upgrade issues (Visual C++)
  • How does the Import Library work? Details?

Вызываем printf из программы на flat assembler (FASM)

flat assembler, в отличие от MASM, практически не делает ничего, что программист не написал явно в исходном коде. В ОС Windows исполняемые файлы и библиотеки имеют формат Portable Executable (PE). Если вы создаете при помощи FASM программу, которая будет выполняться в ОС Windows, то вы должны сами описать в файле исходного кода некоторые части исполняемого файла Portable Executable (чего в MASM вам делать не пришлось бы). Например, вы должны сами описать секции данных, кода, импорта, экспорта, ресурсов и пр. Для программы HelloWorld нужны три секции: кода, данных и импорта.
С секциями кода и данных всё очевидно. В секцию импорта помещается информация о функциях, которые наша программа вызывает из различных библиотек. Нам нужно поместить в секцию импорта данные о функциях стандартной библиотеки языка C (msvcrt.dll), которые мы используем в программе. В программе, показанной ниже, я использую две функции: printfи exit.

Читайте также:
Avast это системная программа

Но каков формат данных в секции импорта? К счастью, мы можем об этом не думать — в заголовочном файле /INCLUDE/MACRO/IMPORT32.INCнаходятся макросы libraryи import, которые генерируют данные для секции импорта; программисту нужно лишь указать этим макросам имя файла библиотеки и названия функций. Об этих макросах читайте раздел 3.1.2 документа flat assembler Programmer’s Manual. Пример описания секции импорта без использования макросов library и import находится в файле /EXAMPLES/PEDEMO/PEDEMO.ASM.
Достигнуть некоторого просветления в понимании формата Portable Executableмне помогли следующие ресурсы:

  • Portable Executable — Wikipedia
  • Matt Pietrek — Peering Inside the PE: A Tour of the Win32 Portable Executable File Format
  • Matt Pietrek — An In-Depth Look into the Win32 Portable Executable File Format — 2002
  • PE Format (Windows) — MSDN — Microsoft
  • Румянцев П. В. — Исследование программ Win32: до дизассемблера и отладчика — 2004
  • Румянцев П. В. — Работа с файлами в win32 API — 2009 (Раздел «Внутренности исполняемого файла Win32»)

Ниже приведен код программы HelloWorld на FASM:

; FASM version of HelloWorld program using printf() function
format PE console
entry main
use32

; ========== CODE SECTION ==========
section ‘.text’ code readable executable

printf : jmp [ imp_printf ]
exit : jmp [ imp_exit ]

main :
push message
call printf
add esp , 4

push 0
call exit

; ========== DATA SECTION ==========
section ‘.data’ data readable writeable
message db «Hello, World!» , 0

; ========== IMPORT SECTION ==========
section ‘.idata’ data import readable

; The header included below contains «library» and «import» macros that
; generate import data which must be placed in the import section of PE file
include «C:FASMINCLUDEmacroimport32.inc»

library msvcrt , «MSVCRT.DLL»

import msvcrt ,
imp_printf , ‘printf’ ,
imp_exit , ‘exit’

Пояснения к программе HelloWorld на FASM

format PE console определяет формат двоичного файла, который должен сгенерировать компилятор; формат — Portable Executable, подсистема — console.

entry main устанавливает точку входа в программу — функцию main.

use32 заставляет компилятор генерировать 32-разрядный машинный код.

section ‘.text’ code readable executable описывает секцию кода. ‘.text’ — это имя секции (имена секций, насколько я понимаю, не несут никакой функциональной нагрузки и могут быть любыми, но не длиннее 8 символов). code readable executable — атрибуты (флаги), которые характеризуют секцию как секцию кода, содержимое которой можно читать и исполнять.

section ‘.data’ data readable writeable секция данных, для которой разрешены чтение и запись.

section ‘.idata’ data import readable секция импорта, в которой описывается, какие функции из каких библиотек использует наша программа. О том, как устроена секция импорта в файле PE хорошо написано в книге П. В. Румянцева «Работа с файлами в win32 API» в разделе Импорт функций и механизм импорта. Раздел импорта состоит, грубо говоря, из двух массивов.

Массив структур IMAGE_IMPORT_DESCRIPTOR(определения структур см. в заголовочном файле WinNT.h) содержит информацию об используемых нашей программой библиотеках. Количество элементов в массиве равно количеству библиотек. В каждом элементе этого массива содержится имя библиотеки, из которой импортируются функции, и указатель FirstThunk, который указывает на массив структур IMAGE_THUNK_DATA. Каждый элемент массива структур IMAGE_THUNK_DATA содержит информацию об одной импортируемой функции — это либо ее порядковый номер (ordinal), либо указатель на структуру IMAGE_IMPORT_BY_NAME, которая содержит имя функции.

printf : jmp [ imp_printf ]
Команда вида jmp [ metka ] выполняет прыжок по адресу, который берется из участка памяти, на который указывает метка metka. Не путайте эту команду с командой jmp metka , которая выполняет прыжок по адресу, на который указывает метка metka . В приведенной выше команде imp_printf — это метка, которая указывает на структуру IMAGE_THUNK_DATA . При загрузке исполняемого файла в память загрузчик помещает в место в памяти, на которое указывает imp_printf адрес функции printf в библиотеке msvcrt.dll. Так что команда printf : jmp [ imp_printf ] прыгает на функцию printf.

Ну и наконец, я хотел бы показать, как выглядит наша программа без макросов library и import:

; FASM version of HelloWorld program using printf() function
format PE console
entry main
use32

; ========== CODE SECTION ==========
section ‘.text’ code readable executable

main :
push message
call [ printf ]
add esp , 4

push 0
call [ exit ]

; ========== DATA SECTION ==========
section ‘.data’ data readable writeable
message db «Hello, World!» , 0

; ========== IMPORT SECTION ==========
section ‘.idata’ data import readable

; — array of IMAGE_IMPORT_DESCRIPTOR structures —
dd 0 , 0 , 0 , RVA msvcrt_name , RVA msvcrt_table
dd 0 , 0 , 0 , 0 , 0
; —

; — array of IMAGE_THUNK_DATA structures —
msvcrt_table :
printf dd RVA _printf
exit dd RVA _exit
dd 0
; —

msvcrt_name db ‘MSVCRT.DLL’ , 0

; IMAGE_IMPORT_BY_NAME structure
_printf :
dw 0
db ‘printf’ , 0

; IMAGE_IMPORT_BY_NAME structure
_exit :
dw 0
db ‘exit’ , 0

В приведенном коде директива RVAозначает Relative Virtual Address— адрес относительно начала файла на диске, а не адрес оперативной памяти. Следует понимать разницу между этими двумя адресами. Файл на диске состоит из байтов (можно еще сказать, является потоком байтов). Байты файла можно условно пронумеровать от 0 до . Такой номер байта — это и есть RVA.

При запуске программы содержимое файла копируется (точнее — проецируется, но не будем об этом сейчас) в оперативную память по определенному адресу, который обычно равен 0x00400000 (этот адрес указывается в заголовке файла Portable Executable — см. поле ImageBase в структуре IMAGE_OPTIONAL_HEADER в файле WinNT.h). Поэтому, условно говоря, байт в файле, у которого RVA = X, будет находиться в оперативной памяти по адресу X + 0x00400000.

Читайте также:
Программа для того чтобы интернет работал быстрее

Отладка (Debugging)

Отладка — это исследования работы скомпилированной программы во время ее выполнения. Отладка выполняется при помощи специальных программ, называемых отладчиками (debuggers). Отладчики позволяют пользователю

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

Как работает отладчик?Как я понимаю, для работы отладчику необходима поддержка со стороны операционной системы. Поэтому такие ОС, как Windows и Linux предоставляют API для выполнения отладки (см. например The Debugging Application Programming Interface). ОС может перевести процессор в такой режим, когда после выполнения каждой машинной команды, он будет генерировать прерывание — это и позволяет, как я понимаю, выполнять программу пошагово.
Где взять отладчик?Для Windows стандартным является отладчик от фирмы Microsoft под названием WinDbg, он поставляется в составе Windows SDK(см. Debugging Tools for Windows). О том, как пользоваться отладчиком WinDbg см. статью Getting Started with WinDbg (User-Mode).
Другой вариант — отладчик с открытым исходным кодом OllyDbg. Пользоваться им довольно просто: вы нажимаете на кнопку «Открыть» и выбираете исполняемый файл (exe) программы, которую хотите отлаживать. Программа тут же запускается и происходит останов на ее точке входа (функции main). В окне программы вы видите четыре окошка: дизассемблированный код, регистры процессора, шестнадцатеричный дамп памяти, стек (stack). Интерфейс программы интуитивно понятен, а в составе дистрибутива есть руководство пользователя.

Заключение

Если выбирать между MASM и FASM с точки зрения обучения языку ассемблера, то я пожалуй выбираю FASM. Его можно легко установить (надо просто скачать дистрибутив с сайта). Он позволяет создавать любые двоичные файлы и помогает программисту создавать двоичные файлы форматов PE, ELF и COFF. С MASM мне пришлось помучиться, чтобы разобраться с вызовом функций из стандартной библиотеки языка C, с FASM всё оказалось куда проще.

Источник: dvsav.ru

Пример программы на ассемблере fasm

Вы используете устаревший браузер. Этот и другие сайты могут отображаться в нём некорректно.
Необходимо обновить браузер или попробовать использовать другой.

Программирование на языке Assembler в FASM

Дата публикации 6 янв 2004

Программирование на языке Assembler в FASM — Архив WASM.RU

ВведениеВ начале было слово. Если точнее то было просто предложение от Kinder-а написать статью посвящённую макросам в FASM. Я согласился попробовать, но рассматривать макросы отдельно от синтаксиса как-то не очень правильно, а синтаксис без примеров разобрать сложно и в результате получилось сочинение о том как писать программы в FASM.

В этом сочинении будут рассмотрены основные моменты отличающие FASM от других компиляторов, правила по которым пишутся макросы и форматы выходных файлов создаваемые FASM-ом. Так же в рамках данного сочинения мы создадим несколько контролов в виде макросов. Основы.Данный раздел является вольным
пересказом соответствующего раздела
руководства, поставляемого с
компилятором.Данная статья посвящена использованию макросов в компиляторе FASM. Для начала вопрос: «Что такое макрос?» (поскольку я не могу услышать Ваш ответ прямо сейчас, когда пишу эту статью, отправляйте свои ответы мне по электронной почте, если Ваше мнение отличается от моего мнения).

Макрос- это инструкция препроцессору компилятора развернуть, встретившееся в коде программы, имя макроса (возможно с параметрами) в последовательность строк кода ассемблера с использованием переданных параметров (если таковые заданы). Далее предлагаю Вам ознакомиться с основными директивами, используемыми внутри определений макросов. Внутри определений макросов можно использовать инструкции ifи elseпри этом каждая инструкция if должна закрываться инструкцией end if. Пример из руководства, поставляемого вместе с компилятором:

macro mov op1,op2
if op1 in push — pop», в любом другом случае используется стандартная инструкция «mov op1,op2». Оператор inпозволяет проверить соответствие операнда нескольким значениям в угловых скобках.

Можно ещё более расширить эту инструкцию для пересылки трёх значений второго в первый, а третьего во второй:

macro mov op1,op2,op3
if arg3 eq
mov op1,op2
mov op1,op2
mov op2,op3

В данном случае нас интересует инструкция eq, которая позволяет проверить эквивалентен ли операнд какому либо значению, в нашем случае мы проверяем его отсутствие, и если он отсутствует, то подставляется ветвь ifиначе подставляется ветвь else.

Директива purgeпозволяет отменить последнее определение макроса.

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

macro stdcall proc,[arg];
Операндами этого макроса служат один обязательный (proc) и несколько необязательных параметров (arg). Директива reverseсообщает препроцессору, что следующие строки необходимо повторить столько раз, сколько параметров argпередано макросу начиная с последнего параметра.

Директива commonсообщает препроцессору, что следующие строки необходимо повторить только один раз. Директива forwardсообщает препроцессору, что следующие строки необходимо повторить столько раз, сколько параметров argпередано макросу начиная с первого параметра. Действие директив common, forwardи reverseзаканчивается другой директивой common, forwardили re-verseсоответственно или закрывающейся фигурной скобкой. Если ни одна из этих директив не встречается в определении макроса, то макрос развернётся для всех параметров начиная с первого. Неизвестное количество параметров можно передать и другому макросу: macro invoke proc,[arg]
if arg eq
stdcall [proc],arg

В этом примере при выполнении ветви ifв макрос stdcallкроме параметра [proc]передаются все полученные параметры arg.

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

macro jif op1,cond,op2,label
cmp op1,op2
j#cond label

При выполнении макроса jif ax,ae,10h,exit макрос будет развёрнут в следующую конструкцию:

Так же этот оператор можно использовать и для составления имён переменных или макросов внутри макроопределений:

macro ver [name]
name#.mas: times 10 db 0

Теперь при вызове данного макроса в секции данных

ver Chif,Rab

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru