我已阅读Extended Asm - Assembler Instructions with C Expression Operands和A 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编码。
===========================
答案 0 :(得分:1)
如果你想在一个函数体中放置一个跳转目标,你可以使用asm volatile (".globl my_label\n" "my_label:" );
并从asm跳转到那里。
编译器如何构建堆栈帧的选择将取决于优化级别和内联,因此没有安全的方法来编写asm以匹配您要跳转的任何函数的结尾成。
你展示的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,以便编译器知道发生了什么?