embedded/code/application/return/main.c
00001: #include <stdio.h>
00002:
00003: //lint -e530 -e123 -e428
00004:
00005: typedef struct {
00006: int i0_;
00007: int i1_;
00008: int i2_;
00009: } func_return_t;
00010:
00011: func_return_t foo (int _param)
00012: {
00013: func_return_t local;
00014: int reg_esp, reg_ebp;
00015:
00016: asm volatile(
00017: // get EBP
00018: "movl %%ebp, %0 \n"
00019: // get ESP
00020: "movl %%esp, %1 \n"
00021: : "=r" (reg_ebp), "=r" (reg_esp)
00022: );
00023: printf ("foo (): EBP = %x\n", reg_ebp);
00024: printf ("foo (): ESP = %x\n", reg_esp);
00025: printf ("foo (): (EBP) = %x\n", *(int *)reg_ebp);
00026: printf ("foo (): return address = %x\n", *(((int *)reg_ebp + 1)));
00027: local.i0_ = 1;
00028: local.i1_ = 2;
00029: local.i2_ = 3;
00030: printf ("foo (): &_param = %p\n", &_param);
00031: printf ("foo (): return value = %x\n", *(((int *)&_param) - 1));
00032: printf ("foo (): &local = %p\n", &local);
00033: printf ("foo (): ®_esp = %p\n", ®_esp);
00034: printf ("foo (): ®_ebp = %p\n", ®_ebp);
00035: return local;
00036: }
00037:
00038: int main ()
00039: {
00040: int reg_esp, reg_ebp;
00041: func_return_t local = foo (100);
00042:
00043: asm volatile(
00044: // get EBP
00045: "movl %%ebp, %0 \n"
00046: // get ESP
00047: "movl %%esp, %1 \n"
00048: : "=r" (reg_ebp), "=r" (reg_esp)
00049: );
00050: printf ("main (): EBP = %x\n", reg_ebp);
00051: printf ("main (): ESP = %x\n", reg_esp);
00052: printf ("main (): &local = %p\n", &local);
00053: printf ("main (): ®_esp = %p\n", ®_esp);
00054: printf ("main (): ®_ebp = %p\n", ®_ebp);
00055: return 0;
00056: }
图10.21
在这个示例程序中,main()和foo()函数内都定义了一个类型为func_return_t的local变量,且foo()的返回值类型也是func_return_t。毫无疑问,两个local变量的内存都将分配在各自函数的栈帧中,那foo()函数的local变量的值是如何通过函数返回值传递到main()函数的local变量中的呢?编译这个程序并运行以观察其结果,如图10.22所示。图10.23示例说明了在foo()函数内所看到的栈布局。
yunli.blog.51CTO.com
/embedded/build
$
make
yunli.blog.51CTO.com
/embedded/build
$
./release/return.exe
foo (): EBP = 22cd18
foo (): ESP = 22cce0
foo (): (EBP) = 22cd58
foo (): return address = 40125a
foo (): &_param = 0x22cd24
foo (): return value = 22cd3c
foo (): &local = 0x22cd00
foo (): ®_esp = 0x22cd10
foo (): ®_ebp = 0x22cd0c
main (): EBP = 22cd58
main (): ESP = 22cd20
main (): &local = 0x22cd3c
main (): ®_esp = 0x22cd4c
main (): ®_ebp = 0x22cd48
图10.22
从图中可以看出,main()函数调用foo()函数时除了将foo()函数所需的参数压入到栈中外,还将局部变量local的地址也压入到栈中,当foo()函数在进行函数返回时会将它的local变量的值通过这一指针拷贝到main()函数的local变量中。正是因为存在这一拷贝操作,所以在x86处理器上将结构当做函数返回类型是相对耗时的。