使用c

时间:2016-06-25 09:29:11

标签: c gcc assembly x86

我已阅读Extended Asm - Assembler Instructions with C Expression OperandsA side-by-side look at GNU Assembler (GAS) and Netwide Assembler (NASM),但有些问题尚无法解决。

好吧,我动态设计了一段代码。

; int xx_method_stub(void *fix_arg1, void* fix_arg2, void* arg3)
push  ebp                   ; 55
mov   ebp, esp              ; 89 E5
sub   esp, imm8_local_size  ; 83 EC imm8_local_size
mov   [ebp-4], imm_ptr_mid  ; C7 45 FC imm_ptr_mid
jmp   rel16_offset          ; E9 rel16_offset

查看有关它的详细信息here,可能有点过分。

现在它跳转到设计良好的地址,堆栈帧上下文如下:

16(%ebp)  - third function parameter
12(%ebp)  - second function parameter
 8(%ebp)  - first function parameter
 4(%ebp)  - old %EIP (the function's "return address")
 0(%ebp)  - old %EBP (previous function's base pointer)
-4(%ebp)  - first local variable

到目前为止,我想在c中需要一个jmp标签代码。

void stubthunk_init(stubthunk *stub, mid_t mid) {
    memcpy(stub, &stubthunk_templet, sizeof(stubthunk));
    stub->ph_mid = mid;
    stub->ph_eip_to_dispatch = (int) ((uintptr_t) dispatch - ((uintptr_t) stub + sizeof(stubthunk)));

// TODO retrieve stack variables as c-syntax local variables to make a function call in c for for portability.
//stack frame context
void *param_1; // 8(%%ebp)
void* param_2; //12(%%ebp)
void* local_1; //-4(%%ebp)

    disp:

#ifdef _MSC_VER
    __asm {
        mov param_1 [ebp+8]
        mov param_2 [ebp+12]
        mov local_1 [ebp-4]
    }
#else
    __asm__ __volatile(
        "mov 8(%%ebp), %0\n\t"
        "mov 12(%%ebp), %1\n\t"
        "mov -4(%%ebp), %2\n\t"
        :"=m" (param_1), "=m" (param_2), "=m" (local_1)
        :
        : /* clobbered register.  */
    );
#endif
    //USE #param_1 to restore or blance the stack
}

所以

有没有办法让它在c 中获取jmp代码块并检索堆栈变量作为c语法局部变量来在c中进行函数调用以便我不要不必在asm中编写更多代码,在这种情况下,无论函数调用约定如何,编译器确实对我有帮助,例如arm,x86,x64,......

我希望我可以自己为c中的函数prologue和结尾设置堆栈帧。通过这种方式,我可以将一个函数改装成一个jmp代码blok,并以我自己的方式手动平衡堆栈。

或者,就像在masm中一样,有一个persudo-directive invoke,例如invoke MessageBox, NULL, addr MsgBoxText, addr MsgBoxCaption, MB_OK,但它只存在于masm中。

======更新===========

我的目标:

static native int foo(int otherArgsMaybeExist);
int stdcall Java_xx_foo(void *fixedArgEnv, void *fixedArgCls, jint otherArgsMaybeExist){
    return 0;
}

// TODO release stubthunk *stub
stubthunk *stub = (stubthunk*) alloc_code(sizeof(stubthunk));
stubthunk_init(stub, (intptr_t) argsize);

现在,我在内存中动态创建一个stdcall函数启动代码 除了一些必要的数据之外应该尽可能少(这里传递一个jmethodID,以便让跟随的interpret_stdcall_x86知道被叫谁。)

使用native修饰符向stub注册java方法并输入本机世界后,它将进入我的代码。事实上,它是像Windows上的Detours这样的蹦床。

跳跃后,所有拦截的方法都会进入interpret_stdcall_x86, 它负责堆栈的爆炸。

原来是这样的:

foo -> Java_xx_foo -> return

现在,将会像:

foo -> stubthunk + interpret_stdcall_x86 + blance the stack -> return

这里,thubthunk是硬编码,但是使用指令动态创建。然而,我希望我可以使用c为interpret_stdcall_x86编码。

===========================

1 个答案:

答案 0 :(得分:1)

如果你想在一个函数体中放置一个跳转目标,你可以使用asm volatile (".globl my_label\n" "my_label:" );并从asm跳转到那里。

但是,你不应期望这种方法有效。

编译器如何构建堆栈帧的选择将取决于优化级别和内联,因此没有安全的方法来编写asm以匹配您要跳转的任何函数的结尾成。

目前尚不清楚这一切的目的是什么,以及为什么你不能用C做这件事。

你展示的inline-asm已损坏:

__asm__ __volatile(
    "mov 8(%%ebp), %0\n\t"   // mov mem,mem  isn't valid.
    "mov 12(%%ebp), %1\n\t"
    "mov -4(%%ebp), %2\n\t"
    :"=m" (param_1), "=m" (param_2), "=m" (local_1)
     // instead, use "=r" constraints to have the outputs in registers
     // from there, the compiler will put them where it wants them
    :
    : /* clobbered register.  */
);

我不知道从内联asm自己加载堆栈中的args是否有意义。为什么不直接使用函数args,以便编译器知道发生了什么?