C函数返回结构体在汇编下的实现
编译器:vc++6.0(因为此种实现依赖编译器处理)
此处只简要叙述一下机制。并附部分关键指令序列。
准备:
1,关于EBP:称做栈基址指针。为什么这样说呢?我们先来看看函数调用的过程:
参数从右到左压栈。
call指令执行,该指令将导致EIP压栈。
每个函数前两句必定是:push ebp mov ebp,esp。则call指令后,跳到被调函数出开始执行。保存ebp,即ebp压栈。
局部变量压栈。一般是sub esp,xxx的形式。
这就是将ebp称为基指针的原因:ebp-xx访问的时局部变量;ebp+xx访问的是参数。最左边参数地址是ebp+8h。ebp坐镇中间为基准。
2,函数返回值统一放入eax中。只要放得下。
3,栈扩展方向为从高地址到低地址。结构内的变量存贮方式:低地址对应声明顺序靠前的成员。一定要注意这里的区别!它关系到反汇编生成的代码里面的数字是怎么算出来的。但如果你自己写汇编代码就不用考虑这些了。只取成员名即可。
4,不能直接在两个存储器变量间用mov指令。
主要原理:
当调用一个返回结构体的函数时,在vc++下,是这样处理:
首先sub esp,xx,在堆栈上开辟一个空间。大小为结构体大小。
然后lea eax,[esp-xx],即将结构体在堆栈中的地址送eax。
push 参数。
push eax。
call 函数。
被调用函数内部:
routine:
push ebp mov ebp,esp
一般是定义一个结构体局部变量:
struct aa a;
sub esp, sizeof aa
然后处理结构体,
.
.
.
.
最后return a。
首先mov eax,[ebp+8h] ;将外面的调用函数在堆栈内开辟的结构体指针赋予eax。
然后将被调用函数在堆栈内开辟的结构体内的值赋到调用函数开辟的结构体内。
一般形式是:mov ecx,[ebp-结构体大小] ;赋第一个成员
mov [eax],ecx
mov ecx,[ebp-结构体大小+第一个成员大小(考虑对齐)]
&nbs
相关文档:
经常需要在程序中将远程传来的字节流进行结构化,或者将结构化的数据变成字节流传给远程主机。在C/C++程序中,结构化数据通常用结构体来组织,结构体也能够方便的转换为字节流,因此结构化的数据传输本不该成为问题,但在VC或GCC的默认设置下编译出的程序,却有一个值得注意的问题——结构体的对齐。 ......
/* =========================================================================== */
/* Project: mp3 player */
/* File: & ......
// backlightDlg.cpp : implementation file
//
#include "stdafx.h"
#include "backlight.h"
#include "backlightDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CbacklightDlg dialog
CbacklightDlg::CbacklightDlg(CWnd* pParent /*=NULL*/)
: CDialog(CbacklightDlg::IDD, pParent)
{
......
├—WINDOWS
│ ├—system32(存放Windows的系统文件和硬件驱动程序)
│ │ ├—config(用户配置信息和密码信息)
│ │ │ └—systemprofile(系统配置信息,用于恢复系统)
│ │ ├—drivers(用来存放硬件驱动文件,不建议删除)
│ │ ├—spool(用来存放系统打印文件。 ......
原文链接:http://blog.csdn.net/sytstarac/archive/2009/08/05/4411519.aspx
编译器:vc++6.0(因为此种实现依赖编译器处理)
此处只简要叙述一下机制。并附部分关键指令序列。
准备:
1,关于EBP:称做栈基址指针。为什么这样说呢?我们先来看看函数调用的过程:
参数从右到左压栈。
call指令执行,该指令将导致EIP压 ......