Мне нужно написать код, который вызывает внешнюю функцию, которая может быть либо вызовом stdcall, либо cdecl в 32-битном приложении Windows.
Мой код, вызывающий, не может заранее знать, какой из них будет. Прямо сейчас, если я попытаюсь вызвать функцию cdecl из сайта вызова, который был определен как stdcall, я получаю диалог исключения checkEsp, и я предполагаю, что это по уважительной причине.
Есть ли способ сделать это?Вызов функции, которая может быть либо cdecl, либо stdcall
ответ
Это можно сделать следующим образом:
mov esi, esp
push arg3
push arg2
push arg1
call [SomeExternalProc]
mov esp, esi ; now the stack is always properly cleaned
Внешняя процедура должна сохранить ЕУИ. Или вы можете использовать любой другой регистр, сохраненный внешней процедурой, или даже переменную памяти - локальную или глобальную.
Хорошо, порядок аргументов одинаковый для CDECL и STDCALL - в обратном порядке.
Спасибо! это потрясающе – shoosh
cdecl и stdcall по определению несовместимы. В cdecl вызывающий пользователь очищает стек, в stdcall вызывающий очищает стек. Если вы принимаете stdcall, но на самом деле это cdecl, никто не очищает стек. Это означает, что ваш ESP (указатель стека) будет запутан после вызова. Может быть, если вы дадите более подробную информацию, возможно, работа вокруг, но нет возможности вызвать функцию, не зная, что это вызов, не испортив ваш стек.
См.: http://en.wikipedia.org/wiki/X86_calling_conventions для определения разницы.
Ну, есть ли надежный способ проверить эту ситуацию и просто исправить ESP, если это необходимо? Что вообще делает checkEsp? – shoosh
ESP - это указатель стека. Он отслеживает, где находится ваш стек. Теоретически, вы могли бы сохранить ESP в переменной в куче и получить ее после вызова, но это было бы очень грязно ... и я никогда не пробовал этого, поэтому я даже не уверен, что это сработает. Я не уверен в проверке механизма ESP, чтобы убедиться, что ESP правильно поддерживается до и после вызова. Лучшей стратегией было бы проверить соглашение о вызове и настроить ваш вызов на основе этого, хотя я не видел согласованного метода для программной проверки соглашения о вызове во время выполнения. – Enkid
Вы также можете использовать ALLOCA(), которая имеет побочный эффект сохранения и восстановления указателя стека:
{
alloca((uintptr_t)callback & 2);
callback();
}
- 1. C# GetFunctionPointerForDelegate cdecl вместо stdcall
- 2. Смежные соглашения о вызовах cdecl и stdcall
- 3. Изменение соглашения о вызове от cdecl до stdcall
- 4. Сортировка строки, которая может содержать либо время, либо расстояние
- 5. Как определить переменную, которая может быть либо массив или список
- 6. Обработка вывода, который может быть либо массивом, либо одной строкой
- 7. Как использовать обратный вызов cdecl с pinvoke
- 8. Как определить позицию символа, которая может быть либо буквой, либо подчеркиванием
- 9. LINQ to JSON - ошибка NullReferenceException от JToken, которая может быть либо JValue, либо JArray
- 10. Советы по сортировке строки, которая может быть либо ASCII, либо UTF-16
- 11. Самый странный повторный вызов функции когда-либо
- 12. Может ли EventArgs когда-либо быть нулевым?
- 13. Jquery: может event.target когда-либо быть неопределенным
- 14. Функция tagged `stdcall` не распознается как` stdcall`
- 15. Продвинутый прототип даты - может ли это когда-либо быть нулевым?
- 16. Как создать функцию, которая может возвращать что-либо в actionscript
- 17. Как написать функцию C, которая принимает либо int, либо float?
- 18. Определяется, может ли log4j шифровать либо сообщения журнала, либо файлы
- 19. Значение ESP не было должным образом сохранено во время вызова функции. смешивание STDCALL и Cdecl
- 20. Как можно -9% 7 быть либо -2, либо 5?
- 21. Получить левый элемент функции Либо
- 22. Pythonic способ перебора переменной, которая является либо элементом, либо списком
- 23. Портлет: форма, которая подчиняется либо действию, либо непосредственно фазе визуализации?
- 24. VBA Excel - функция, которая возвращает либо число, либо строку
- 25. C++ шаблоны: вызов какой-либо функции соответствует двум вариантам
- 26. WARN: переменная не может быть привязана (она либо не существует, либо была оптимизирована)
- 27. Супер ошибка выражения должна быть либо нулевой, либо функция
- 28. iPhone, ошибка: объект не может быть установлен - либо свойство readonly, либо нет установителя.
- 29. Aeson decode JSON object, который может быть либо строкой, либо int
- 30. вызов функции, которая может существовать в пакете
Попробуйте использовать функцию внешней интерфейс (FFI) библиотеки. –
FFI все еще должен знать вызывающее соглашение – shoosh
@HansPassant порядок аргументов один и тот же – shoosh