我有以下代码(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)(如果被调用者的地址是&#34;方式&#34; /实际上已经弹出)。我也试过这个也没有成功。 callee现在应该从堆栈中获取数字并添加4。 eax寄存器应该保持callee到caller的返回值(调用约定),但是在这里我忽略了返回值。
有人可以帮助我吗?
答案 0 :(得分:4)
(使用x86-32调用约定),函数的参数被推送到堆栈 first ,然后是返回地址。因此,您的Border defaultBorder = tf.getBorder();
...
tf.setBorder(defaultBorder);
指令会弹出返回地址,后续pop
尝试返回地址0x00000004,这是未映射的内存,导致崩溃。
此外,在此约定中,被调用者不应该弹出其参数。来电者会这样做。
您应该编写的代码是
ret
您可以通过编译
自行确认callee:
movl 4(%esp), %eax
addl $4, %eax
ret
使用选项unsigned int callee(unsigned int x) { return x + 4; }
并检查生成的-m32 -O2 -S -fomit-frame-pointer
文件;你应该得到与上面相同的汇编代码。