최신목록

2017년 3월 15일 수요일

[C/C++]Name Mangling 과 GetProcAddress

이기종이 사용하는 라이브러리를 만드는 미션~ 윈도우 프로그래밍에 익숙해서 당연한 거라 여겨졌던 부분들에 대한 내용이다.

1. __declspec(dllexport) 를 사용하여 함수를 export 해야한다 ?
이것은 MS에서 만든 키워드로 unix/linux에는 사용할 수 없는 코드이다. 아래와 같이 구분하여 정의를 해준다.


#ifdef _WIN32
# define EXPORT_API(ret_type) __declspec(dllexport) ret_type
#else  //WIN32
# define EXPORT_API(ret_type) ret_type
#endif //WIN32

EXPORT_API(int) EncodeBase64(const char* in_str, char* out_str, size_t* out_size)
{
      .....
}

2. def 파일로 define을 해주어야 한다? extern "C"는 C코드에서 사용하기 위해서 넣어진 코드이다?
_declspec(dllexport)를 사용하면 def 파일을 따로 만들어주지 않아도 함수가 export 된다. 하지만 depends 로 보면 아래와 같이 name mangling 이 적용된다.


C++에서 import 할거면 이대로 좋은거라 생각하고 Loadlibrary와 GetProcAddress를 이용하여 로드 하였으나 Error code 0x7f (ERROR_PROC_NOT_FOUND) 를 내놓는다. GetProcAddress로는 C type 의 name만을 콜할 수 있고 mangling된 풀네임으로 콜 할 수는 있다.
        GetProcAddress("EncodeBase64@@YAHPBDP...") (앞에 ?를 붙여야되나?? ㅎ)

그러므로 extern "C"를 해주거나 def 파일을 정의해주어서 mangling을 피한다. Visual C++ compiler에서는 원래 C 코드로 컴파일하도록 설정(c/c++->고급->컴파일옵션) 하여 이를 대신할 수도 있다. extern C는 C++에서만 사용할 수 있는 코드로 C 코드로 컴파일시는 extern "C"가 [Error C2059 구문 오류 : 문자열] 이란 에러를 생성한다.

결론적으로 아래와 같은 선언문 하나면 def 파일이나 C 코드로 컴파일 옵션 없이 export가 된다.

#ifdef __cplusplus
# define EXTERN_C extern "C"
#else
# define EXTERN_C 
#endif

#ifdef _WIN32
# define EXPORT_API(ret_type) EXTERN_C __declspec(dllexport) ret_type __stdcall
#else  //WIN32
# define EXPORT_API(ret_type) EXTERN_C ret_type
#endif //WIN32

**__stdcall과 __cdecl중 무엇을 사용해야하는지는 선택이며 caller가 맞는 형식으로 로드하면 된다. [Name Mangling  과 calling convention] 을 참고한다.

depends로 본 결과는 아래와 같다.

그런데 이기종은 def파일을 사용해야하는건가? 이건또 다음에 정리~

이제 caller에서는

typedef int ( __stdcall *PFN_ENCODEBASE64)(const char* in_str, char* out_str, size_t& out_size);

m_pfnEncodebase64 = (PFN_ENCODEBASE64) GetProcAddress(m_hModule, "EncodeBase64");


이렇게 dynamic load 시 함수포인터 얻는다~


댓글 없음:

댓글 쓰기