在GCC

2012-10-04 57 views
0

使用內聯彙編調用方法,以便正如我所說的,我想打電話給使用使用gcc內聯彙編的方法。所以,我搜索了x86如何工作,以及調用約定是什麼,然後我嘗試了一些簡單的調用,完美地工作。然後我試圖嵌入V8,這是我原來的目標,但它沒有工作這麼好...... 這裏是我的代碼:在GCC

v8::Handle<v8::Value> V8Method::staticInternalMethodCaller(const v8::Arguments& args, int argsize, void* object, void* method) 
{ 
    int i = 0; 
    char* native_args; 

    // Move the ESP to the end of the array (argsize is the array size in byte) 
    asm("subl %1, %%esp;" 
     "movl %%esp, %0;" 
     : "=r"(native_args) 
     : "r"(argsize)); 


    // This for loop only converts V8 type to native type, 
    // and puts them in the array: 

    for (; i < args.Length(); ++i) 
    { 
     if (args[i]->IsInt32()) 
     { 
      *(int*)(native_args) = args[i]->Int32Value(); 

      native_args += sizeof(int); 
     } 
     else if (args[i]->IsNumber()) 
     { 
      *(float*)(native_args) = (float)(args[i]->NumberValue()); 

      native_args += sizeof(float); 
     } 
    } 

    // Then call the method: 

    asm("call *%1;" : : "c"(object), "r"(method)); 

    return v8::Null(); 
} 

,這裏是生成的彙編:

__ZN3srl8V8Method26staticInternalMethodCallerERKN2v89ArgumentsEiPvS5_: 
LFB1178: 
    .cfi_startproc 
    .cfi_personality 0,___gxx_personality_v0 
    .cfi_lsda 0,LLSDA1178 
    pushl %ebp 
    .cfi_def_cfa_offset 8 
    .cfi_offset 5, -8 
    movl %esp, %ebp 
    .cfi_def_cfa_register 5 
    pushl %ebx 
    subl $68, %esp 
    .cfi_offset 3, -12 
    movl $0, -12(%ebp) 
    movl 12(%ebp), %eax 
/APP 
# 64 "method.cpp" 1 
    subl %eax, %esp; movl %esp, %ebx; addl $4, %esp 
# 0 "" 2 
/NO_APP 
    movl %ebx, -16(%ebp) 
    jmp L74 
L77: 
    movl -12(%ebp), %eax 
    movl %eax, (%esp) 
    movl 8(%ebp), %ecx 
LEHB25: 
    call __ZNK2v89ArgumentsixEi 
LEHE25: 
    subl $4, %esp 
    movl %eax, -36(%ebp) 
    leal -36(%ebp), %eax 
    movl %eax, %ecx 
    call __ZNK2v86HandleINS_5ValueEEptEv 
    movl %eax, %ecx 
LEHB26: 
    call __ZNK2v85Value7IsInt32Ev 
LEHE26: 
    testb %al, %al 
    je L75 
    movl -12(%ebp), %eax 
    movl %eax, (%esp) 
    movl 8(%ebp), %ecx 
LEHB27: 
    call __ZNK2v89ArgumentsixEi 
LEHE27: 
    subl $4, %esp 
    movl %eax, -32(%ebp) 
    leal -32(%ebp), %eax 
    movl %eax, %ecx 
    call __ZNK2v86HandleINS_5ValueEEptEv 
    movl %eax, %ecx 
LEHB28: 
    call __ZNK2v85Value10Int32ValueEv 
LEHE28: 
    movl %eax, %edx 
    movl -16(%ebp), %eax 
    movl %edx, (%eax) 
    movl -16(%ebp), %eax 
    movl (%eax), %ebx 
    movl $LC4, 4(%esp) 
    movl $__ZSt4cout, (%esp) 
LEHB29: 
    call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 
    movl -16(%ebp), %edx 
    movl %edx, (%esp) 
    movl %eax, %ecx 
    call __ZNSolsEPKv 
    subl $4, %esp 
    movl $LC5, 4(%esp) 
    movl %eax, (%esp) 
    call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 
    movl %ebx, (%esp) 
    movl %eax, %ecx 
    call __ZNSolsEi 
    subl $4, %esp 
    movl $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%esp) 
    movl %eax, %ecx 
    call __ZNSolsEPFRSoS_E 
    subl $4, %esp 
    addl $4, -16(%ebp) 
    jmp L76 
L75: 
    movl -12(%ebp), %eax 
    movl %eax, (%esp) 
    movl 8(%ebp), %ecx 
    call __ZNK2v89ArgumentsixEi 
LEHE29: 
    subl $4, %esp 
    movl %eax, -28(%ebp) 
    leal -28(%ebp), %eax 
    movl %eax, %ecx 
    call __ZNK2v86HandleINS_5ValueEEptEv 
    movl %eax, %ecx 
LEHB30: 
    call __ZNK2v85Value8IsNumberEv 
LEHE30: 
    testb %al, %al 
    je L76 
    movl -12(%ebp), %eax 
    movl %eax, (%esp) 
    movl 8(%ebp), %ecx 
LEHB31: 
    call __ZNK2v89ArgumentsixEi 
LEHE31: 
    subl $4, %esp 
    movl %eax, -24(%ebp) 
    leal -24(%ebp), %eax 
    movl %eax, %ecx 
    call __ZNK2v86HandleINS_5ValueEEptEv 
    movl %eax, %ecx 
LEHB32: 
    call __ZNK2v85Value11NumberValueEv 
LEHE32: 
    fstps -44(%ebp) 
    flds -44(%ebp) 
    movl -16(%ebp), %eax 
    fstps (%eax) 
    movl -16(%ebp), %eax 
    movl (%eax), %ebx 
    movl $LC4, 4(%esp) 
    movl $__ZSt4cout, (%esp) 
LEHB33: 
    call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 
    movl -16(%ebp), %edx 
    movl %edx, (%esp) 
    movl %eax, %ecx 
    call __ZNSolsEPKv 
    subl $4, %esp 
    movl $LC5, 4(%esp) 
    movl %eax, (%esp) 
    call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 
    movl %ebx, (%esp) 
    movl %eax, %ecx 
    call __ZNSolsEf 
    subl $4, %esp 
    movl $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%esp) 
    movl %eax, %ecx 
    call __ZNSolsEPFRSoS_E 
    subl $4, %esp 
    addl $4, -16(%ebp) 
L76: 
    incl -12(%ebp) 
L74: 
    movl 8(%ebp), %ecx 
    call __ZNK2v89Arguments6LengthEv 
    cmpl -12(%ebp), %eax 
    setg %al 
    testb %al, %al 
    jne L77 
movl 16(%ebp), %eax 
    movl 20(%ebp), %edx 
    movl %eax, %ecx 
/APP 
# 69 "method.cpp" 1 
    call *%edx; 
# 0 "" 2 
/NO_APP 
    call __ZN2v84NullEv 
    leal -20(%ebp), %edx 
    movl %eax, (%esp) 
    movl %edx, %ecx 
    call __ZN2v86HandleINS_5ValueEEC1INS_9PrimitiveEEENS0_IT_EE 
    subl $4, %esp 
    movl -20(%ebp), %eax 
jmp L87 
L83: 
    movl %eax, (%esp) 
    call __Unwind_Resume 
L84: 
    movl %eax, (%esp) 
    call __Unwind_Resume 
L85: 
    movl %eax, (%esp) 
    call __Unwind_Resume 
L86: 
    movl %eax, (%esp) 
    call __Unwind_Resume 
LEHE33: 
L87: 
    movl -4(%ebp), %ebx 
    leave 
    .cfi_restore 5 
    .cfi_restore 3 
    .cfi_def_cfa 4, 4 
    ret 
    .cfi_endproc 

所以,這個靜態方法是一個回調(我之前做了一些簽名檢查),女巫應該調用提供有效C++本機參數的特定方法。爲了加快速度並避免args的副本,我試圖將所有參數加載到本地數組中,然後修改ESP以使此數組成爲參數。

方法調用的效果很好,但我沒有得到正確的參數......我已經做了很多關於函數調用的研究,調用約定,以及大量的試驗(這是所有成功的),但我不」不知道發生了什麼...有什麼我錯過了嗎?

基本上,被叫方應該在ESP中的頂部得到它的參數,在我的情況下,數組...(我精確的排列是有效的)

我用GCC。

+2

不要爲是法國人還是不親遺憾,但請不要* *感到很抱歉對我們造成這個爛攤子!請格式化您的代碼,以便普通人可以閱讀它(這涉及新的行,空格,縮進,typedefs等)Merci! –

回答

2

有許多問題要嘗試什麼。

  • 使用內聯彙編不能修改%esp,因爲編譯器 可能是使用%esp引用局部變量和參數。這可能工作,如果編譯器使用%ebp來代替,但沒有保證。

  • 你永遠不會返回之前撤消%esp修改。

  • 在你的內聯彙編,你需要聲明%esp是側實現。

  • 你可能需要通過object作爲一種無聲的第一個參數。 method是一個實例方法,而不是一個靜態方法?

  • 所有這一切都取決於你所使用的調用約定:cdeclstdcall

+0

編譯器正在使用'%ebp',我知道沒有保證,但是當我查看生成的ASM時,它使用'%ebp'。而且,我忘記撤銷'%esp'修改,但它並沒有改變args在被調用者內部是無效的事實。Side-affected?在C++中,僅存在其使用'%ecx'傳遞對象(' 「C」(對象)'),其作用就像用於CDECL參數... – SRLKilling

+0

更多可能性THISCALL約定:呼叫等'ARGS [I] - > Int32Value()'是破壞你的本地參數數組?也許'float'應該以'double'的形式傳遞?錯誤的論點究竟是什麼樣的? –

+0

順便說一句,gcc上的thiscall不會在'%ecx'中傳遞'this'。它被傳遞到堆棧上。 http://en.wikipedia.org/wiki/X86_calling_conventions#thiscall –

0

我建議不要嘗試這種自己動手做,有很多煩人的小細節必須得到完全正確的。我建議改爲使用FFCALL library,特別是avcall這一套方法。

我想象這樣的事情會做你想要什麼:

v8::Handle<v8::Value> V8Method::staticInternalMethodCaller(const v8::Arguments& args, int argsize, void* object, void* method) 
{ 
    // Set up the argument list with the function pointer, return type, and 
    // pointer to value storing the return value (assuming int, change if 
    // necessary) 
    int return_value; 
    av_alist alist; 
    av_start_int(alist, method, &return_value); 

    for(int i = args.Length() - 1; i >= 0; i--) 
    { 
     // Push the arguments onto the argument list 
     if (args[i]->IsInt32()) 
     { 
      av_int(alist, args[i]->Int32Value()); 
     } 
     else if (args[i]->IsNumber()) 
     { 
      av_double(alist, (float)(args[i]->NumberValue()); 
     } 
    } 

    av_call(alist); // Call the function 

    return v8::Null(); 
} 
+0

嗯,這個庫看起來不錯,但我在做C++不是C ...另外,即使我決定使用一個庫,我還是想學習,知道哪裏是我的錯誤,我不瞭解我的代碼中的失敗。 – SRLKilling