[英]Call C function from asm file by passing function address in a register
[英]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)
这会将值5
和4
移动到地址分别位于%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.