2017-04-18 32 views
3

我有以下代码(caller.c):如何获得参数在被调用的整数?

#include <stdio.h> 

extern int callee(int); 

int main(int argc, char *argv[]){ 
    callee(4); 
    return 1; 
} 

和(callee.s):

.globl callee 

callee: 
    pop %eax 
    add $4, %eax 
    ret 

我与编译: GCC -m32 caller.c callee.s

并运行:

./a.out

区隔(核心转储)

我想知道我的错误是什么,因为我相信主现在应该推送一个32位的堆栈号。我没有改变堆栈,所以被调用者现在应该能够从同一个堆栈中弹出该号码。也许我应该在pop之前添加(添加$ 4,%esp)(如果被调用者的地址处于“方式”/实际被弹出的状态)。我也尝试过,但没有成功。被叫方现在应该从堆栈中获取数字并添加4。 eax寄存器应该是从被调用者到调用者的返回值(调用约定)的地方,但是在这里我忽略了返回值。

有人能帮助我吗?

相关的问题: calling assembly function from c

调用约定: https://en.wikipedia.org/wiki/X86_calling_conventions

+1

这会失败,因为您的'pop%eax'接受_CALL_指令推送的返回地址并放入_EAX_中。删除'pop%eax'并简单地通过'mov 4(%esp),%eax'访问第一个参数。执行转移到函数(32位代码)后,返回地址为0(ESP),第一个参数为4(ESP),第二个参数为8(ESP)等。 –

+0

要从函数返回int,将其加载到'eax'中(然而,请检查您的平台/编译器的具体情况)。 –

回答

4

(随着X86-32调用约定)的参数的函数被压入堆栈第一,然后返回地址。因此,你的pop指令弹出返回地址,并且随后ret试图返回到地址0x00000004,这是未映射的内存,导致崩溃。

另外,在这个约定中,被调用者是而不是应该弹出它的参数。来电者会这样做。

你应该写的代码是

callee: 
    movl 4(%esp), %eax 
    addl $4, %eax 
    ret 

您可以通过编辑

unsigned int callee(unsigned int x) { return x + 4; } 

与选项-m32 -O2 -S -fomit-frame-pointer和检查产生的.s文件确认自己这一点;你应该得到与上面相同的汇编代码。