Для работы понадобится ОС Linux и установленные в ней компиляторы gcc, g++. Проверить наличие компилятора можно командой whereis, а установить - командой sudo apt install в терминале. Имеется простейший код на GNU Assembler, возвращающий 1 (файл asm.s):
.text
.globl _new
_new:
mov $1,%rax
ret
Хотим запустить его в C# с помощью PInvoke. Для этого потребуется промежуточная динамическая библиотека на языке C с кодом (файл my.c):
#define EXPORT __attribute__((visibility("default")))
EXPORT int foo(void);
int foo(void)
{
extern int _new();
return _new();
}
Эти два файла нужно собрать в shared library (файл lib.so) командой
gcc -shared -fpic -o lib.so my.c asm.s
Полученный файл lib.so нужно подложить в папку с исполняемым файлом результирующей программы на C#. У меня это подкаталог проекта /bin/Debug/netcoreapp3.1/. Код на C# для запуска функции _new выглядит так:
using System.Runtime.InteropServices;
class Program{
[DllImport("lib.so")] public static extern int foo ();
static void Main(string[] args)
{
int code = foo();
System.Console.WriteLine(code);
}
}
Запускается он командой dotnet run, если у вас установлена исполняемая среда .NET Core. В консоли вы увидите 1. Чтобы добавить прослойку между C# и C в виде кода на C++, нужно добавить в проект файл my.cpp с кодом:
extern "C"{
#define EXPORT __attribute__((visibility("default")))
EXPORT int foocpp(void)
{
extern int foo();
return foo();
}}
и заменить в коде C# название внешней функции foo на foocpp. Тогда изменится команда сборки и будет выглядеть так:
g++ -shared -fpic -o lib.so my.cpp -x c my.c -x assembler asm.s
После чего запускаем dotnet run и видим 1 в консоли.