Как обернуть вызов C shared library в вызов C++ shared library под Linux для вызова из C#?

Есть программа на GNU Assembler, возвращающая значение (asm.s):

.text
   .globl _new

   _new:               
   mov $1, %rax
   ret

Есть библиотечная функция 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

Пробую через PInvoke в C# .NET Core вызвать:

using System.Runtime.InteropServices;
class Program{
[DllImport("lib.so")] public static extern int foocpp ();
 static void Main(string[] args)
        {
            int code = foocpp();
System.Console.WriteLine(code);
}
}

После

dotnet run

получаю сообщение

Hosting components are already initialized. Re-initialization to execute an app is not allowed.

Ошибка не ясна, поэтому требуется сделать обёртку на С++ для lib.so, которую уже вызывать через DllImport в C#.

Как будет выглядеть программа на C++, и как изменятся команды сборки на gcc, g++?

Предполагаю, что код будет выглядеть так (my.cpp), но есть затруднение с написанием команды сборки C++ shared library:

 extern "C" {
#define EXPORT __attribute__((visibility("default")))        
        EXPORT int foocpp(void)
        {
            extern int foo();
            return foo();
        }
}

И пробую собрать так:

g++ -shared -fpic -o lib.so my.cpp my.c asm.s

Получаю ошибку:

symbol lookup error: undefined symbol: foo


Ответы (1 шт):

Автор решения: Pavel Mayorov

Связка C# - Си в вашем коде прекрасно работает, и сообщение об ошибке это только подтверждает.

Проблема вашего кода в том, что _start - это популярное имя для системной точки входа (ENTRY POINT) в программу. Эта функция находится в стандартной библиотеке языка Си, и когда вы вызываете её - вы как бы пытаетесь запустить свою же программу ещё раз. Но рантайм .NET Core это обнаруживает, и не даёт вам уйти в вечную рекурсию с переполнением стека.

Переименуйте вашу функцию на ассемблере и попробуйте настроить связку "Си - Asm" ещё раз.

→ Ссылка