簡體   English   中英

如何在C中從ASM調用C函數?

[英]How to call a C function from ASM in C?

我正在使用此代碼,但調試時會出現Segmentation fault 我正在使用MinGW進行編譯:

#include <stdio.h>
#include <stdlib.h>

int CallMe(int a, int b)
{
    printf("Called.");
    return a + b;
}

int main()
{
    printf("CallMe at 0x00%x\n", (unsigned int)&CallMe);
    printf("Calling CallMe... ");

    asm (
        "movl $5, (%eax);\r\n"
        "movl $4, (%ebx);\r\n"
        "call 0x00401334;\r\n"
    );

    printf("\n");

    return 0;
}

功能地址可以。 有任何想法嗎?

提前致謝。

@EricZ指出,第一個問題是通話。

但是,修復該問題並不一定會使該段錯誤消失。 您的兩個舉動也引起了問題:

movl $5, (%eax)
movl $4, (%ebx)

這會將值54移動到地址分別位於%eax%ebx 在此特定程序中,尚未定義這些地址。 如果要將它們作為參數傳遞,則需要將它們壓入堆棧。

pushl $5
pushl $4
call CallMe     % With some compilers, this may need to be _CallMe
addl  $8,%esp   % assuming a 32-bit processor

或者,如果函數期望它們在寄存器中(我不是說在這種情況下會這樣做,但是如果 ...),請刪除括號:

movl $5, %eax
movl $4, %ebx

您可能需要閱讀有關調用約定的信息,例如http://en.wikipedia.org/wiki/X86_calling_conventions

通常,請勿通過其硬編碼地址來調用該函數。 嘗試改為調用函數名稱。 函數名稱實際上是函數地址。

call 0x00401334

==>

call CallMe

這是在main()函數中真正執行的操作:

0x401268 <main>:    push   %ebp
0x401269 <main+1>:  mov    %esp,%ebp
0x40126b <main+3>:  sub    $0x8,%esp
0x40126e <main+6>:  call   0x401350 <__main>
0x401273 <main+11>: add    $0xfffffff8,%esp
0x401276 <main+14>: push   $0x401218  <--- address of CallMe
0x40127b <main+19>: push   $0x401242
0x401280 <main+24>: call   0x4013c0 <printf>
0x401285 <main+29>: add    $0x10,%esp
0x401288 <main+32>: add    $0xfffffff4,%esp
0x40128b <main+35>: push   $0x401250
0x401290 <main+40>: call   0x4013c0 <printf>
0x401295 <main+45>: add    $0x10,%esp
0x401298 <main+48>: movl   $0x5,(%eax)  <--- begin of your ASM block
0x40129e <main+54>: movl   $0x4,(%ebx)
0x4012a4 <main+60>: call   0x8024c1  <--- eewww! wrong address

所以現在的問題是:為什么將CALL 0x00401218組裝為CALL 0x008024C1

當然,您還將看到參數不是通過寄存器傳遞的,而是通過將它們壓入堆棧傳遞的。

實際上,我通過使用以下命令獲得了它:

asm (
    "pushl $5;\r\n"
    "pushl $4;\r\n"
    "call _CallMe;\r\n"
    "addl %esp,$8;\r\n"
);

我之前遇到的關於堆棧不平衡的問題是由我的代碼中的錯誤引起的,該錯誤使用addl %esp,8而不是addl %esp,$8 前者(嘗試)將地址8的內存內容添加到ESP ,而不是將常量8添加到ESP

如果要收集函數結果並將其保存(例如,保存在變量中),可以執行以下操作:

int res;
...
...

asm (
    "pushl $5;\r\n"
    "pushl $4;\r\n"
    "call _CallMe;\r\n"
    "addl $8,%%esp;\r\n"
    "movl %%eax,%0;\r\n" : "=m" (res)
);

如果您確實想使用其地址來調用該函數,則可以采用以下幾種方法:

通過將地址放在變量中,例如void指針:

void *addr;

addr = (void *)CallMe;
asm (
    "pushl $5;\r\n"
    "pushl $4;\r\n"
    "calll *%1;\r\n"
    "addl $8,%%esp;\r\n"
    "movl %%eax,%0;\r\n" : "=m" (res) : "m" (addr)
);

或通過將要調用的地址放入寄存器中:

asm (
    "pushl $5;\r\n"
    "pushl $4;\r\n"
    "movl $0x00401218,%%eax;\r\n"
    "calll *%%eax;\r\n"
    "addl $8,%%esp;\r\n"
    "movl %%eax,%0;\r\n" : "=m" (res)
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM