@Koncord

Есть функция для вызова функций с параметрами загруженными в стек. Для x86 всё понятно, но как можно портировать на x86-64?

inline uintptr_t CallNative(void* func, unsigned int* data, size_t size)
{
    uintptr_t low;
    uintptr_t high;
    uintptr_t result;
#ifdef __i386__
asm(
        "MOV EDI,ESP\n"
        "SUB EDI,%3\n"
        "MOV ESI,%4\n"
        "MOV ECX,%3\n"
        "PUSH DS\n"
        "POP ES\n"
        "CLD\n"
        "REP MOVSB\n"
        "MOV ESI,ESP\n"
        "SUB ESP,%3\n"
        "CALL %2\n"
        "MOV ESP,ESI\n"
        "MOV %0,EAX\n"
        "MOV %1,EDX\n"
        : "=m"(low), "=m"(high)
        : "m"(func), "m"(size), "m"(data)
        : "eax", "edx", "ecx", "esi", "edi", "cc"
);
    *reinterpret_cast<uintptr_t*>(&result) = low;
    *reinterpret_cast<uintptr_t*>(((uintptr_t) &result) + 4) = high;
#endif
    return result;
}
  • Вопрос задан
  • 286 просмотров
Пригласить эксперта
Ответы на вопрос 2
@none7
Код будет системозависимый. В Linux первые 6 аргументов передаются в регистрах (rdi, rsi, rdx, rcx, r8, r9), остальные по старинке . В Windows первые четыре в регистрах(rcx, rdx, r8, r9), остальные в стеке, НО место в стеке под первые 4 всё равно нужно выделить и лучше сохранить туда аргументы тоже; ради va_arg функций. Стек нужно выровнить по границе 16 байт ибо sse2 используется повсюду.
Кстати лучше всё таки реализовывать такую функцию не в C++ исходнике, а в отдельном .s файле. Ведь если функция возвращает double, то нет никаких гарантий, что всё вернётся в целости.
Ответ написан
Foolleren
@Foolleren
Компас есть, копать не люблю...
емнип инлайновый ассеблер немного вне закона для X64 у некоторых компиляторов
если ваш именно такой, то придётся внутри оставить только
#ifdef __i386__
asm(
бла бла бла
);
#endif


return result; - не прокатит - надо руками положить в rax
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы