Вызов функций с различным количеством аргументов - PullRequest
0 голосов
/ 24 июня 2018

Я декомпилирую очень старую игру, и моя цель - восстановить 100% нативный код.Таким образом, мне нужно было бы максимально сохранить существующую архитектуру (например, просто использование std::function не очень полезно).

У меня есть коллекция статических функций с различнымиколичество параметров.Они хранятся в такой структуре:

struct ScriptFunction 
{
    const wchar_t* m_name;
    void* m_func;  // ptr to specific function 
    void* m_returnType;
    int m_argCount;
};

И заполняются следующим образом:

ScriptFunction s_functions[206] = {
    {L"AddMoveAroundDesire", &ScriptFunctions::AddMoveAroundDesire, &CScriptType::s_void, 2},
    {L"AddDoNothingDesire", &ScriptFunctions::AddDoNothingDesire, &CScriptType::s_void, 2},
    {L"AddAttackDesire", &ScriptFunctions::AddAttackDesire, &CScriptType::s_void, 3},
    {L"AddAttackDesireEx", &ScriptFunctions::AddAttackDesireEx, &CScriptType::s_void, 4},
    {L"AddGetItemDesire", &ScriptFunctions::AddGetItemDesire, &CScriptType::s_void, 2},
 ...

Итак, как мне вызвать ScriptFunction :: m_func с заданным m_argCount и void ** аргументы?Я должен как-то поместить параметры в стек и вызвать func-call, но понятия не имею.

Какой-то асм-код?va_list?Но как заполнить его во время выполнения?

UPD: Invoker выглядит следующим образом

void CScriptAccessible::InvokeInternal(ScriptFunction* scriptFunc, void** args)
{
    // here I have to push params from **args** to stack 
    // and somehow call ScriptFunction::m_func
    // In assembly I could see pushes to stack in a loop (driven by 
    // ScriptFunction::m_argCount). But I'm wondering, whether it's 
    // possible to do in C++ (push args on stack and call function by just address)
}

1 Ответ

0 голосов
/ 25 июня 2018

В языке существует только решение switch / cast. Это позволяет компилятору генерировать правильное соглашение о вызовах: например, , в x86-64 Linux первые несколько аргументов передаются в предопределенных регистрах. (Оптимизатор может объединить разные пути в переходы в своего рода развернутый цикл того типа, который вы ожидаете.) Помните также, что только в C / C ++ вообще не существует «стека».

Кстати, использование void* для функций также не гарантируется (поскольку оно может указывать на любой объект , но они не являются объектами), хотя обычно это работает (а POSIX требует его для dlsym) .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...