제목이 긴데... 윈도우 파트에만 한정하기도 그렇고... 하여튼.
이런 것들이 연관되어서 문제가 꽤 있었고 골머리를 오래 싸맸다.
C++ 로 만든 DLL 을 C 에서 사용하고 싶다거나
C 로 만든 DLL 을 C++ 에서 사용하고 싶다거나.
지금 생각하면 큰 문제는 아닌 것 같은데..; 정리 삼아.
먼저 Calling Convention 에 대해 간단히 요약해보자.
주로 사용되는 stdcall / cdecl 과 fastcall 이라고 볼 수 있겠다.
c++ 을 자주 사용하다 보니 thiscall 도 자주 보게 된다만 잠시 논외로 하고..
글을 보는 사람들 모두가 알고 있겠지만, 이 Calling Convention 이 중요하게 다루어지는 이유는
함수를 호출함에 있어서 스택의 정리 주체가 누구냐 ?
stdcall 은 CALLEE 가, cdecl 은 CALLER 가 스택을 정리한다.
이상하게 난 이런거 잘 못외워서 노래를 불러댔는데 '자기의 일은 스스로 하자~'
이런 마음가짐이 좋은 어린이의 기준이기 때문에 stdcall-좋은 함수는 스택을 알아서 정리한다.
이렇게 외웠고 아직 잘 써먹고 있다-_-;;
별 어려운 내용도 아니기야 하지만, 이걸 모르고 넘어가면
나중에 두 개 이상의 모듈을 사용해서 Export / Import 형식으로 코딩을 해야할 때 머리 쥐어 짠다.
어셈블리로 함수호출부 구현 중에 이걸 모르고 에러가 나면 재앙 수준.
자 여기에 설명이 하나가 추가가 되는데 stdcall 은 WINAPI 및 C++ 에서 사용된다. 라는 부분이다.
이게 귀찮다. stdcall 은 C++ 의 표준 호출 규약이다.
여기서 발생하는 문제가 Name Mangling
간단히 설명하면, C++ 에서 지원하는 함수 오버로딩의 특징 때문에
같은 이름의 함수라도 Argument 와 Return 형에 따라 이름을 다르게 주어야 한다. 그래서 생긴게 이 규칙.
간단히 예를 들어보면...
void __declspec(dllexport) test(int a, int b); | ?test@@YGXHH@Z |
int __declspec(dllexport) test(int a, int b, char c); | ?test@@YGHHHD@Z |
C++ 프로젝트에서의 네임 맹글링
뭐 이렇다. 맹글링 된 함수명을 돌려보려면 Visual Studio 의 undname을 활용하면 편리하다.
stdcall 은 C++ 에서 채택한 표준 호출규약인데, 이 C++ 의 오버로딩 특징 때문에
stdcall 을 인자로 준 함수들은 다 네임 맹글링이 걸려 버린다. C 프로젝트에서도 네임 맹글링을 걸 수 있다!
void __declspec(dllexport) __stdcall Function1(int a, int b) | _Function1@8 |
void __declspec(dllexport) __cdecl Function2(int a, int b) | Function2 |
C 프로젝트에서 __stdcall 을 주었을 때의 네임 맹글링
그렇다고 해서 C 프로젝트에서 stdcall 을 주면 오버로딩이 되느냐 ?
그건 재정의 에러가 발생해서 안됩니다.
하나 더 해보면, C++ 프로젝트에서 __stdcall 로 정의된 함수와 __cdecl 로 정의된 함수도 맹글링이 다르다.
뭐 당연한 얘기.
void __declspec(dllexport) __stdcall Function1(int a, int b) | ?Function1@@YGXHH@Z |
void __declspec(dllexport) __cdecl Function2(int a, int b) | ?Function2@@YAXHH@Z |
C++ 프로젝트에서 __stdcall 과 __cdecl 의 차이
중간정리 하면,
stdcall 로 함수를 만들면 네임 맹글링이 걸린다.
C++ 에서는 stdcall 과 cdecl 로 걸리는 네임 맹글링이 다르다. 이정도가 되겠다.
저기 이상한 게 있는데요 ?
C++ 프로젝트에서의 네임 맹글링과 C 프로젝트에서의 맹글링이 다른가요 ?
어라 그러네요.
void test(int, int) ==> ?test@@YGXHH@Z
void Function1(int, int) ==> _Function1@8
이래서 함수를 찾을 때 잘 찾아야 한다.
C 프로젝트냐, C++ 프로젝트냐, cdecl 이냐, stdcall 이냐에 따라 네임 맹글링이 완전히 바뀐다.
이런 이유 때문에, 오픈 소스 DLL 이 C++ 인데 난 C로 짜야 한다면 ? 혹은 그 반대라면 ? 정말 굉장히 매우 귀찮아진다.
이런 네임 맹글링을 막기 위해 C++ 프로젝트에서는 아래와 같은 전처기리 명령어를 사용한다.
#ifdef __cplusplus
extern "C"{
#endif
...
#ifdef __cplusplus
}
#endif
이러면 C++ 로 만들어진 프로젝트에서, extern 블록 안에 있는 함수들이 네임 맹글링을 사용하지 않는다.
extern C 에 대한 설명은 인터넷 도처에 매우 많으니..
그래서, C++ DLL 함수를 에서 C에서 사용하려면 extern C를 활용하면 되고
Calling Convention 이 뭔지 모르겠으면 undname 을 사용해서 어떤 호출을 사용하는지 보면 된다.
C DLL 을 C++ 에서 사용하고 싶다면 ? 네임 맹글링이 박혀 있으면 stdcall, 안 박혀 있으면 cdecl.
아 원래 이걸 정리하려는게 아니었는데 마무리가 이상하네. 음 뭔가 정리할 게 더 있었는데. 나중에~
'Research > Windows' 카테고리의 다른 글
windbg 심볼 / 치트 시트 (0) | 2014.12.17 |
---|---|
C++ constructor 생성자 호출 방식 (0) | 2014.10.10 |
프로세스별 핸들 목록 리스팅 (2) | 2014.08.22 |
LPTHREAD_START_ROUTINE 은 stdcall 이어야만 하는가 (0) | 2014.08.20 |
스크랩 - C++상에서 발생하는 name mangling에 관한 내용 (0) | 2014.08.14 |