How to wrap a function with variable length arguments?

后端 未结 7 2060
借酒劲吻你
借酒劲吻你 2020-12-05 12:54

I am looking to do this in C/C++.

I came across Variable Length Arguments but this suggests a solution with Python & C using libffi.

Now, if I want to wr

7条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-05 13:25

    Actually, there's a way to call a function that has no va_list version from a wrapper. The idea is to use assembler, do not touch arguments in stack, and temporary replace the function return address.

    Example for Visual C x86. call addr_printf calls printf():

    __declspec( thread ) static void* _tls_ret;
    
    static void __stdcall saveret(void *retaddr) {
        _tls_ret = retaddr;
    }
    
    static void* __stdcall _getret() {
        return _tls_ret;
    }
    
    __declspec(naked)
    static void __stdcall restret_and_return_int(int retval) {
        __asm {
            call _getret
            mov [esp], eax   ; /* replace current retaddr with saved */
            mov eax, [esp+4] ; /* retval */
            ret 4
        }
    }
    
    static void __stdcall _dbg_printf_beg(const char *fmt, va_list args) {
        printf("calling printf(\"%s\")\n", fmt);
    }
    
    static void __stdcall _dbg_printf_end(int ret) {
        printf("printf() returned %d\n", ret);
    }
    
    __declspec(naked)
    int dbg_printf(const char *fmt, ...)
    {
        static const void *addr_printf = printf;
        /* prolog */
        __asm {
            push ebp
            mov  ebp, esp
            sub  esp, __LOCAL_SIZE
            nop
        }
        {
            va_list args;
            va_start(args, fmt);
            _dbg_printf_beg(fmt, args);
            va_end(args);
        }
        /* epilog */
        __asm {
            mov  esp, ebp
            pop  ebp
        }
        __asm  {
            call saveret
            call addr_printf
            push eax
            push eax
            call _dbg_printf_end
            call restret_and_return_int
        }
    }
    

提交回复
热议问题