VC6对函数返回过程的优化(下)

LabVIEW调用DLL返回指针的实战指南:从VC6.0到MoveBlock内存操作 本文提供了在LabVIEW中调用C/C++动态链接库并处理返回指针的完整实战指南。针对DLL函数返回指针的常见需求,详细解析了从VC6.0创建DLL到在LabVIEW端使用MoveBlock内存操作函数安全读取数据的全流程,涵盖了单值、数组及结构体的处理方法,并强调了跨平台兼容性与内存释放等关键注意事项。 阅读详情

1:    // test.cpp : Defines the entry point for the console application.
2:    //
3:
4:    #include "stdafx.h"
5:
6:    struct complex{
7:        int i; //x
8:        int j; //y
9:        int k; //z
10:       int t; //time. w=-ict
11:   };
12:
13:   complex test( int a, int b, int c , int d);
14:
15:   int main(int argc, char* argv[])
16:   {

0040D440   push        ebp
0040D441   mov         ebp,esp
0040D443   sub         esp,80h
0040D449   push        ebx
0040D44A   push        esi
0040D44B   push        edi
0040D44C   lea         edi,[ebp-80h]
0040D44F   mov         ecx,20h
0040D454   mov         eax,0CCCCCCCCh
0040D459   rep stos    dword ptr [edi]

17:       int a, b, c, d;
18:       struct complex z;
19:
20:       a = 0x11;
0040D45B   mov         dword ptr [ebp-4],11h
21:       b = 0x30;
0040D462   mov         dword ptr [ebp-8],30h
22:       c = 0x88;
0040D469   mov         dword ptr [ebp-0Ch],88h
23:       d = 0x9302;
0040D470   mov         dword ptr [ebp-10h],9302h
24:
25:       z = test( a, b, c, d);
0040D477   mov         eax,dword ptr [ebp-10h]
0040D47A   push        eax
0040D47B   mov         ecx,dword ptr [ebp-0Ch]
0040D47E   push        ecx
0040D47F   mov         edx,dword ptr [ebp-8]
0040D482   push        edx
0040D483   mov         eax,dword ptr [ebp-4]
0040D486   push        eax
0040D487   lea         ecx,[ebp-40h]
0040D48A   push        ecx
0040D48B   call        @ILT+15(test) (00401014)
0040D490   add         esp,14h
0040D493   mov         edx,dword ptr [eax]
0040D495   mov         dword ptr [ebp-30h],edx
0040D498   mov         ecx,dword ptr [eax+4]
0040D49B   mov         dword ptr [ebp-2Ch],ecx
0040D49E   mov         edx,dword ptr [eax+8]
0040D4A1   mov         dword ptr [ebp-28h],edx
0040D4A4   mov         eax,dword ptr [eax+0Ch]
0040D4A7   mov         dword ptr [ebp-24h],eax
0040D4AA   mov         ecx,dword ptr [ebp-30h]
0040D4AD   mov         dword ptr [ebp-20h],ecx
0040D4B0   mov         edx,dword ptr [ebp-2Ch]
0040D4B3   mov         dword ptr [ebp-1Ch],edx
0040D4B6   mov         eax,dword ptr [ebp-28h]
0040D4B9   mov         dword ptr [ebp-18h],eax
0040D4BC   mov         ecx,dword ptr [ebp-24h]
0040D4BF   mov         dword ptr [ebp-14h],ecx

26:
27:       return 0;
0040D4C2   xor         eax,eax
28:   }
0040D4C4   pop         edi
0040D4C5   pop         esi
0040D4C6   pop         ebx
0040D4C7   add         esp,80h
0040D4CD   cmp         ebp,esp
0040D4CF   call        __chkesp (0040d400)
0040D4D4   mov         esp,ebp
0040D4D6   pop         ebp
0040D4D7   ret

29:
30:
31:   struct complex test( int a, int b, int c, int d)
32:   {
0040D4E0   push        ebp
0040D4E1   mov         ebp,esp
0040D4E3   sub         esp,50h
0040D4E6   push        ebx
0040D4E7   push        esi
0040D4E8   push        edi
0040D4E9   lea         edi,[ebp-50h]
0040D4EC   mov         ecx,14h
0040D4F1   mov         eax,0CCCCCCCCh
0040D4F6   rep stos    dword ptr [edi]

33:       struct complex z;
34:       z.i = a;
0040D4F8   mov         eax,dword ptr [ebp+0Ch]
0040D4FB   mov         dword ptr [ebp-10h],eax

35:       z.j = b;
0040D4FE   mov         ecx,dword ptr [ebp+10h]
0040D501   mov         dword ptr [ebp-0Ch],ecx

36:       z.k = c;
0040D504   mov         edx,dword ptr [ebp+14h]
0040D507   mov         dword ptr [ebp-8],edx

37:       z.t = d;
0040D50A   mov         eax,dword ptr [ebp+18h]
0040D50D   mov         dword ptr [ebp-4],eax

38:
39:       return z;
0040D510   mov         ecx,dword ptr [ebp+8]
0040D513   mov         edx,dword ptr [ebp-10h]
0040D516   mov         dword ptr [ecx],edx
0040D518   mov         eax,dword ptr [ebp-0Ch]
0040D51B   mov         dword ptr [ecx+4],eax
0040D51E   mov         edx,dword ptr [ebp-8]
0040D521   mov         dword ptr [ecx+8],edx
0040D524   mov         eax,dword ptr [ebp-4]
0040D527   mov         dword ptr [ecx+0Ch],eax
0040D52A   mov         eax,dword ptr [ebp+8]

40:   }
0040D52D   pop         edi
0040D52E   pop         esi
0040D52F   pop         ebx
0040D530   mov         esp,ebp
0040D532   pop         ebp
0040D533   ret

哈哈,终于没办法优化了。现在的方法就是把常规的4个32bits的返回值放到stack里面去,指向这个返回值的地址放到EAX返回。

额外的话题,几种函数调用的方式:
★__cdecl
cb
的默认值,它会在输出函数名前加_,并保留此函数名不变,参数按照从右到左的顺序依次传递给栈,也可以写成_cdecl和cdecl形式。和_stdcall最大的不同是,返回的时候栈由调用者(Caller)而非被调用子程序(Callee)来调整。这样的好处是支持变长度参数列表,因为Callee并不方便知道变量的长度。
★__fastcall
她修饰的函数的参数将尽可能地使用寄存器来处理,其函数名前加@,参数按照从左到右的顺序压栈;
★__pascal
它说明的函数名使用Pascal格式的命名约定。这时函数名全部大写。参数按照从左到右的顺序压栈;
★__stdcall
使用标准约定的函数名。函数名不会改变。使用__stdcall修饰时。参数按照由右到左的顺序压栈,也可以是_stdcall;

对于_cdecl, 函数调用的堆栈变化的解说:
1.将函数参数入栈,第一个参数在栈顶,最后一个参数在栈底。
2.将CALL指令下一行代码的地址入栈。
2.跳转--eip的值被重新设置为被调函数的起始地址。
3.进入函数代码空间后,将基址指针EBP入栈,然后让基址指针EBP指向当前堆栈栈顶,并使用它访问存在堆栈中的函数输入参数及堆栈中的其他数据。
4.sub esp,N
堆栈指针ESP减少一个值,如44H,向上移动一个距离,留出一个空间给该函数作为临时存储区。也就是说,子函数的变量都是存储在栈中。这里N是函数内局部变量的总字节数加上一个整数,一般为40。此后esp即为被调函数的堆栈指针了。
5.初始化esp ~ esp-N之间的N字节空间
这是对堆栈中已分配给局部变量使用的内存空间的初始化,一般全部设置为
0xcc。
6. 顺序执行函数内语句。
此时函数的堆栈位于所有局部变量的内存空间之后,二者之间一般有
40字节的隔离带。
{
   //
以上准备工作做好后,函数正式被执行,如下所示。
   1.将其他指针或寄存器中的值入栈,以便在函数中使用这些寄存器。
   2.执行代码。
   3.执行return()返回执行结果,将要返回的值存入EAX中或栈中。
   4.步骤6.1中的指针出栈。
}
7.
将EBP的值传给堆栈指针ESP,使ESP复原为2.c之前的值。此时进入函数时EBP的值在栈顶。
8.基址指针EBP出栈,复原为2.b之前的EBP的值。
9.执行RET指令,“调用函数”的地址出栈,本函数返回到CALL指令的下一行。
3.函数返回到CALL指令下一行,将堆栈指针加一个数值,以使堆栈指针恢复到以上步骤1执行之前的值。该数值是上面第一步入栈参数的总长度。

最后的那个check ESP的函数我也打印出来,其实就是检查堆栈调整后EBP是否和ESP相等。如果不等,调用错误处理代码。
__chkesp:
0040D400   jne         __chkesp+3 (0040d403)
0040D402   ret
0040D403   push        ebp
0040D404   mov         ebp,esp
0040D406   sub         esp,0
0040D409   push        eax
0040D40A   push        edx
0040D40B   push        ebx
0040D40C   push        esi
0040D40D   push        edi
0040D40E   push        offset string "The value of ESP was not properl"... (00422e90)
0040D413   push        offset string "" (00422c50)
0040D418   push        2Ah
0040D41A   push        offset string "i386//chkesp.c" (00422e80)
0040D41F   push        1
0040D421   call        _CrtDbgReport (00408b10)
0040D426   add         esp,14h
0040D429   cmp         eax,1
0040D42C   jne         __chkesp+2Fh (0040d42f)
0040D42E   int         3
0040D42F   pop         edi
0040D430   pop         esi
0040D431   pop         ebx
0040D432   pop         edx
0040D433   pop         eax
0040D434   mov         esp,ebp
0040D436   pop         ebp
0040D437   ret
0040D438   int         3

VC6.0编程经典实例深入剖析 本文还有配套的精品资源,点击获取 简介:本教程详细解读了Microsoft Visual C++ 6.0(VC6.0)这一经典集成开发环境的使用,通过丰富的实例分析,帮助读者深入理解并掌握C++编程的基础知识和应用技巧。教程内容覆盖从基本语法、数据类型、函数使用、面向对象编程,到内存管理、输入输出流、MFC框架、异常处理和调试技巧等多个方面。通过实际项目案例,如GUI程序或... 阅读详情

相关推荐

VC6_FixFont:优化Visual C++ 6.0字体体验

在本章,我们将深入了解VC6_FixFont工具的核心功能,这是一个旨在改善老版本的Visual Studio 6.0用户界面字体显示的工具。随着技术的发展,许多开发者仍在使用这款经典的开发环境,但受限于旧版字体显示问题,界面美观性和可读性受到较大影响。VC6_FixFont的推出,正是为了解决这些问题。字体渲染是将字体信息转换为用户可以阅读的像素点阵的过程。现代操作系统采用了多种技术来改善字体的显示效果,包括消除锯齿和字体平滑。这些技术可以提升字体边缘的平滑度,使其在屏幕上显示得更加美观。

weixin_36064575的博客 1003

file: i386/chkesp.c Line: 42错误产生原因

The value of ESP was not properly saved across a function call. 错误在调用DLL中的函数有时候会出现如下对话框的错误:Microsoft Visual C++ Debug Library:Debug Error:Program: ... Module:file: i386/chkesp.cLine:

4429

VC6.0环境下OpenGL绘制直线的实践教程

简介:在Windows平台上,使用Visual C++ 6.0(VC6.0)结合OpenGL库进行2D和3D图形编程是常见的开发实践。本文将介绍如何在VC6.0环境下,通过创建MFC对话框应用程序,配置OpenGL环境,并在其中使用OpenGL函数来绘制基本的直线图形。文章详细阐述了OpenGL的初始化过程,包括创建设备上下文、设置像素格式、初始化渲染上下文。此外,还展示了如何通过代码实现直线绘制,并说明了如何通过对话框控件来控制直线的起点和终点坐标,以及如何响应控件更改事件来更新绘图。

weixin_35973118的博客 1034

DLL调试出错

"Debug Error !Program : TradNSP.EXEModule :File : i386/chkesp.cLine : 42The value of ESP was not properly saved across a function call. This is usually a result of calling a function decla

后恋的专栏 659

通过VC6++和OpenGL实现的3D彩色自行车渲染

本章节深入探讨了3D图形渲染的基础概念,包括顶点变换、投影、视图变换、着色与纹理映射。同时,我们分析了3D图形的交互技术,包括鼠标和键盘事件的处理、用户界面设计以及碰撞检测与响应实现。掌握这些知识对于创建高性能、交互性强的OpenGL应用程序至关重要。通过本章内容的学习,读者应能够利用OpenGL库在VC6++环境中创建和实现基础的3D图形交互应用程序。

weixin_42515842的博客 1098

将VC2008项目迁移到VC6的实践指南

在软件开发的历程中,随着技术的不断革新和开发需求的演变,项目往往会遇到从旧版本的Visual Studio迁移到新版本的情况。这一章节将为您提供一个概览,了解在不同Visual Studio版本间进行项目转换的意义、可能遇到的挑战以及转换带来的潜在优势。.sln文件是Visual Studio解决方案文件,它是一种文本文件,用于定义Visual Studio项目的结构。这种文件保存了解决方案的布局,包括项目、项目依赖、全局设置等信息。以下是一个.sln文件的基础结构和内容解析:EndProject。

weixin_30356433的博客 691

DLL 调用错误 -The value of ESP was not properly saved across a function call.

在调用DLL中的函数有时候会出现如下对话框的错误:Microsoft Visual C++ Debug Library:Debug Error:Program: ... Module:File: i386/chkesp.cLine: 42The value of ESP was not properly saved across a function call. This is usually a

HappySong的专栏 2万+

越过 __chkesp 检测的缓冲区溢出

越过 __chkesp 检测的缓冲区溢出

VC6对函数返回过程的优化(上)

写了一天的计划,轻松一下脑筋,看看VC++6.0是怎么优化函数的返回值的过程。创建一个叫test的控制台项目。编译然后把反汇编的选项打开。先作一个加法运算: c = a + b1:    // test.cpp : Defines the entry point for the console application.2:    //3:4:    #include "stdafx.h"5:6

why 494

产生chkesp的函数调用方式

产生__chkesp的函数调用方式.pdf

ROS中tf2_ros::Buffer.lookupTransform的正确使用姿势:从踩坑到填坑

本文深入解析了ROS中tf2_ros::Buffer.lookupTransform接口的正确使用方法,重点剖析了因tf2_ros::TransformListener生命周期管理不当导致的经典问题。文章提供了从理解Buffer与Listener共生关系、类成员设计黄金法则到参数详解与异常处理的完整避坑指南,并给出了构建健壮坐标变换工具类的实战方案,帮助开发者稳定实现机器人坐标系变换。

weixin_29253711的博客 134

VC6.0的BUG_2_return相关

无条件break、continue后的代码也会被删除),在文本处理中,想要删除一行的代码,那么按照此原理,对于下述代码该如何处理呢?**从而陷入死循环**汇编代码不停的。的处理机制出现BUG。所以上述代码就会变成。......

Deutsh的博客 237

微信小店推客分销系统源码获取与自研开发全攻略(2025年最新版)

源码选择建议快速试错:选用开源项目(如启航系统),3天可上线基础功能长期布局:购买商业源码授权,重点定制分佣规则与UI交互完全自研:适合年GMV过亿的大型企业,需前置投入风控与合规设计行动清单注册微信开放平台账号,完成视频号机构认证下载开源项目代码,部署本地测试环境联系三家源码供应商,获取合规性审计报告设计三级分佣比例表,通过法律顾问合规审查通过以上路径,可高效构建合规、稳定、高转化的微信小店推客分销系统,抢占2025年视频号电商红利。

2401_85184777的博客 1281

C++函数返回值的特殊情况(返回引用、非引用、引用左值)

1、返回非引用       string make_plural(size_t i,const string &word,const string &ending)       {              return (i==1)?word:word+ending;       }       以上函数,当i等于1时,函数返回word形参的副本;当i不等于1时函数返回一个临时

GROWTH 1853

保姆级教程:用Qlib和LightGBM从零搭建你的第一个AI量化选股策略(附完整代码)

本文提供了一份详细的教程,教你如何使用Qlib和LightGBM从零搭建AI量化选股策略。教程涵盖了环境配置、数据获取、特征工程、模型训练和策略回测等关键步骤,并附有完整代码和常见问题解决方案,适合量化投资初学者快速上手。

weixin_29191081的博客 444

侧杆试验 - 高速撞击 - 显式动力学 - ANSYS Workbench

显式动力学是一种时间积分方法,用于在速度很重要时执行动态模拟。显式动力学考虑快速变化的条件或不连续事件,例如自由落体、高速撞击和施加的负载。由于这些“非线性动力学”已集成到模拟中,因此显式动力学是模拟高度瞬态物理现象的首选。有些侧面碰撞是指车辆侧向撞上路边的坚硬物体,如树木或电线杆。这通常是由于驾驶员失去控制、超速、误判拐角或在湿滑路面上打滑造成的。

jianqimingtian的博客 1289

关于返回结构体的函数

【前言】写作本文,源于最近回复的《汇编中函数返回结构体的方法》一文。在网络上也已经有一些相关文章和相关问题,有的文章已经给出了一部分结果,但总体而言还缺少比较重要的结论。本文以分析 VC6 编译器,32 位架构为主来重复性分析这个话题。     (一)不超过 8 bytes 的小结构体可以通过 EDX:EAX 返回。     本文的范例代码取材于 《汇编中函数返回结构体的方法》一文,并在此基础上进行修改和试验。要研究的第一份代码如下,定义一个不超过 8 bytes 的小结构体,不超过 8 by...

edmond999的专栏 3952

新手避坑指南:用COMSOL Multiphysics仿真气体放电(汤逊vs.流注)

本文详细介绍了使用COMSOL Multiphysics仿真气体放电的实战指南,涵盖汤逊理论和流注模型的实现方法。通过对比两种放电模型的关键参数和物理场配置,帮助新手避免常见错误,准确预测气体击穿过程。文章还提供了工程应用案例,如高压绝缘子设计优化,展示了仿真技术在电力设备绝缘设计中的实际价值。

weixin_28716181的博客 472

VC6.0 编译优化开关

<br /><br />VC6.0编译器参数的设置主要通过VC的菜单项Project->Settings->C/C++页来完成。我们可以看到这一页的最下面Project Options中的内容,一般如下:<br /><br />/nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /Fp"Debug/WritingDlgTest.pch" /Yu"stdafx.h" /Fo"

kevin556187的专栏 1190

【YOLO系列】YOLOv4详解:模型结构、损失函数、训练方法及代码实现

摘要:YOLOv4在目标检测领域实现了精度与速度的平衡,通过CSPDarknet53骨干网络、SPP+PANet特征融合及CIoU损失函数等创新,在MS COCO数据集达到65.7% AP50,V100显卡实现62FPS实时检测。核心优化包括Mosaic数据增强、自对抗训练和解耦头结构,显著提升小目标检测和遮挡场景鲁棒性。代码实现采用CSP模块和SPP多尺度池化,兼顾计算效率与检测性能,为工业落地提供高效解决方案。(149字)

一碗白开水一 1357

使用 Python 构建 Reddit 热帖爬虫:抓取热门讨论帖和评论

在现代互联网中,Reddit 被誉为全球最大、最活跃的讨论平台之一,汇聚了各种主题的帖子、评论和社交互动。因此,抓取 Reddit 上的热门帖子和评论可以为我们提供一个丰富的文本数据源,可以用于情感分析、话题建模、趋势分析等应用。Reddit 提供了官方的 API,可以让开发者获取包括帖子、评论、用户信息等在内的各种数据。我们可以结合上述方法,抓取多个热门帖子,并将每个帖子的标题、作者、发布时间和评论内容保存到一个数据结构中。每个帖子的对象包含了丰富的信息,如标题、内容、发布时间、作者等。

2201_76125261的博客 381

我看VC2005中的返回值优化

一直以来,我都认为C++中,返回大对象或多个对象就是一场恶梦:额外的开销太多,对于原生类型还可以承受,但对大对象来说,就严重地影响效率。所以STL的容器再方便,那也仅限于操作int,double这些类型,换作是操作自定义类型,一不小心就会掉近了陷阱。不过这方面还好,有boost的指针类型对象容器可以利用,是一种比较好的解决方案。另一方面,返回值的处理也不能都像Blitz::Array操作那样,可以

Jarod 的半个程序员 1545

运放单电源供电和双电源供电的实际应用案例

文章摘要:本文对比分析了运放单电源与双电源供电的典型应用场景及电路设计要点。单电源供电适用于低成本、小体积设备,如便携音箱(5V供电+中点偏置)、工业4-20mA信号转换(12V供电+电压跟随)和物联网传感器(3.3V低功耗设计);双电源供电则适合高精度要求场景,如Hi-Fi音响(±15V对称输出)、医疗设备(±5V微弱信号放大)和精密仪器(±15V宽动态范围)。文末提供常见运放选型对照表,涵盖LM324、TL082等型号的供电参数与核心特性,为不同应用场景提供选型参考。(149字)

qq_37999850的博客 608

VC6.0工程设置介绍

打开或新建一个包 含至少一个工程的Workspace后,VC6的Project菜单中的“Settings…”命令就变为有效,选择它或者按下热键Alt+F7后,便可 调出工程设置对话框,这里面的选项将影响整个工程的建立和调试过程,因此很重要,虽然在一般情况下,其中的大多数选项都不用改变,但了解一下它们的含义能够消除我们心中存在的神秘感,并加深我们对VC工程的理解。在这个对话框 中,左上方的

冷秋魂的专栏 9189

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

上一篇: VC6对函数返回过程的优化(上)
下一篇: 脱壳经验谈之一----给脱壳新手的建议
whypp
博客等级 码龄21年 58粉丝 69原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值