В данной статье я хочу рассмотреть вопросы, которые могут возникнуть у человека, приступившего к изучению ассемблера, связанные с установкой различных трансляторов и трансляцией программ под Windows и Linux, а также указать ссылки на ресурсы и книги, посвященные изучению данной темы.
MASM
Используется для создания драйверов под Windows.
По ссылке переходим на сайт и скачиваем пакет (masm32v11r.zip). После инсталляции программы на диске создается папка с нашим пакетом C:masm32. Создадим программу prog11.asm, которая ничего не делает.
.586P
.model flat, stdcall
_data segment
_data ends
_text segment
start:
ret
_text ends
end start
Произведём ассемблирование (трансляцию) файла prog11.asm, используя ассемблер с сайта masm32.
Ключ /coff используется здесь для трансляции 32-битных программ.
Линковка производится командой link /subsystem:windows prog11.obj (link /subsystem:console prog11.obj)
Как сказано в Википедии
MASM — один из немногих инструментов разработки Microsoft, для которых не было отдельных 16- и 32-битных версий.
Также ассемблер версии 6. можно взять на сайте Кипа Ирвина kipirvine.com/asm, автора книги «Язык ассемблера для процессоров Intel».
Кстати, вот ссылка на личный сайт Владислава Пирогова, автора книги “Ассемблер для Windows”.
MASM с сайта Microsoft
Далее скачаем MASM (версия 8.0) с сайта Microsoft по ссылке. Загруженный файл носит название «MASMsetup.exe». При запуске этого файла получаем сообщение -«Microsoft Visual C++ Express Edition 2005 required».
Открываем этот файл архиватором (например 7zip). Внутри видим файл setup.exe, извлекаем его, открываем архиватором. Внутри видим два файла vc_masm.msi,vc_masm1.cab. Извлекаем файл vc_masm1.cab, открываем архиватором. Внутри видим файл FL_ml_exe_____X86.3643236F_FC70_11D3_A536_0090278A1BB8. Переименовываем его в файл fl_ml.exe, далее, произведём ассемблирование файла prog11.asm, используя ассемблер fl_ml.exe.
MASM в Visual Studio
Также MASM можно найти в папке с Visual Studio (у меня VS 10) вот здесь: C:Program FilesMicrosoft Visual Studio 10.0VCbinml.exe.
Для того, чтобы запустить на 32- или 64-разрядной системе и создавать программы, работающие как под 32-, так и под 64-разрядной Windows, подходит MASM32 (ml.exe, fl_ml.exe). Для того, чтобы работать на 32- и 64-разрядных системах и создавать программы, работающие под 64-разрядной Windows, но неработающие под 32-разрядной нужен ассемблер ml64.exe. Лежит в папке C:Program FilesMicrosoft Visual Studio 10.0VCbinamd64 и вот здесь — C:Program FilesMicrosoft Visual Studio 10.0VCbinx86_amd64.
TASM
Программный пакет компании Borland, предназначенный для разработки программ на языке ассемблера для архитектуры x86. В настоящее время Borland прекратила распространение своего ассемблера.
Скачать можно, например, здесь. Инсталлятора нет, просто извлекаем программу. Вот исходник из книги Питера Абеля (рис. 3.2) «Язык Ассемблера для IBM PC и программирования».
stacksg segment para stack 'stack'
db 12 dup ('stackseg')
stacksg ends
codesg segment para 'code'
begin proc far
assume ss:stacksg,cs:codesg,ds:nothing
push ds
sub ax,ax
push ax
mov ax, 0123h
add ax, 0025h
mov bx,ax
add bx,ax
mov cx,bx
sub cx,ax
sub ax,ax
nop
ret
begin endp
codesg ends
end begin
Выполним ассемблирование (трансляцию) файла abel32.asm.
Корректность работы программы можно проверить, произведя линковку (tlink.exe) объектного файла и запустив полученный файл в отладчике.
Как было сказано выше, MASM можно использовать для работы с 16-битными программами. Выполним ассемблирование (трансляцию) программы abel32.asm с помощью ассемблера MASM:
Ключ /coff здесь не используется.
Линковка производится файлом link16.exe
Вот здесь приводится порядок действий, которые необходимо выполнить для запуска TASM в DOSbox. Для линковки понадобится файл DPMI16BI.OVL
FASM
В статье Криса Касперски «Сравнение ассемблерных трансляторов» написано, что «FASM — неординарный и весьма самобытный, но увы, игрушечный ассемблер. Пригоден для мелких задач типа „hello, world“, вирусов, демок и прочих произведений хакерского творчества.»
Скачаем FASM с официального сайта. Инсталлятора нет, просто извлекаем программу. Откроем fasm editor — C:fasmfasmw.exe. В папке C:fasmEXAMPLESHELLO есть файл HELLO.asm.
include 'win32ax.inc'
.code
start:
invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
invoke ExitProcess,0
.end start
Откроем файл HELLO.asm из fasmw.exe. Изменим строку include ‘win32ax.inc’ на строку include ‘c:fasmINCLUDEWIN32AX.INC’. Запускаем из меню Run → Run.
Вот ссылки на ресурсы, посвященные FASM:
→ FASM на Cyberforum’е
→ FASM на asmworld .com программы под Dos
→ Цикл статей «Ассемблер под Windows для чайников»
→ Сайт на narod’е
FASM в Linux
Для того, использовать FASM в Linux (у меня Ubuntu), скачаем соответствующий дистрибутив (fasm-1.71.60.tgz), распакуем его, в папке у нас будет бинарный файл fasm, копируем этот файл в /usr/local/bin для того, чтобы можно было запускать его из консоли, как любую другую команду.Выполним ассемблирование программы hello.asm из папки fasm/examples/elfexe/hello.asm.
Корректность работы программы можно проверить в отладчике.
Nasm
Nasm успешно конкурирует со стандартным в Linux- и многих других UNIX-системах ассемблером Gas.
Nasm в Linux можно установить с помощью менеджера пакетов или из командной строки: в дистрибутиве Debian (Ubuntu) командой apt-get install nasm, в дистрибутивах Fedora, CentOS, RedHat командой yum install nasm.
Создадим программу, которая 5 раз выводит сообщение “Hello”. Пример взят из книги Андрея Викторовича Столярова “Программирование на языке ассемблера NASM для ОС UNIX”. Учебник, а также библиотека “stud_io.inc” есть на личном сайте автора.
%include "stud_io.inc"
global _start
section .text
_start: mov eax, 0
again: PRINT "Hello"
PUTCHAR 10
inc eax
cmp eax, 5
jl again
FINISH
Выполним ассемблирование и линковку и запустим файл hello.asm.
$ nasm -f elf hello.asm
$ ld hello.o -o hello
$ ./hello
Для 64bit необходимо использовать команду nasm -f elf64 hello.asm
NASM для Windows
NASM для Windows можно установить, скачав соответствующий дистрибутив с соответствующего сайта.
Ассемблирование:
nasm -f bin имя_файла.asm -o имя_файла.com
Ссылки на ресурсы, посвященные Nasm:
→ Сайт А.В. Столярова
→ Сайт, на котором лежит электронный учебник (в архиве)
→ То же самое
AS
Стандартный ассемблер практически во всех разновидностях UNIX, в том числе Linux и BSD. Свободная версия этого ассемблера называется GAS (GNU assembler). Позволяет транслировать программы с помощью компилятора GCC.
Из учебников удалось найти только книгу на английском «Programming from the ground up». На русском удалось найти только одну главу из книги С. Зубкова «Assembler для DOS, Windows и UNIX».
Возьмем пример программы, которая ничего не делает, с сайта. Создадим программу gas.s
.section .text
.globl _start
_start:
movl $1, %eax
movl $2, %ebx
int $0x80
Выполним ассемблирование (трансляцию), линковку и запуск программы:
$ as -o gas.o gas.s
$ ld -o gas gas.o
$ ./gas
Если в данной программе изменить _start на main, то можно выполнить ассемблирование (трансляцию) и линковку компилятором gcc.
.section .text
.globl main
main:
movl $1, %eax
movl $2, %ebx
int $0x80
Выполним ассемблирование (трансляцию), линковку и запуск программы:
$ gcc gas.s -o gas
$ ./gas
Выводы: если вы изучаете программирование под Windows, то вы можете остановить свой выбор на Masm; Tasm больше не поддерживается, но для обучения по старым классическим учебникам подойдёт.
Под Linux Gas подойдет тем, кто использует GCC, а тем, кому не нравится синтаксис Gas, подойдёт Nasm.
P.S. Про обработку строк в ассемблере на примере создания транслятора простого «эзотерического» языка можно прочитать здесь.
P.P.S. Упрощенный ограниченный набор ассемблерных инструкций используется в учебной модели компьютера Little Man Computer, которому у меня также посвящено несколько статей ссылка.
Програмирование на fasm под Win64 часть 1 «Ассемблер, отладчик, IDE»
| Редактировалось 10 янв 2018
Введение
Я начинаю цикл статей по ассемблеру fasm. Возможно у вас есть вопрос: “Зачем в 21 веке нужен ассемблер?”. Я бы ответил так: Конечно, знание ассемблера не обязятельно, но оно способствует пониманию, во что превращается ваш код, как он работает, это позволяет почувствовать силу. Ну и в конце концов: Писать на ассемблере просто приятно (ну по крайней мере небольшие приложения).
Так что надеюсь, что мои статьи будут вам полезны.Где взять fasm?
Собственно тут: http://flatassembler.net/download.php
На этой странице Томаш Грыштар(создатель fasm-а) выкладывает последнюю версию ассемблера. Там есть версии для DOS, Linux, Unix и Windows, нам нужна для Windows. В скачанном архиве находятся следующие компоненты:
- fasm.exe – собственно сам ассемблер
- fasmw.exe – IDE (среда разработки)
- fasm.pdf – документация
- папка source – исходники fasm-а (написан на самом себе)
- папка include – папка с заголовками, импортами, и т.д.
- папка examples – примеры программ на fasm-е
Содержимое fasm.pdf дублирует 2 раздела документации “flat assembler 1.71 Programmer’s Manual” и “Windows programming” отсюда: http://flatassembler.net/docs.phpIDE (среда разработки)
Перед тем, как писать программы нужно определиться, в чём их писать. Для fasm-а существуют разные IDE, например: fasmw.exe(находится в архиве с fasm-ом), RadAsm, WinAsm Studio, Fresh, … Выберайте, какая вам больше по вкусу. Сразу скажу, что IDE из поставки fasm-а обладает минимальным количеством фичей, так что я бы рекомендовал использовать альтернативную IDE. Я, например, использую RadAsm 3.0, его можно взять здесь: https://fbedit.svn.sourceforge.net/svnroot/fbedit/RadASM30/Release/RadASM.zip (это хорошая IDE, но к сожалений она больше не обновляется) К статье приложен файл Fasm.ini, там выбрана чёрная тема, добавлены x64 регистры и добавлена подсветка для большего числа инструкций. Можете поставить его вместо Fasm.ini поумолчанию, только исправьте в нём пути к папке с fasm-ом в 6 и 7 строках. Там написано:
0=path,C:Program Files (x86)fasm;$A..Ollydbg 1=include,C:Program Files (x86)fasmINCLUDEЕсли вы распаковали fasm в папку <полный путь>, то надо заменить приведённый выше код на:
0=path,<полный путь>fasm;$A..Ollydbg 1=include,<полный путь>fasmINCLUDEОтладчик
Писать программы это — хорошо, но нужно находить и исправлять баги, для этого нужен отладчик. Существуют разные отладчики способные отлаживать 64-битный код например: WinDbg, fdbg, x64dbg. Наиболее удобный на мой взгляд — x64dbg, его можно скачать здесь.
Это — всё, что я хотел рассказать в первой части.
Вложения:
-
Fasm.zip
- Размер файла:
- 6,8 КБ
- Просмотров:
- 1.279
_qwe8013
Active Member
- Регистрация:
- 30 ноя 2016
- Публикаций:
- 2
Комментарии
-
omne999666 16 июл 2020
Легко все описано и освоилось напоследок удивило вложения файлика архива Fasm.zip в котором много интересного для настроек новых инструкций и регистров. Вводно понятно в месте содержания .ini и дополнение есть самим что не на есть знаниями.
-
addedie 22 сен 2019
перезалейте пожалуйста эту версию RadAsm, буду весьма благодарен….
-
седьмой 10 июл 2017
Спасибо, все разобрался, код работает под windows 7 — 64.
-
седьмой 10 июл 2017
Спасибо, очень интересно, но почему то Fasm в ОС вин 64 не компилируется код, скаченный по этой ссылке
код взял вот отсюда
-
use16 ;Генерировать 16-битный код
-
org 100h ;Указание компилятору вести отсчёт смещения от адреса 100h, так как DOS грузит по данному смещению.
-
mov dx,hello ;В DX адрес строки.
-
mov ah,9 ;Номер функции DOS.
-
int 21h ;Обращение к функции DOS.
-
int 21h ;/ Завершение программы
-
;——————————————————-
-
hello db ‘Hello, world!$’
код взял по ссылке http://www.programmersforum.ru/showthread.php?t=306951&page=2 Может быть там надо что то перенастроить? Выдает сообщение, что не может откомпилировать код в системе вин 64. Сам уже кажется понял, этот код для доса, а можно где то взять рабочий код минимальный для проверки работы компилятора Fasm вин 64?
-
Из песочницы, Assembler
Рекомендация: подборка платных и бесплатных курсов создания сайтов — https://katalog-kursov.ru/
Коротко о FASM, ассемблере, WinAPI
-
Что такое FASM? — Это компилятор ассемблера (flat assembler).
-
Что такое ассемблер? — это машинные инструкции, то есть команды что делать процессору.
-
Что такое Windows API/WinAPI? — Это функции Windows, без них нельзя работать с Windows.
Что дают WinAPI функции? — Очень много чего:
-
Работа с файлами.
-
Работа с окнами, отрисовка картинок, OpenGL, DirectX, GDI, и все в таком духе.
-
Взаимодействие с другими процессами.
-
Работа с портами.
-
Работа с консолью Windows
-
И еще очень много интересных функций.
Зачем нужен ассемблер?
На нем можно сделать все что угодно, от ОС до 3D игр.
Вот плюсы ассемблера:
-
Он очень быстрый.
-
На нем можно сделать любую программу.
А вот минусы ассемблера:
-
Долго делать программу. (относительно)
-
Сложен в освоении.
Что нужно для программирования на ассемблере (FASM)?
-
FASM компилятор — https://flatassembler.net/
-
FASM Editor 2.0 — Удобная IDE для FASM, от fasmworld.ru (asmworld), качаем от сюда: https://fasmworld.ru/content/files/tools/FEditor-v2.0.rar
-
OlyDbg — удобный отладчик ассемблера от ollydbg.de: https://www.ollydbg.de/odbg201.zip
Это все мероприятие весит всего лишь 8.5MB.
Установка компонентов (если можно так назвать)
Архив FASM-а распаковуем в C:\FASM или любой другой, но потом не забудьте настроить FASMEditor.
Архив FASMEdit-a распаковуем куда-то, в моем случае C:\FASM Editor 2.0
Архив OlyDbg распаковуем тоже куда-то, в моем случае C:\Users****DocumentsFasmEditorProjects
Настройка FASM Editor-a
Для этого его нужно запустить.
Сразу вас приветствует FASM Editor соей заставкой.
Теперь вам нужно зайти в вкладку «Сервис» (на картинке выделил синим) -> «Настройки…»
Жмем на кнопку с названием «…» и выбираем путь к файлам или папкам.
Теперь мы полностью готовы. К началу.
Пишем «Hello world!» на FASM
В Fasm Editor нужно нажать на кнопку слева сверху или «файл» -> «новый». Выбираем любое, но можно выбрать «Console»
По началу вас это может напугать, но не боимся и разбираемся.
format PE Console ; говорим компилятору FASM какой файл делать
entry start ; говорим windows-у где из этой каши стартовать программу.
include 'win32a.inc' ; подключаем библиотеку FASM-а
;можно и без нее но будет очень сложно.
section '.data' data readable writeable ; секция данных
hello db 'hello world!',0 ; наша строка которую нужно вывести
section '.code' code readable writeable executable ; секция кода
start: ; метка старта
invoke printf, hello ; вызываем функцию printf
invoke getch ; вызываем её для того чтоб программа не схлопнулась
;то есть не закрылась сразу.
invoke ExitProcess, 0 ; говорим windows-у что у нас программа закончилась
; то есть нужно программу закрыть (завершить)
section '.idata' data import readable ; секция импорта
library kernel, 'kernel32.dll', ; тут немного сложней, объясню чуть позже
msvcrt, 'msvcrt.dll'
import kernel, ExitProcess, 'ExitProcess'
import msvcrt, printf, 'printf', getch, '_getch'
На самом деле из всей этой каши текста, команд всего 3: на 16, 18, 21 строках. (и то это не команды, а макросы. Мы к командам даже не подобрались)
Все остальное это просто подготовка программы к запуску.
Программа при запуске должна выглядеть так:
Самое интересное то что программа весит 2КБ. (Можно сократить и до 1КБ, но для упрощения и так пойдет)
Разбор: что значат этот весь текст?
На 1 строчке: «format PE Console» — это строчка говорит FASM-у какой файл скомпилировать, точнее 1 слово, все остальные слова это аргументы (можно так сказать).
PE — EXE файл, программа.
Console — говорим что это у нас консольная программа, но вам некто не мешает сделать из консольной программы оконную и наоборот.
Но есть кроме это остальные:
-
format MZ — EXE-файл НО под MS-DOS
-
format PE — EXE-файл под Windows, аналогично format PE GUI 4.0
-
format PE64 — EXE-файл под Windows, 64 битное приложение.
-
format PE GUI 4.0 — EXE-файл под Windows, графическое приложение.
-
format PE Console — EXE-файл под Windows, консольная программа. (просто подключается заранее консоль)
-
format PE Native — драйвер
-
format PE DLL — DLL-файл Windows, поясню позднее.
-
format COFF — OBJ-файл Linux
-
format MS COFF — аналогично предыдущему
-
format ELF — OBJ-файл для gcc (Linux)
-
format ELF64 — OBJ-файл для gcc (Linux), 64-bit
Сразу за командой (для компилятора) format PE Console
идет ;
это значит комментарий. К сожалению он есть только однострочный.
3 строка: entry start
-
Говорим windows-у гдев каком месте стартовать. «start» это метка, но о метках чуть позже.
5 строка: include 'win32a.inc'
-
Подключает к проекту файл, в данном случае «win32a.inc» он находиться в папке INCLUDE (в папке с FASM). этот файл создает константы и создает макросы для облегчения программирования.
8 строка: section '.data' data readable writeable
-
Секция данных, то есть программа делиться на секции (части), к этим секциям мы можем дать разрешение, имя.
Флаг «data» (Флаг это битбайтаргумент хранившей в себе какую-то информацию) говорит то что эта секция данных.
Флаги «readable writeable» говорят то что эта секция может читаться кем-то и записываться кем-то.
Текст ‘.data’ — имя секции
10 строка: hello db 'hello world!',0
hello — это метка, она может быть любого имени (почти, есть некоторые зарезервированные имена), эта метка хранит в себе адрес строки, это не переменная, а просто адрес, но чтобы не запоминать адреса в ручную, помогает FASM он запоминает адрес и потом когда видит эту метку снова, то он заменяет слово на адрес.
db — говорит то что под каждый символ резервируем 1 байт. То есть 1 символ храниться в одном байте.
‘hello world!’ — наша строка в кодировке ASCII
Что значит «,0» в конце строки? — это символ с номером 0 (или просто ноль), у вас на клавиатуре нет клавиши которая имела символ с номером 0, по этому этот символ используют как показатель конца строки. То есть это значит конец строки. Просто ноль записываем в байт после строки.
12 строка: section '.code' code readable writeable executable
Флаг «code» — говорит то что это секция кода.
Флаг «executable» — говорит то что эта секция исполняема, то есть в этой секции может выполняться код.
Все остальное уже разобрали.
14 строка: start:
Это второй вид меток. Просто эта метка указывает на следующую команду. Обратите внимание на то что в 3 строке мы указали start как метку входа в программу, это она и есть. Может иметь эта метка любое имя, главное не забудьте ваше новое имя метки вписать в entry
15 строка: invoke printf, hello
-
Функция printf — выводит текстчисло в консоль. В данном случае текст по адресу «hello»
Это штото на подобие команды, но это и близко не команда ассемблера, а просто макрос.
Макрос — Это макро команда для компилятора, то есть вместо имени макроса подставляется что-то другое.
Например, макро команда invoke делиться на такие команды: (взят в пример команда с 15 строки)
push hello
call [printf]
Не переживайте если нечего не поняли.
17 строка: invoke getch
-
getch — функция получения нажатой кнопки, то есть просто ждет нажатия кнопки и потом возвращает нажатую кнопку.
20 строка: invoke ExitProcess, 0
-
ExitProcess — WinAPI функция, она завершает программу. Она принимает значение, с которым завершиться, то есть код ошибки, ноль это нет ошибок.
23 строка: section '.idata' data import readable
Флаг «import» — говорит то что это секция импорта библиотек.
24-25 строки:
library kernel, 'kernel32.dll', msvcrt, 'msvcrt.dll'
-
Макро команда «library» загружает DLL библиотеки в виртуальную память (не в ОЗУ, вам ОЗУ не хватит чтоб хранить всю виртуальную память).
Что такое DLL объясню позже.
kernel — имя которое привязывается к библиотеке, оно может быть любым.
Следующий текст после запятой: 'kernel32.dll'
— это имя DLL библиотеки который вы хотите подключить.
Дальше есть знак это значит что текст на следующей строке нужно подставить в эту строку.
То есть код:
library kernel, 'kernel32.dll', msvcrt, 'msvcrt.dll'
Заменяется на:
library kernel, 'kernel32.dll', msvcrt, 'msvcrt.dll'
Это нужно потому что у ассемблера 1 строка это 1 команда.
27-28 строка:
import kernel, ExitProcess, 'ExitProcess'
import
— Макро команда, которая загружает функции из DLL.
kernel
— Имя к которой привязана DLL, может быть любым.
ExitProcess
— Как будет называться функция в программе, это имя будет только в вашей программе, и по этому имени вы будете вызывать функцию. (WinAPI функция)
'ExitProcess'
— Это имя функции которое будет загружено из DLL, то есть это имя функции которое прописано в DLL.
Дальше думаю не стоит объяснять, вроде все понятно.
Что такое DLL библиотека?
Это файл с расширением DLL. В этом файле прописаны функции (какие ни будь). Это обычная программа, но которая не запускается по двойному щелчку, а загружается к программе в виртуальную память, и потом вызываются функции находящиеся в этой DLL.
Подводим итог
На ассемблере писать можно не зная самого языка, а используя всего лишь макро команды компилятора. За всю статью я упомянул всего 2 команды ассемблера это push hello
и call [printf]
. Что это значит расскажу в следующей статье.
Содержание
- MASM, TASM, FASM, NASM под Windows и Linux
- Assembler. Установка интерпретатора и запуск первой программы через DOSBox
- Регистры
- Флаги
- Маленькая шпаргалка для заметок:
- Turbo Assembler v.5.0 (TASM) для Windows 10
- Описание и возможности
- Как установить
- Достоинства и недостатки
- Похожие приложения
- Системные требования
- Скачать
- Вопросы и ответы
- GUI Turbo Assembler 5.0 (TASM) для Windows 10
- Описание и возможности
- Как пользоваться
- Загрузка и установка
- Инструкция по работе
- Достоинства и недостатки
- Похожие приложения
- Системные требования
- Скачать
- Видеообзор
- Вопросы и ответы
- Tasm Windows 7|Windows 8|8.1 Full Screen 32bit-64bit Version Single Installer Updated Fullscreen
MASM, TASM, FASM, NASM под Windows и Linux
В данной статье я хочу рассмотреть вопросы, которые могут возникнуть у человека, приступившего к изучению ассемблера, связанные с установкой различных трансляторов и трансляцией программ под Windows и Linux, а также указать ссылки на ресурсы и книги, посвященные изучению данной темы.
Используется для создания драйверов под Windows.
По ссылке переходим на сайт и скачиваем пакет (masm32v11r.zip). После инсталляции программы на диске создается папка с нашим пакетом C:masm32. Создадим программу prog11.asm, которая ничего не делает.
Произведём ассемблирование (трансляцию) файла prog11.asm, используя ассемблер с сайта masm32.
Ключ /coff используется здесь для трансляции 32-битных программ.
Линковка производится командой link /subsystem:windows prog11.obj (link /subsystem:console prog11.obj)
MASM — один из немногих инструментов разработки Microsoft, для которых не было отдельных 16- и 32-битных версий.
Также ассемблер версии 6. можно взять на сайте Кипа Ирвина kipirvine.com/asm, автора книги «Язык ассемблера для процессоров Intel».
Кстати, вот ссылка на личный сайт Владислава Пирогова, автора книги “Ассемблер для Windows”.
MASM с сайта Microsoft
Открываем этот файл архиватором (например 7zip). Внутри видим файл setup.exe, извлекаем его, открываем архиватором. Внутри видим два файла vc_masm.msi,vc_masm1.cab. Извлекаем файл vc_masm1.cab, открываем архиватором. Внутри видим файл FL_ml_exe_____X86.3643236F_FC70_11D3_A536_0090278A1BB8. Переименовываем его в файл fl_ml.exe, далее, произведём ассемблирование файла prog11.asm, используя ассемблер fl_ml.exe.
MASM в Visual Studio
Также MASM можно найти в папке с Visual Studio (у меня VS 10) вот здесь: C:Program FilesMicrosoft Visual Studio 10.0VCbinml.exe.
Для того, чтобы запустить на 32- или 64-разрядной системе и создавать программы, работающие как под 32-, так и под 64-разрядной Windows, подходит MASM32 (ml.exe, fl_ml.exe). Для того, чтобы работать на 32- и 64-разрядных системах и создавать программы, работающие под 64-разрядной Windows, но неработающие под 32-разрядной нужен ассемблер ml64.exe. Лежит в папке C:Program FilesMicrosoft Visual Studio 10.0VCbinamd64 и вот здесь — C:Program FilesMicrosoft Visual Studio 10.0VCbinx86_amd64.
Программный пакет компании Borland, предназначенный для разработки программ на языке ассемблера для архитектуры x86. В настоящее время Borland прекратила распространение своего ассемблера.
Скачать можно, например, здесь. Инсталлятора нет, просто извлекаем программу. Вот исходник из книги Питера Абеля (рис. 3.2) «Язык Ассемблера для IBM PC и программирования».
Выполним ассемблирование (трансляцию) файла abel32.asm.
Корректность работы программы можно проверить, произведя линковку (tlink.exe) объектного файла и запустив полученный файл в отладчике.
Как было сказано выше, MASM можно использовать для работы с 16-битными программами. Выполним ассемблирование (трансляцию) программы abel32.asm с помощью ассемблера MASM:
Ключ /coff здесь не используется.
Линковка производится файлом link16.exe
В статье Криса Касперски «Сравнение ассемблерных трансляторов» написано, что «FASM — неординарный и весьма самобытный, но увы, игрушечный ассемблер. Пригоден для мелких задач типа „hello, world“, вирусов, демок и прочих произведений хакерского творчества.»
Скачаем FASM с официального сайта. Инсталлятора нет, просто извлекаем программу. Откроем fasm editor — C:fasmfasmw.exe. В папке C:fasmEXAMPLESHELLO есть файл HELLO.asm.
Откроем файл HELLO.asm из fasmw.exe. Изменим строку include ‘win32ax.inc’ на строку include ‘c:fasmINCLUDEWIN32AX.INC’. Запускаем из меню Run → Run.
Вот ссылки на ресурсы, посвященные FASM:
Для того, использовать FASM в Linux (у меня Ubuntu), скачаем соответствующий дистрибутив (fasm-1.71.60.tgz), распакуем его, в папке у нас будет бинарный файл fasm, копируем этот файл в /usr/local/bin для того, чтобы можно было запускать его из консоли, как любую другую команду.Выполним ассемблирование программы hello.asm из папки fasm/examples/elfexe/hello.asm.
Корректность работы программы можно проверить в отладчике.
Nasm успешно конкурирует со стандартным в Linux- и многих других UNIX-системах ассемблером Gas.
Nasm в Linux можно установить его с помощью менеджера пакетов или из командной строки: в дистрибутиве Debian (Ubuntu) командой apt-get install nasm, в дистрибутивах Fedora, CentOS, RedHat командой yum install nasm.
Создадим программу, которая 5 раз выводит сообщение “Hello”. Пример взят из книги Андрея Викторовича Столярова “Программирование на языке ассемблера NASM для ОС UNIX”. Учебник, а также библиотека “stud_io.inc” есть на личном сайте автора.
Выполним ассемблирование и линковку и запустим файл hello.asm.
NASM для Windows можно установить, скачав соответствующий дистрибутив с соответствующего сайта.
Ссылки на ресурсы, посвященные Nasm:
Стандартный ассемблер практически во всех разновидностях UNIX, в том числе Linux и BSD. Свободная версия этого ассемблера называется GAS (GNU assembler). Позволяет транслировать программы с помощью компилятора GCC.
Из учебников удалось найти только книгу на английском «Programming from the ground up». На русском удалось найти только одну главу из книги С. Зубкова «Assembler для DOS, Windows и UNIX».
Возьмем пример программы, которая ничего не делает, с сайта. Создадим программу gas.s
Выполним ассемблирование (трансляцию), линковку и запуск программы:
Если в данной программе изменить _start на main, то можно выполнить ассемблирование (трансляцию) и линковку компилятором gcc.
Выполним ассемблирование (трансляцию), линковку и запуск программы:
Выводы: если вы изучаете программирование под Windows, то вы можете остановить свой выбор на Masm; Tasm больше не поддерживается, но для обучения по старым классическим учебникам подойдёт.
Под Linux Gas подойдет тем, кто использует GCC, а тем, кому не нравится синтаксис Gas, подойдёт Nasm.
Источник
Assembler. Установка интерпретатора и запуск первой программы через DOSBox
В данной статье разбирается способ установки интерпретатора и запуск файла EXE через DOSBox. Планировалось погрузить читателя в особенности программирования на TASM, но я согласился с комментаторами. Есть много учебников по Ассемблер и нет смысла перепечатывать эти знания вновь. Лично мне в изучении очень помог сайт av-assembler.ru. Рекомендую. В комментариях также вы найдёте много другой литературы по Assembler. А теперь перейдём к основной теме статьи.
Для начала давайте установим наш старенький интерпретатор.
Ссылка
Почему именно vk.com?
Я прекрасно понимаю, что это ещё тот колхоз делиться файлами через обсуждения VK, но кто знает, во что может превратиться эта маленькая группа в будущем.
После распаковки файлов, советую сохранить их в папке Asm на диск C, чтобы иметь меньше расхождений с представленным тут материалом. Если вы разместите директорию в другое место, изменится лишь путь до файлов, когда вы будете использовать команду mount.
Для запуска интерпретатора нам так же потребуется эмулятор DOSBox. Он и оживит все наши компоненты. Скачаем и установим его!
Ссылка
В папке Asm я специально оставил файл code.asm. Именно на нём мы и потренируемся запускать нашу программу. Советую сохранить его копию, ибо там хранится весь код, который в 99% случаев будет присутствовать в каждом вашем проекте.
Итак. Запускаем наш DOSBox и видим следующее:
Для простоты сопоставим имя пути, по которому лежит наша папка Asm. Чтобы это сделать, пропишем следующую команду:
Здесь вместо d: мы можем использовать любую другую букву. Например назвать i или s. А C это наш реальный диск. Мы прописываем путь до наших файлов ассемблера.
Теперь, откроем смонтированный диск:
Прописав команду dir, мы сможем увидеть все файлы, которые там хранятся. Здесь можно заметить и наш файл CODE с расширением ASM, а также дату его создания.
И только теперь мы начинаем запускать наш файл! Бедные программисты 20 века, как они только терпели всё это? Пропишем следующую команду:
После мы увидим следующее сообщение, а наша директория пополнится новым файлом с расширением OBJ.
Теперь пропишем ещё одну команду:
В нашей папке появилась ещё пара файлов – CODE.MAP и CODE.EXE. Последний как раз и есть исполняемый файл нашего кода assembler.
Если он появился, значит, мы можем запустить режим отладки нашей программы, введя команду последнюю команду. Обратите внимание, теперь мы не указываем расширение файла, который запускаем.
Этот старинный интерфейс насквозь пропитан духом ушедшей эпохи старых операционных систем. Тем не менее…
Нажав F7 или fn + F7 вы сможете совершить 1 шаг по коду. Синяя строка начнёт движение вниз, изменяя значения регистров и флагов. Пока это всего лишь шаблон, на котором мы потренировались запускать нашу программу в режиме дебага. Реальное “волшебство” мы увидим лишь с полноценным кодом на asm.
Небольшой пример для запуска
Прога проверяет, было ли передано верное число открывающих и закрывающих скобок:
Давайте ознакомимся с имеющимися разделами.
Code segment – место, где turbo debug отражает все найденные строки кода. Важное замечание – все данные отражаются в TD в виде 16-ричной системы. А значит какая-нибудь ‘12’ это на самом деле 18, а реальное 12 это ‘C’. CS аналогичен разделу “Begin end.” на Pascal или функции main.
Data segment, отражает данные, которые TD обнаружил в d_s. Справа мы видим их символьную (char) интерпретацию. В будущем мы сможем увидеть здесь наш “Hello, world”, интерпретируемый компилятором в числа, по таблице ASCII. Хорошей аналогией DS является раздел VAR, как в Pascal. Для простоты можно сказать, что это одно и тоже.
Stack segment – место хранения данных нашего стека.
Регистры
Все эти ax, bx, cx, si, di, ss, cs и т. д. – это наши регистры, которые используются как переменные для хранения данных. Да, это очень грубое упрощение. Переменные из Pascal и регистры Assembler это не одно и тоже, но надеюсь, такая аналогия даёт более чёткую картину. Здесь мы сможем хранить данные о циклах, арифметических операциях, системных прерываниях и т. д.
Флаги
Все эти c, z, s, o, p и т.д. это и есть наши флаги. В них хранится промежуточная информация о том, например, было ли полученное число чётным, произошло ранее переполнение или нет. Они могут хранить результат побитого сдвига. По опыту, могу сказать, на них обращаешь внимание лишь при отладке программы, а не во время штатного исполнения.
Маленькая шпаргалка для заметок:
mount d: c:asm – создаём виртуальный диск, где корень –папка asm
tasm code.asm – компилируем исходный код
tlink code.obj – создаём исполняемый файл
td code – запускаем debug
F7 – делаем шаг в программе
Буду ждать комментарии от всех, кому интересен Assembler. Чувствую, я где-то мог накосячить в терминологии или обозначении того или иного элемента. Но статья на Habr отличный повод всё повторить.
Источник
Turbo Assembler v.5.0 (TASM) для Windows 10
Сегодня многие современные приложения разрабатываются на языке программирования ассемблере. Для облегчения работы с данным софтом используется программный пакет TASM, речь о котором, собственно говоря, и пойдет в сегодняшнем обзоре. На нашем портале можно бесплатно скачать Turbo Assembler v.5.0 (TASM) для Windows 10 x32/x64 Bit. Перед загрузкой инструмента рекомендуем обязательно ознакомиться с его основными функциями и предназначением.
Описание и возможности
Программное обеспечение, обозреваемое в сегодняшней статье, может использоваться разработчиками в двух вариациях. Первый способ – ручной ввод различных команд программирования. Во втором случае речь идет об использовании удобного графического интерфейса, наделенного такими функциями:
Если вы не обладаете нужными знаниями в сфере разработки, нет никакого смысла загружать пакет на ПК. Инструмент предназначен для программистов.
Как установить
Обозреваемый сегодня софт является сложным и многофункциональным инструментом для разработки различных приложений. Для того чтобы освоить все функции пакета, необходимо пройти специальные курсы или хотя бы просмотреть обучающие видеоролики в сети. Несмотря на всю сложность утилиты, инсталляция ее проходит по стандартному сценарию. Для этого делаем следующие шаги:
При первом запуске программного обеспечения видим, что интерфейс на английском языке. Изменить его можно в разделе «Option», перейдя в папку «General».
Достоинства и недостатки
Теперь самое время разобраться с сильными и слабыми аспектами пакета для программирования. Сделаем это в виде небольших списков.
Похожие приложения
Назовем еще несколько интересных решений, используемых в сфере разработки:
Системные требования
Приложение имеет относительно невысокие требования к параметрам электронной машины. Рассмотрим эти рекомендации немного подробнее:
Скачать
Осталось лишь кликнуть по ссылке и начать использование клиента для программирования на ПК.
Версия: | v.5.0 |
Разработчик: | Borland |
Информация обновлена и актуальна на: | 2022 год |
Название: | Turbo Assembler |
Операционная система: | Microsoft Windows 32/64 Бит |
Язык: | Русский |
Лицензия: | Бесплатно |
Вопросы и ответы
Всего несколько простых шагов и удобная утилита для разработки в вашем полном распоряжении. Надеемся, трудностей с использованием софта у вас не возникнет. Если вопросы появятся, задать их можно специалистам портала через форму обратной связи, расположенную внизу.
Источник
GUI Turbo Assembler 5.0 (TASM) для Windows 10
Инструмент, о котором мы расскажем в этом материале, представляет собой программный пакет, используемый для разработки различного софта на языке ассемблера. Предлагаем бесплатно скачать GUI Turbo Assembler 5.0 (TASM) для Windows 10 x32/x64 Bit и познакомиться с данным продуктом ближе. По уже имеющейся на сайте традиции разберемся с возможностями утилиты, сразу после чего поговорим о ее загрузке и инсталляции на компьютер или ноутбук.
Описание и возможности
Программное обеспечение может использоваться как специалистами для полноценной работы, так и новичками для обучения. Приложение включает полноценную справочную систему, где можно найти ответы на все интересующие вас вопросы по теме. Графический интерфейс инструмента для программирования довольно простой и симпатичный. Работать с ним вполне комфортно. К ключевым возможностям можно отнести:
Утилита часто применяется для обучения программированию на языке ассемблере. Для расширения функций программы используются наборы дополнительных макросов.
Как пользоваться
Скачивание и установка приложения проводится довольно быстро и легко. Для этого не понадобится каких-то особых знаний и умений. Читайте инструкцию и выполняйте каждый ее шаг.
Загрузка и установка
Перед загрузкой утилиты важно понимать, что она относится к сложным и многогранным инструментам. Перед началом работы с ней потребуется пройти соответствующее обучение. Но для начала давайте произведем инсталляцию программы на компьютер. Для этого делаем следующее:
TASM в вашем полном распоряжении. Можно смело переходить к изучению и использованию программного обеспечения.
Инструкция по работе
Конечно же, в двух словах описать принципы работы с утилитой не получится. Для полного освоения софта вам потребуется не один день. Единственное, на чем хотелось бы сделать акцент, это то, что ввод, редактирование или копирование кодов здесь осуществляется через удобную панель. На этой же панели расположены основные клавиши для тестирования и запуска готового проекта. Кроме этого, в разделе настроек пользователь может изменить конфигурацию графического интерфейса или воспользоваться некоторыми дополнительными функциями.
При желании изучить все функции программного обеспечения можно почитать обучающую литературу по данной теме или просмотреть видео в сети.
Достоинства и недостатки
Пришло время уделить внимание рассмотрению сильных и слабых сторон приложения, о котором мы говорим сегодня.
Похожие приложения
В качестве среды разработки на ПК или ноутбуке можно также использовать такие решения:
Системные требования
Назовем рекомендуемые параметры электронной машины для стабильной работы софта:
Скачать
Прямо сейчас у вас есть возможность получить желаемый инструмент на свой ПК по ссылке ниже.
Версия: | 5.0 |
Разработчик: | Borland |
Информация обновлена и актуальна на: | 2022 год |
Название: | GUI Turbo Assembler |
Платформа: | Microsoft Windows XP, 7, 8 или 10 |
Язык: | Русский |
Лицензия: | Бесплатно |
Пароль к архиву: | bestsoft.club |
Видеообзор
Начните изучение программы с этого небольшого ролика. Уверены, он будет полезным для вас.
Вопросы и ответы
Теперь вы можете смело переходить к практике и устанавливать приложение на ПК. Если в процессе этого появятся трудности, мы всегда рады помочь советом. Достаточно лишь описать проблему через форму обратной связи ниже.
Источник
Tasm Windows 7|Windows 8|8.1 Full Screen 32bit-64bit Version Single Installer Updated Fullscreen
Share
But However it doesn’t work / supports the 64 bits of Windows i.e Windows 7 64 bit / Windows 8 Version, so i have created a separate configured Version of the software for the same purpose.,it will run smoothly,with fullscreen mode and has many features such as
Installation Guide
First of all You Need To Download The TASM from above link- >
Now Launch The Software by the Tasm 1.4 Shortcut Present on your Desktop..
Here are the Basic Function Commands of Tasm are same as that of normal version like
First make sure the screen is showing : C:Tasm> in Dos Command
Now, To Open MS-Dos Editor Type :
edit “yourfilename.extension” and it will open
check the Below screenshot
To Perform Tasm,Tlink And Execution Debugging
The Same commands are used
For Compiling : tasm “filename.asm” [without quotes]
for Linking : tlink “filename.obj” [without quotes]
For Debugger : simply “td” [without quotes] or you can use td “filename” [without quotes]
For Execution : filename.exe
here are the screenies for the above functions
Support
Источник
64-разрядная архитектура ворвалась в нашу жизнь как торнадо, затягивая в себя всё больше инженеров и прикладных программистов. Новые термины стали появляться как грибы после дождя, а давать им толкового объяснения никто не торопился. В данной статье рассматриваются фундаментальные основы кодинга на платформах Win64, с реальными примерами в отладчике.
Оглавление:
1. Вводная часть;
2. Организация памяти в режиме “Long-mode” х64;
3. Доп.регистры GPR и префикс REX;
4. RIP-относительная адресация;
5. Соглашение “Fast-Call” – быстрый вызов функций;
6. Заключение.
1. Вводная часть
С обзором архитектур связано и без того множество нестыковок, а выход на сцену в 2003 году 64-битных ОС ещё больше усугубил ситуацию. Более того, в результате модификаций одних и тех-же инженерных решений, в литературе встречаются и синонимы, которые сбивают логическую нить. Так-что сразу обозначим здесь основные моменты..
1.1. Первое, на что стоит обратить внимание – это названия архитектур процессоров, согласно их разрядности. Так, на данный момент 64-битная от AMD называется AMD64, а в закрытых офисах Intel отдали предпочтение имени Intel-64. И тут нас ожидает мозговой штурм!
Дело в том, что на заре 64-бит эры Intel окрестила свою архитектуру как IA-32e, всего-то добавив к привычной аббревиатуре литер(е) “Extended”, расширенный. Но на презентации критики посчитали такое название не отражающим разрядность в 64-бит, и буквально спустя год монархи переименовали её в EM64T – теперь это звучит громко и подразумевает «Extended Memory 64 Technology». Такой зоопарк имён привёл к тому, что имеем шесть разных названий одной и той-же архитектуры: х86-64, IA-32e, EM64T, Intel-64, AMD64, AA64 (последнее от «Amd Architecture»).
А вот что не вписывается ни в какие ворота, это когда Intel-64 обзывают как IA-64. Предположение в корне не верно, т.к. под IA-64 кроется «Itanium Architecture», которая никак не пересекается с Intel-64. Процессоры «Intel Itanium» имели ядро RISC (когда одну команду исполняют множество простых инструкций), а процессоры IA-32 построены уже на ядре CISC (подмножество простых инструкций собираются в одну сложную). Написанные для процессоров Itanium приложения не будут работать на Intel-64, и наоборот.
1.2. Второй момент – это режимы работы 64-битных процессоров, с которыми мы не раз столкнёмся в данном треде. Согласно докам их всего три, и программное обеспечение ОС переключает эти режимы при помощи битов в модельно-специфичных регистрах MSR. От младшего к старшему следуют они в таком порядке:
• Legacy-mode. Унаследованный от древних 16/32-разрядных процессоров х86. Режим впитал в себя четыре моды: RM, SMM, VM, PM (Real, Sys-Management, Virtual, и Protected соответственно). Он был родным для отправленных на свалку истории Win2k и Windows-XP.
• Compatibility-mode. Режим совместимости х64 с х32. Процессор переключается в этот режим, когда на 64-бит платформе запускаются 32-бит приложения. Чтобы поддерживать совместимость со-старым софтом, инженерам пришлось заключить с ним мезальянс и тащить на себе всё это бремя вплоть до наших времён. Режим не поддерживает Virtual-моду унаследованного, поэтому софт реального режима RM в нём не работает. Со стороны ОС поддержка осуществляется технологией WOW64 (Windows on Windows).
• Long-mode. Родной для х64 режим с плоской организацией памяти Flat. Сегментация в привычном виде отсутствует. К восьми имеющимся добавлены ещё 8 регистров R8-R15 общего назначения GPR (General Purpose Registers), и разрядность всех 16-ти расширена с 32 до 64-бит. Написанный для х32 код должен быть перекомпилирован с учётом 64-битной архитектуры.
Вот несколько ссылок по теме на документацию Intel и AMD в формате *.pdf
Лично на мой взгляд доки от AMD предпочтительней, хотя выводы можно сделать только в сравнении:
—
Ссылка скрыта от гостей
документов Intel и AMD (SDM = Software Developer Manual, APM = AMD Programming Manual);
—
Ссылка скрыта от гостей
– описание архитектуры Intel-64 & IA-32;
—
Ссылка скрыта от гостей
– руководство по программированию для разработчиков;
—
Ссылка скрыта от гостей
– руководство по программированию процессоров AMD;
—
Ссылка скрыта от гостей
– описание архитектуры AMD64.
2. Организация памяти в режиме “Long-mode” х64
Нельзя назвать плавным переход на х64 – в архитектуру было внесено множество новых решений, и в большей степени это коснулось организации вирт.памяти. В связи с тем, что стало доступным огромное пространство, инженеры без зазрения совести просто удалили львиную долу системных механизмов. А ведь в этом есть смысл..
Вспомним, как на программном уровне представляется сегментная модель вирт.памяти в архитектуре IA-32.
Значит имеем общее пространство размером 4GB, которое делится на несколько сегментов – кода, данных, стека. Свойства их определяют 8-байтные дескрипторы, которые собраны в глобальную таблицу GDT – Global Descriptor Table.
В самих 16-битных сегментных регистрах CS,DS,ES,SS,FS,GS лежат селекторы с полем индекса (порядкового номера) соответствующих дескрипторов в таблице GDT. При этом 3-младших бита в селекторах обнуляются (биты RPL и TI), так-что индекс всегда кратен 8-ми, по размеру дескриптора. Непосредственно в дескрипторах указывается уже тип сегмента, его базовый адрес, размер (лимит), и атрибуты защиты.
Теперь начнём с того, что расширенные до 64-бит регистры позволяют адресовать линейную память размером: 2^64=16 эксаБайт, или 16 млн.тераБайт. Если даже взять самое тяжеловесное в природе приложение, в таком объёме оно тупо потеряется и будет занимать порядка 0.001%. Зато системные расходы на её поддержку выйдут за рамки разумного: как-минимум потребуется таблица страниц «PageTable» исполинских размеров, и соответственно на поиск адреса в ней уйдёт больше времени.
Поэтому инженеры ограничили указатель на вирт.память 48-битами, в результате чего аппетиты системы поубавились до 256 тераБайт, хотя моя Win7-х64 использует только 16 из них (8 приложениям, 8 ядру), а Win10 юзает уже на полную катушку 256. В то-же время, во-внешней шине памяти под адрес отводится итого меньше: всего 40-бит, что влечёт за собой поддержку мат.платами физической DDR общим размером в 1 тераБайт. Сомневаюсь, что у большинства из нас установлено хотя-бы 64 гига из них, но видимо у инженеров далеко идущие планы. В итоге имеем макс.256ТБ виртуальной, и до 1ТБ физ.памяти. На этом фоне потолок IA-32 в 4ГБ кажется ничтожно малым.
Такой расклад навёл инженеров на мысль, что пришло время вообще избавиться от устаревшей сегментной модели, ведь памяти теперь предостаточно и располагай хоть 1000 программных секций следом, одна за другой. Они приняли идею с энтузиазмом, и наконец затенили три сегментных регистра DS,ES,SS. Три оставшихся CS,FS,GS на костылях всё-же функционируют, но и в их дескрипторах игнорируются все поля, кроме атрибутов. Отменим, что полностью изкоренить сегментную модель нельзя – она жёстко прошита в CPU на аппаратном уровне. Придётся в корне менять микро-архитектуру CPU, что приведёт к краху пока ещё держащихся на плаву 32-бит приложений. Может на следующем витке эволюции, но не на этом точно.
В доках AMD имеется фрагмент ниже, где серым обозначены игнорируемые биты. Здесь видно, что размер дескрипторов как и прежде остался 8-байт, а база, лимит и некоторые атрибуты, отправлены инженерами в утиль. Как только процессор переходит в режим Long-mode, база во-всех сегментных регистрах выставляется в нуль, а лимит на 48-битный максимум. О том, что это дескриптор 64-битного сегмента, свидетельствует взведённый бит(21) под ником(L). Если-же процессор находится в режиме совместимости с х32, бит(L) будет сброшен, все затенённые поля авто-активируются, и мы получаем обратно сегментную модель IA-32.
• Бит(D) – Default-Operand Size (размер операндов: 0=32, 1=64 бит);
• Бит(L) – Long mode (1=режим х64, 0=совместимости);
• Бит(P) – Present (1=сегмент загружен в память);
• Бит(DPL) – Descriptor Privilege Level (уровень кольца защиты 0-3);
• Бит(C) – Conforming (соответствие привилегий: 0=доступ напрямую, 1=через системный шлюз).
А вот с дескрипторами сегментных регистров FS и GS дела обстоят немного иначе.
Инженеры оставили их, чтобы использовать в качестве доп.базовых регистров при вычислении адреса. Базы этих сегментов могут иметь отличные от нуля значения, что облегчает доступ к определенным структурам системы. К примеру по адресу [GS:60h]
можно найти указатель на инфо-структуру TЕВ 64-битного потока (Thread Environment Block), под которую выделяется отдельный сегмент.
Поле базы FS и GS расширено до 64 бит, и хранится теперь не в самом дескрипторе (в нём уже нет места, см.скрин выше), а в MSR-регистрах IA32_FS_BASE
и IA32_GS_BASE
(см.доки Intel том.4). Проверить, что базы реально прописаны в MSR (а не в дескрипторах) можно при помощи CPUID.8000_0001
– запрос должен вернуть взведённый бит(29) в регистре EDX. Для чтениязаписи этих значений с уровня драйверов, были введены новые инструкции: rdfs(gs)base
и wrfs(gs)base
.
C-подобный:
mov eax,0x80000001 ;// IA32_FS_BASE support
cpuid ;// Requst..
bt edx,29 ;// Bit-Test
jnc @f ;// Jump no Carry flag
rdfsbase rax ;// Else: save FS-base to RAX
rdgsbase rbx ;// save GS-base to RBX
@@: nop
Модель плоской Flat памяти – это простейшая форма сегментации. Здесь базовые адреса всех сегментов имеют значение нуль, а лимиты выставлены на макс (хотя и в сегментной модели IA-32 мастдая можем наблюдать такую-же картину). Сброс базы ниже плинтуса фактически отключает трансляцию сегментов, и он охватывает всё пространство вирт.адресов – дескрипторы ссылаются теперь на этот единственный плоский сегмент.
Не нужно думать, что в модели Flat отсутствуют атрибуты защиты-доступа. Конечно-же они есть, только зарыты не в дескрипторах как прежде, а на более высоком уровне, в 64-битных записях РТЕ «Page Table Entry» системной таблицы-страниц. Если учесть, что большие сегменты всегда чекаются на мелкие 4К-страницы (привет своп вирт.памяти), то атрибуты этих страниц имеют приоритет над атрибутами в дескрипторах сегментов, поэтому механизм функционирует исправно. Надеюсь скрин прояснит выше-сказанное:
3. Расширенные регистры GPR и префикс REX
Теперь про регистры и логику обращения к ним..
Выше упоминалось, что инженеры не только расширили имеющиеся 32-битные регистры до 64-бит, но и удвоили их кол-во. Такой размах нужен для того, чтобы минимизировать обращения к сравнительно медленной памяти ОЗУ. Раньше, при отсутствии свободных регистров мы сохраняли данные в стек, для чего контролёру нужно было сначала дождаться освобождения внешней шины, и лишь потом за’PUSH’ить содержимое регистра в стековую память.
Именно поэтому в процессор был добавлен кэш, куда сбрасывались все последние обращения к ОЗУ. То-есть следующий PUSH уже не запрашивал шину, а обращался к 64-байтной линейке кэш. И регистры CPU, и кэш построен на одном типе памяти – статической SRAM (на триггерах, а не как DRAM на конденсаторах), поэтому никаких задержек при обмене данными ядра с кэшем не возникает.
В таблице ниже видно, что инженеры породили 8 новых векторных AVX-регистров: YMM8-YMM15 (Advanced Vector Extensions), такое-же число потоковых SSE: XMM8-XMM15 (Streaming SIMD Extensions), и бонусом 8 регистров общего назначения GPR: R8-R15 (General Purpose Registers). В последних процессорах регистры AVX расширены до 512-бит (AVX512) и ожидается увеличение их разрядности вплоть до 1024-бит. Для поддержки таких монстров кол-во регистров AVX было увеличено с 16 до 32-х, и называются они теперь ZMM0-ZMM31. В столбце «Бит» данной таблицы указана разрядность одного регистра:
Обратите внимание, что регистры MMX являются частью 80-битных регистров сопроцессора FPU, занимая в них младшие 64-бита мантиссы так, что для инструкций MMX остаётся исключительно целочисленная арифметика, без дробной части. При таком раскладе, в любой момент времени (внутри одного блока кода) мы можем использовать или регистры FPU, или MMX, но не оба сразу – в противном случае получим винегрет из данных.
Чтобы решить эту проблему, инженеры ввели независимый от FPU пул 128-битных регистров SSE, который позже был расширен до 256-бит AVX. Здесь наблюдаем аналогичную картину, когда SSE живут внутри AVX. Соответственно их инструкции так-же нельзя комбинировать. Отличительной особенностью SSEAVX является доступность им операций как со-скалярными числами (тогда инструкции заканчиваются на «ss», scalar), так и с упакованными (окончание «ps», packet) – это значительно расширяет область их применения. А вообще в эти регистры можно пихать любые типы данных:
Обратим свой взор на упакованный формат. Это четыре отдельных 32-битных числа с плавающей запятой (одинарной точности), над которыми за теоретический такт процессора можно произвести независимые вычисления. На аналогичную операцию сопр FPU потратил-бы в 4 раза больше времени! Основным требованием здесь является «правильная» организация массива данных (в виде непрерывного потока Stream), и обязательное выравнивание массива на 8-байтную границу (для скалярных типов это не принципиально). Типичный пример использования фишки – 3D графика.
Инструкции AVX пошли ещё дальше, и могут иметь уже не два, а тричетыре операнда для тех случаев, когда значения операндов-источников нужно сохранить для последующих вычислений. К таким инструкциям привязывается не рассматриваемый здесь префикс «VEX».
А вот как выглядят «мемберы» новых регистров общего назначения GPR.
Четыре первых регистра RAX..RDX как и прежде позволяют обращаться к любым своим частям, в том числе и к старшим байтам 16-битных слов AH..DH. Как видно из рисунка, в регистрах R8..R15 это поле уже отсутствует, и мы можем использовать лишь мл.байты слов R8b..R15b. Непонятно зачем были добавлены и мл.байты индексных + базовых регистров под никами SIL..SPL, которых не было в IA-32. Видимо просто в поле «Opcode» инструкций оставались свободные биты. Указатель RIP остался в девственном виде, с мин.значением в 16-бит. Интересным моментом является то, что запись 32-битных значений в 64-бит регистры всегда обнуляет старшую их часть:
3.1. Назначение префикса REX
Теперь спустимся в тёмные подвалы микро-архитектуры и рассмотрим, как кодируются инструкции в 64-битном коде. Для этого откроем доку Intel том(2) «Instruction Set Reference», где на стр.35 представлен формат ниже.
Значит макс.размер инструкции составляет 15-байт, из которых обязательно лишь поле «Opcode». Этот код операции ограничен разрядность 24-бита (три байта), а если их не хватает, то инструкция «отжимает» биты[5:3] у следующего поля «Mod R/M». Итого получаем 27-битный опкод, в которых можно закодировать 134 лярда теоретических инструкций. Впечатляет..
Далее идёт байт «SIB» – он кодирует регистры при относительной адресации, например конструкцию с базой и индексом [EBX+ESI]
, или при обращениях к стековому фрейму [EBP+8]
. В последнем случае значение(8) считается отклонением и хранится в поле «Displacement». Адрес может вычисляться и в более извращённой форме [EBX+4*ESI+2]
. Тогда значение(4) будет определять масштаб, под который отводятся 2-бита «Scale» байта SIB.
Последний дворд «Immediate» выделяется для непосредственных значений, типа число в арифметике, адрес вызываемой функции, и т.д. Обратите внимание, что два этих поля в режиме х64 не расширяются до 64-бит: они по-прежнему ограничены 32-битным числом со-знаком. Однако поддерживаются некоторые 64-бит смещения, и непосредственные формы инструкции MOV – в этом случае два этих поля объединяются.
Инструкции опционально могут иметь префиксы, а при обращении к 64-битным регистрам префикс «REX» является вообще обязательным. Он всегда занимает позицию после унаследованного Legacy-префикса, чтобы в режиме совместимости с IA-32 им можно было принебречь.
Старшая тетрада 1-байтного REX жёстко прошита значением 0100=4, а потому диапазон его значений лежит в пределах 40..4Fh. Младшая-же тетрада является флагами расширений так, что если в ней взведён старший бит(W), то операндом инструкции считается весь 64-бит регистр, а если он сброшен, только 8/16/32-битная его часть. Таким макаром, при обращении к регистрам RAX-R15 значения этого префикса будет большеравно 48h, иначе меньше. Оставшаяся триада с битами(RXB) конфискует перечисленные ниже поля в байтах «Mod R/M» и «SIB», чтобы в них можно было закодировать 64-битные регистры:
Посмотрим в отладчике х64Dbg на код, в котором я собрал обращения к разным частям 64-бит регистров: Byte, Word, Dword, Qword. Как видно из скрина, отладчик разделяет опкод от его префикса двоеточием. Первые 4 инструкции предваряются префиксом REX=48h
, значит их операндом является весь 64-бит регистр. Три байта 83.EC.08
первой строки занимают в инструкции поля «Opcode, ModR/M, Immediate» соответственно. Обратите внимание, что второй операнд(8) инструкции SUB не расширяется до 64-бит, хотя и был отправлен в регистр RSP. Инструкция по адресу 0х00401019 имеет уже 2-байтый префикс F3.48
, где Legacy(F3) олицетворяет повторение, а А5h – это опкод:
Начиная с адреса 0х00401020 видим запись значения(5) в младшие части 64-битного регистра R8.
Здесь уже бит REX.W сброшен, и его значение равно 41h < 48h. Соответственно инструкции оперируют байтом, вордом, и двордом, после чего REX опять перемещается в верхнюю половину тетрады 49-48h, и жизнь налаживается.
А вот инструкции SSE с регистрами XMM0-XMM15 вообще не используют префикс REX. Коды их операций занимают всё 3-байтное поле «Opcode», и как правило первым идёт байт 0Fh, в качестве управляющего Escape. Этот байт является флагом декодеру инструкций, что пора выходить из привычной зоны комфорта, и переключаться на регистры SSEAVX. Опкод 0Fh как псевдо-префикс используют и многие другие инструкции, например LFENCE=0F.AE.E8
, RDTSC=0F.31
, и прочие.
4. RIP-относительная адресация
Выше упоминалось, что поля «Displacement & Immediate» в Long расширяются до 64-бит только в исключительных случаях, придерживаясь старой политики x32. Тогда как процессору удаётся охватить всё плоское пространство в 256 тераБайт, ведь 32-бит указатель способен адресовать всего 4 гига?
Здесь инженеры нашли решение, которое заключается в неявной адресации памяти, относительно указателя на сл.инструкцию RIP. Эффективный адрес получается суммированием 32-битного операнда (число со-знаком, играет роль смещения), и регистра RIP (база с текущим адресом). Результатом будет обращение по указателю RIP+2Gb вперёд, или назад. То-есть имеем уже знакомую нам схему: Scale+Index+Base.
Отшлифованная годами практика доказала, что чем дальше адрес отстоит от текущего значения RIP, тем меньше вероятность его применения. Это позволяет в 2-раза сократить разрядность адресов в командах. В случае, когда 32-битного смещения недостаточно, компилятор формирует полный 64-бит адрес, после чего опять возвращается к схеме с 32-бит. Такой подход практически ликвидировал главный недостаток кода х64 – большой размер исполняемых файлов.
В отличии от х64, архитектура х32 полностью ограничивала доступ к регистру EIP. Его нельзя было использовать в качестве базы при обращениях к памяти, нельзя запушить в стек, и вообще исключены любые операции с ним. Правда имелась возможность фиктивно запихать EIP в стек, и снять от туда в произвольный регистр инструкциями CALLPOP, но это хак, и юзался он в основном малварью для вычисления дельты в шелл-кодах. С переходом на х64 инженеры сняли запрет лишь на RIP-адресацию, а остальные замки так и остались висеть закрытыми. Вот несколько примеров доступных операций в 64-бит режиме (RIP всегда указывает на сл.инструкцию):
C-подобный:
.code
start: push rip ;// Ошибка! Invalid Operand.
mov rax,rip ;// Ошибка! ^^^^
mov rax,[rip+rbp] ;// Ошибка! ^^^^
jmp rip ;// Ошибка! ^^^^
jmp qword[rip] ;// ОК! Перейти по адресу в RIP
dq $+8 ;// ....(адрес перехода, нацелен на call)
call @f ;// ОК! Адрес возврата в стеке -------------+
@@: pop rax ;// ОК! RAX = текущее значение RIP <--------+
mov rbx,$ ;// ОК! RBX = текущее значение RIP
mov rcx,[rip] ;// ОК! RCX = qword с текущего адреса RIP
mov rdx,[rip+100h] ;// ОК! RDX = RIP-относительное чтение адреса
5. Соглашение о вызове “Fast-Call” – быстрый вызов функций
Узким местом в архитектуре была и остаётся оперативная память ОЗУ. При любых обращениях к ней CPU тратит огромное кол-во своих тактов отстукивая в холостую, пока запрашиваемые данные не скопируются из ОЗУ в кэш. Все контролёры памяти имеют параметр «Burst-Length». Он определяет кол-во повторений чтения, при открытой DRAM-строке. Как правило BL=8 и разрядность шины = 64-бит, или 8-байт. Поэтому контролёр читает память в пакетном режиме сразу минимум по: 8х8=64 байт, которые принимает кэш в виде одной «Cache-Line». Размер кэш-линейки своего процессора можете подсмотреть в программе CPU-Z:
Теперь как нам предлагают вызывать функции WinAPI 32-битные системы?
Они используют соглашение _stdcall (standart), когда все аргументы функции передаются через стек, справа-налево. После того-как функция отработает, на выходе она сама должна очистить свой стековый фрейм от аргументов. Системные WinAPI делаю это инструкцией RET 4*(кол-во аргументов)
. Вот пример:
Основным недостатком данного соглашения является активное использование стека, ведь PUSH это реальный запрос к внешней памяти ОЗУ, что влечёт за собой падение производительности. С учётом этих проблем, в 64-битных системах Win применяется другой тип вызова _fastcall (быстрый). Здесь 4 первых аргумента передаются через регистры RCX,RDX,R8,R9, а если функция ожидает больше аргументов, то остальные как и прежде – через стек. Использование регистров для засылки аргументов полностью ликвидирует связанные в памятью задержки, а потому вызов осуществляется намного быстрее. Листинг запроса той-же функции представлен ниже:
С быстрым вызовом связана пара нюансов:
• Аргументы передаются в обратном порядке слева-направо. Если на скринах выше сравнить их в последнем столбце то видно, что порядок их обратный.
• Обратите внимание на конструкцию subadd rsp,20
, которая берёт в контейнер непосредственный вызов функции. Так индусы из Microsoft по-старинке резервируют место в стеке для четырёх аргументов не смотря на то, что и находятся они теперь в регистрах RCX,RDX,R8,R9.
В данном случае функция имеет 4 аргумента, поэтому в резерв уходят 4х8=32-байта, или 20h. Если у функции аргументов больше (например 7), то оставшиеся три помещаются в стек. Здесь компилятор зарезервирует уже 7х8=56, плюс 8-байт под адрес-возврата, итого 64=40h. Причём резервосвобождение фреймов нам нужно предусматривать перед вызовом каждой функцией, что сильно напрягает. По сути это то, что называется «стек очищает вызывающий», в отличии от stdcall, где очисткой фрейма от оставшегося мусора озадачена сама функция. Вот пример последовательного вызова MessageBox() и CreateFile() с семью аргументами:
В компиляторе FASM имеется огромное кол-во умных макросов, среди которых есть и парочка frameendf. Они специально были написаны разработчиком продукта Томашом Грыштаром, чтобы привести бинарник в более приглядный вид, удалив из него этот бессмысленный резерв фреймов на входе и выходе из каждой функции. По мнению автора лучше один раз выделить большой фрейм, чем несколько раз мелкие.
Fasm относится к многопроходным компиляторам. На первом проходе транслятор вычисляет в исходнике API-функцию с наибольшим числом аргументов, и по их кол-ву сразу выделяет соответствующий фрейм. Теперь все функции, которые находятся внутри макросов frameendf будут использовать для своих нужд этот общий фрейм. Такая конструкция выглядит более логичной, чем неоптимизированная в дефолте. Вот пример и то, что получим в результате:
C-подобный:
.code
start:
nop
frame
invoke MessageBox,0,szHello,szCapt,0
nop
invoke CreateFile,path, GENERIC_READ + GENERIC_WRITE,
FILE_SHARE_READ + FILE_SHARE_WRITE,
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
endf
nop
Значит первой строкой sub rsp,8
компиль выравнивает стек на 16-байтную границу, что является обязательным для кода х64. Причём делает он это на автомате (без нашего участия), при помощи макросов из инклуда «win64ax.inc». Далее идёт NOP и следом резервируется стековый фрейм сразу для обоих API-функций, по кол-ву аргументов CreateFile(). Как видим, после MessageBox() фрейм уже не возвращается системе, и остаётся активным до конца. Макросами frameendf
можно оборачивать весь код, или отдельные его блоки.
А в остальном программирование в х64 ничем не отличается от х32. Радует то, что наделённые разумом макросы делают за нас всю черновую работу, если только код наш не маргинальный, с стиле проприетарного call
в место invoke
. Тогда можно запросто нарваться на повсюду разбросанные шипы, то как выравнивание стека, последовательность аргументов и многое другое. Просто подключайте инклуд «win64ax.inc», и всё будет пучком.
Под занавес приведу небольшой пример, в котором соберу всё выше-сказанное. Вот его алго:
• GetVersionEx() в структуру «OSVERSIONINFO» возвращает версию системы:
C-подобный:
struct OSVERSIONINFOA
dwOSVersionInfoSize dd sizeof.OSVERSIONINFOA
dwMajorVersion dd 0
dwMinorVersion dd 0
dwBuildNumber dd 0
dwPlatformId dd 0
szCSDVersion rb 128
ends
• GlobalMemoryStatusEx() возвращает основную инфу о системной памяти.
Функция с одним аргументом, и ожидает указатель на структуру «MEMORYSTATUSEX»:
C-подобный:
struct MEMORYSTATUSEX
dwLength dd sizeof.MEMORYSTATUSEX
dwMemoryLoad dd 0 ;// занятая физ.память в процентах
dwTotalPhys dq 0 ;// всего физической
dwAvailPhys dq 0 ;// ..(свободно)
dwTotalPageFile dq 0 ;// размер файла-подкачки
dwAvailPageFile dq 0 ;// ..(свободно)
dwTotalVirtual dq 0 ;// всего виртуальной
dwAvailVirtual dq 0 ;// ..(свободно)
dwAvailExtVirtual dq 0 ;// резерв.
ends
• Использование инструкций SSE с регистрами XMM, для перевода величин в формат с плавающей точкой.
• printf() из msvcrt.dll для вывода данных на консоль.
• В качестве примера – оформление и вызов собственных процедур с 8 аргументами, по соглашению «fastcall».
Выше говорилось, что инструкцией sub rsp,20h
компилятор уже выделяет фрейм в стеке, как-минимум для четырёх аргументов. Поэтому если мы планируем вызов системных API из своей процедуры, то должны заранее сохранить в этот выделенный фрейм регистры RCX,RDX,R8,R9, где им собственно и место. Иначе вызываемая API затерёт их под себя, и наши аргументы отправятся к праотцам:
C-подобный:
format pe64 console
include 'win64ax.inc'
entry start
;//-----------------
section '.data' data readable writeable
osVer OSVERSIONINFOA
ms MEMORYSTATUSEX
szHelp db 'This is Long-mode "_fastcall" proc example.',0
szCapt db 'CPU registers dump & Function virtual address.',10,0
gb dq 1024 shl 20 ;//1024 x 1024 x 1024
doubleA dq 0
doubleB dq 0
buff dd 0
;//-----------------
section '.code' code readable executable
start:
frame ;//<---- Волшебный макрос
invoke SetConsoleTitle,<'System memory info',0>
mov dword[osVer],sizeof.OSVERSIONINFOA
invoke GetVersionEx, osVer
invoke GlobalMemoryStatusEx, ms
;//------------- Версия Windows.
;// printf() поместит в RCX первый свой аргумент в виде строки спецификаторов,
;// поэтому начинаем передавать аргументы со-второго RDX
mov edx,[osVer.dwMajorVersion] ;// запись 32-бит обнуляет старшую часть 64-бит регистра
mov r8d,[osVer.dwMinorVersion]
mov r9d,[osVer.dwBuildNumber]
mov r10d,osVer.szCSDVersion
cinvoke printf,<10,' Microsoft Windows [Version: %d.%d.%d. %s]',10,0>,
rdx,r8,r9,r10
;//------------- Физической памяти
mov rdx,[ms.dwTotalPhys] ;// всего
shr rdx,20 ;// ..(в Мбайтах)
mov r8,[ms.dwAvailPhys] ;// свободно
shr r8,20 ;// ..(в Мбайтах)
mov r9,100 ;// ...и в процентах
sub r9d,[ms.dwMemoryLoad]
cinvoke printf, <10,
' Physical memory',10,
' -------------------------',10,
' Total : %5d Mb',10,
' Free : %5d Mb = %d%%',10,10,0>,rdx,r8,r9
;//------------- Файл подкачки
movsd xmm0,[ms.dwTotalPageFile]
divsd xmm0,[gb] ;// в гигабайтах
movsd [doubleA],xmm0
movsd xmm0,[ms.dwAvailPageFile]
divsd xmm0,[gb]
movsd [doubleB],xmm0
mov rdx,[doubleA]
mov r8, [doubleB]
cinvoke printf, <' PageFile',10,
' -------------------------',10,
' Total : %5.2f Gb',10,
' Free : %5.2f Gb',10,10,0>,rdx,r8
;//------------- Виртуальная
movsd xmm0,[ms.dwTotalVirtual]
divsd xmm0,[gb]
movsd [doubleA],xmm0
movsd xmm0,[ms.dwAvailVirtual]
divsd xmm0,[gb]
movsd [doubleB],xmm0
mov rdx,[doubleA]
mov r8, [doubleB]
cinvoke printf, <' Virtual memory',10,
' -------------------------',10,
' Total : %.2f Gb',10,
' Free : %.2f Gb',10,0>,rdx,r8
endf
;//------------- Вызов своей процедуры с 8 аргументами
fastcall Convert,szHelp,szCapt,rax,rbx,
r10,[printf],[SetConsoleTitle],[GlobalMemoryStatusEx]
cinvoke getch
cinvoke exit,0
;//-----------------------------
proc Convert a,b,c,d,e,f,h,g
mov [a],rcx
mov [b],rdx
mov [c],r8
mov [d],r9
cinvoke printf,<10,10,' ---> %s',10,' ---> %s',
10,' RAX: 0x%016I64x',
10,' RBX: 0x%016I64x',
10,' R10: 0x%016I64x',10,
10,' 0x%016I64x <-- printf() address',
10,' 0x%016I64x <-- SetCosoleTitle() address',
10,' 0x%016I64x <-- GlobalMemoryStatusEx() address',10,0>,
[a],[b],[c],[d],[e],[f],[h],[g]
ret
endp
;//-----------------
section '.idata' import data readable
library kernel32, 'kernel32.dll',msvcrt, 'msvcrt.dll'
import kernel32, GlobalMemoryStatusEx,'GlobalMemoryStatusEx',
SetConsoleTitle,'SetConsoleTitleA',GetVersionEx,'GetVersionExA'
import msvcrt, printf,'printf',getch,'_getch',exit,'exit'
Посмотрим на выхлоп функции GlobalMemoryStatus().
Моя тестовая машина с 64-битной семёркой на борту вполне себе сносно функционирует даже при 1.5 ГБ физ.памяти. И это при том, что запущен браузер Хром с несколькими вкладками, тотал, офис и фотошоп. В файле-подкачки свободен гиг, а виртуальной 8 тераБайт для приложений, и столько-же для ядра.
А вот логи десятки..
Из четырёх физических доступен всего один, но и этого ей недостаточно, т.к. шесть из десяти в подкачке занято. Зато виртуальной хоть отбавляй, аж 128 ТБайт, только юзать их (кроме игр) как-правило некому. Все системные либы грузятся в верхнюю область пользовательского 48-бит пространства, хотя на семёрке Kernel32.dll тусуется где-то между небом и землёй, по середине.
6. Заключение
Что-то букаф в треде получилось много, видимо пора заканчивать..
В скрепку кладу исполняемый *.exe для тестов, и файл «fasmw.ini» для тех, кто хочет поменять визуальную тему FASM’a на Black. У меня он установлен по-пути D:InstallFASM, а вам нужно открыть его в блокноте, и указать свой путь до инклуд. Сделайте бэкап оригинального *.ini на случай, если что-то пойдёт не так. Всем удачи, пока!
На сегодняшний день существует огромное количество языков программирования высокого уровня. На их фоне программирование на низкоуровневом языке — ассемблере — может на первый взгляд показаться чем-то устаревшим и нерациональным. Однако это только кажется. Следует признать, что ассемблер фактически является языком процессора, а значит, без него не обойтись, пока существуют процессоры. Основными достоинствами программирования на ассемблере являются максимальное быстродействие и минимальный размер получаемых программ.
Недостатки зачастую обусловлены лишь склонностью современного рынка к предпочтению количества качеству. Современные компьютеры способны легко справиться с нагромождением команд высокоуровневых функций, а если нелегко — будьте добры обновите аппаратную часть вашей машины! Таков закон коммерческого программирования. Если же речь идет о программировании для души, то компактная и шустрая программа, написанная на ассемблере, оставит намного более приятное впечатление, нежели высокоуровневая громадина, обремененная кучей лишних операций. Бытует мнение, что программировать на ассемблере могут только избранные. Это неправда. Конечно, талантливых программистов-ассемблерщиков можно пересчитать по пальцам, но ведь так обстоит дело практически в любой сфере человеческой деятельности. Не так уж много найдется водителей-асов, но научиться управлять автомобилем сумеет каждый — было бы желание. Ознакомившись с данным циклом статей, вы не станете крутым хакером. Однако вы получите общие сведения и научитесь простым способам программирования на ассемблере для Windows, используя ее встроенные функции и макроинструкции компилятора. Естественно, для того, чтобы освоить программирование для Windows, вам необходимо иметь навыки и опыт работы в Windows. Сначала вам будет многое непонятно, но не расстраивайтесь из- за этого и читайте дальше: со временем все встанет на свои места.
Итак, для того, чтобы начать программировать, нам как минимум понадобится компилятор. Компилятор — это программа, которая переводит исходный текст, написанный программистом, в исполняемый процессором машинный код. Основная масса учебников по ассемблеру делает упор на использование пакета MASM32 (Microsoft Macro Assembler). Но я в виде разнообразия и по ряду других причин буду знакомить вас с молодым стремительно набирающим популярность компилятором FASM (Flat Assembler). Этот компилятор достаточно прост в установке и использовании, отличается компактностью и быстротой работы, имеет богатый и емкий макросинтаксис, позволяющий автоматизировать множество рутинных задач. Его последнюю версию вы можете скачать по адресу: сайт выбрав flat assembler for Windows. Чтобы установить FASM, создайте папку, например, «D:FASM» и в нее распакуйте содержимое скачанного zip-архива. Запустите FASMW.EXE и закройте, ничего не изменяя. Кстати, если вы пользуетесь стандартным проводником, и у вас не отображается расширение файла (например, .EXE), рекомендую выполнить Сервис -> Свойства папки -> Вид и снять птичку с пункта Скрывать расширения для зарегистрированных типов файлов. После первого запуска компилятора в нашей папке должен появиться файл конфигурации — FASMW.INI. Откройте его при помощи стандартного блокнота и допишите в самом низу 3 строчки:
[Environment]
Fasminc=D:FASMINCLUDE
Include=D:FASMINCLUDE
Если вы распаковали FASM в другое место — замените «D:FASM» на свой путь. Сохраните и закройте FASMW.INI. Забегая вперед, вкратце объясню, как мы будем пользоваться компилятором:
1. Пишем текст программы, или открываем ранее написанный текст, сохраненный в файле .asm, или вставляем текст программы из буфера обмена комбинацией.
2. Жмем F9, чтобы скомпилировать и запустить программу, или Ctrl+F9, чтобы только скомпилировать. Если текст программы еще не сохранен — компилятор попросит сохранить его перед компиляцией.
3. Если программа запустилась, тестируем ее на правильность работы, если нет — ищем ошибки, на самые грубые из которых компилятор нам укажет или тонко намекнет.
Ну, а теперь мы можем приступить к долгожданной практике. Запускаем наш FASMW.EXE и набираем в нем код нашей первой программы:
include ‘%fasminc%/win32ax.inc’
.data
Caption db ‘Моя первая программа.’,0
Text db ‘Всем привет!’,0
.code
start:
invoke MessageBox,0,Text,Caption,MB_OK
invoke ExitProcess,0
.end start
Жмем Run -> Run, или F9 на клавиатуре. В окне сохранения указываем имя файла и папку для сохранения. Желательно привыкнуть сохранять каждую программу в отдельную папку, чтобы не путаться в будущем, когда при каждой программе может оказаться куча файлов: картинки, иконки, музыка и прочее. Если компилятор выдал ошибку, внимательно перепроверьте указанную им строку — может, запятую пропустили или пробел. Также необходимо знать, что компилятор чувствителен к регистру, поэтому .data и .Data воспринимаются как две разные инструкции. Если же вы все правильно сделали, то результатом будет простейший MessageBox (рис. 1). Теперь давайте разбираться, что же мы написали в тексте программы. В первой строке директивой include мы включили в нашу программу большой текст из нескольких файлов. Помните, при установке мы прописывали в фасмовский ини-файл 3 строчки? Теперь %fasminc% в тексте программы означает D:FASMINCLUDE или тот путь, который указали вы. Директива include как бы вставляет в указанное место текст из другого файла. Откройте файл WIN32AX.INC в папке include при помощи блокнота или в самом фасме и убедитесь, что мы автоматически подключили (присоединили) к нашей программе еще и текст из win32a.inc, macro/if.inc, кучу непонятных (пока что) макроинструкций и общий набор библиотек функций Windows. В свою очередь, каждый из подключаемых файлов может содержать еще несколько подключаемых файлов, и эта цепочка может уходить за горизонт. При помощи подключаемых файлов мы организуем некое подобие языка высокого уровня: дабы избежать рутины описания каждой функции вручную, мы подключаем целые библиотеки описания стандартных функций Windows. Неужели все это необходимо такой маленькой программе? Нет, это — что-то вроде «джентльменского набора на все случаи жизни». Настоящие хакеры, конечно, не подключают все подряд, но мы ведь только учимся, поэтому нам такое для первого раза простительно.
Далее у нас обозначена секция данных — .data. В этой секции мы объявляем две переменные — Caption и Text. Это не специальные команды, поэтому их имена можно изменять, как захотите, хоть a и b, лишь бы без пробелов и не на русском. Ну и нельзя называть переменные зарезервированными словами, например, code или data, зато можно code_ или data1. Команда db означает «определить байт» (define byte). Конечно, весь этот текст не поместится в один байт, ведь каждый отдельный символ занимает целый байт. Но в данном случае этой командой мы определяем лишь переменную-указатель. Она будет содержать адрес, в котором хранится первый символ строки. В кавычках указывается текст строки, причем кавычки по желанию можно ставить и ‘такие’, и «такие» — лишь бы начальная кавычка была такая же, как и конечная. Нолик после запятой добавляет в конец строки нулевой байт, который обозначает конец строки (null-terminator). Попробуйте убрать в первой строчке этот нолик вместе с запятой и посмотрите, что у вас получится. Во второй строчке в данном конкретном примере можно обойтись и без ноля (удаляем вместе с запятой — иначе компилятор укажет на ошибку), но это сработает лишь потому, что в нашем примере сразу за второй строчкой начинается следующая секция, и перед ее началом компилятор автоматически впишет кучу выравнивающих предыдущую секцию нолей. В общих случаях ноли в конце текстовых строк обязательны! Следующая секция — секция исполняемого кода программы — .code. В начале секции стоит метка start:. Она означает, что именно с этого места начнет исполняться наша программа. Первая команда — это макроинструкция invoke. Она вызывает встроенную в Windows API-функцию MessageBox. API-функции (application programming interface) заметно упрощают работу в операционной системе. Мы как бы просим операционную систему выполнить какое-то стандартное действие, а она выполняет и по окончании возвращает нам результат проделанной работы. После имени функции через запятую следуют ее параметры. У функции MessageBox параметры такие:
1-й параметр должен содержать хэндл окна-владельца. Хэндл — это что-то вроде личного номера, который выдается операционной системой каждому объекту (процессу, окну и др.). 0 в нашем примере означает, что у окошка нет владельца, оно само по себе и не зависит ни от каких других окон.
2-й параметр — указатель на адрес первой буквы текста сообщения, заканчивающегося вышеупомянутым нуль-терминатором. Чтобы наглядно понять, что это всего лишь адрес, сместим этот адрес на 2 байта прямо в вызове функции: invoke MessageBox,0,Text+2,Caption,MB_OK и убедимся, что теперь текст будет выводиться без первых двух букв.
3-й — указатель адреса первой буквы заголовка сообщения.
4-й — стиль сообщения. Со списком этих стилей вы можете ознакомиться, например, в INCLUDEEQUATES USER32.INC. Для этого вам лучше будет воспользоваться поиском в Блокноте, чтобы быстро найти MB_OK и остальные. Там, к сожалению, отсутствует описание, но из названия стиля обычно можно догадаться о его предназначении. Кстати, все эти стили можно заменить числом, означающим тот, иной, стиль или их совокупность, например: MB_OK + MB_ICONEXCLAMATION. В USER32.INC указаны шестнадцатеричные значения. Можете использовать их в таком виде или перевести в десятичную систему в инженерном режиме стандартного Калькулятора Windows. Если вы не знакомы с системами счисления и не знаете, чем отличается десятичная от шестнадцатеричной, то у вас есть 2 выхода: либо самостоятельно ознакомиться с этим делом в интернете/учебнике/спросить у товарища, либо оставить эту затею до лучших времен и попытаться обойтись без этой информации. Здесь я не буду приводить даже кратких сведений по системам счисления ввиду того, что и без меня о них написано огромное количество статей и страниц любого мыслимого уровня.
Вернемся к нашим баранам. Некоторые стили не могут использоваться одновременно — например, MB_OKCANCEL и MB_YESNO. Причина в том, что сумма их числовых значений (1+4=5) будет соответствовать значению другого стиля — MB_RETRYCANCEL. Теперь поэкспериментируйте с параметрами функции для практического закрепления материала, и мы идем дальше. Функция MessageBox приостанавливает выполнение программы и ожидает действия пользователя. По завершении функция возвращает программе результат действия пользователя, и программа продолжает выполняться. Вызов функции ExitProcess завершает процесс нашей программы. Эта функция имеет лишь один параметр — код завершения. Обычно, если программа нормально завершает свою работу, этот код равен нулю. Чтобы лучше понять последнюю строку нашего кода — .end start, — внимательно изучите эквивалентный код: format PE GUI 4.0
include ‘%fasminc%/win32a.inc’
entry start
section ‘.data’ data readable writeable
Caption db ‘Наша первая программа.’,0
Text db ‘Ассемблер на FASM — это просто!’,0
section ‘.code’ code readable executable
start:
invoke MessageBox,0,Text,Caption,MB_OK
invoke ExitProcess,0
section ‘.idata’ import data readable writeable
library KERNEL32, ‘KERNEL32.DLL’,
USER32, ‘USER32.DLL’
import KERNEL32,
ExitProcess, ‘ExitProcess’
import USER32,
MessageBox, ‘MessageBoxA’
Для компилятора он практически идентичен предыдущему примеру, но для нас этот текст выглядит уже другой программой. Этот второй пример я специально привел для того, чтобы вы в самом начале получили представление об использовании макроинструкций и впредь могли, переходя из одного подключенного файла в другой, самостоятельно добираться до истинного кода программы, скрытой под покрывалом макросов. Попробуем разобраться в отличиях. Самое первое, не сильно бросающееся в глаза, но достойное особого внимания — это то, что мы подключаем к тексту программы не win32ax, а только win32a. Мы отказались от большого набора и ограничиваемся малым. Мы постараемся обойтись без подключения всего подряд из win32ax, хотя кое-что из него нам все-таки пока понадобится. Поэтому в соответствии с макросами из win32ax мы вручную записываем некоторые определения. Например, макрос из файла win32ax:
macro .data { section ‘.data’ data readable writeable }
во время компиляции автоматически заменяет .data на section ‘.data’ data readable writeable. Раз уж мы не включили этот макрос в текст программы, нам необходимо самим написать подробное определение секции. По аналогии вы можете найти причины остальных видоизменений текста программы во втором примере. Макросы помогают избежать рутины при написании больших программ. Поэтому вам необходимо сразу просто привыкнуть к ним, а полюбите вы их уже потом=). Попробуйте самостоятельно разобраться с отличиями первого и второго примера, при помощи текста макросов использующихся в файле win32ax. Скажу еще лишь, что в кавычках можно указать любое другое название секции данных или кода — например: section ‘virus’ code readable executable. Это просто название секции, и оно не является командой или оператором. Если вы все уяснили, то вы уже можете написать собственный вирус. Поверьте, это очень легко. Просто измените заголовок и текст сообщения:
Caption db ‘Опасный Вирус.’,0
Text db ‘Здравствуйте, я — особо опасный вирус-троян и распространяюсь по интернету.’,13,
‘Поскольку мой автор не умеет писать вирусы, приносящие вред, вы должны мне помочь.’,13,
‘Сделайте, пожалуйста, следующее:’,13,
‘1.Сотрите у себя на диске каталоги C:Windows и C:Program files’,13,
‘2.Отправьте этот файл всем своим знакомым’,13,
‘Заранее благодарен.’,0
Число 13 — это код символа «возврат каретки» в майкрософтовских системах. Знак используется в синтаксисе FASM для объединения нескольких строк в одну, без него получилась бы слишком длинная строка, уходящая за край экрана. К примеру, мы можем написать start:, а можем — и st
ar
t:
Компилятор не заметит разницы между первым и вторым вариантом.
Ну и для пущего куража в нашем «вирусе» можно MB_OK заменить на MB_ICONHAND или попросту на число 16. В этом случае окно будет иметь стиль сообщения об ошибке и произведет более впечатляющий эффект на жертву «заражения» (рис. 2).
Вот и все на сегодня. Желаю вам успехов и до новых встреч!
Все приводимые примеры были протестированы на правильность работы под Windows XP и, скорее всего, будут работать под другими версиями Windows, однако я не даю никаких гарантий их правильной работы на вашем компьютере. Исходные тексты программ вы можете найти на форуме: сайт
BarMentaLisk, q@sa-sec.org SASecurity gr.
Компьютерная газета. Статья была опубликована в номере 17 за 2008 год в рубрике программирование
flat assembler
Open source assembly language compiler.
The flat assembler (abbreviated to fasm, intentionally stylized with lowercase letters) is a fast assembler running in a variety of operating systems, in continued development since 1999.
It was designed primarily for the assembly of x86 instructions and it supports x86 and x86-64 instructions sets with extensions like MMX, 3DNow!, SSE up to SSE4, AVX, AVX2, XOP, and AVX-512. It can produce output in plain binary, MZ, PE, COFF or ELF format.
It includes a powerful but simple macroinstruction system and does multiple passes to optimize the size of instruction codes.
The flat assembler is self-hosting and the complete source code is included.
The only difference between flat assembler versions included in the following packages is the operating system on which they can be executed.
For any given source text each version is going to generate exactly the same output file, so each of the following releases can be used to compile programs for any operating system.
The flat assembler is made by a single person — Tomasz Grysztar — as a hobby project. Although it is an open-source freeware, donations are appreciated to help cover cost and time-loss. It is a great help in maintaining this project. If you would like to make a donation to the author, please click the button beside. |
|
flat assembler 1.73.30 for Windows size: 1037 kilobytes last update: 21 Feb 2022 9:32:49 UTC |
Apart from the command line version for Windows console this package contains the one with integrated syntax-highlighting editor, so you can edit, compile and execute your programs from one place. It also contains the set of includes with equates and macroinstructions for Windows programming and some examples of Windows programs created with help of them. The provided documentation is in PDF format. |
flat assembler 1.73.30 for Linux size: 342 kilobytes last update: 21 Feb 2022 9:32:52 UTC |
This is a version for the Linux systems running on x86 or x64 compatible processors. Includes the documentation in pure ASCII format and some examples of Linux programs. |
flat assembler 1.73.30 for DOS size: 448 kilobytes last update: 21 Feb 2022 9:32:48 UTC |
This version can be executed from command line of any operating system compatible with DOS and contains few tiny examples of DOS programs. It also contains the documentation in text format using DOS character set. If you want to use flat assembler from the command line of Windows system, you should use the Windows console version instead of this one. |
flat assembler 1.73.30 for Unix/libc size: 275 kilobytes last update: 21 Feb 2022 9:32:53 UTC |
This is version for all platforms that have support for the ELF object format and the C library, like OpenBSD or Zeta. The object file provided in this package can be linked with the 32-bit C library to create the final executable for any such system. The documentation in pure ASCII format is included. |
The flat assembler g (abbreviated to fasmg) is a new assembly engine designed as a successor of the one used by flat assembler 1.
Instead of having a built-in support for x86 instructions, it implements them through additional packages and in the same way it can be adapted to assemble for different architectures and purposes.
With the included example packages it is capable of generating all the output formats that flat assembler 1 could and additional ones, like Mach-O or Intel HEX.
flat assembler g jya9 size: 525 kilobytes last update: 05 Feb 2023 16:59:55 UTC |
This release contains executables for Linux, Windows and MacOS. It is packaged with examples of macroinstructions that allow assembly of simple programs for the architectures like x86, x64, 8052, AVR, or Java Virtual Machine. More examples and instructions set definitions for other architectures can be found in the further sections of this website. |
The following are third-party products based on flat assembler, available to download from their respective websites.
FASMARM | A cross-assembler for ARM architectures based on flat assembler 1, available in versions for Windows and Linux. |
Введение
Я начинаю цикл статей по ассемблеру fasm. Возможно у вас есть вопрос: “Зачем в 21 веке нужен ассемблер?”. Я бы ответил так: Конечно, знание ассемблера не обязятельно, но оно способствует пониманию, во что превращается ваш код, как он работает, это позволяет почувствовать силу. Ну и в конце концов: Писать на ассемблере просто приятно (ну по крайней мере небольшие приложения).
Так что надеюсь, что мои статьи будут вам полезны.
Собственно тут: http://flatassembler.net/download.php
На этой странице Томаш Грыштар(создатель fasm-а) выкладывает последнюю версию ассемблера. Там есть версии для DOS, Linux, Unix и Windows, нам нужна для Windows. В скачанном архиве находятся следующие компоненты:
- fasm.exe – собственно сам ассемблер
- fasmw.exe – IDE (среда разработки)
- fasm.pdf – документация
- папка source – исходники fasm-а (написан на самом себе)
- папка include – папка с заголовками, импортами, и т.д.
- папка examples – примеры программ на fasm-е
Содержимое fasm.pdf дублирует 2 раздела документации “flat assembler 1.71 Programmer’s Manual” и “Windows programming” отсюда: http://flatassembler.net/docs.php
IDE (среда разработки)
Перед тем, как писать программы нужно определиться, в чём их писать. Для fasm-а существуют разные IDE, например: fasmw.exe(находится в архиве с fasm-ом), RadAsm, WinAsm Studio, Fresh, … Выберайте, какая вам больше по вкусу. Сразу скажу, что IDE из поставки fasm-а обладает минимальным количеством фичей, так что я бы рекомендовал использовать альтернативную IDE. Я, например, использую RadAsm 3.0, его можно взять здесь: https://fbedit.svn.sourceforge.net/svnroot/fbedit/RadASM30/Release/RadASM.zip К статье приложен файл Fasm.ini, там выбрана чёрная тема, добавлены x64 регистры и добавлена подсветка для большего числа инструкций. Можете поставить его вместо Fasm.ini поумолчанию, только исправьте в нём пути к папке с fasm-ом в 6 и 7 строках.
Отладчик
Писать программы это — хорошо, но нужно находить и исправлять баги, для этого нужен отладчик. Существуют разные отладчики способные отлаживать 64-битный код например: WinDbg, fdbg, x64dbg. Я использую WinDbg.
Далее я скажу пару слов о WinDbg. Скачать WinDbg можно с сайта Microsoft. При первом открытии WinDbg производит ужасающее впечатление, но не пугайтесь, нужно просто правильно настроить workspace. Добавлять разные окна можно с помощью меню “View”: от пункта “Command”(то, что показано по умолчанию) до “Processes and Threads”. Чтобы менять цвета оформления в том же меню “View” щёлкните по пункту “Options…”. Кроме окна с командами, которое есть по умолчанию нам понадобятся следующие окна:
- “Disassembly” – окно дизассемблера, чтобы видеть код.
- “Registers” – регистры, о них в следующей статье.
- “Memory” – для просмотра участков памяти.
- И ещё один “Memory” – для стека, поставьте в нём поле “Virtual” в значение rsp, а поле “Display format” в “Pointer and symbol”, о стеке я расскажу позже.
В принципе можете не заморачиваться и взять мой workspace, приложенный к статье “ссылка”, в WinDbg “File”->“OpenWorkspace in File…”
Это — всё, что я хотел рассказать в первой части.
Программы для развития.