Предотвращение искажения имен в C (не C++) с помощью MinGW для динамического поиска символов

У меня есть программа на C, где я получаю указатели функций «динамически» по имени функции (т.е. я передаю имя функции в виде строки и получаю указатель на функцию). Я уже делаю это в Linux, используя dlopen и dlsym, и я полагаю, что это также будет работать в любой другой Unix-подобной системе с dlfcn.

Проблемы начались, когда я попытался портировать эту программу на Windows с помощью MinGW. Когда я пытаюсь найти имя, используя «GetProcAddress (handle, symbol_name), где «symbol_name» — это имя моей функции обратного вызова, а «handle» — это дескриптор текущего исполняемого файла, возвращаемый «GetModuleHandle (NULL)», я ничего не получаю. потому что изменение имени MinGW добавляет «_» к моему имени символа.

Очевидное решение (префикс «_» к нужному мне символу) кажется немного «опасным» для переносимости (может ли компилятор добавить два символа подчеркивания для некоторых из них? Я не знаю), поэтому я спрашиваю:

  • Есть ли лучший способ предотвратить искажение имен моих символов компилятором? (или их подмножество, только обратные вызовы, которые мне нужно найти динамически);

  • Или способ заставить GetProcAddress найти их, даже если они искажены?

Я также попробовал вариант -fno-leading-underscore, но он также убрал искажение всех внешних символов, что сделало невозможным связывание программы с stdlib и т. д. (также немного пугают предупреждения в документации).

Также обратите внимание, что я использую чистый C — ни в одной части моего кода нет C++ — и весь мой код живет в одном «.exe».

ТИА


person Marconi    schedule 12.02.2011    source источник


Ответы (2)


Не уверен, в чем ваша проблема, так как я не могу воспроизвести ее с помощью самого простого примера DLL, который я могу придумать:

/* hello_dll.c */
#include <stdio.h>

__declspec(dllexport) void hello ( void )
{
    puts ( "Hello, DLL!");
}

/* hello_exe.c */
#include <windows.h>
#include <stdio.h>  

int main () {
    typedef void (*pfunc)(void);

    HANDLE hself;

    pfunc hello;

    hself = GetModuleHandle(NULL);

    hello = (pfunc)GetProcAddress(hdll, "hello");

    hello();

    return 0;
}

Это командная строка с использованием MinGW gcc без специальных флагов, и все работает:

gcc src\hello_dll.c src\hello_exe.c -o bin\hello.exe
$ bin\hello.exe
Hello, DLL!
$ gcc --version
gcc (GCC) 4.5.0

Это не работает без __declspec(dllexport), если вы получаете функцию от себя; при создании DLL с gcc -shared кажется, что это не обязательно, но требуется при экспорте функции из exe.

person Pete Kirkham    schedule 12.02.2011
comment
_ добавлен для функций stdcall. Я не думаю, что это будет добавлено для cdecl. - person David Heffernan; 12.02.2011
comment
Спасибо! Я только что создал макрос для предоставления этого объявления при компиляции в Windows и добавил его во все мои динамические функции обратного вызова. - person Marconi; 13.02.2011

C не использует изменение имени. В частности, он не добавляет к имени никакой информации о типе (в отличие от C++). Но некоторые платформы вносят небольшие изменения в имя, например добавляют префикс подчеркивания. И в отличие от C++, это зависит только от платформы, но не зависит от компилятора.

На всех платформах, которые я видел до сих пор, я видел либо отсутствие изменений, либо начальное подчеркивание.

Поэтому я предлагаю вам использовать некоторые ifdefs, чтобы определить, использует ли текущая платформа символ подчеркивания или нет.

(В Windows есть еще одна небольшая модификация для определенных функций API Windows, позволяющая отличать ANSI от версии Unicode. Но это, вероятно, не относится к вашему случаю.)

Может быть, кто-то еще может указать на какую-то официальную документацию для C ABI на разных платформах.

person Codo    schedule 12.02.2011