设为首页 加入收藏

TOP

vc如何返回函数结果及压栈参数(一)
2014-11-23 17:34:43 】 浏览:412
Tags:如何 返回 函数 结果 参数
首先说明,本文的分析对象是运行在IA32平台上的程序,试验用的编译器是Visual C++ 6.0中的cl.exe(Microsoft 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86)。
IA32程序利用程序堆栈来支持过程(procedure)调用,比如创建局部数据、传递参数、保存返回值信息、保存待今后恢复的寄存器等。为了一个过程调用而分配的堆栈空间称为一个stack frame。最顶层的stack frame由两个寄存器标识:ebp保存stack frame的基址,esp保存栈顶地址,因为在过程执行的时候栈顶寄存器的值会经常变化,所以绝大多数的信息都是通过ebp来相对寻址的。图1描绘了stack frame的基本结构。注意在IA32机器上,栈是向低地址方向增长,所以栈顶的地址值小于等于栈底的地址值。
stack "bottom"
________________ ______
| | |
| . | |
| | |
| . | |
| | |--->Earlier frames
| . | |
| | |
| . | |
| | | |
| |________________|__|___
| | . | |
| | . | |
| | . | |
Decreasing |________________| |
address | Argument n | |
| 4m-->|________________| |
| (m为整数) | . | |-->Caller's frame
| | . | |
| |________________| |
| | Argument 1 | |
| +8-->|________________| |
V | Return address | |
+4-->|________________|__|___
| Saved ebp | |
Frame Pointer-->|________________| |
ebp |Saved registers| |
|local variables| |
| and | |-->Current frame
| temporaries | |
|________________| |
| Argument | |
| build area | |
Stack pointer-->|________________|__|___
esp stack "top"
图1
调用C函数时,不管参数类型如何(包括浮点和struct类型)调用者(caller)负责从右至左将参数依次压栈,最后压入返回地址并跳转到被调函数入口处执行,其中每个参数都要按4字节地址对齐。按照地址来说被传递的参数和返回地址都是位于调用者stack frame中的。如果函数的返回值类型是整型(包括char,short,int,long及它们的无符号型)或指针类型的话,那么就利用EAX寄存器来传回返回值。请看下面的函数:
long foo_long(long offset)
{
long val = 2006 + offset;
return val;
}
用 /c /Od /FAsc 的编译选项(下文均同)编译出如下的汇编码:
PUBLIC _foo_long
_TEXT SEGMENT
_offset$ = 8
_val$ = -4
_foo_long PROC NEAR
; 38 : {
push ebp ;保存调用者的stack frame基址
mov ebp, esp
push ecx
; 39 : long val = 2006 + offset;
mov eax, DWORD PTR _offset$[ebp]
add eax, 2006
mov DWORD PTR _val$[ebp], eax
; 40 : return val;
; 将返回值保存进eax寄存器
mov eax, DWORD PTR _val$[ebp]
; 41 : }
mov esp, ebp
pop ebp
ret 0
_foo_long ENDP
_TEXT ENDS
如果函数返回的是结构体数据(非结构体指针)那得通过哪个中转站传递呢?这就要分三种情况:
1、结构体大小不超过4字节,那么仍然使用EAX寄存器传递返回值。比如:
/* 4字节大小结构体 */
typedef struct small_t
{
char m1;
char m2;
char m3;
char m4;
} small_t;
small_t create_small(void)
{
small_t small = {'s','m','a','l'};
return small;
}
void call_small(void)
{
small_t small_obj = create_small();
}
编译出的汇编码是:
;create_small函数
PUBLIC _create_small
_TEXT SEGMENT
_small$ = -4
_create_small PROC NEAR
; 16 : {
push ebp
mov ebp, esp
push ecx
; 17 : small_t small = {'s','m','a','l'};
mov BYTE PTR _small$[ebp], 115 ; 00000073H
mov BYTE PTR _small$[ebp+1], 109 ; 0000006dH
mov BYTE PTR _small$[ebp+2], 97 ; 00000061H
mov BYTE PTR _small$[ebp+3], 1
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇VC常用数据类型使用转换详解 下一篇VC程序中Windows XP风格程序界面..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目