2016-08-02 23 views
10

Gdybym zadeklarować funkcję tak:DLL przy użyciu __stdcall bez dekoracji nazwy: dlaczego to działa?

#ifdef TEST_EXPORTS 
#define TEST_API __declspec(dllexport) 
#else 
#define TEST_API __declspec(dllimport) 
#endif 

TESTAPI int __stdcall myadd(int a, int b); 

Symbol w DLL jest [email protected], który ma sens dla mnie (po kilku godzinach czytania inne pytania tutaj, że jest).

Ale biblioteki okien wydają się robić coś innego. Używają również __stdcall (w przebraniu WINAPI), ale symbole w bibliotekach DLL nie mają dekoracji nazwy. Jeśli powyższa metoda znajduje się w bibliotekach systemu Windows, symbol będzie następujący: myadd.

Domyślam się, że używają pliku def, aby alias symboli. Ale dlaczego mój linker wie o tym, kiedy łączę się z jedną z tych bibliotek DLL?

Pliki nagłówkowe systemu Windows deklarują te funkcje jako WINAPI, więc jeśli je wywołam, linker powinien wyszukać dekorowaną nazwę, ponieważ jest to funkcja __stdcall. Jednak w jakiś sposób linker wie, jak zrzucić dekorację nazwy.

Próbowałem powtórzyć to, pisząc małą bibliotekę DLL i usuwając dekorację nazwy z pliku def. Zgodnie z oczekiwaniami otrzymuję błędy linkera, ponieważ linker wciąż szuka dekorowanej nazwy. Zrobiłem to w czystym C, aby upewnić się, że mangling C++ nie ma na to wpływu.

edit: wyjaśnienie, MSVC 14,0/VS2015, 32-bitowy

+0

Należy zauważyć, że x64 nie używa dekoracji nazwy. –

+0

@JonathanPotter: * "Zauważ, że x64 nie używa dekorowania nazw." * - Dotyczy to tylko "extern" C "'. Symbole C++ muszą mieć udekorowane nazwy eksportowe dla rozdzielczości przeciążenia. – IInspectable

Odpowiedz

6

Istnieją pewne ledwo udokumentowane magia w pracy tutaj. Przyjrzyjmy się funkcji WIN32API, takiej jak RegQueryValueExW. Jest ona zdefiniowana w pliku winreg.h tak:

WINADVAPI LSTATUS APIENTRY RegQueryValueExW(...); 

Gdzie WIADVAPI jest __declspec(dllimport) i APIENTRY to pseudonim dla __stdcall konwencji nazewnictwa. Zauważ też, że wszystkie funkcje w nagłówku są zadeklarowane jako extern "C". Tak więc za wszelką cenę funkcja ta powinna używać dekorowania nazw, a jej eksport DLL powinien być [email protected]. Jednak kiedy patrzymy advapi32.dll eksportu za pomocą polecenia dumpbin /exports widzimy nazwę undecorated:

advapi exports

pozwala teraz dokładnie zbadać advapi32.lib plik używając dumpbin /headers advapi32.lib polecenie:

enter image description here

zanotować undecorate specifier, która pozwala połączyć udekorowaną nazwę z nieozdobionym eksportem. Możesz osiągnąć ten sam wynik dla biblioteki dll, używając pliku def z sekcją EXPORTS zawierającą nieskorowane nazwy. Zobacz artykuł this i this answer, aby uzyskać dodatkowe informacje.

Ponadto, wszystkie powyższe zapisy są ważne tylko dla aplikacji x86. Funkcje C w środowisku 64 bitowym są połączone without name decoration:

Forma dekoracji dla funkcji C zależy od wywołującego konwencją stosowaną w deklaracji, jak pokazano w poniższej tabeli. To jest również format dekoracji, który jest używany, gdy kod C++ jest zadeklarowany jako zewnętrzny łącznik "C". Domyślna konwencja wywoływania to __cdecl. Zwróć uwagę, że w środowisku 64-bitowym funkcje nie są dekorowane.

+0

To wszystko. Starałem się być sprytny i umieścić udekorowane nazwiska w pliku def. Lib jest rzeczywiście brakującym ogniwem. Definiuje on udekorowany symbol i przekazuje wywołanie do nieoznaczonego symbolu dll. – Stefan

Powiązane problemy