Пример программы в FASM: вывод на консоль текстового файла в Win32

FASM - Flat assembler - это бесплатный ассемблер, которым можно транслировать программы для DOS, Windows, Linux и Unix. Он в себе содержит также компоновщик, поэтому получение исполняемого файла очень простое: fasm.exe <filename.asm>. FASM постоянно развивается и наряду с архитектурой x86-64 поддерживает последние наборы инструкций SSE и AVX. По этой ссылке вы можете скачать новейшую версию FASM.

Учебника FASM - по крайней мере, на русском языке - не существует, есть документация на сайте этого продукта. Поэтому начинающие программисты ищут информацию и примеры программ на FASM в Интернете.

В этом примере мы рассмотрим консольную программу в FASM, которая получает имя текстового файла из командной строки и выводит его содержимое на консоль. В данном случае мы будем использовать функции из библиотеки msvcrt.dll. Она поставляется вместе с Windows и называется, как можно понять из имени dll, Microsoft Visual C Runtime Library. Список функций из этой dll и примеры их использования вы можете увидеть на англоязычном сайте, посвящённом C++. Здесь есть справочник на русском языке по библиотеке msvcrt времени выполнения.

В начале программы вы видите строку include 'win32ax.inc'. Чтобы не писать весь путь к подключаемому файлу с макоопределениями win32ax.inc, надо зайти в "свойства моего компьютера" во вкладку "дополнительно" и выбрать "переменные среды". Там надо создать переменную среды с именем include и дать ей значение в виде пути к папке include каталога с FASM, например: c:\fasm\include.

Далее в тексте программы вы видите несколько констант для работы с файлами. Текст программы должен быть в кодировке OEM (code page 866), т.к. Windows в консоли использует её. Если вы хотите использовать кодировку Windows (code page 1251), то раскомментируйте вызовы
invoke SetConsoleOutputCP,1251
invoke SetConsoleCP,1251
При этом заметьте, что шрифт в консоли должен быть не Consolas и не точечным, а Lucida Console, иначе в некоторых случаях вы будете видеть закорючки вместо русских букв. Шрифт можно менять в свойствах Far (правой кнопкой по иконке) или свойствах программы cmd.exe (правой кнопкой в верхнем левом углу окна программы). Для перекодировки строки из кодировки Windows в OEM перед выводом на экран также можно использовать CharToOemA. В закомментированных строках перекодируются параметры программы (полный путь с именем файла данной программы и заданный ей параметр).

Если эта программа будет запущена из консольной программы (напр., из Far manager), то она унаследует консоль Far. Если раскомментировать вызовы
invoke FreeConsole
invoke AllocConsole
то программа создаст свою консоль.

В программе делается проверка на ошибки после вызовов функций из msvcrt.dll макросом cinvoke. Для разнообразия в одном случае используется макрос .if, который наряду с макросами .while, .repeat облегчает восприятие текста программы и уменьшает число меток ценой некоторого "загрязнения" результирующего кода. В этих макросах можно использовать выражения и скобки, например:
.if eax <> 0 & [mem1] > ebx & (ecx > [mem2])
Предусмотрена возможность делать сравнения для переменных со знаком. Также показано, как можно задавать строки в виде литералов прямо в вызовах invoke и cinvoke.

В конце программы в секции .idata перечисляются используемые файлы dll и импортируемые из них функции. В дальнейшем мы увидим, что явно создавать эту секцию и выписывать всё это не всегда обязательно, это может сделать макрос.

Далее идёт текст вышеописанной программы.

; Пример Win32 консольной программы для FASM, которая получает в строке вызова
; имя текстового файла и выводит его содержимое и размер на консоль.
; Сделано IQFun.ru, см. www.iqfun.ru/articles/fasm-primer-console-output.shtml
; Создавайте этот файл в кодировке DOS (OEM, code page 866).

format PE CONSOLE
include 'win32ax.inc'

SEEK_SET equ 0  ; Относительно начала файла, начало файла - позиция 0
SEEK_CUR equ 1  ; Относительно текущей позиции, > 0 - вперед, < 0 - назад
SEEK_END equ 2  ; Относительно конца файла (значение pos - отрицательное)
NULL     equ 0
EOF      equ -1

section '.data' data readable writeable

argc    dd ?
argv    dd ?
env     dd ?
fp      dd ?
flength dd ?
fbuf    dd ?
msg     db  '%s %s%s',0
errmsg  db "Ошибка! Нужно задать имя текстового файла для вывода.",0

section '.code' code readable executable

entry start

start:
; invoke  FreeConsole
; invoke  AllocConsole
; cinvoke printf,'%s%s',,<13,10,0>
; invoke SetConsoleOutputCP,1251
; invoke SetConsoleCP,1251

 cinvoke printf,'%s',<'Привет',13,10,0>

 ; Получаем полный путь к программе и заданный ей параметр аналогично программе на C
 cinvoke __getmainargs,argc,argv,env,0
 cmp [argc],2
 jne .err
 mov esi,[argv]

; invoke CharToOemA,dword [esi],dword [esi]
; invoke CharToOemA,dword [esi+4],dword [esi+4]

 ; Выводим имя программы с путём и параметр
 cinvoke printf,msg,dword [esi],dword [esi+4],<13,10,0>

 ; Открываем заданный текстовый файл в режиме "только чтение" и "двоичный"
 cinvoke fopen,dword [esi+4],'rb'
 test eax,eax
 jz .err
 mov [fp],eax

 ; Устанавливаем указатель чтения-записи в конец файла
 cinvoke fseek,[fp],0,SEEK_END
 .if eax <> 0
  jmp .err
 .endif

 ; Узнаём значение этого указателя, который равен размеру файла
 cinvoke ftell,[fp]
 test eax,eax
 jz .err
 mov [flength],eax

 ; Запрашиваем динамическую память размером длина файла + 1 байт
 inc eax
 cinvoke malloc,eax
 test eax,eax
 jz .err
 mov [fbuf],eax

 ; Возвращаем указатель чтения-записи в начало файла
 cinvoke fseek,[fp],0,SEEK_SET
 test eax,eax
 jnz .err

 ; Читаем весь файл в динамическую память
 cinvoke fread,[fbuf],1,[flength],[fp]
 cmp eax,[flength]
 jne .err

 ; Записываем 0 за концом данных для обозначения конца строки
 mov eax,[fbuf]
 add eax,[flength]
 mov byte [eax],0

 ; Выводим файл на консоль
 cinvoke puts,[fbuf]
 cinvoke printf,'Длина файла = %u%s',[flength],<13,10,0>

 ; Закрываем файл
 cinvoke fclose,[fp]
 test eax,eax
 jnz .err

 ; Освобождаем динамическую память
 cinvoke free,[fbuf]

.finish:
 cinvoke puts,'Press any key...'
 cinvoke _getch
 invoke ExitProcess,0

.err:
 cinvoke puts,errmsg
 jmp .finish

section '.idata' import data readable writeable

library kernel,'kernel32.dll',\
msvcrt,'msvcrt.dll',\
user32,'user32.dll'

import kernel,\
ExitProcess,'ExitProcess',\
GetCommandLineA,'GetCommandLineA',\
AllocConsole,'AllocConsole',\
FreeConsole,'FreeConsole',\
SetConsoleOutputCP,'SetConsoleOutputCP',\
SetConsoleCP,'SetConsoleCP'

import msvcrt,\
__getmainargs,'__getmainargs',\
fopen,'fopen',\
fseek,'fseek',\
ftell,'ftell',\
malloc,'malloc',\
free,'free',\
fread,'fread',\
fclose,'fclose',\
printf,'printf',\
_getch,'_getch',\
puts,'puts'

import user32,\
CharToOemA,'CharToOemA'

© IQFun.ru, 2016 г.

Новости игр и головоломок

Опубликована

19.11.2021 большая база анаграммных фраз множества авторов.

Докажите, что вы не чат-бот!

18.11.2021 Тест - викторина № 82 на знания, ассоциации и чувство юмора.

Опубликована 1-я серия мультсериала "Математический кружок":

23.10.2019 "Великая теорема Стёпы Мошкина".

Как я озадачил Бронштейна,

07.06.2019 показав гроссмейстеру свю трёхходовку.

На AlaFun.ru возник

27.09.2018 новый стишок-антипод.

Слово - анаграмма - метаграмма.

16.06.2018 Юмористическая викторина № 81.

Вставьте буквы вместо точек.

31.05.2018 Словесный тест IQ № 80.

На AlaFun.ru возник

21.05.2018 новый стишок-антипод на неувядающую классику.

Слово - анаграмма - метаграмма.

26.03.2018 Юмористическая викторина № 68, дополнение.

Установлен новый рекорд.

04.01.2018 Сделать из мухи слона за 7 шагов.

Отметьте верные и неверные утверждения.

24.10.2017 Викторина на логику № 79.