test_lib.exe のソースを見ると
#ifdef AES_MODES fn->fn_test_align = (g_talign*)GetProcAddress(h_dll, etad_name); fn->fn_mode_reset = (g_reset*)GetProcAddress(h_dll, eres_name); fn->fn_ecb_enc = (g_enc1*)GetProcAddress(h_dll, ecbe_name); fn->fn_ecb_dec = (g_dec1*)GetProcAddress(h_dll, ecbd_name); fn->fn_cbc_enc = (g_enc2*)GetProcAddress(h_dll, cbce_name); fn->fn_cbc_dec = (g_dec2*)GetProcAddress(h_dll, cbcd_name); fn->fn_cfb_enc = (g_enc3*)GetProcAddress(h_dll, cfbe_name); fn->fn_cfb_dec = (g_enc3*)GetProcAddress(h_dll, cfbd_name); fn->fn_ofb_cry = (g_enc3*)GetProcAddress(h_dll, ofb_name); fn->fn_ctr_cry = (g_enc4*)GetProcAddress(h_dll, ctr_name); if( !fn->fn_mode_reset || !fn->fn_test_align || !fn->fn_ecb_enc || !fn->fn_ecb_dec || !fn->fn_cbc_enc || !fn->fn_cbc_dec || !fn->fn_cfb_enc || !fn->fn_cfb_dec || !fn->fn_ofb_cry || !fn->fn_ctr_cry ) ok = 0; #endifと、DLLを LoadLibrary した後で、GetProcAddress により関数のアドレスを取得し、呼び出すという事をしていた。
で、名前の定義は aestst.h に記述されており、x86 と x64 で切り替えている。
#if defined( _WIN64 ) #define gt_name "aes_init" #define ek_name128 "aes_encrypt_key128" #define ek_name192 "aes_encrypt_key192" #define ek_name256 "aes_encrypt_key256" #define ek_name "aes_encrypt_key" #define eb_name "aes_encrypt" #define dk_name128 "aes_decrypt_key128" #define dk_name192 "aes_decrypt_key192" #define dk_name256 "aes_decrypt_key256" #define dk_name "aes_decrypt_key" #define db_name "aes_decrypt" #define etad_name "aes_test_alignment_detection" #define eres_name "aes_mode_reset" #define ecbe_name "aes_ecb_encrypt" #define ecbd_name "aes_ecb_decrypt" #define cbce_name "aes_cbc_encrypt" #define cbcd_name "aes_cbc_decrypt" #define cfbe_name "aes_cfb_encrypt" #define cfbd_name "aes_cfb_decrypt" #define ofb_name "aes_ofb_crypt" #define ctr_name "aes_ctr_crypt" #else #define gt_name "_aes_init@0" #define ek_name128 "_aes_encrypt_key128@8" #define ek_name192 "_aes_encrypt_key192@8" #define ek_name256 "_aes_encrypt_key256@8" #define ek_name "_aes_encrypt_key@12" #define eb_name "_aes_encrypt@12" #define dk_name128 "_aes_decrypt_key128@8" #define dk_name192 "_aes_decrypt_key192@8" #define dk_name256 "_aes_decrypt_key256@8" #define dk_name "_aes_decrypt_key@12" #define db_name "_aes_decrypt@12" #define etad_name "_aes_test_alignment_detection@4" #define eres_name "_aes_mode_reset@4" #define ecbe_name "_aes_ecb_encrypt@16" #define ecbd_name "_aes_ecb_decrypt@16" #define cbce_name "_aes_cbc_encrypt@20" #define cbcd_name "_aes_cbc_decrypt@20" #define cfbe_name "_aes_cfb_encrypt@20" #define cfbd_name "_aes_cfb_decrypt@20" #define ofb_name "_aes_ofb_crypt@20" #define ctr_name "_aes_ctr_crypt@24" #endifなるほど、だから x64 ではリンクエラーにならず、x86ではリンクエラーになったのだ。
x86 と x64 でマングリングの名前が違う事に自分も苛ついてはいました。
def ファイルに alias 指定できないの???と思って調べたら、ありました。
EXPORTS
alias=function_name
としてやれば良かったようです。
という事で、リンクエラーになった x86 用のビルドだけ以下のdefファイルを適用するようにしました。
LIBRARY Aes EXPORTS _aes_init=_aes_init@0 _aes_encrypt_key128=_aes_encrypt_key128@8 _aes_encrypt_key192=_aes_encrypt_key192@8 _aes_encrypt_key256=_aes_encrypt_key256@8 _aes_encrypt_key=_aes_encrypt_key@12 _aes_encrypt=_aes_encrypt@12 _aes_decrypt_key128=_aes_decrypt_key128@8 _aes_decrypt_key192=_aes_decrypt_key192@8 _aes_decrypt_key256=_aes_decrypt_key256@8 _aes_decrypt_key=_aes_decrypt_key@12 _aes_decrypt=_aes_decrypt@12 _aes_test_alignment_detection=_aes_test_alignment_detection@4 _aes_mode_reset=_aes_mode_reset@4 _aes_ecb_encrypt=_aes_ecb_encrypt@16 _aes_ecb_decrypt=_aes_ecb_decrypt@16 _aes_cbc_encrypt=_aes_cbc_encrypt@20 _aes_cbc_decrypt=_aes_cbc_decrypt@20 _aes_cfb_encrypt=_aes_cfb_encrypt@20 _aes_cfb_decrypt=_aes_cfb_decrypt@20 _aes_ofb_crypt=_aes_ofb_crypt@20 _aes_ctr_crypt=_aes_ctr_crypt@24こうする事で、見事にLNK2019を回避する事ができました。
今まで、やり方がわからなくて、Delphi 用 DLL には序数で指定したりと、大変だったんですよね。
2022/06/29 追記:
bigtypes.h に
#ifndef RETURN_VALUES # define RETURN_VALUES # if defined( DLL_EXPORT ) # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) # define VOID_RETURN __declspec( dllexport ) void __stdcall # define INT_RETURN __declspec( dllexport ) int __stdcall # elif defined( __GNUC__ ) # define VOID_RETURN __declspec( __dllexport__ ) void # define INT_RETURN __declspec( __dllexport__ ) int # else # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers # endif # elif defined( DLL_IMPORT ) # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) # define VOID_RETURN __declspec( dllimport ) void __stdcall # define INT_RETURN __declspec( dllimport ) int __stdcall # elif defined( __GNUC__ ) # define VOID_RETURN __declspec( __dllimport__ ) void # define INT_RETURN __declspec( __dllimport__ ) int # else # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers # endif # elif defined( __WATCOMC__ ) # define VOID_RETURN void __cdecl # define INT_RETURN int __cdecl # else # define VOID_RETURN void # define INT_RETURN int # endif #endifと定義されていて、x64は呼び出し規約が異なるので問題なく動作するが、x86で利用する場合は利用する側で
DLL_IMPORT をプリプロセッサの定義に追加しないと、コールスタックが破壊されて、よくわからないエラーになる
尚、aes.dll を使った dll を書きたい場合は、DLL_EXPORT や DLL_IMPORT といった汎用的な定義で判別していると、定義がバッティングするので、AES_DLL_EXPORT と言った定義に変更した方が良いと思う。できれば、DLL_IMPORT は定義しなくても AES_DLL_EXPORT が定義されていなかったら、利用する側のコードだと判別できるので、このマクロの書き方は改良した方が良いかな?
もうひとつ、vsyasm の -f オプションが Win32 ではなく win32 しか認識しないので、
vsyasm.props ファイルを修正する
... <CommandLineTemplate Condition="'$(Platform)'=='Win32'">"$(YASM_PATH)"vsyasm.exe -Xvc -f win32 [AllOptions] [AdditionalOptions] [Inputs]</CommandLineTemplate> <CommandLineTemplate Condition="'$(Platform)'!='Win32'">"$(YASM_PATH)"vsyasm.exe -Xvc -f $(Platform) [AllOptions] [AdditionalOptions] [Inputs]</CommandLineTemplate> ...
0 件のコメント:
コメントを投稿