Предотвратете изкривяването на имената в 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".

TIA


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 има друга малка модификация за определени функции на Windows API за разграничаване на ANSI от версията на Unicode. Но това вероятно не е от значение за вашия случай.)

Може би някой друг може да посочи официална документация за C ABI на различни платформи.

person Codo    schedule 12.02.2011