Мое приложение падает, потому что библиотечная функция, которую я вызываю, изменяет ESP, хотя она объявлена как cdecl.
Библиотека (libclang.dll) скомпилирована с использованием MinGW, и я использую ее из проекта VC ++. Функции экспортируются как C-функции, и Dependency Walker сообщает мне, что они имеют правильное соглашение о вызовах cdecl. Функции импортируются в мой проект с использованием dllimport, включая файл Clang «index.h». Кажется, не все функции портят ESP, поэтому некоторые функции работают успешно, другие приводят к сбоям.
Вот сборка работающей функции:
// call to clang_getNumDiagnostics(TU); - works!
5AF3EFAB mov esi,esp
5AF3EFAD mov eax,dword ptr [ebp-30h]
5AF3EFB0 push eax
5AF3EFB1 call dword ptr [__imp__clang_getNumDiagnostics (5AF977E0h)]
5AF3EFB7 add esp,4
5AF3EFBA cmp esi,esp
5AF3EFBC call @ILT+7135(__RTC_CheckEsp) (5AF16BE4h)
Следующий вызов функции изменит esp (добавление 4) и, следовательно, приведет к сбою из-за проверки во время выполнения в __RTC_CheckEsp.
// call to clang_getTranslationUnitCursor(TU); - fails!
5AF3EFC1 mov esi,esp
5AF3EFC3 mov eax,dword ptr [ebp-30h]
5AF3EFC6 push eax
5AF3EFC7 lea ecx,[ebp-234h]
5AF3EFCD push ecx
5AF3EFCE call dword ptr [__imp__clang_getTranslationUnitCursor (5AF9780Ch)]
5AF3EFD4 add esp,8
5AF3EFD7 cmp esi,esp
5AF3EFD9 call @ILT+7135(__RTC_CheckEsp) (5AF16BE4h)
Я уже опубликовал вопрос для этой проблемы, но мне показалось, что я специально спросил о соглашении о вызовах cdecl, чтобы получить более конкретную информацию о возможности прерывания esp, так как я думаю, что это может быть источником проблема ... Таким образом, извините этот "двойной пост".
Источник также может быть вызван неверной вызываемой функцией (возможно, из-за проблемы в файле def, который я создал с помощью dlltool, а затем создал импорт lib из - ординалы отличались от показанных Dependency Walker - я попробовал это с исправленными порядковыми номерами, но без изменений). Я чувствую, что это вряд ли источник проблемы, потому что другие вызовы функций работают нормально и возвращают правильные значения ...
Спасибо!
[Update]
По запросу сборка для __imp__clang_getTranslationUnitCursor
6660A4A0 push ebp
6660A4A1 mov ebp,esp
6660A4A3 push edi
6660A4A4 push ebx
6660A4A5 mov eax,dword ptr [ebp+8]
6660A4A8 mov ebx,eax
6660A4AA mov al,0
6660A4AC mov edx,14h
6660A4B1 mov edi,ebx
6660A4B3 mov ecx,edx
6660A4B5 rep stos byte ptr es:[edi]
6660A4B7 mov eax,dword ptr [ebp+8]
6660A4BA mov dword ptr [eax],12Ch
6660A4C0 mov eax,dword ptr [ebp+8]
6660A4C3 mov edx,dword ptr [ebp+0Ch]
6660A4C6 mov dword ptr [eax+10h],edx
6660A4C9 mov eax,dword ptr [ebp+8]
6660A4CC pop ebx
6660A4CD pop edi
6660A4CE pop ebp
6660A4CF ret 4
[Обновление 2]
Поскольку и VC ++, и GCC используют cdecl по умолчанию, и нет способа принудительно ввести другое соглашение о вызовах по умолчанию в GCC без явного указания этого в объявлении функции (что не делается для проблемных функций), я на самом деле уверен, что cdecl используется везде .
Я нашел эту ссылку , в которой указаны некоторые различия, которые могут объяснить, почему некоторые функции работают, а другие нет:
Visual C ++ / Win32
Объекты размером более 8 байт возвращаются в память.
Когда в памяти выполняется возврат, вызывающий передает указатель на ячейку памяти в качестве первого параметра (скрытый). Вызываемый заполняет память и возвращает указатель. Абонент выводит скрытый указатель вместе с остальными аргументами.
MinGW г ++ / Win32
Объекты размером более 8 байт возвращаются в память.
Когда в памяти выполняется возврат, вызывающая сторона передает указатель на ячейку памяти в качестве первого параметра (скрытый). Вызываемый заполняет память и возвращает указатель. callee извлекает скрытый указатель из стека при возврате.
может в этом проблема? Есть ли способ, которым я могу решить эту проблему? или мне нужно изменить Index.h Clang и переключиться на stdCall?
[Обновление 3]
Вот соответствующий GCC-Bug . Кажется, что в 4.6 (64-битной) и 4.7 (32-битной) вы можете использовать новый атрибут функции ms_abi , чтобы исправить проблему, описанную в [Обновление 2].