ЭВМ и Периферийные устройства лекция 10
Упрощаем программирование в MASM. Функции.
Упрощаем программирование в MASM. Файлы.
Упрощаем программирование в MASM. Файлы.
Упрощаем программирование в MASM. Консоль.
Как связать C++ и Assembler под Windows
1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)
1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)
1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)
1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)
1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)
2) Сгенерировать *.dll из ассемблерного файла и вызывать функции из неё в C++ или другим языком высокого уровня;
2) Сгенерировать *.dll из ассемблерного файла и вызывать функции из неё в C++ или другим языком высокого уровня;
2) Сгенерировать *.dll из ассемблерного файла и вызывать функции из неё в C++ или другим языком высокого уровня;
3) Inline Assembler
3) Inline Assembler
3) Inline Assembler. Вызов С функций
3) Inline Assembler. Вызов С++ функций
Важно
210.50K
Category: programmingprogramming

Функции, файлы, консоль, связь с C++ в MASM

1. ЭВМ и Периферийные устройства лекция 10

2. Упрощаем программирование в MASM. Функции.

Функции возвращают значение в регистр еах. Выглядит это примерно так:
.data?
hResult dd ?
call/invoke SomeFunc
mov hResult,eax
В Си аналогичный код выглядит проще:
HANDLE hResult;
hResult = SomeFunc();
Казалось бы чего там, одна строчка, но в большом проекте таких
строк может быть много, можно ошибиться, забыть. Для упрощения
можно использовать макрос FUNC.
mov hResult,FUNC(SomeFunc)
;(переменную hResult нужно объявлять)

3. Упрощаем программирование в MASM. Файлы.

На чистом Асме, точнее на WinApi, ввод/вывод (консоль, файлы) явно
сложнее чем на Си. Но если всего лишь записать буфер в файл, то нет
смысла в всяческих правах доступа и наследуемых дескрипторах. В MASM
имеются макросы и процедуры, способные упростить работу с файлами до
уровня Си. Например, создать файл, открыть его для чтения/записи и
поместить хендл в переменную:
mov hFile, fcreate("test.log")
Узнать размер файла:
mov flen, fsize(hFile)
Записать туда данные:
mov bwritten, fwrite(hFile,buffer,bcnt);хендл,адрес буфера с данными, к-тво
;байт для записи

4. Упрощаем программирование в MASM. Файлы.

А вот пример функции, которая откроет файл, запишет туда данные, и
закроет его:
invoke write_disk_file, chr$("file.txt"),addr lpData,fl;имя, буфер, к-тво байт для
;записи

5. Упрощаем программирование в MASM. Консоль.

Намного проще работать с консолью - если на чистом WinApi нужно
открыть дескриптор на запись, вызвать функции с несколькими
параметрами, то с помощью макроссов можно просто:
invoke StdOut,chr$("console")
Или даже так:
print "console"
Естественно, никакого волшебства тут нет, в основе всего этого
лежит тот жe WinApi.

6. Как связать C++ и Assembler под Windows

Существует 3 способа:
1) Разместить ассемблерный код в отдельном файле *.asm. Сгенерировать
ассемблерный *.obj файл и связать его с *.cpp файлом (С++);
2) Разместить ассемблерный код в отдельном файле. Сгенерировать *.dll из
ассемблерного файла и вызывать функции из неё в C++ или другим
языком высокого уровня;
3) Использовать inline assembler, позволяющий делать вставки
ассемблерного кода в высокоуровневом языке.

7. 1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)

Особенности:
Создаётся отдельный .ASM файл, процедуры которого вызываются из
высокоуровневого С++ кода.
Преимущества:
• Относительно простой способ;
Недостатки:
• Ассемблерный код будет размещён всегда отдельном файле;
• Необходимость прописывать прототипы ASM функций в С++ коде

8. 1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)

Особенности:
Если надо вызывать из ассемблера библиотечные методы, достаточно в
начале секции кода указать, какие именно методы мы собираемся
использовать.
(ASM)
EXTRN printf : proc ;we'll use printf
Далее можно просто использовать call:
(ASM)
;printf(ebx,eax)
push eax;
push ebx
call printf
add esp, 8 ;pop x2

9. 1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)

Если же вы захотите использовать invoke (что удобнее и логичнее), то нужно
прописать прототип
(ASM)
.data
helloFormat BYTE "Hello, %s!", 10, 13, 0
whatToPrint DWORD “PrintIt”
printf PROTO arg1:Ptr Byte, printlist: VARARG ; Мы используем Сишный printf с
;описанием прототипа
Далее можно просто использовать invoke:
(ASM)
invoke printf, ADDR helloFormat, whatToPrint

10. 1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)

Если вы хотите из Asm файла вызывать методы С++ то используется
указанный ранее подход, но при этом в С++ файле у вызываемого метода вы
должны сделать приписку extern "C"
(C++)
extern "C"
void* readName()
{
char* name = (char*)calloc(1, 255);
scanf("%s", name);
while (getchar() != '\n');
return name; //eax= name
}
(ASM)
invoke readName ; eax=name

11. 1) Разместить ассемблерный код в отдельном файле. Сгенерировать ассемблерный *.obj файл и связать его с *.cpp файлом (С++)

Если вам нужно вызвать ASM методы из C++, то в С++ нужно прописать
прототип:
(C++)
extern "C"
{
long calcSumm(long a, long * retAddr);
}

int _tmain(int argc, _TCHAR* argv[])
{
long retVar=1;
long res=calcSumm(31,&retVar);
}
(ASM)
calcSumm PROC a:DWORD,retAddr:DWORD

ret
calcSumm ENDP

12. 2) Сгенерировать *.dll из ассемблерного файла и вызывать функции из неё в C++ или другим языком высокого уровня;

Особенности:
На основе ASM файла генерируется *.DLL, которая вызывается в языках
высокого уровня.
Преимущества:
• Универсальный способ, подходящий для связи многих языков;
Недостатки:
• Ассемблерный код будет размещён в отдельном файле;
• Необходимость приписывать вызов функций из DLL.

13. 2) Сгенерировать *.dll из ассемблерного файла и вызывать функции из неё в C++ или другим языком высокого уровня;

Быстро создать шаблон DLL для MASM вы можете из редактора MASM32

14. 2) Сгенерировать *.dll из ассемблерного файла и вызывать функции из неё в C++ или другим языком высокого уровня;

Далее нужную функцию или функции нужно просто вызвать из DLL
средствами вашего языка программирования. Например так:
(C++)
include "stdafx.h"
#include <stdio.h>
#pragma comment(lib,"..\\Debug\\MasmDLL.lib")
extern "C" void _stdcall TestProc1(char lpString[]);
int _tmain(int argc, _TCHAR* argv[])
{
char hello[] = "Hello World!";
TestProc1(hello);
printf("Press Enter To Exit...");
getchar();
return 0;
}

15. 3) Inline Assembler

Особенности:
Inline Assembler, то есть использование встроенного в язык высокого уровня
ассемблерного кода (или ассемблерных вставок, как их ещё называют).
Inline Assembler в Visual Studio использует синтаксис MASM.
Преимущества:
• Самый простой способ. Вы просто пишите ассемблерные вставки в C++
коде. Никаких дополнительных подключений, дополнительных файлов,
специального прописывания прототипов и прочего.
• Удобно писать и отлаживать такой код.
Недостатки:
• Встроенный код на языке ассемблера не поддерживает все макросы и
директивы данных Microsoft Macro Assembler (MASM);
• Программы со встроенным кодом на языке ассемблера не всегда можно
перенести на другие аппаратные платформы. При разработке
переносимой версии старайтесь не использовать встроенный код
ассемблера;
• 64 битные приложения не поддерживаются.

16. 3) Inline Assembler

Ключевое слово __asm вызывает встроенный ассемблер и может
использоваться в любом месте, в котором может использоваться оператор С
или С++.
Он не может отображаться самостоятельно. За ним должна следовать
группа инструкций, заключенная в круглые скобки, либо, в крайнем случае,
пустая пара круглых скобок. Термин "блок __asm" в этом разделе относится к
любой инструкции или группе инструкций, в скобках или без них.
(С++)
__asm{…}
Кроме того, можно поставить __asm перед каждой инструкцией по сборке.
(С++)
__asm push ebp
__asm mov ebp, esp
__asm sub esp, __LOCAL_SIZE
Поскольку ключевое слово __asm является разделителем операторов, можно
также помещать инструкции ассемблера на одной строке.
(С++)
__asm push ebp __asm mov ebp, esp __asm sub esp, __LOCAL_SIZE

17. 3) Inline Assembler. Вызов С функций

В этом примере в стек помещаются указатели на строки world, hello и format
(в этом порядке), затем вызывается процедура printf.
(C++)
int _tmain(int argc, _TCHAR* argv[])
{
char format[] = "%s %s\n";
char hello[6] = "Hello";
char world[] = "World";
__asm //Ассемблерная вставка
{
lea eax,world // eax = адрес earth
push eax // поместить eax в вершину стека
lea eax,hello // eax = адрес hello
push eax
lea eax,format
push eax
call DWORD ptr printf
// или использя непрямой вызов
// mov eax, printf
// call eax
pop ebx // чистим стек
pop ebx
pop ebx
}
getchar();// ждем нажатие кнопки
return 0;
}

18. 3) Inline Assembler. Вызов С++ функций

Блок __asm может вызывать только глобальные функции C++, которые не
являются перегруженными. При вызове перегруженной глобальной функции
C++ или функции-члена C++ компилятор выдает ошибку.
Кроме того, можно вызывать любые функции, которые объявлены с
компоновкой extern "C". Благодаря этому блок __asm в программе C++
может вызывать функции библиотеки C, поскольку во всех стандартных
файлах заголовков функции библиотеки объявляются с компоновкой extern
"C".

19. Важно

Обычные компиляторы, работающие с высокоуровневым кодом (например
MSBuild от Microsoft) сами по себе неплохо оптимизируют код.
Далеко не всегда имеет смысл программировать что-либо именно на
ассемблере. Это может не дать ощутимого эффекта.
Однако если правильно выбрать фрагмент программы, можно получить
преимущество по сравнению с работой компилятора для языка высокого
уровня.
Плюс существуют ситуации, когда язык высокого уровня не позволяет
сделать в точности то, чего вы хотите добиться.
English     Русский Rules