简体   繁体   中英

How to call a C function from ASM in C?

I'm using this code but it gives me Segmentation fault when debugging. I'm compiling with 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;
}

The function address is ok. Any ideas?

Thanks in advance.

First problem is the call, as @EricZ points out.

However, fixing that won't necessarily make the segfault go away. Your two moves are also causing a problem:

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

This is moving values 5 and 4 into locations whose addresses are in %eax and %ebx , respectively. In this particular program, those addresses haven't been defined. If you want to pass them as parameters, you need to push them onto the stack.

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

Or, if the function expects them in the registers (I'm not saying it would in this case, but if ...), remove the parentheses:

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

You might want to read up on calling conventions, eg, http://en.wikipedia.org/wiki/X86_calling_conventions .

Generally, don't call the function by its hard-coded address. Try call the function name instead. Function name is effectively the function address.

call 0x00401334

==>

call CallMe

This is what is really executing in your main() function:

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

So the question is now: why a CALL 0x00401218 is assembled as CALL 0x008024C1 ?

Of course, you will see also that parameters are not being passed by registers, but by pushing them into the stack.

In fact, I've got it by using this:

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

The problem I had before, about stack not bein balanced, was caused by a mistake in my code, that used addl %esp,8 instead of addl %esp,$8 . The former (tries to) add the contents of memory at address 8 to ESP , instead of adding the constant 8 to ESP .

If you want to collect the result of your function and save it, for example, in a variable, you can do as this:

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)
);

If you really want to call the function using its address, you can do it several ways:

By putting the address in a variable, say, a void pointer:

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)
);

Or by putting the address to call in a register:

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)
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM